docs(adr): ADR-050 SIGN_MODE_TEXTUAL (#10701)

## [Rendered ADR](https://github.com/cosmos/cosmos-sdk/blob/am/adr-textual/docs/architecture/adr-050-sign-mode-textual.md)

## Description



Closes: #6513

Support documents:
- context: #6513
- specification living doc HackmD: https://hackmd.io/7RkGfv_rQAaZzEigUYhcXw



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Amaury 2022-05-27 17:32:16 +02:00 committed by GitHub
parent e2ec380db5
commit 0cee47dbd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 789 additions and 0 deletions

View File

@ -0,0 +1,284 @@
# ADR 050: SIGN_MODE_TEXTUAL: Annex 1 Value Renderers
## Changelog
- Dec 06, 2021: Initial Draft
- Feb 07, 2022: Draft read and concept-ACKed by the Ledger team.
## Status
Accepted. Implementation started. Small value renderers details still need to be polished.
## Abstract
This Annex describes value renderers, which are used for displaying Protobuf values in a human-friendly way using a string array.
## Value Renderers
Value Renderers describe how values of different Protobuf types should be encoded as a string array. Value renderers can be formalized as a set of bijective functions `func renderT(value T) []string`, where `T` is one of the below Protobuf types for which this spec is defined.
### Protobuf `number`
- Applies to:
- protobuf numeric integer types (`int{32,64}`, `uint{32,64}`, `sint{32,64}`, `fixed{32,64}`, `sfixed{32,64}`)
- strings whose `customtype` is `github.com/cosmos/cosmos-sdk/types.Int` or `github.com/cosmos/cosmos-sdk/types.Dec`
- bytes whose `customtype` is `github.com/cosmos/cosmos-sdk/types.Int` or `github.com/cosmos/cosmos-sdk/types.Dec`
- Trailing decimal zeroes are always removed
- Formatting with `'`s for every three integral digits.
- Usage of `.` to denote the decimal delimiter.
#### Examples
- `1000` (uint64) -> `1'000`
- `"1000000.00"` (string representing a Dec) -> `1'000'000`
- `"1000000.10"` (string representing a Dec) -> `1'000'000.1`
### `coin`
- Applies to `cosmos.base.v1beta1.Coin`.
- Denoms are converted to `display` denoms using `Metadata` (if available). **This requires a state query**. The definition of `Metadata` can be found in the [bank Protobuf definition](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc1/proto/cosmos/bank/v1beta1/bank.proto#L79-L108). If the `display` field is empty or nil, then we do not perform any denom conversion.
- Amounts are converted to `display` denom amounts and rendered as `number`s above
- We do not change the capitalization of the denom. In practice, `display` denoms are stored in lowercase in state (e.g. `10 atom`), however they are often showed in UPPERCASE in everyday life (e.g. `10 ATOM`). Value renderers keep the case used in state, but we may recommend chains changing the denom metadata to be uppercase for better user display.
- One space between the denom and amount (e.g. `10 atom`).
- In the future, IBC denoms could maybe be converted to DID/IIDs, if we can find a robust way for doing this (ex. `cosmos:cosmos:hub:bank:denom:atom`)
#### Examples
- `1000000000uatom` -> `["1'000 atom"]`, because atom is the metadata's display denom.
### `coins`
- an array of `coin` is display as the concatenation of each `coin` encoded as the specification above, the joined together with the delimiter `", "` (a comma and a space, no quotes around).
- the list of coins is ordered by unicode code point of the display denom: `A-Z` < `a-z`. For example, the string `aAbBcC` would be sorted `ABCabc`.
### Example
- `["3cosm", "2000000uatom"]` -> `2 atom, 3 COSM` (assuming the display denoms are `atom` and `COSM`)
- `["10atom", "20Acoin"]` -> `20 Acoin, 10 atom` (assuming the display denoms are `atom` and `Acoin`)
### `repeated`
- Applies to all `repeated` fields, except `cosmos.tx.v1beta1.TxBody#Messages`, which has a particular encoding (see [ADR-050](./adr-050-sign-mode-textual.md)).
- A repeated type has the following template:
```
<message_name> has <int> <field_name>
<field_name> (<int>/<int>): <value rendered 1st line>
<optional value rendered in the next lines>
<field_name> (<int>/<int>): <value rendered 1st line>
<optional value rendered in the next lines>
End of <field_name>.
```
where:
- `message_name` is the name of the Protobuf message which holds the `repeated` field,
- `int` is the length of the array,
- `field_name` is the Protobuf field name of the repeated field,
- add an optional `s` at the end if `<int> > 1` and the `field_name` doesn't already end with `s`.
#### Examples
Given the proto definition:
```proto
message AllowedMsgAllowance {
repeated string allowed_messages = 1;
}
```
and initializing with:
```go
x := []AllowedMsgAllowance{"cosmos.bank.v1beta1.MsgSend", "cosmos.gov.v1.MsgVote"}
```
we have the following value-rendered encoding:
```
Allowed messages: 2 strings
Allowed messages (1/2): cosmos.bank.v1beta1.MsgSend
Allowed messages (2/2): cosmos.gov.v1.MsgVote
End of Allowed messages
```
### `message`
- Applies to Protobuf messages whose name does not start with `Msg`
- For `sdk.Msg`s, please see [ADR-050](./adr-050-sign-mode-textual.md)
- alternatively, we can decide to add a protobuf option to denote messages that are `sdk.Msg`s.
- Field names follow [sentence case](https://en.wiktionary.org/wiki/sentence_case)
- replace `_` with a spaces
- capitalize first letter of the setence
- Field names are ordered by their Protobuf field number
- Nesting:
- if a field contains a nested message, we value-render the underlying message using the template:
```
<field_name>: <1st line of value-rendered message>
> <lines 2-n of value-rendered message> // Notice the `>` prefix.
```
- `>` character is used to denote nesting. For each additional level of nesting, add `>`.
#### Examples
Given the following Protobuf messages:
```proto
enum VoteOption {
VOTE_OPTION_UNSPECIFIED = 0;
VOTE_OPTION_YES = 1;
VOTE_OPTION_ABSTAIN = 2;
VOTE_OPTION_NO = 3;
VOTE_OPTION_NO_WITH_VETO = 4;
}
message WeightedVoteOption {
VoteOption option = 1;
string weight = 2 [(cosmos_proto.scalar) = "cosmos.Dec"];
}
message Vote {
uint64 proposal_id = 1;
string voter = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
reserved 3;
repeated WeightedVoteOption options = 4;
}
```
we get the following encoding for the `Vote` message:
```
Vote object
> Proposal id: 4
> Vote: cosmos1abc...def
> Options: 2 WeightedVoteOptions
> Options (1/2): WeightedVoteOption object
>> Option: Yes
>> Weight: 0.7
> Options (2/2): WeightedVoteOption object
>> Option: No
>> Weight: 0.3
> End of Options
```
### Enums
- String case convention: snake case to sentence case
- Allow optional annotation for textual name (TBD)
- Algorithm:
- convert enum name (`VoteOption`) to snake_case (`VOTE_OPTION`)
- truncate that prefix + `_` from the enum name if it exists (`VOTE_OPTION_` gets stripped from `VOTE_OPTION_YES` -> `YES`)
- convert rest to sentence case: `YES` -> `Yes`
- in summary: `VOTE_OPTION_YES` -> `Yes`
#### Examples
See example above with `message Vote{}`.
### `google.protobuf.Any`
- Applies to `google.protobuf.Any`
- Rendered as:
```
Object: <type_url>
> <value rendered underlying message>
```
#### Examples
```
Object: /cosmos.gov.v1.Vote
> Proposal id: 4
> Vote: cosmos1abc...def
> Options: 2 WeightedVoteOptions
> Options (1/2): WeightedVoteOption object
>> Option: Yes
>> Weight: 0.7
> Options (2/2): WeightedVoteOption object
>> Option: No
>> Weight: 0.3
> End of Options
```
### `google.protobuf.Timestamp`
Rendered as either ISO8601 (`2021-01-01T12:00:00Z`).
### `google.protobuf.Duration` (TODO)
- rendered in terms of weeks, days, hours, minutes and seconds as these time units can be measured independently of any calendar and duration values are in seconds (so months and years can't be used precisely)
- total seconds values included at the end so users have both pieces of information
- Ex:
- `1483530 seconds` -> `2 weeks, 3 days, 4 hours, 5 minutes, 30 seconds (1483530 seconds total)`
### bytes
- Bytes are rendered in base64.
### address bytes
We currently use `string` types in protobuf for addresses so this may not be needed, but if any address bytes are used in sign mode textual they should be rendered with bech32 formatting
### strings
Strings are rendered as-is.
### Default Values
- Default Protobuf values for each field are skipped.
#### Example
```proto
message TestData {
string signer = 1;
string metadata = 2;
}
```
```go
myTestData := TestData{
Signer: "cosmos1abc"
}
```
We get the following encoding for the `TestData` message:
```
TestData object
> Signer: cosmos1abc
```
### [ABANDONED] Custom `msg_title` instead of Msg `type_url`
_This paragraph is in the Annex for informational purposes only, and will be removed in a next update of the ADR._
<details>
<summary>Click to see abandoned idea.</summary>
- all protobuf messages to be used with `SIGN_MODE_TEXTUAL` CAN have a short title associated with them that can be used in format strings whenever the type URL is explicitly referenced via the `cosmos.msg.v1.textual.msg_title` Protobuf message option.
- if this option is not specified for a Msg, then the Protobuf fully qualified name will be used.
```proto
message MsgSend {
option (cosmos.msg.v1.textual.msg_title) = "bank send coins";
}
```
- they MUST be unique per message, per chain
#### Examples
- `cosmos.gov.v1.MsgVote` -> `governance v1 vote`
#### Best Pratices
We recommend to use this option only for `Msg`s whose Protobuf fully qualified name can be hard to understand. As such, the two examples above (`MsgSend` and `MsgVote`) are not good examples to be used with `msg_title`. We still allow `msg_title` for chains who might have `Msg`s with complex or non-obvious names.
In those cases, we recommend to drop the version (e.g. `v1`) in the string if there's only one version of the module on chain. This way, the bijective mapping can figure out which message each string corresponds to. If multiple Protobuf versions of the same module exist on the same chain, we recommend keeping the first `msg_title` with version, and the second `msg_title` with version (e.g. `v2`):
- `mychain.mymodule.v1.MsgDo` -> `mymodule do something`
- `mychain.mymodule.v2.MsgDo` -> `mymodule v2 do something`
</details>

View File

@ -0,0 +1,505 @@
# ADR 050: SIGN_MODE_TEXTUAL
## Changelog
- Dec 06, 2021: Initial Draft.
- Feb 07, 2022: Draft read and concept-ACKed by the Ledger team.
- May 16, 2022: Change status to Accepted.
## Status
Accepted. Implementation started. Small value renderers details still need to be polished.
## Abstract
This ADR specifies SIGN_MODE_TEXTUAL, a new string-based sign mode that is targetted at signing with hardware devices.
## Context
Protobuf-based SIGN_MODE_DIRECT was introduced in [ADR-020](./adr-020-protobuf-transaction-encoding.md) and is intended to replace SIGN_MODE_LEGACY_AMINO_JSON in most situations, such as mobile wallets and CLI keyrings. However, the [Ledger](https://www.ledger.com/) hardware wallet is still using SIGN_MODE_LEGACY_AMINO_JSON for displaying the sign bytes to the user. Hardware wallets cannot transition to SIGN_MODE_DIRECT as:
- SIGN_MODE_DIRECT is binary-based and thus not suitable for display to end-users. Technically, hardware wallets could simply display the sign bytes to the user. But this would be considered as blind signing, and is a security concern.
- hardware cannot decode the protobuf sign bytes due to memory constraints, as the Protobuf definitions would need to be embedded on the hardware device.
In an effort to remove Amino from the SDK, a new sign mode needs to be created for hardware devices. [Initial discussions](https://github.com/cosmos/cosmos-sdk/issues/6513) propose a string-based sign mode, which this ADR formally specifies.
## Decision
We propose to have SIGN_MODE_TEXTUALs signing payload `SignDocTextual` to be an array of strings, encoded as a `\n`-delimited string (see point #9). Each string corresponds to one "screen" on the hardware wallet device, with no (or little) additional formatting done by the hardware wallet itself.
```proto
message SignDocTextual {
repeated string screens = 1;
}
```
The string array MUST follow the specifications below.
### 1. Bijectivity with Protobuf transactions
The encoding and decoding operations between a Protobuf transaction (whose definition can be found [here](https://github.com/cosmos/cosmos-sdk/blob/master/proto/cosmos/tx/v1beta1/tx.proto#L13)) and the string array MUST be bijective.
We concede that bijectivity is not strictly needed. Avoiding transaction malleability only requires collision resistance on the encoding. Lossless encoding also does not require decodability. However, bijectivity assures both non-malleability and losslessness.
Bijectivity will be tested in two ways:
- by providing a set of test fixtures between a transaction's Proto JSON representation and its TEXTUAL representation, and checking that encoding/decoding in both directions matches the fixtures,
- by using property testing on the proto transaction itself, and testing that the composition of encoding and decoding yields the original transaction itself.
This also prevents users signing over any hashed transaction data (fee, transaction body, `Msg` content that might be hashed etc), which is a security concern for Ledger's security team.
We propose to maintain functional tests using bijectivity in the SDK.
### 2. Only ASCII 32-127 characters allowed
Ledger devices have limited character display capabilities, so all strings MUST only contain ASCII characters in the 32-127 range.
In particular, the newline `"\n"` (ASCII: 10) character is forbidden.
### 3. Strings SHOULD have the `<key>: <value>` format
Given the Regex `/^(\* )?(>* )?(.*: )?(.*)$/`, all strings SHOULD match the Regex with capture groups 3 and 4 non-empty. This is helpful for UIs displaying SignDocTextual to users.
- The initial `*` character is optional and denotes the Ledger Expert mode, see #5.
- Strings can also include a number of `>` character to denote nesting.
- In the case where the first Regex capture group is not empty, it represents an indicative key, whose associated value is given in the second capture group. This MAY be used in the Ledger app to perform custom on-screen formatting, for example to break long lines into multiple screens.
This Regex is however not mandatory, to allow for some flexibility, for example to display an English sentence to denote end of sections.
The `<value>` itself can contain the `": "` characters.
### 4. Values are encoded using Value Renderers
Value Renderers describe how Protobuf types are encoded to and decoded from a string array. The full specification of Value Renderers can be found in [Annex 1](./adr-050-sign-mode-textual-annex1.md).
### 5. Strings starting with `*` are only shown in Expert mode
Ledger devices have the an Expert mode for advanced users. Expert mode needs to be manually activated by the device holder, inside the device settings. There is currently no official documentation on Expert mode, but according to the [@Ledger_Support twitter account](https://twitter.com/Ledger_Support/status/1364524431800950785),
> Expert mode enables further, more sophisticated features. This could be useful for advanced users
Strings starting with the `*` character will only be shown in Expert mode. These strings are either hardcoded in the transaction envelope (see point #7).
For hardware wallets that don't have an expert mode, all strings MUST be shown on the device.
### 6. Strings MAY contain `>` characters to denote nesting
Protobuf objects can be arbitrarily complex, containing nested arrays and messages. In order to help the Ledger-signing users, we propose to use the `>` symbol in the beginning of strings to represent nested objects, where each additional `>` represents a new level of nesting.
### 7. Encoding of the Transaction Envelope
We define "transaction envelope" as all data in a transaction that is not in the `TxBody.Messages` field. Transaction envelope includes fee, signer infos and memo, but don't include `Msg`s. `//` denotes comments and are not shown on the Ledger device.
```
Chain ID: <string>
Account number: <uint64>
*Public Key: <base64_string>
Sequence: <uint64>
<TxBody> // See #8.
Fee: <coins> // See value renderers for coins encoding.
*Fee payer: <string> // Skipped if no fee_payer set
*Fee granter: <string> // Skipped if no fee_granter set
Memo: <string> // Skipped if no memo set
*Gas Limit: <uint64>
*Timeout Height: <uint64> // Skipped if no timeout_height set
Tipper: <string> // If there's a tip
Tip: <string>
*This transaction has <int> body extension: // Skipped if no body extension options
*<repeated Any>
*This transaction has <int> body non-critical extensions: // Skipped if no body non-critical extension options
*<repeated Any> // See value renderers for Any and array encoding.
*This transaction has <int> body auth info extensions: // Skipped if no auth info extension options
*<repeated Any>
*This transaction has <int> other signers: // Skipped if there is only one signer
*Signer (<int>/<int>):
*Public Key: <base64_string>
*Sequence: <uint64>
*End of other signers
```
### 8. Encoding of the Transaction Body
Transaction Body is the `Tx.TxBody.Messages` field, which is an array of `Any`s, where each `Any` packs a `sdk.Msg`. Since `sdk.Msg`s are widely used, they have a slightly different encoding than usual array of `Any`s (Protobuf: `repeated google.protobuf.Any`) described in Annex 1.
```
This transaction has <int> message: // Optional 's' for "message" if there's is >1 sdk.Msgs.
// For each Msg, print the following 2 lines:
Msg (<int>/<int>): <string> // E.g. Msg (1/2): bank v1beta1 send coins
<value rendering of Msg struct>
End of transaction messages
```
#### Example
Given the following Protobuf message:
```proto
message Grant {
google.protobuf.Any authorization = 1 [(cosmos_proto.accepts_interface) = "Authorization"];
google.protobuf.Timestamp expiration = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
}
message MsgGrant {
option (cosmos.msg.v1.signer) = "granter";
option (cosmos.msg.v1.textual.type_url) = "authz v1beta1 grant";
string granter = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string grantee = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}
```
and a transaction containing 1 such `sdk.Msg`, we get the following encoding:
```
This transaction has 1 message:
Msg (1/1): authz v1beta1 grant
Granter: cosmos1abc...def
Grantee: cosmos1ghi...jkl
End of transaction messages
```
### 9. Signing Payload and Wire Format
This string array is encoded as a single `\n`-delimited string before transmitted to the hardware device, and this long string is the signing payload signed by the hardware wallet.
## Additional Formatting by the Hardware Device
Hardware devices differ in screen sizes and memory capacities. The above specifications are all verified on the protocol level, but we still allow the hardware device to add custom formatting rules that are specific to the device. Rules can include:
- if a string is too long, show it on multiple screens,
- break line between the `key` and `value` from #3,
- perform line breaks on a number or a coin values only when necessary. For example, a `sdk.Coins` with multiple denoms would be better shown as one denom per line instead of an coin amount being cut in the middle.
## Examples
#### Example 1: Simple `MsgSend`
JSON:
```json
{
"body": {
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...abc",
"to": "cosmos1...def",
"amount": [
{
"denom": "uatom",
"amount": 10000000
}
]
}
]
},
"auth_info": {
"signer_infos": [
{
"public_key": "iQ...==",
"mode_info": { "single": { "mode": "SIGN_MODE_TEXTUAL" } },
"sequence": 2
}
],
"fee": {
"amount": [
{
"denom": "atom",
"amount": 0.002
}
],
"gas_limit": 100000
}
},
// Additional SignerData.
"chain_id": "simapp-1",
"account_number": 10
}
```
SIGN_MODE_TEXTUAL:
```
Chain ID: simapp-1
Account number: 10
*Public Key: iQ...== // Base64 pubkey
Sequence: 2
This transaction has 1 message:
Message (1/1): bank v1beta1 send coins
From: cosmos1...abc
To: cosmos1...def
Amount: 10 atom // Conversion from uatom to atom using value renderers
End of transaction messages
Fee: 0.002 atom
*Gas: 100'000
```
#### Example 2: Multi-Msg Transaction with 3 signers
#### Example 3: Legacy Multisig
#### Example 4: Fee Payer with Tips
```json
{
"body": {
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...tipper",
"to": "cosmos1...abc",
"amount": [
{
"denom": "uatom",
"amount": 10000000
}
]
}
]
},
"auth_info": {
"signer_infos": [
{
"public_key": "iQ...==",
"mode_info": { "single": { "mode": "SIGN_MODE_DIRECT_AUX" } },
"sequence": 42
},
{
"public_key": "iR...==",
"mode_info": { "single": { "mode": "SIGN_MODE_TEXTUAL" } },
"sequence": 2
}
],
"fee": {
"amount": [
{
"denom": "atom",
"amount": 0.002
}
],
"gas_limit": 100000,
"payer": "cosmos1...feepayer"
},
"tip": {
"amount": [
{
"denom": "ibc/CDC4587874B85BEA4FCEC3CEA5A1195139799A1FEE711A07D972537E18FDA39D",
"amount": 200
}
],
"tipper": "cosmos1...tipper"
}
},
// Additional SignerData.
"chain_id": "simapp-1",
"account_number": 10
}
```
SIGN_MODE_TEXTUAL for the feepayer:
```
Chain ID: simapp-1
Account number: 10
*Public Key: iR...==
Sequence: 2
This transaction has 1 message:
Message (1/1): bank v1beta1 send coins
From: cosmos1...abc
To: cosmos1...def
Amount: 10 atom
End of transaction messages
Fee: 0.002 atom
Fee Payer: cosmos1...feepayer
Tipper: cosmos1...tipper
Tip: 200 ibc/CDC4587874B85BEA4FCEC3CEA5A1195139799A1FEE711A07D972537E18FDA39D
*Gas: 100'000
*This transaction has 1 other signer:
*Signer (1/2):
*Public Key: iQ...==
*Sign mode: Direct Aux
*Sequence: 42
*End of other signers
```
#### Example 5: Complex Transaction with Nested Messages
JSON:
```json
{
"body": {
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...abc",
"to": "cosmos1...def",
"amount": [
{
"denom": "uatom",
"amount": 10000000
}
]
},
{
"@type": "/cosmos.gov.v1.MsgSubmitProposal",
"proposer": "cosmos1...ghi",
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...jkl",
"to": "cosmos1...mno",
"amount": [
{
"denom": "uatom",
"amount": 20000000
}
]
},
{
"@type": "/cosmos.authz.v1beta1.MsgExec",
"grantee": "cosmos1...pqr",
"msgs": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...stu",
"to": "cosmos1...vwx",
"amount": [
{
"denom": "uatom",
"amount": 30000000
}
]
},
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from": "cosmos1...abc",
"to": "cosmos1...def",
"amount": [
{
"denom": "uatom",
"amount": 40000000
}
]
}
]
}
],
"initial_deposit": [
{
"denom": "atom",
"amount": 100.01
}
]
}
]
},
"auth_info": {
"signer_infos": [
{
"public_key": "iQ...==",
"mode_info": { "single": { "mode": "SIGN_MODE_TEXTUAL" } },
"sequence": 2
},
{
"public_key": "iR...==",
"mode_info": { "single": { "mode": "SIGN_MODE_DIRECT" } },
"sequence": 42
}
],
"fee": {
"amount": [
{
"denom": "atom",
"amount": 0.002
}
],
"gas_limit": 100000
}
},
// Additional SignerData.
"chain_id": "simapp-1",
"account_number": 10
}
}
```
SIGN_MODE_TEXTUAL for 1st signer `cosmos1...abc`:
```
Chain ID: simapp-1
Account number: 10
*Public Key: iQ...==
Sequence: 2
This transaction has 2 messages:
Message (1/2): bank v1beta1 send coins
From: cosmos1...abc
To: cosmos1...def
Amount: 10 atom
Message (2/2): gov v1 submit proposal
Messages: 2 Messages
> Message (1/2): bank v1beta1 send coins
> From: cosmos1...jkl
> To: cosmos1...mno
> Amount: 20 atom
> Message (2/2): authz v1beta exec
> Grantee: cosmos1...pqr
> Msgs: 2 Msgs
>> Msg (1/2): bank v1beta1 send coins
>> From: cosmos1...stu
>> To: cosmos1...vwx
>> Amount: 30 atom
>> Msg (2/2): bank v1beta1 send coins
>> From: cosmos1...abc
>> To: cosmos1...def
>> Amount: 40 atom
> End of Msgs
End of transaction messages
Proposer: cosmos1...ghi
Initial Deposit: 100.01 atom
End of transaction messages
Fee: 0.002 atom
*Gas: 100'000
*This transaction has 1 other signer:
*Signer (2/2):
*Public Key: iR...==
*Sign mode: Direct
*Sequence: 42
*End of other signers
```
## Consequences
### Backwards Compatibility
SIGN_MODE_TEXTUAL is purely additive, and doesn't break any backwards compatibility with other sign modes.
### Positive
- Human-friendly way of signing in hardware devices.
- Once SIGN_MODE_TEXTUAL is shipped, SIGN_MODE_LEGACY_AMINO_JSON can be deprecated and removed. On the longer term, once the ecosystem has totally migrated, Amino can be totally removed.
### Negative
- Some fields are still encoded in non-human-readable ways, such as public keys in base64.
- New ledger app needs to be released, still unclear
### Neutral
- If the transaction is complex, the string array can be arbitrarily long, and some users might just skip some screens and blind sign.
## Further Discussions
- Some details on value renderers need to be polished, see [Annex 1](./adr-050-sign-mode-textual-annex1.md).
- Are ledger apps able to support both SIGN_MODE_LEGACY_AMINO_JSON and SIGN_MODE_TEXTUAL at the same time?
- Open question: should we add a Protobuf field option to allow app developers to overwrite the textual representation of certain Protobuf fields and message? This would be similar to Ethereum's [EIP4430](https://github.com/ethereum/EIPs/pull/4430), where the contract developer decides on the textual representation.
- Internationalization.
## References
- [Annex 1](./adr-050-sign-mode-textual-annex1.md)
- Initial discussion: https://github.com/cosmos/cosmos-sdk/issues/6513
- Living document used in the working group: https://hackmd.io/fsZAO-TfT0CKmLDtfMcKeA?both
- Working group meeting notes: https://hackmd.io/7RkGfv_rQAaZzEigUYhcXw
- Ethereum's "Described Transactions" https://github.com/ethereum/EIPs/pull/4430