From 0051e87c091181dc14fa4011181dacf4bceaef4d Mon Sep 17 00:00:00 2001 From: Tian Date: Tue, 17 Sep 2024 10:03:26 -0400 Subject: [PATCH] allow megavault operator to set vault params (#2262) --- protocol/app/msgs/internal_msgs.go | 2 - protocol/app/msgs/internal_msgs_test.go | 2 - protocol/app/msgs/normal_msgs.go | 2 + protocol/app/msgs/normal_msgs_test.go | 2 + protocol/lib/ante/internal_msg.go | 1 - protocol/x/vault/client/cli/tx.go | 69 +++++++++++++++++++ protocol/x/vault/client/cli/util.go | 21 ++++++ .../keeper/msg_server_set_vault_params.go | 9 +-- .../msg_server_set_vault_params_test.go | 65 ++++++++++++----- 9 files changed, 146 insertions(+), 27 deletions(-) diff --git a/protocol/app/msgs/internal_msgs.go b/protocol/app/msgs/internal_msgs.go index 1403318f96..e11ae894a3 100644 --- a/protocol/app/msgs/internal_msgs.go +++ b/protocol/app/msgs/internal_msgs.go @@ -196,8 +196,6 @@ var ( "/dydxprotocol.stats.MsgUpdateParamsResponse": nil, // vault - "/dydxprotocol.vault.MsgSetVaultParams": &vault.MsgSetVaultParams{}, - "/dydxprotocol.vault.MsgSetVaultParamsResponse": nil, "/dydxprotocol.vault.MsgUnlockShares": &vault.MsgUnlockShares{}, "/dydxprotocol.vault.MsgUnlockSharesResponse": nil, "/dydxprotocol.vault.MsgUpdateDefaultQuotingParams": &vault.MsgUpdateDefaultQuotingParams{}, diff --git a/protocol/app/msgs/internal_msgs_test.go b/protocol/app/msgs/internal_msgs_test.go index 0b183c962e..2b2e18cdc1 100644 --- a/protocol/app/msgs/internal_msgs_test.go +++ b/protocol/app/msgs/internal_msgs_test.go @@ -152,8 +152,6 @@ func TestInternalMsgSamples_Gov_Key(t *testing.T) { "/dydxprotocol.stats.MsgUpdateParamsResponse", // vault - "/dydxprotocol.vault.MsgSetVaultParams", - "/dydxprotocol.vault.MsgSetVaultParamsResponse", "/dydxprotocol.vault.MsgUnlockShares", "/dydxprotocol.vault.MsgUnlockSharesResponse", "/dydxprotocol.vault.MsgUpdateDefaultQuotingParams", diff --git a/protocol/app/msgs/normal_msgs.go b/protocol/app/msgs/normal_msgs.go index 4ebcb70452..720a703d8c 100644 --- a/protocol/app/msgs/normal_msgs.go +++ b/protocol/app/msgs/normal_msgs.go @@ -248,6 +248,8 @@ var ( // vault "/dydxprotocol.vault.MsgDepositToMegavault": &vault.MsgDepositToMegavault{}, "/dydxprotocol.vault.MsgDepositToMegavaultResponse": nil, + "/dydxprotocol.vault.MsgSetVaultParams": &vault.MsgSetVaultParams{}, + "/dydxprotocol.vault.MsgSetVaultParamsResponse": nil, } NormalMsgsSlinky = map[string]sdk.Msg{ diff --git a/protocol/app/msgs/normal_msgs_test.go b/protocol/app/msgs/normal_msgs_test.go index d46fbe4611..c50fd1f3cb 100644 --- a/protocol/app/msgs/normal_msgs_test.go +++ b/protocol/app/msgs/normal_msgs_test.go @@ -149,6 +149,8 @@ func TestNormalMsgs_Key(t *testing.T) { // vault "/dydxprotocol.vault.MsgDepositToMegavault", "/dydxprotocol.vault.MsgDepositToMegavaultResponse", + "/dydxprotocol.vault.MsgSetVaultParams", + "/dydxprotocol.vault.MsgSetVaultParamsResponse", // ibc application module: ICA "/ibc.applications.interchain_accounts.v1.InterchainAccount", diff --git a/protocol/lib/ante/internal_msg.go b/protocol/lib/ante/internal_msg.go index e58e43d43b..0111dfa177 100644 --- a/protocol/lib/ante/internal_msg.go +++ b/protocol/lib/ante/internal_msg.go @@ -129,7 +129,6 @@ func IsInternalMsg(msg sdk.Msg) bool { *stats.MsgUpdateParams, // vault - *vault.MsgSetVaultParams, *vault.MsgUnlockShares, *vault.MsgUpdateDefaultQuotingParams, *vault.MsgUpdateOperatorParams, diff --git a/protocol/x/vault/client/cli/tx.go b/protocol/x/vault/client/cli/tx.go index 21d7f1c4ce..024eb5d17a 100644 --- a/protocol/x/vault/client/cli/tx.go +++ b/protocol/x/vault/client/cli/tx.go @@ -1,7 +1,9 @@ package cli import ( + "encoding/json" "fmt" + "strconv" "github.com/spf13/cast" "github.com/spf13/cobra" @@ -25,6 +27,7 @@ func GetTxCmd() *cobra.Command { } cmd.AddCommand(CmdDepositToMegavault()) + cmd.AddCommand(CmdSetVaultParams()) return cmd } @@ -72,3 +75,69 @@ func CmdDepositToMegavault() *cobra.Command { return cmd } + +func CmdSetVaultParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-vault-params [authority] [vault_type] [vault_number] [status] [quoting_params_json]", + Short: "Broadcast message SetVaultParams", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) (err error) { + // Parse vault type. + vaultType, err := GetVaultTypeFromString(args[1]) + if err != nil { + return err + } + + // Parse vault number. + vaultNumber, err := strconv.ParseUint(args[2], 10, 32) + if err != nil { + return err + } + + // Parse status. + status, err := GetVaultStatusFromString(args[3]) + if err != nil { + return err + } + + // Parse quoting_params (optional). + var quotingParams *types.QuotingParams + if args[4] != "" { + if err := json.Unmarshal([]byte(args[4]), "ingParams); err != nil { + return fmt.Errorf("invalid quoting params JSON: %w", err) + } + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + // Create MsgSetVaultParams. + msg := &types.MsgSetVaultParams{ + Authority: args[0], + VaultId: types.VaultId{ + Type: vaultType, + Number: uint32(vaultNumber), + }, + VaultParams: types.VaultParams{ + Status: status, + QuotingParams: quotingParams, // nil if not provided. + }, + } + + // Validate vault params. + if err := msg.VaultParams.Validate(); err != nil { + return err + } + + // Broadcast or generate the transaction. + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + // Add the necessary flags. + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/protocol/x/vault/client/cli/util.go b/protocol/x/vault/client/cli/util.go index 0d5834a595..cc1c501887 100644 --- a/protocol/x/vault/client/cli/util.go +++ b/protocol/x/vault/client/cli/util.go @@ -15,3 +15,24 @@ func GetVaultTypeFromString(rawType string) (vaultType types.VaultType, err erro return vaultType, fmt.Errorf("invalid vault type: %s", rawType) } } + +// GetVaultStatusFromString returns a vault status from a string. +func GetVaultStatusFromString(rawStatus string) (vaultStatus types.VaultStatus, err error) { + switch rawStatus { + case "deactivated": + return types.VaultStatus_VAULT_STATUS_DEACTIVATED, nil + case "stand_by": + return types.VaultStatus_VAULT_STATUS_STAND_BY, nil + case "quoting": + return types.VaultStatus_VAULT_STATUS_QUOTING, nil + case "close_only": + return types.VaultStatus_VAULT_STATUS_CLOSE_ONLY, nil + default: + return vaultStatus, fmt.Errorf(`invalid vault status: %s. + options are: + - deactivated + - stand_by + - quoting + - close_only`, rawStatus) + } +} diff --git a/protocol/x/vault/keeper/msg_server_set_vault_params.go b/protocol/x/vault/keeper/msg_server_set_vault_params.go index f1aa758f01..295b421d7f 100644 --- a/protocol/x/vault/keeper/msg_server_set_vault_params.go +++ b/protocol/x/vault/keeper/msg_server_set_vault_params.go @@ -15,8 +15,11 @@ func (k msgServer) SetVaultParams( goCtx context.Context, msg *types.MsgSetVaultParams, ) (*types.MsgSetVaultParamsResponse, error) { - // Check if authority is valid. - if !k.HasAuthority(msg.Authority) { + ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) + operator := k.GetOperatorParams(ctx).Operator + + // Check if authority is valid (must be a module authority or operator). + if !k.HasAuthority(msg.Authority) && msg.Authority != operator { return nil, errorsmod.Wrapf( govtypes.ErrInvalidSigner, "invalid authority %s", @@ -24,8 +27,6 @@ func (k msgServer) SetVaultParams( ) } - ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) - // Validate parameters. if err := msg.VaultParams.Validate(); err != nil { return nil, err diff --git a/protocol/x/vault/keeper/msg_server_set_vault_params_test.go b/protocol/x/vault/keeper/msg_server_set_vault_params_test.go index 587a511301..1e1b812995 100644 --- a/protocol/x/vault/keeper/msg_server_set_vault_params_test.go +++ b/protocol/x/vault/keeper/msg_server_set_vault_params_test.go @@ -9,42 +9,57 @@ import ( testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/cometbft/cometbft/types" "github.com/dydxprotocol/v4-chain/protocol/x/vault/keeper" - "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" + vaulttypes "github.com/dydxprotocol/v4-chain/protocol/x/vault/types" "github.com/stretchr/testify/require" ) func TestMsgSetVaultParams(t *testing.T) { tests := map[string]struct { + // Operator. + operator string // Msg. - msg *types.MsgSetVaultParams + msg *vaulttypes.MsgSetVaultParams // Expected error expectedErr string }{ - "Success - Vault Clob 0": { - msg: &types.MsgSetVaultParams{ + "Success - Gov Authority, Vault Clob 0": { + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: lib.GovModuleAddress.String(), VaultId: constants.Vault_Clob0, VaultParams: constants.VaultParams, }, }, - "Success - Vault Clob 1": { - msg: &types.MsgSetVaultParams{ + "Success - Gov Authority, Vault Clob 1": { + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: lib.GovModuleAddress.String(), VaultId: constants.Vault_Clob1, VaultParams: constants.VaultParams, }, }, - "Failure - Invalid Authority": { - msg: &types.MsgSetVaultParams{ + "Success - Operator Authority, Vault Clob 1": { + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: constants.AliceAccAddress.String(), + VaultId: constants.Vault_Clob1, + VaultParams: constants.VaultParams, + }, + }, + "Failure - Invalid Authority": { + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ + Authority: constants.BobAccAddress.String(), // not a module authority or operator. VaultId: constants.Vault_Clob0, VaultParams: constants.VaultParams, }, expectedErr: "invalid authority", }, "Failure - Empty Authority": { - msg: &types.MsgSetVaultParams{ + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: "", VaultId: constants.Vault_Clob0, VaultParams: constants.VaultParams, @@ -52,12 +67,13 @@ func TestMsgSetVaultParams(t *testing.T) { expectedErr: "invalid authority", }, "Failure - Vault Clob 0. Invalid Quoting Params": { - msg: &types.MsgSetVaultParams{ + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: lib.GovModuleAddress.String(), VaultId: constants.Vault_Clob0, - VaultParams: types.VaultParams{ - Status: types.VaultStatus_VAULT_STATUS_STAND_BY, - QuotingParams: &types.QuotingParams{ + VaultParams: vaulttypes.VaultParams{ + Status: vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY, + QuotingParams: &vaulttypes.QuotingParams{ Layers: 3, SpreadMinPpm: 4_000, SpreadBufferPpm: 2_000, @@ -68,23 +84,36 @@ func TestMsgSetVaultParams(t *testing.T) { }, }, }, - expectedErr: types.ErrInvalidActivationThresholdQuoteQuantums.Error(), + expectedErr: vaulttypes.ErrInvalidActivationThresholdQuoteQuantums.Error(), }, "Failure - Vault Clob 1. Unspecified status": { - msg: &types.MsgSetVaultParams{ + operator: constants.AliceAccAddress.String(), + msg: &vaulttypes.MsgSetVaultParams{ Authority: lib.GovModuleAddress.String(), VaultId: constants.Vault_Clob0, - VaultParams: types.VaultParams{ + VaultParams: vaulttypes.VaultParams{ QuotingParams: &constants.QuotingParams, }, }, - expectedErr: types.ErrUnspecifiedVaultStatus.Error(), + expectedErr: vaulttypes.ErrUnspecifiedVaultStatus.Error(), }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { - tApp := testapp.NewTestAppBuilder(t).Build() + tApp := testapp.NewTestAppBuilder(t).WithGenesisDocFn(func() (genesis types.GenesisDoc) { + genesis = testapp.DefaultGenesis() + // Set megavault operator. + testapp.UpdateGenesisDocWithAppStateForModule( + &genesis, + func(genesisState *vaulttypes.GenesisState) { + genesisState.OperatorParams = vaulttypes.OperatorParams{ + Operator: tc.operator, + } + }, + ) + return genesis + }).Build() ctx := tApp.InitChain() k := tApp.App.VaultKeeper ms := keeper.NewMsgServerImpl(k)