diff --git a/UPGRADING.md b/UPGRADING.md index 1096386992..93b745cb74 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -32,6 +32,54 @@ clientCtx = clientCtx. Refer to SimApp `root_v2.go` and `root.go` for an example with an app v2 and a legacy app. +#### Textual sign mode + +A new sign mode is available in the SDK that produces more human readable output, currently only available on Ledger +devices but soon to be implemented in other UIs. + +:::tip +This sign mode does not allow offline signing +::: + +When using (legacy) application wiring, the following must be added to `app.go` after setting the app's bank keeper: + +```golang + enabledSignModes := append(tx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL) + txConfigOpts := tx.ConfigOptions{ + EnabledSignModes: enabledSignModes, + TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper), + } + txConfig, err := tx.NewTxConfigWithOptions( + appCodec, + txConfigOpts, + ) + if err != nil { + log.Fatalf("Failed to create new TxConfig with options: %v", err) + } + app.txConfig = txConfig +``` + +And in the application client (usually `root.go`): + +```golang + if !clientCtx.Offline { + txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) + txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx) + txConfigWithTextual, err := tx.NewTxConfigWithOptions( + codec.NewProtoCodec(clientCtx.InterfaceRegistry), + txConfigOpts, + ) + if err != nil { + return err + } + clientCtx = clientCtx.WithTxConfig(txConfigWithTextual) + } +``` + +When using `depinject` / `app v2`, **it's enabled by default** if there's a bank keeper present. + +To learn more see the [docs](https://docs.cosmos.network/main/learn/advanced/transactions#sign_mode_textual) and the [ADR-050](https://docs.cosmos.network/main/build/architecture/adr-050-sign-mode-textual). + ### Modules #### `x/group` diff --git a/client/v2/autocli/msg.go b/client/v2/autocli/msg.go index 096450ee4c..5e0db2fb25 100644 --- a/client/v2/autocli/msg.go +++ b/client/v2/autocli/msg.go @@ -6,6 +6,7 @@ import ( "github.com/cockroachdb/errors" "github.com/spf13/cobra" + "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/types/dynamicpb" @@ -115,17 +116,19 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor } // enable sign mode textual and config tx options - b.TxConfigOpts.EnabledSignModes = append(b.TxConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) - b.TxConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx) + if !clientCtx.Offline && !slices.Contains(b.TxConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) { + b.TxConfigOpts.EnabledSignModes = append(b.TxConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) + b.TxConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx) + } - txConfigWithTextual, err := authtx.NewTxConfigWithOptions( + txConfig, err := authtx.NewTxConfigWithOptions( codec.NewProtoCodec(clientCtx.InterfaceRegistry), b.TxConfigOpts, ) if err != nil { return err } - clientCtx = clientCtx.WithTxConfig(txConfigWithTextual) + clientCtx = clientCtx.WithTxConfig(txConfig) clientCtx.Output = cmd.OutOrStdout() // set signer to signer field if empty diff --git a/client/v2/go.mod b/client/v2/go.mod index 64a9374762..ccff3bb9ef 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -13,6 +13,7 @@ require ( github.com/cosmos/gogoproto v1.4.11 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 gotest.tools/v3 v3.5.1 @@ -139,7 +140,6 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect diff --git a/docs/learn/advanced/01-transactions.md b/docs/learn/advanced/01-transactions.md index 13d3727b66..c2d779a830 100644 --- a/docs/learn/advanced/01-transactions.md +++ b/docs/learn/advanced/01-transactions.md @@ -94,7 +94,13 @@ create the final transaction by appending a fee. Note that the fee payer of the #### `SIGN_MODE_TEXTUAL` -`SIGN_MODE_TEXTUAL` is a new sign mode for delivering a better signing experience on hardware wallets, it is currently still under implementation. If you wish to learn more, please refer to [ADR-050](https://github.com/cosmos/cosmos-sdk/pull/10701). +`SIGN_MODE_TEXTUAL` is a new sign mode for delivering a better signing experience on hardware wallets and it is included in the v0.50 release. In this mode, the signer signs over the human-readable string representation of the transaction (CBOR) and makes all data being displayed easier to read. The data is formatted as screens, and each screen is meant to be displayed in its entirety even on small devices like the Ledger Nano. + +There are also _expert_ screens, which will only be displayed if the user has chosen that option in its hardware device. These screens contain things like account number, account sequence and the sign data hash. + +Data is formatted using a set of `ValueRenderer` which the SDK provides defaults for all the known messages and value types. Chain developers can also opt to implement their own `ValueRenderer` for a type/message if they'd like to display information differently. + +If you wish to learn more, please refer to [ADR-050](../../build/architecture/adr-050-sign-mode-textual.md). #### Custom Sign modes diff --git a/simapp/app.go b/simapp/app.go index 578f6aae67..e13f0456b5 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -66,6 +66,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/msgservice" + sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -75,6 +76,7 @@ import ( authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" @@ -146,7 +148,7 @@ type SimApp struct { // keepers AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper + BankKeeper bankkeeper.BaseKeeper StakingKeeper *stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper @@ -286,6 +288,22 @@ func NewSimApp( authtypes.NewModuleAddress(govtypes.ModuleName).String(), logger, ) + + // optional: enable sign mode textual by overwriting the default tx config (after setting the bank keeper) + enabledSignModes := append(tx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL) + txConfigOpts := tx.ConfigOptions{ + EnabledSignModes: enabledSignModes, + TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper), + } + txConfig, err := tx.NewTxConfigWithOptions( + appCodec, + txConfigOpts, + ) + if err != nil { + panic(err) + } + app.txConfig = txConfig + app.StakingKeeper = stakingkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), app.AccountKeeper, app.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), authcodec.NewBech32Codec(sdk.Bech32PrefixValAddr), authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr), ) @@ -457,7 +475,7 @@ func NewSimApp( app.ModuleManager.RegisterInvariants(app.CrisisKeeper) app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) - err := app.ModuleManager.RegisterServices(app.configurator) + err = app.ModuleManager.RegisterServices(app.configurator) if err != nil { panic(err) } diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 1b82913679..7ff428e91a 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -13,7 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" - "github.com/cosmos/cosmos-sdk/codec" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" @@ -73,20 +72,24 @@ func NewRootCmd() *cobra.Command { } // This needs to go after CreateClientConfig, as that function - // sets the RPC client needed for SIGN_MODE_TEXTUAL. - enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) - txConfigOpts := tx.ConfigOptions{ - EnabledSignModes: enabledSignModes, - TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), + // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode + // is only available if the client is online. + if !initClientCtx.Offline { + enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) + txConfigOpts := tx.ConfigOptions{ + EnabledSignModes: enabledSignModes, + TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), + } + txConfig, err := tx.NewTxConfigWithOptions( + initClientCtx.Codec, + txConfigOpts, + ) + if err != nil { + return err + } + + initClientCtx = initClientCtx.WithTxConfig(txConfig) } - txConfigWithTextual, err := tx.NewTxConfigWithOptions( - codec.NewProtoCodec(encodingConfig.InterfaceRegistry), - txConfigOpts, - ) - if err != nil { - return err - } - initClientCtx = initClientCtx.WithTxConfig(txConfigWithTextual) if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { return err diff --git a/simapp/simd/cmd/root_v2.go b/simapp/simd/cmd/root_v2.go index 170aa94b0f..74cfdcced4 100644 --- a/simapp/simd/cmd/root_v2.go +++ b/simapp/simd/cmd/root_v2.go @@ -23,9 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" - txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -78,17 +76,6 @@ func NewRootCmd() *cobra.Command { return err } - // This needs to go after CreateClientConfig, as that function sets the RPC client needed for SIGN_MODE_TEXTUAL. - txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) - txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx) - txConfigWithTextual, err := tx.NewTxConfigWithOptions( - codec.NewProtoCodec(clientCtx.InterfaceRegistry), - txConfigOpts, - ) - if err != nil { - return err - } - clientCtx = clientCtx.WithTxConfig(txConfigWithTextual) if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil { return err }