变更记录

  • 05/19/2020:初始草案

状态

提议中

背景

Cosmos SDK 中的资产通过 Coins 类型表示,该类型由 amount 和 denom 组成, 其中 amount 可以是任意大或任意小的值。此外,Cosmos SDK 使用基于账户的模型, 其中主要有两类账户:基础账户和模块账户。 所有账户类型都有一组由 Coins 构成的余额。x/bank 模块负责跟踪所有账户的全部余额, 同时也跟踪应用中的余额总供应量。 对于余额中的 amount,Cosmos SDK 假定其对应的计价单位是静态且固定的, 无论具体的面额本身是什么。换句话说,构建在 Cosmos-SDK 链之上的客户端和应用 可以选择定义并使用任意的计价单位来提供更好的用户体验;但是一旦交易或操作进入 Cosmos SDK 状态机,amount 就会被视为单一固定单位。例如,对于 Cosmos Hub(Gaia), 客户端通常假定 1 ATOM = 10^6 uatom,因此 Cosmos SDK 中的所有交易和操作 实际上都是以 10^6 这一单位体系为基础运行的。 这显然会带来较差且受限的用户体验,尤其是在网络互操作性增强、资产类型总量随之增加的情况下。 我们提议让 x/bank 额外按 denom 跟踪元数据,以帮助客户端、钱包提供方和区块浏览器 改进用户体验,并消除它们对计价单位进行自行假设的要求。

决策

x/bank 模块将被更新为按 denom 存储并索引元数据,具体来说是按“base” 或最小单位进行索引,也就是 Cosmos SDK 状态机实际使用的单位。 元数据还可以包含一个长度非零的面额列表。每个条目都包含该面额的名称 denom、 相对于基础单位的指数,以及一组别名。每个条目应被解释为 1 denom = 10^exponent base_denom(例如 1 ETH = 10^18 wei 和 1 uatom = 10^0 uatom)。 对于客户端而言,有两个面额字段尤为重要:base 表示最小可能单位,display 表示在人类交流和交易所中通常使用的展示单位。这两个字段的值都关联到面额列表中的某个条目。 denom_units 列表以及 display 条目都可以通过治理进行修改。 因此,我们可以将该类型定义如下:
message DenomUnit {
  string denom    = 1;
  uint32 exponent = 2;  
  repeated string aliases = 3;
}

message Metadata {
  string description = 1;
  repeated DenomUnit denom_units = 2;
  string base = 3;
  string display = 4;
}
例如,ATOM 的元数据可以定义如下:
{
  "name": "atom",
  "description": "The native staking token of the Cosmos Hub.",
  "denom_units": [
    {
  "denom": "uatom",
  "exponent": 0,
      "aliases": [
        "microatom"
      ],
    
},
    {
  "denom": "matom",
  "exponent": 3,
      "aliases": [
        "milliatom"
      ]
    
},
    {
  "denom": "atom",
  "exponent": 6,
    }
  ],
  "base": "uatom",
  "display": "atom",
}
基于上述元数据,客户端可以推断出以下内容:
  • 4.3atom = 4.3 * (10^6) = 4,300,000uatom
  • 字符串 “atom” 可以在代币列表中用作展示名称。
  • 余额 4300000 可以显示为 4,300,000uatom、4,300matom 或 4.3atom。 如果客户端作者没有明确决定使用其他表示方式,那么 display 面额对应的 4.3atom 会是一个合理的默认值。
客户端应当能够同时通过 CLI 和 REST 接口按 denom 查询元数据。 此外,我们还将在这些接口中增加处理器,以便在任意单位之间进行转换, 因为 Cosmos SDK 中已经具备这方面的基础框架。 最后,我们需要确保 x/bank 模块的 GenesisState 中包含元数据, 并且这些元数据同样按基础 denom 建立索引。
type GenesisState struct {
    SendEnabled   bool        `json:"send_enabled" yaml:"send_enabled"`
  Balances      []Balance   `json:"balances" yaml:"balances"`
  Supply        sdk.Coins   `json:"supply" yaml:"supply"`
  DenomMetadata []Metadata  `json:"denom_metadata" yaml:"denom_metadata"`
}

后续工作

为了让客户端无需手动或通过接口先将资产转换为基础面额,我们可以考虑支持对给定输入单位的自动转换。

影响

正面

  • 为客户端、钱包提供方和区块浏览器提供有关资产面额的额外数据, 以改进用户体验,并消除对面额单位进行假设的需要。

负面

  • x/bank 模块需要少量额外存储空间。 由于资产总量预计不会很大,因此额外存储开销应当很小。

中性

参考资料


Changelog

  • 05/19/2020: Initial draft

Status

Proposed

Context

Assets in the Cosmos SDK are represented via a Coins type that consists of an amount and a denom, where the amount can be any arbitrarily large or small value. In addition, the Cosmos SDK uses an account-based model where there are two types of primary accounts — basic accounts and module accounts. All account types have a set of balances that are composed of Coins. The x/bank module keeps track of all balances for all accounts and also keeps track of the total supply of balances in an application. With regards to a balance amount, the Cosmos SDK assumes a static and fixed unit of denomination, regardless of the denomination itself. In other words, clients and apps built atop a Cosmos-SDK-based chain may choose to define and use arbitrary units of denomination to provide a richer UX, however, by the time a tx or operation reaches the Cosmos SDK state machine, the amount is treated as a single unit. For example, for the Cosmos Hub (Gaia), clients assume 1 ATOM = 10^6 uatom, and so all txs and operations in the Cosmos SDK work off of units of 10^6. This clearly provides a poor and limited UX especially as interoperability of networks increases and as a result the total amount of asset types increases. We propose to have x/bank additionally keep track of metadata per denom in order to help clients, wallet providers, and explorers improve their UX and remove the requirement for making any assumptions on the unit of denomination.

Decision

The x/bank module will be updated to store and index metadata by denom, specifically the “base” or smallest unit — the unit the Cosmos SDK state-machine works with. Metadata may also include a non-zero length list of denominations. Each entry contains the name of the denomination denom, the exponent to the base and a list of aliases. An entry is to be interpreted as 1 denom = 10^exponent base_denom (e.g. 1 ETH = 10^18 wei and 1 uatom = 10^0 uatom). There are two denominations that are of high importance for clients: the base, which is the smallest possible unit and the display, which is the unit that is commonly referred to in human communication and on exchanges. The values in those fields link to an entry in the list of denominations. The list in denom_units and the display entry may be changed via governance. As a result, we can define the type as follows:
message DenomUnit {
  string denom    = 1;
  uint32 exponent = 2;  
  repeated string aliases = 3;
}

message Metadata {
  string description = 1;
  repeated DenomUnit denom_units = 2;
  string base = 3;
  string display = 4;
}
As an example, the ATOM’s metadata can be defined as follows:
{
  "name": "atom",
  "description": "The native staking token of the Cosmos Hub.",
  "denom_units": [
    {
  "denom": "uatom",
  "exponent": 0,
      "aliases": [
        "microatom"
      ],
    
},
    {
  "denom": "matom",
  "exponent": 3,
      "aliases": [
        "milliatom"
      ]
    
},
    {
  "denom": "atom",
  "exponent": 6,
    }
  ],
  "base": "uatom",
  "display": "atom",
}
Given the above metadata, a client may infer the following things:
  • 4.3atom = 4.3 * (10^6) = 4,300,000uatom
  • The string “atom” can be used as a display name in a list of tokens.
  • The balance 4300000 can be displayed as 4,300,000uatom or 4,300matom or 4.3atom. The display denomination 4.3atom is a good default if the authors of the client don’t make an explicit decision to choose a different representation.
A client should be able to query for metadata by denom both via the CLI and REST interfaces. In addition, we will add handlers to these interfaces to convert from any unit to another given unit, as the base framework for this already exists in the Cosmos SDK. Finally, we need to ensure metadata exists in the GenesisState of the x/bank module which is also indexed by the base denom.
type GenesisState struct {
    SendEnabled   bool        `json:"send_enabled" yaml:"send_enabled"`
  Balances      []Balance   `json:"balances" yaml:"balances"`
  Supply        sdk.Coins   `json:"supply" yaml:"supply"`
  DenomMetadata []Metadata  `json:"denom_metadata" yaml:"denom_metadata"`
}

Future Work

In order for clients to avoid having to convert assets to the base denomination — either manually or via an endpoint, we may consider supporting automatic conversion of a given unit input.

Consequences

Positive

  • Provides clients, wallet providers and block explorers with additional data on asset denomination to improve UX and remove any need to make assumptions on denomination units.

Negative

  • A small amount of required additional storage in the x/bank module. The amount of additional storage should be minimal as the amount of total assets should not be large.

Neutral

References