x/bank
Abstract
This document specifies the bank module of the Cosmos SDK.
The bank module is responsible for handling multi-asset coin transfers between
accounts and tracking special-case pseudo-transfers which must work differently
with particular kinds of accounts (notably delegating/undelegating for vesting
accounts). It exposes several interfaces with varying capabilities for secure
interaction with other modules which must alter user balances.
In addition, the bank module tracks and provides query support for the total
supply of all assets used in the application.
This module is used in the Cosmos Hub.
Contents
Supply
The supply
functionality:
- passively tracks the total supply of coins within a chain,
- provides a pattern for modules to hold/interact with
Coins
, and
- introduces the invariant check to verify a chain's total supply.
Total Supply
The total Supply
of the network is equal to the sum of all coins from the
account. The total supply is updated every time a Coin
is minted (eg: as part
of the inflation mechanism) or burned (eg: due to slashing or if a governance
proposal is vetoed).
Module Accounts
The supply functionality introduces a new type of auth.Account
which can be used by
modules to allocate tokens and in special cases mint or burn tokens. At a base
level these module accounts are capable of sending/receiving tokens to and from
auth.Account
s and other module accounts. This design replaces previous
alternative designs where, to hold tokens, modules would burn the incoming
tokens from the sender account, and then track those tokens internally. Later,
in order to send tokens, the module would need to effectively mint tokens
within a destination account. The new design removes duplicate logic between
modules to perform this accounting.
The ModuleAccount
interface is defined as follows:
type ModuleAccount interface {
auth.Account // same methods as the Account interface
GetName() string // name of the module; used to obtain the address
GetPermissions() []string // permissions of module account
HasPermission(string) bool
}
WARNING!
Any module or message handler that allows either direct or indirect sending of funds must explicitly guarantee those funds cannot be sent to module accounts (unless allowed).
The supply Keeper
also introduces new wrapper functions for the auth Keeper
and the bank Keeper
that are related to ModuleAccount
s in order to be able
to:
- Get and set
ModuleAccount
s by providing the Name
.
- Send coins from and to other
ModuleAccount
s or standard Account
s
(BaseAccount
or VestingAccount
) by passing only the Name
.
Mint
or Burn
coins for a ModuleAccount
(restricted to its permissions).
Permissions
Each ModuleAccount
has a different set of permissions that provide different
object capabilities to perform certain actions. Permissions need to be
registered upon the creation of the supply Keeper
so that every time a
ModuleAccount
calls the allowed functions, the Keeper
can lookup the
permissions to that specific account and perform or not perform the action.
The available permissions are:
Minter
: allows for a module to mint a specific amount of coins.
Burner
: allows for a module to burn a specific amount of coins.
Staking
: allows for a module to delegate and undelegate a specific amount of coins.
State
The x/bank
module keeps state of the following primary objects:
- Account balances
- Denomination metadata
- The total supply of all balances
- Information on which denominations are allowed to be sent.
In addition, the x/bank
module keeps the following indexes to manage the
aforementioned state:
- Supply Index:
0x0 | byte(denom) -> byte(amount)
- Denom Metadata Index:
0x1 | byte(denom) -> ProtocolBuffer(Metadata)
- Balances Index:
0x2 | byte(address length) | []byte(address) | []byte(balance.Denom) -> ProtocolBuffer(balance)
- Reverse Denomination to Address Index:
0x03 | byte(denom) | 0x00 | []byte(address) -> 0
Params
The bank module stores it's params in state with the prefix of 0x05
,
it can be updated with governance or the address with authority.
- Params:
0x05 | ProtocolBuffer(Params)
https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc3/proto/cosmos/bank/v1beta1/bank.proto#L11-L16
Keepers
The bank module provides these exported keeper interfaces that can be
passed to other modules that read or update account balances. Modules
should use the least-permissive interface that provides the functionality they
require.
Best practices dictate careful review of bank
module code to ensure that
permissions are limited in the way that you expect.
Denied Addresses
The x/bank
module accepts a map of addresses that are considered blocklisted
from directly and explicitly receiving funds through means such as MsgSend
and
MsgMultiSend
and direct API calls like SendCoinsFromModuleToAccount
.
Typically, these addresses are module accounts. If these addresses receive funds
outside the expected rules of the state machine, invariants are likely to be
broken and could result in a halted network.
By providing the x/bank
module with a blocklisted set of addresses, an error occurs for the operation if a user or client attempts to directly or indirectly send funds to a blocklisted account, for example, by using IBC.
Common Types
An input of a multiparty transfer
// Input models transaction input.
message Input {
string address = 1;
repeated cosmos.base.v1beta1.Coin coins = 2;
}
Output
An output of a multiparty transfer.
// Output models transaction outputs.
message Output {
string address = 1;
repeated cosmos.base.v1beta1.Coin coins = 2;
}
BaseKeeper
The base keeper provides full-permission access: the ability to arbitrary modify any account's balance and mint or burn coins.
Restricted permission to mint per module could be achieved by using baseKeeper with WithMintCoinsRestriction
to give specific restrictions to mint (e.g. only minting certain denom).
// Keeper defines a module interface that facilitates the transfer of coins
// between accounts.
type Keeper interface {
SendKeeper
WithMintCoinsRestriction(MintingRestrictionFn) BaseKeeper
InitGenesis(sdk.Context, *types.GenesisState)
ExportGenesis(sdk.Context) *types.GenesisState
GetSupply(ctx sdk.Context, denom string) sdk.Coin
HasSupply(ctx sdk.Context, denom string) bool
GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error)
IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool)
GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool)
HasDenomMetaData(ctx sdk.Context, denom string) bool
SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata)
IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool)
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error
UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error
// GetAuthority gets the address capable of executing governance proposal messages. Usually the gov module account.
GetAuthority() string
types.QueryServer
}
SendKeeper
The send keeper provides access to account balances and the ability to transfer coins between
accounts. The send keeper does not alter the total supply (mint or burn coins).
// SendKeeper defines a module interface that facilitates the transfer of coins
// between accounts without the possibility of creating coins.
type SendKeeper interface {
ViewKeeper
InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
GetParams(ctx sdk.Context) types.Params
SetParams(ctx sdk.Context, params types.Params) error
IsSendEnabledDenom(ctx sdk.Context, denom string) bool
SetSendEnabled(ctx sdk.Context, denom string, value bool)
SetAllSendEnabled(ctx sdk.Context, sendEnableds []*types.SendEnabled)
DeleteSendEnabled(ctx sdk.Context, denom string)
IterateSendEnabledEntries(ctx sdk.Context, cb func(denom string, sendEnabled bool) (stop bool))
GetAllSendEnabledEntries(ctx sdk.Context) []types.SendEnabled
IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
BlockedAddr(addr sdk.AccAddress) bool
}
ViewKeeper
The view keeper provides read-only access to account balances. The view keeper does not have balance alteration functionality. All balance lookups are O(1)
.
// ViewKeeper defines a module interface that facilitates read only access to
// account balances.
type ViewKeeper interface {
ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error
HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
GetAccountsBalances(ctx sdk.Context) []types.Balance
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
SpendableCoin(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool))
IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool))
}
Messages
MsgSend
Send coins from one address to another.
https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L21-L32
The message will fail under the following conditions:
- The coins do not have sending enabled
- The
to
address is restricted
MsgMultiSend
Send coins from and to a series of different address. If any of the receiving addresses do not correspond to an existing account, a new account is created.
https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L37-L45
The message will fail under the following conditions:
- Any of the coins do not have sending enabled
- Any of the
to
addresses are restricted
- Any of the coins are locked
- The inputs and outputs do not correctly correspond to one another
MsgUpdateParams
The bank
module params can be updated through MsgUpdateParams
, which can be done using governance proposal. The signer will always be the gov
module account address.
https://github.com/cosmos/cosmos-sdk/blob/e167855c9b99c4e58c1455533c6f88af5ff78ae1/proto/cosmos/bank/v1beta1/tx.proto#L56-L69
The message handling can fail if:
- signer is not the gov module account address.
MsgSetSendEnabled
Used with the x/gov module to set create/edit SendEnabled entries.
https://github.com/cosmos/cosmos-sdk/blob/1bb627e7324278218560d2dd61e010881394f504/proto/cosmos/bank/v1beta1/tx.proto#L94-L107
The message will fail under the following conditions:
- The authority is not a bech32 address.
- The authority is not x/gov module's address.
- There are multiple SendEnabled entries with the same Denom.
- One or more SendEnabled entries has an invalid Denom.
Events
The bank module emits the following events:
Message Events
MsgSend
Type |
Attribute Key |
Attribute Value |
transfer |
recipient |
{recipientAddress} |
transfer |
amount |
{amount} |
message |
module |
bank |
message |
action |
send |
message |
sender |
{senderAddress} |
MsgMultiSend
Type |
Attribute Key |
Attribute Value |
transfer |
recipient |
{recipientAddress} |
transfer |
amount |
{amount} |
message |
module |
bank |
message |
action |
multisend |
message |
sender |
{senderAddress} |
Keeper Events
In addition to message events, the bank keeper will produce events when the following methods are called (or any method which ends up calling them)
MintCoins
{
"type": "coinbase",
"attributes": [
{
"key": "minter",
"value": "{{sdk.AccAddress of the module minting coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being minted}}",
"index": true
}
]
}
{
"type": "coin_received",
"attributes": [
{
"key": "receiver",
"value": "{{sdk.AccAddress of the module minting coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being received}}",
"index": true
}
]
}
BurnCoins
{
"type": "burn",
"attributes": [
{
"key": "burner",
"value": "{{sdk.AccAddress of the module burning coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being burned}}",
"index": true
}
]
}
{
"type": "coin_spent",
"attributes": [
{
"key": "spender",
"value": "{{sdk.AccAddress of the module burning coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being burned}}",
"index": true
}
]
}
addCoins
{
"type": "coin_received",
"attributes": [
{
"key": "receiver",
"value": "{{sdk.AccAddress of the address beneficiary of the coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being received}}",
"index": true
}
]
}
subUnlockedCoins/DelegateCoins
{
"type": "coin_spent",
"attributes": [
{
"key": "spender",
"value": "{{sdk.AccAddress of the address which is spending coins}}",
"index": true
},
{
"key": "amount",
"value": "{{sdk.Coins being spent}}",
"index": true
}
]
}
Parameters
The bank module contains the following parameters
SendEnabled
The SendEnabled parameter is now deprecated and not to be use. It is replaced
with state store records.
DefaultSendEnabled
The default send enabled value controls send transfer capability for all
coin denominations unless specifically included in the array of SendEnabled
parameters.
Client
CLI
A user can query and interact with the bank
module using the CLI.
Query
The query
commands allow users to query bank
state.
simd query bank --help
balances
The balances
command allows users to query account balances by address.
simd query bank balances [address] [flags]
Example:
simd query bank balances cosmos1..
Example Output:
balances:
- amount: "1000000000"
denom: stake
pagination:
next_key: null
total: "0"
The denom-metadata
command allows users to query metadata for coin denominations. A user can query metadata for a single denomination using the --denom
flag or all denominations without it.
simd query bank denom-metadata [flags]
Example:
simd query bank denom-metadata --denom stake
Example Output:
metadata:
base: stake
denom_units:
- aliases:
- STAKE
denom: stake
description: native staking token of simulation app
display: stake
name: SimApp Token
symbol: STK
total
The total
command allows users to query the total supply of coins. A user can query the total supply for a single coin using the --denom
flag or all coins without it.
simd query bank total [flags]
Example:
simd query bank total --denom stake
Example Output:
amount: "10000000000"
denom: stake
send-enabled
The send-enabled
command allows users to query for all or some SendEnabled entries.
simd query bank send-enabled [denom1 ...] [flags]
Example:
simd query bank send-enabled
Example output:
send_enabled:
- denom: foocoin
enabled: true
- denom: barcoin
pagination:
next-key: null
total: 2
Transactions
The tx
commands allow users to interact with the bank
module.
simd tx bank --help
send
The send
command allows users to send funds from one account to another.
simd tx bank send [from_key_or_address] [to_address] [amount] [flags]
Example:
simd tx bank send cosmos1.. cosmos1.. 100stake
gRPC
A user can query the bank
module using gRPC endpoints.
Balance
The Balance
endpoint allows users to query account balance by address for a given denomination.
cosmos.bank.v1beta1.Query/Balance
Example:
grpcurl -plaintext \
-d '{"address":"cosmos1..","denom":"stake"}' \
localhost:9090 \
cosmos.bank.v1beta1.Query/Balance
Example Output:
{
"balance": {
"denom": "stake",
"amount": "1000000000"
}
}
AllBalances
The AllBalances
endpoint allows users to query account balance by address for all denominations.
cosmos.bank.v1beta1.Query/AllBalances
Example:
grpcurl -plaintext \
-d '{"address":"cosmos1.."}' \
localhost:9090 \
cosmos.bank.v1beta1.Query/AllBalances
Example Output:
{
"balances": [
{
"denom": "stake",
"amount": "1000000000"
}
],
"pagination": {
"total": "1"
}
}
The DenomMetadata
endpoint allows users to query metadata for a single coin denomination.
cosmos.bank.v1beta1.Query/DenomMetadata
Example:
grpcurl -plaintext \
-d '{"denom":"stake"}' \
localhost:9090 \
cosmos.bank.v1beta1.Query/DenomMetadata
Example Output:
{
"metadata": {
"description": "native staking token of simulation app",
"denomUnits": [
{
"denom": "stake",
"aliases": [
"STAKE"
]
}
],
"base": "stake",
"display": "stake",
"name": "SimApp Token",
"symbol": "STK"
}
}
The DenomsMetadata
endpoint allows users to query metadata for all coin denominations.
cosmos.bank.v1beta1.Query/DenomsMetadata
Example:
grpcurl -plaintext \
localhost:9090 \
cosmos.bank.v1beta1.Query/DenomsMetadata
Example Output:
{
"metadatas": [
{
"description": "native staking token of simulation app",
"denomUnits": [
{
"denom": "stake",
"aliases": [
"STAKE"
]
}
],
"base": "stake",
"display": "stake",
"name": "SimApp Token",
"symbol": "STK"
}
],
"pagination": {
"total": "1"
}
}
DenomOwners
The DenomOwners
endpoint allows users to query metadata for a single coin denomination.
cosmos.bank.v1beta1.Query/DenomOwners
Example:
grpcurl -plaintext \
-d '{"denom":"stake"}' \
localhost:9090 \
cosmos.bank.v1beta1.Query/DenomOwners
Example Output:
{
"denomOwners": [
{
"address": "cosmos1..",
"balance": {
"denom": "stake",
"amount": "5000000000"
}
},
{
"address": "cosmos1..",
"balance": {
"denom": "stake",
"amount": "5000000000"
}
},
],
"pagination": {
"total": "2"
}
}
TotalSupply
The TotalSupply
endpoint allows users to query the total supply of all coins.
cosmos.bank.v1beta1.Query/TotalSupply
Example:
grpcurl -plaintext \
localhost:9090 \
cosmos.bank.v1beta1.Query/TotalSupply
Example Output:
{
"supply": [
{
"denom": "stake",
"amount": "10000000000"
}
],
"pagination": {
"total": "1"
}
}
SupplyOf
The SupplyOf
endpoint allows users to query the total supply of a single coin.
cosmos.bank.v1beta1.Query/SupplyOf
Example:
grpcurl -plaintext \
-d '{"denom":"stake"}' \
localhost:9090 \
cosmos.bank.v1beta1.Query/SupplyOf
Example Output:
{
"amount": {
"denom": "stake",
"amount": "10000000000"
}
}
Params
The Params
endpoint allows users to query the parameters of the bank
module.
cosmos.bank.v1beta1.Query/Params
Example:
grpcurl -plaintext \
localhost:9090 \
cosmos.bank.v1beta1.Query/Params
Example Output:
{
"params": {
"defaultSendEnabled": true
}
}
SendEnabled
The SendEnabled
enpoints allows users to query the SendEnabled entries of the bank
module.
Any denominations NOT returned, use the Params.DefaultSendEnabled
value.
cosmos.bank.v1beta1.Query/SendEnabled
Example:
grpcurl -plaintext \
localhost:9090 \
cosmos.bank.v1beta1.Query/SendEnabled
Example Output:
{
"send_enabled": [
{
"denom": "foocoin",
"enabled": true
},
{
"denom": "barcoin"
}
],
"pagination": {
"next-key": null,
"total": 2
}
}