diff --git a/protocol/app/flags/permissioned_keys_flags.go b/protocol/app/flags/permissioned_keys_flags.go new file mode 100644 index 00000000000..46c4779cf19 --- /dev/null +++ b/protocol/app/flags/permissioned_keys_flags.go @@ -0,0 +1,29 @@ +package flags + +import ( + "github.com/spf13/cobra" +) + +const ( + FlagAuthenticators = "authenticators" +) + +// AddTxPermissionedKeyFlagsToCmd adds common flags to a module tx command. +func AddTxPermissionedKeyFlagsToCmd(cmd *cobra.Command) { + f := cmd.Flags() + f.UintSlice(FlagAuthenticators, nil, "Authenticators to use for authenticating this transaction.") +} + +// GetPermisionedKeyAuthenticatorsForExtOptions returns the authenticators from the provided command flags. +func GetPermisionedKeyAuthenticatorsForExtOptions(cmd *cobra.Command) ([]uint64, error) { + flags := cmd.Flags() + values, err := flags.GetUintSlice(FlagAuthenticators) + if err == nil { + authenticators := make([]uint64, len(values)) + for i, v := range values { + authenticators[i] = uint64(v) + } + return authenticators, nil + } + return nil, err +} diff --git a/protocol/daemons/slinky/client/sidecar_version_checker.go b/protocol/daemons/slinky/client/sidecar_version_checker.go index 8e654f9ea8a..66e98e1e82a 100644 --- a/protocol/daemons/slinky/client/sidecar_version_checker.go +++ b/protocol/daemons/slinky/client/sidecar_version_checker.go @@ -3,6 +3,7 @@ package client import ( "context" "fmt" + "strings" "cosmossdk.io/log" "github.com/hashicorp/go-version" @@ -50,7 +51,13 @@ func (s *SidecarVersionCheckerImpl) CheckSidecarVersion(ctx context.Context) err if err != nil { return err } - current, err := version.NewVersion(slinkyResponse.Version) + + versionStr := slinkyResponse.Version + if idx := strings.LastIndex(versionStr, "/"); idx != -1 { + versionStr = versionStr[idx+1:] + } + + current, err := version.NewVersion(versionStr) if err != nil { return fmt.Errorf("failed to parse current version: %w", err) } diff --git a/protocol/daemons/slinky/client/sidecar_version_checker_test.go b/protocol/daemons/slinky/client/sidecar_version_checker_test.go index 11eb2d47fa9..5bd25393df6 100644 --- a/protocol/daemons/slinky/client/sidecar_version_checker_test.go +++ b/protocol/daemons/slinky/client/sidecar_version_checker_test.go @@ -2,6 +2,7 @@ package client_test import ( "context" + "strings" "testing" "cosmossdk.io/log" @@ -46,6 +47,36 @@ func TestSidecarVersionChecker(t *testing.T) { fetcher.Stop() }) + t.Run("Checks sidecar version passes with prefix before version", func(t *testing.T) { + slinky := mocks.NewOracleClient(t) + slinky.On("Stop").Return(nil) + slinky.On("Start", mock.Anything).Return(nil).Once() + require.True(t, strings.HasPrefix(client.MinSidecarVersion, "v"), "MinSidecarVersion must start with 'v'") + + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: client.MinSidecarVersion[1:], // Remove the "v" prefix + }, nil) + fetcher = client.NewSidecarVersionChecker(slinky, logger) + require.NoError(t, fetcher.Start(context.Background())) + require.NoError(t, fetcher.CheckSidecarVersion(context.Background())) + fetcher.Stop() + }) + + t.Run("Checks sidecar version passes without v prefix", func(t *testing.T) { + slinky := mocks.NewOracleClient(t) + slinky.On("Stop").Return(nil) + slinky.On("Start", mock.Anything).Return(nil).Once() + slinky.On("Version", mock.Anything, mock.Anything). + Return(&types.QueryVersionResponse{ + Version: "tests/integration/v1.2.0", + }, nil) + fetcher = client.NewSidecarVersionChecker(slinky, logger) + require.NoError(t, fetcher.Start(context.Background())) + require.NoError(t, fetcher.CheckSidecarVersion(context.Background())) + fetcher.Stop() + }) + t.Run("Checks sidecar version incorrectly formatted", func(t *testing.T) { slinky := mocks.NewOracleClient(t) slinky.On("Stop").Return(nil) diff --git a/protocol/docker-compose.yml b/protocol/docker-compose.yml index 6c0e0d2eafa..021c6ff5719 100644 --- a/protocol/docker-compose.yml +++ b/protocol/docker-compose.yml @@ -116,7 +116,7 @@ services: volumes: - ./localnet/dydxprotocol3:/dydxprotocol/chain/.dave/data slinky0: - image: ghcr.io/skip-mev/slinky-sidecar:v1.0.13 + image: ghcr.io/skip-mev/slinky-sidecar:v1.1.0 entrypoint: > sh -c "slinky --marketmap-provider dydx_migration_api --oracle-config /etc/slinky/oracle.json --log-std-out-level error" environment: diff --git a/protocol/x/accountplus/client/cli/tx.go b/protocol/x/accountplus/client/cli/tx.go index a4c11f63382..04cecb6b78d 100644 --- a/protocol/x/accountplus/client/cli/tx.go +++ b/protocol/x/accountplus/client/cli/tx.go @@ -1,6 +1,7 @@ package cli import ( + "encoding/base64" "fmt" "github.com/cosmos/cosmos-sdk/client" @@ -35,10 +36,14 @@ func CmdAddAuthenticator() *cobra.Command { if err != nil { return err } + config, err := base64.StdEncoding.DecodeString(args[2]) + if err != nil { + return err + } msg := types.MsgAddAuthenticator{ Sender: args[0], AuthenticatorType: args[1], - Data: []byte(args[2]), + Data: config, } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) }, diff --git a/protocol/x/clob/client/cli/tx_batch_cancel.go b/protocol/x/clob/client/cli/tx_batch_cancel.go index 3051f953584..b4b500b0051 100644 --- a/protocol/x/clob/client/cli/tx_batch_cancel.go +++ b/protocol/x/clob/client/cli/tx_batch_cancel.go @@ -7,6 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/spf13/cast" @@ -70,11 +73,30 @@ func CmdBatchCancel() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/clob/client/cli/tx_cancel_order.go b/protocol/x/clob/client/cli/tx_cancel_order.go index 303d3621920..96d3bdbd658 100644 --- a/protocol/x/clob/client/cli/tx_cancel_order.go +++ b/protocol/x/clob/client/cli/tx_cancel_order.go @@ -4,6 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/spf13/cast" @@ -58,11 +61,30 @@ func CmdCancelOrder() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/clob/client/cli/tx_place_order.go b/protocol/x/clob/client/cli/tx_place_order.go index 28e9d69ff11..5882df90d0b 100644 --- a/protocol/x/clob/client/cli/tx_place_order.go +++ b/protocol/x/clob/client/cli/tx_place_order.go @@ -4,6 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/spf13/cast" @@ -77,11 +80,30 @@ func CmdPlaceOrder() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/sending/client/cli/tx_create_transfer.go b/protocol/x/sending/client/cli/tx_create_transfer.go index dfb8073bdcb..c161d37cc9e 100644 --- a/protocol/x/sending/client/cli/tx_create_transfer.go +++ b/protocol/x/sending/client/cli/tx_create_transfer.go @@ -6,6 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" @@ -65,11 +68,30 @@ func CmdCreateTransfer() *cobra.Command { if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/sending/client/cli/tx_deposit_to_subaccount.go b/protocol/x/sending/client/cli/tx_deposit_to_subaccount.go index 07f53c9e8e6..13730b16043 100644 --- a/protocol/x/sending/client/cli/tx_deposit_to_subaccount.go +++ b/protocol/x/sending/client/cli/tx_deposit_to_subaccount.go @@ -4,6 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" @@ -60,11 +63,30 @@ Note, the '--from' flag is ignored as it is implied from [sender_key_or_address] if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd } diff --git a/protocol/x/sending/client/cli/tx_withdraw_from_subaccount.go b/protocol/x/sending/client/cli/tx_withdraw_from_subaccount.go index 9302f59d022..ae1f57cabec 100644 --- a/protocol/x/sending/client/cli/tx_withdraw_from_subaccount.go +++ b/protocol/x/sending/client/cli/tx_withdraw_from_subaccount.go @@ -4,6 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + customflags "github.com/dydxprotocol/v4-chain/protocol/app/flags" + aptypes "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types" assettypes "github.com/dydxprotocol/v4-chain/protocol/x/assets/types" "github.com/dydxprotocol/v4-chain/protocol/x/sending/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" @@ -60,11 +63,30 @@ Note, the '--from' flag is ignored as it is implied from [sender_key_or_address] if err := msg.ValidateBasic(); err != nil { return err } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + authenticatorIds, err := customflags.GetPermisionedKeyAuthenticatorsForExtOptions(cmd) + if err == nil && len(authenticatorIds) > 0 { + value, err := codectypes.NewAnyWithValue( + &aptypes.TxExtension{ + SelectedAuthenticators: authenticatorIds, + }, + ) + if err != nil { + return err + } + txf = txf.WithNonCriticalExtensionOptions(value) + } + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, } flags.AddTxFlagsToCmd(cmd) + customflags.AddTxPermissionedKeyFlagsToCmd(cmd) return cmd }