chore: collapse module spec and readme (#13143)
* updates * add auth and separate vesting * authz * capability * crisis * epoching * nft * mint * params * upgrade * fix website build * finish other modules * fix `pre.sh` and update modules title * add docs * display vesting in docs * add page splitting for missing modules * updates * improve `pre.sh` Co-authored-by: marbar3778 <marbar3778@yahoo.com> Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
parent
ca86ec5e93
commit
a0682b14f4
25
docs/pre.sh
25
docs/pre.sh
@ -4,11 +4,30 @@ mkdir -p modules
|
||||
|
||||
for D in ../x/*; do
|
||||
if [ -d "${D}" ]; then
|
||||
rm -rf "modules/$(echo $D | awk -F/ '{print $NF}')"
|
||||
mkdir -p "modules/$(echo $D | awk -F/ '{print $NF}')" && cp -r $D/spec/* "$_"
|
||||
MODDOC=modules/$(echo $D | awk -F/ '{print $NF}')
|
||||
rm -rf $MODDOC
|
||||
mkdir -p $MODDOC && cp -r $D/README.md "$_"
|
||||
if [ -f "$MODDOC/README.md" ]; then
|
||||
cd $MODDOC
|
||||
# This ensures that we have multiples pages for the modules documantation
|
||||
# This is easier to read for the user
|
||||
# In order to split pages, we need to add a <!-- order: X --> in the module README.md, for each pages that we want.
|
||||
csplit -k -q README.md '/<!-- order:/' '{*}' --prefix='section_' --suffix-format='%02d.md'
|
||||
mv section_00.md README.md
|
||||
cd ../..
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cat ../x/README.md | sed 's/\.\/x/\/modules/g' | sed 's/spec\/README.md//g' | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./modules/README.md
|
||||
## Vesting is a submodule of auth, but we still want to display it in docs
|
||||
## TODO to be removed in https://github.com/cosmos/cosmos-sdk/issues/9958
|
||||
mkdir -p modules/vesting
|
||||
cp -r ../x/auth/vesting/README.md modules/vesting
|
||||
cd modules/vesting
|
||||
csplit -k -q README.md '/<!-- order:/' '{*}' --prefix='section_' --suffix-format='%02d.md'
|
||||
mv section_00.md README.md
|
||||
cd ../..
|
||||
|
||||
cat ../x/README.md | sed 's/\.\/x/\/modules/g' | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./modules/README.md
|
||||
|
||||
cp ../cosmovisor/README.md ./run-node/cosmovisor.md
|
||||
|
||||
32
x/README.md
32
x/README.md
@ -6,22 +6,22 @@ order: 0
|
||||
|
||||
Here are some production-grade modules that can be used in Cosmos SDK applications, along with their respective documentation:
|
||||
|
||||
* [Auth](auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK applications.
|
||||
* [Authz](authz/spec/README.md) - Authorization for accounts to perform actions on behalf of other accounts.
|
||||
* [Bank](bank/spec/README.md) - Token transfer functionalities.
|
||||
* [Capability](capability/spec/README.md) - Object capability implementation.
|
||||
* [Crisis](crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken).
|
||||
* [Distribution](distribution/spec/README.md) - Fee distribution, and staking token provision distribution.
|
||||
* [Epoching](epoching/spec/README.md) - Allows modules to queue messages for execution at a certain block height.
|
||||
* [Evidence](evidence/spec/README.md) - Evidence handling for double signing, misbehaviour, etc.
|
||||
* [Feegrant](feegrant/spec/README.md) - Grant fee allowances for executing transactions.
|
||||
* [Governance](gov/spec/README.md) - On-chain proposals and voting.
|
||||
* [Mint](mint/spec/README.md) - Creation of new units of staking token.
|
||||
* [Params](params/spec/README.md) - Globally available parameter store.
|
||||
* [Slashing](slashing/spec/README.md) - Validator punishment mechanisms.
|
||||
* [Staking](staking/spec/README.md) - Proof-of-Stake layer for public blockchains.
|
||||
* [Upgrade](upgrade/spec/README.md) - Software upgrades handling and coordination.
|
||||
* [Nft](nft/spec/README.md) - NFT module implemented based on [ADR43](https://docs.cosmos.network/master/architecture/adr-043-nft-module.html).
|
||||
* [Auth](auth/README.md) - Authentication of accounts and transactions for Cosmos SDK applications.
|
||||
* [Authz](authz/README.md) - Authorization for accounts to perform actions on behalf of other accounts.
|
||||
* [Bank](bank/README.md) - Token transfer functionalities.
|
||||
* [Capability](capability/README.md) - Object capability implementation.
|
||||
* [Crisis](crisis/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken).
|
||||
* [Distribution](distribution/README.md) - Fee distribution, and staking token provision distribution.
|
||||
* [Epoching](epoching/README.md) - Allows modules to queue messages for execution at a certain block height.
|
||||
* [Evidence](evidence/README.md) - Evidence handling for double signing, misbehaviour, etc.
|
||||
* [Feegrant](feegrant/README.md) - Grant fee allowances for executing transactions.
|
||||
* [Governance](gov/README.md) - On-chain proposals and voting.
|
||||
* [Mint](mint/README.md) - Creation of new units of staking token.
|
||||
* [Params](params/README.md) - Globally available parameter store.
|
||||
* [Slashing](slashing/README.md) - Validator punishment mechanisms.
|
||||
* [Staking](staking/README.md) - Proof-of-Stake layer for public blockchains.
|
||||
* [Upgrade](upgrade/README.md) - Software upgrades handling and coordination.
|
||||
* [NFT](nft/README.md) - NFT module implemented based on [ADR43](https://docs.cosmos.network/main/architecture/adr-043-nft-module.html).
|
||||
|
||||
To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md).
|
||||
|
||||
|
||||
620
x/auth/README.md
620
x/auth/README.md
@ -1,7 +1,623 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: "Auth Overview"
|
||||
parent:
|
||||
title: "auth"
|
||||
-->
|
||||
|
||||
# Auth
|
||||
# `x/auth`
|
||||
|
||||
* [Auth](spec/README.md) - Authentication of accounts and transactions for Cosmos SDK applications.
|
||||
## Abstract
|
||||
|
||||
This document specifies the auth module of the Cosmos SDK.
|
||||
|
||||
The auth module is responsible for specifying the base transaction and account types
|
||||
for an application, since the SDK itself is agnostic to these particulars. It contains
|
||||
the middlewares, where all basic transaction validity checks (signatures, nonces, auxiliary fields)
|
||||
are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts.
|
||||
|
||||
This module is used in the Cosmos Hub.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [Gas & Fees](#gas--fees)
|
||||
* [State](#state)
|
||||
* [Accounts](#accounts)
|
||||
* [AnteHandlers](#antehandlers)
|
||||
* [Keepers](#keepers)
|
||||
* [Account Keeper](#account-keeper)
|
||||
* [Parameters](#parameters)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
* [REST](#rest)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
**Note:** The auth module is different from the [authz module](../modules/authz/).
|
||||
|
||||
The differences are:
|
||||
|
||||
* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types.
|
||||
* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter.
|
||||
|
||||
## Gas & Fees
|
||||
|
||||
Fees serve two purposes for an operator of the network.
|
||||
|
||||
Fees limit the growth of the state stored by every full node and allow for
|
||||
general purpose censorship of transactions of little economic value. Fees
|
||||
are best suited as an anti-spam mechanism where validators are disinterested in
|
||||
the use of the network and identities of users.
|
||||
|
||||
Fees are determined by the gas limits and gas prices transactions provide, where
|
||||
`fees = ceil(gasLimit * gasPrices)`. Txs incur gas costs for all state reads/writes,
|
||||
signature verification, as well as costs proportional to the tx size. Operators
|
||||
should set minimum gas prices when starting their nodes. They must set the unit
|
||||
costs of gas in each token denomination they wish to support:
|
||||
|
||||
`simd start ... --minimum-gas-prices=0.00001stake;0.05photinos`
|
||||
|
||||
When adding transactions to mempool or gossipping transactions, validators check
|
||||
if the transaction's gas prices, which are determined by the provided fees, meet
|
||||
any of the validator's minimum gas prices. In other words, a transaction must
|
||||
provide a fee of at least one denomination that matches a validator's minimum
|
||||
gas price.
|
||||
|
||||
Tendermint does not currently provide fee based mempool prioritization, and fee
|
||||
based mempool filtering is local to node and not part of consensus. But with
|
||||
minimum gas prices set, such a mechanism could be implemented by node operators.
|
||||
|
||||
Because the market value for tokens will fluctuate, validators are expected to
|
||||
dynamically adjust their minimum gas prices to a level that would encourage the
|
||||
use of the network.
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
## Accounts
|
||||
|
||||
Accounts contain authentication information for a uniquely identified external user of an SDK blockchain,
|
||||
including public key, address, and account number / sequence number for replay protection. For efficiency,
|
||||
since account balances must also be fetched to pay fees, account structs also store the balance of a user
|
||||
as `sdk.Coins`.
|
||||
|
||||
Accounts are exposed externally as an interface, and stored internally as
|
||||
either a base account or vesting account. Module clients wishing to add more
|
||||
account types may do so.
|
||||
|
||||
* `0x01 | Address -> ProtocolBuffer(account)`
|
||||
|
||||
### Account Interface
|
||||
|
||||
The account interface exposes methods to read and write standard account information.
|
||||
Note that all of these methods operate on an account struct confirming to the
|
||||
interface - in order to write the account to the store, the account keeper will
|
||||
need to be used.
|
||||
|
||||
```go
|
||||
// AccountI is an interface used to store coins at a given address within state.
|
||||
// It presumes a notion of sequence numbers for replay protection,
|
||||
// a notion of account numbers for replay protection for previously pruned accounts,
|
||||
// and a pubkey for authentication purposes.
|
||||
//
|
||||
// Many complex conditions can be used in the concrete struct which implements AccountI.
|
||||
type AccountI interface {
|
||||
proto.Message
|
||||
|
||||
GetAddress() sdk.AccAddress
|
||||
SetAddress(sdk.AccAddress) error // errors if already set.
|
||||
|
||||
GetPubKey() crypto.PubKey // can return nil.
|
||||
SetPubKey(crypto.PubKey) error
|
||||
|
||||
GetAccountNumber() uint64
|
||||
SetAccountNumber(uint64) error
|
||||
|
||||
GetSequence() uint64
|
||||
SetSequence(uint64) error
|
||||
|
||||
// Ensure that account implements stringer
|
||||
String() string
|
||||
}
|
||||
```
|
||||
|
||||
#### Base Account
|
||||
|
||||
A base account is the simplest and most common account type, which just stores all requisite
|
||||
fields directly in a struct.
|
||||
|
||||
```protobuf
|
||||
// BaseAccount defines a base account type. It contains all the necessary fields
|
||||
// for basic account functionality. Any custom account type should extend this
|
||||
// type for additional functionality (e.g. vesting).
|
||||
message BaseAccount {
|
||||
string address = 1;
|
||||
google.protobuf.Any pub_key = 2;
|
||||
uint64 account_number = 3;
|
||||
uint64 sequence = 4;
|
||||
}
|
||||
```
|
||||
|
||||
### Vesting Account
|
||||
|
||||
See [Vesting](https://docs.cosmos.network/main/modules/vesting/).
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# AnteHandlers
|
||||
|
||||
The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool.
|
||||
The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-010-modular-antehandler.md).
|
||||
|
||||
Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`.
|
||||
|
||||
## Decorators
|
||||
|
||||
The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order:
|
||||
|
||||
* `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used.
|
||||
|
||||
* `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions.
|
||||
|
||||
* `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`.
|
||||
|
||||
* `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error.
|
||||
|
||||
* `TxTimeoutHeightDecorator`: Check for a `tx` height timeout.
|
||||
|
||||
* `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error.
|
||||
|
||||
* `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters.
|
||||
|
||||
* `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it deducts fees from the fee granter account.
|
||||
|
||||
* `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context.
|
||||
|
||||
* `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters.
|
||||
|
||||
* `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||
|
||||
* `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||
|
||||
* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks.
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Keepers
|
||||
|
||||
The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts.
|
||||
|
||||
## Account Keeper
|
||||
|
||||
Presently only one fully-permissioned account keeper is exposed, which has the ability to both read and write
|
||||
all fields of all accounts, and to iterate over all stored accounts.
|
||||
|
||||
```go
|
||||
// AccountKeeperI is the interface contract that x/auth's keeper implements.
|
||||
type AccountKeeperI interface {
|
||||
// Return a new account with the next account number and the specified address. Does not save the new account to the store.
|
||||
NewAccountWithAddress(sdk.Context, sdk.AccAddress) types.AccountI
|
||||
|
||||
// Return a new account with the next account number. Does not save the new account to the store.
|
||||
NewAccount(sdk.Context, types.AccountI) types.AccountI
|
||||
|
||||
// Check if an account exists in the store.
|
||||
HasAccount(sdk.Context, sdk.AccAddress) bool
|
||||
|
||||
// Retrieve an account from the store.
|
||||
GetAccount(sdk.Context, sdk.AccAddress) types.AccountI
|
||||
|
||||
// Set an account in the store.
|
||||
SetAccount(sdk.Context, types.AccountI)
|
||||
|
||||
// Remove an account from the store.
|
||||
RemoveAccount(sdk.Context, types.AccountI)
|
||||
|
||||
// Iterate over all accounts, calling the provided function. Stop iteration when it returns true.
|
||||
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
||||
|
||||
// Fetch the public key of an account at a specified address
|
||||
GetPubKey(sdk.Context, sdk.AccAddress) (crypto.PubKey, error)
|
||||
|
||||
// Fetch the sequence of an account at a specified address.
|
||||
GetSequence(sdk.Context, sdk.AccAddress) (uint64, error)
|
||||
|
||||
// Fetch the next account number, and increment the internal counter.
|
||||
GetNextAccountNumber(sdk.Context) uint64
|
||||
}
|
||||
```
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Parameters
|
||||
|
||||
The auth module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
| ---------------------- | --------------- | ------- |
|
||||
| MaxMemoCharacters | uint64 | 256 |
|
||||
| TxSigLimit | uint64 | 7 |
|
||||
| TxSizeCostPerByte | uint64 | 10 |
|
||||
| SigVerifyCostED25519 | uint64 | 590 |
|
||||
| SigVerifyCostSecp256k1 | uint64 | 1000 |
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `auth` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `auth` state.
|
||||
|
||||
```bash
|
||||
simd query auth --help
|
||||
```
|
||||
|
||||
#### account
|
||||
|
||||
The `account` command allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
simd query auth account [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth account cosmos1...
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
'@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "0"
|
||||
address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2
|
||||
pub_key:
|
||||
'@type': /cosmos.crypto.secp256k1.PubKey
|
||||
key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD
|
||||
sequence: "1"
|
||||
```
|
||||
|
||||
#### accounts
|
||||
|
||||
The `accounts` command allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
simd query auth accounts [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth accounts
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
accounts:
|
||||
- '@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "0"
|
||||
address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2
|
||||
pub_key:
|
||||
'@type': /cosmos.crypto.secp256k1.PubKey
|
||||
key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD
|
||||
sequence: "1"
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "8"
|
||||
address: cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: transfer
|
||||
permissions:
|
||||
- minter
|
||||
- burner
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "4"
|
||||
address: cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: bonded_tokens_pool
|
||||
permissions:
|
||||
- burner
|
||||
- staking
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "5"
|
||||
address: cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: not_bonded_tokens_pool
|
||||
permissions:
|
||||
- burner
|
||||
- staking
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "6"
|
||||
address: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: gov
|
||||
permissions:
|
||||
- burner
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "3"
|
||||
address: cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: distribution
|
||||
permissions: []
|
||||
- '@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "1"
|
||||
address: cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "7"
|
||||
address: cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: mint
|
||||
permissions:
|
||||
- minter
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "2"
|
||||
address: cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: fee_collector
|
||||
permissions: []
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
simd query auth params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
max_memo_characters: "256"
|
||||
sig_verify_cost_ed25519: "590"
|
||||
sig_verify_cost_secp256k1: "1000"
|
||||
tx_sig_limit: "7"
|
||||
tx_size_cost_per_byte: "10"
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `auth` module using gRPC endpoints.
|
||||
|
||||
### Account
|
||||
|
||||
The `account` endpoint allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Account
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Account
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"account":{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2",
|
||||
"pubKey":{
|
||||
"@type":"/cosmos.crypto.secp256k1.PubKey",
|
||||
"key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD"
|
||||
},
|
||||
"sequence":"1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Accounts
|
||||
|
||||
The `accounts` endpoint allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Accounts
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Accounts
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"accounts":[
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2",
|
||||
"pubKey":{
|
||||
"@type":"/cosmos.crypto.secp256k1.PubKey",
|
||||
"key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD"
|
||||
},
|
||||
"sequence":"1"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr",
|
||||
"accountNumber":"8"
|
||||
},
|
||||
"name":"transfer",
|
||||
"permissions":[
|
||||
"minter",
|
||||
"burner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
|
||||
"accountNumber":"4"
|
||||
},
|
||||
"name":"bonded_tokens_pool",
|
||||
"permissions":[
|
||||
"burner",
|
||||
"staking"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r",
|
||||
"accountNumber":"5"
|
||||
},
|
||||
"name":"not_bonded_tokens_pool",
|
||||
"permissions":[
|
||||
"burner",
|
||||
"staking"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
|
||||
"accountNumber":"6"
|
||||
},
|
||||
"name":"gov",
|
||||
"permissions":[
|
||||
"burner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl",
|
||||
"accountNumber":"3"
|
||||
},
|
||||
"name":"distribution"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"accountNumber":"1",
|
||||
"address":"cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q",
|
||||
"accountNumber":"7"
|
||||
},
|
||||
"name":"mint",
|
||||
"permissions":[
|
||||
"minter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta",
|
||||
"accountNumber":"2"
|
||||
},
|
||||
"name":"fee_collector"
|
||||
}
|
||||
],
|
||||
"pagination":{
|
||||
"total":"9"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `params` endpoint allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"params": {
|
||||
"maxMemoCharacters": "256",
|
||||
"txSigLimit": "7",
|
||||
"txSizeCostPerByte": "10",
|
||||
"sigVerifyCostEd25519": "590",
|
||||
"sigVerifyCostSecp256k1": "1000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `auth` module using REST endpoints.
|
||||
|
||||
### Account
|
||||
|
||||
The `account` endpoint allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/account?address={address}
|
||||
```
|
||||
|
||||
### Accounts
|
||||
|
||||
The `accounts` endpoint allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/accounts
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `params` endpoint allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/params
|
||||
```
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
**Note:** The auth module is different from the [authz module](../modules/authz/).
|
||||
|
||||
The differences are:
|
||||
|
||||
* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types.
|
||||
* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter.
|
||||
|
||||
## Gas & Fees
|
||||
|
||||
Fees serve two purposes for an operator of the network.
|
||||
|
||||
Fees limit the growth of the state stored by every full node and allow for
|
||||
general purpose censorship of transactions of little economic value. Fees
|
||||
are best suited as an anti-spam mechanism where validators are disinterested in
|
||||
the use of the network and identities of users.
|
||||
|
||||
Fees are determined by the gas limits and gas prices transactions provide, where
|
||||
`fees = ceil(gasLimit * gasPrices)`. Txs incur gas costs for all state reads/writes,
|
||||
signature verification, as well as costs proportional to the tx size. Operators
|
||||
should set minimum gas prices when starting their nodes. They must set the unit
|
||||
costs of gas in each token denomination they wish to support:
|
||||
|
||||
`simd start ... --minimum-gas-prices=0.00001stake;0.05photinos`
|
||||
|
||||
When adding transactions to mempool or gossipping transactions, validators check
|
||||
if the transaction's gas prices, which are determined by the provided fees, meet
|
||||
any of the validator's minimum gas prices. In other words, a transaction must
|
||||
provide a fee of at least one denomination that matches a validator's minimum
|
||||
gas price.
|
||||
|
||||
Tendermint does not currently provide fee based mempool prioritization, and fee
|
||||
based mempool filtering is local to node and not part of consensus. But with
|
||||
minimum gas prices set, such a mechanism could be implemented by node operators.
|
||||
|
||||
Because the market value for tokens will fluctuate, validators are expected to
|
||||
dynamically adjust their minimum gas prices to a level that would encourage the
|
||||
use of the network.
|
||||
@ -1,73 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## Accounts
|
||||
|
||||
Accounts contain authentication information for a uniquely identified external user of an SDK blockchain,
|
||||
including public key, address, and account number / sequence number for replay protection. For efficiency,
|
||||
since account balances must also be fetched to pay fees, account structs also store the balance of a user
|
||||
as `sdk.Coins`.
|
||||
|
||||
Accounts are exposed externally as an interface, and stored internally as
|
||||
either a base account or vesting account. Module clients wishing to add more
|
||||
account types may do so.
|
||||
|
||||
* `0x01 | Address -> ProtocolBuffer(account)`
|
||||
|
||||
### Account Interface
|
||||
|
||||
The account interface exposes methods to read and write standard account information.
|
||||
Note that all of these methods operate on an account struct confirming to the
|
||||
interface - in order to write the account to the store, the account keeper will
|
||||
need to be used.
|
||||
|
||||
```go
|
||||
// AccountI is an interface used to store coins at a given address within state.
|
||||
// It presumes a notion of sequence numbers for replay protection,
|
||||
// a notion of account numbers for replay protection for previously pruned accounts,
|
||||
// and a pubkey for authentication purposes.
|
||||
//
|
||||
// Many complex conditions can be used in the concrete struct which implements AccountI.
|
||||
type AccountI interface {
|
||||
proto.Message
|
||||
|
||||
GetAddress() sdk.AccAddress
|
||||
SetAddress(sdk.AccAddress) error // errors if already set.
|
||||
|
||||
GetPubKey() crypto.PubKey // can return nil.
|
||||
SetPubKey(crypto.PubKey) error
|
||||
|
||||
GetAccountNumber() uint64
|
||||
SetAccountNumber(uint64) error
|
||||
|
||||
GetSequence() uint64
|
||||
SetSequence(uint64) error
|
||||
|
||||
// Ensure that account implements stringer
|
||||
String() string
|
||||
}
|
||||
```
|
||||
|
||||
#### Base Account
|
||||
|
||||
A base account is the simplest and most common account type, which just stores all requisite
|
||||
fields directly in a struct.
|
||||
|
||||
```protobuf
|
||||
// BaseAccount defines a base account type. It contains all the necessary fields
|
||||
// for basic account functionality. Any custom account type should extend this
|
||||
// type for additional functionality (e.g. vesting).
|
||||
message BaseAccount {
|
||||
string address = 1;
|
||||
google.protobuf.Any pub_key = 2;
|
||||
uint64 account_number = 3;
|
||||
uint64 sequence = 4;
|
||||
}
|
||||
```
|
||||
|
||||
### Vesting Account
|
||||
|
||||
See [Vesting](05_vesting.md).
|
||||
@ -1,40 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# AnteHandlers
|
||||
|
||||
The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool.
|
||||
The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-010-modular-antehandler.md).
|
||||
|
||||
Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`.
|
||||
|
||||
## Decorators
|
||||
|
||||
The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order:
|
||||
|
||||
* `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used.
|
||||
|
||||
* `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions.
|
||||
|
||||
* `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`.
|
||||
|
||||
* `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error.
|
||||
|
||||
* `TxTimeoutHeightDecorator`: Check for a `tx` height timeout.
|
||||
|
||||
* `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error.
|
||||
|
||||
* `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters.
|
||||
|
||||
* `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it deducts fees from the fee granter account.
|
||||
|
||||
* `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context.
|
||||
|
||||
* `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters.
|
||||
|
||||
* `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||
|
||||
* `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||
|
||||
* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks.
|
||||
@ -1,47 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Keepers
|
||||
|
||||
The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts.
|
||||
|
||||
## Account Keeper
|
||||
|
||||
Presently only one fully-permissioned account keeper is exposed, which has the ability to both read and write
|
||||
all fields of all accounts, and to iterate over all stored accounts.
|
||||
|
||||
```go
|
||||
// AccountKeeperI is the interface contract that x/auth's keeper implements.
|
||||
type AccountKeeperI interface {
|
||||
// Return a new account with the next account number and the specified address. Does not save the new account to the store.
|
||||
NewAccountWithAddress(sdk.Context, sdk.AccAddress) types.AccountI
|
||||
|
||||
// Return a new account with the next account number. Does not save the new account to the store.
|
||||
NewAccount(sdk.Context, types.AccountI) types.AccountI
|
||||
|
||||
// Check if an account exists in the store.
|
||||
HasAccount(sdk.Context, sdk.AccAddress) bool
|
||||
|
||||
// Retrieve an account from the store.
|
||||
GetAccount(sdk.Context, sdk.AccAddress) types.AccountI
|
||||
|
||||
// Set an account in the store.
|
||||
SetAccount(sdk.Context, types.AccountI)
|
||||
|
||||
// Remove an account from the store.
|
||||
RemoveAccount(sdk.Context, types.AccountI)
|
||||
|
||||
// Iterate over all accounts, calling the provided function. Stop iteration when it returns true.
|
||||
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
||||
|
||||
// Fetch the public key of an account at a specified address
|
||||
GetPubKey(sdk.Context, sdk.AccAddress) (crypto.PubKey, error)
|
||||
|
||||
// Fetch the sequence of an account at a specified address.
|
||||
GetSequence(sdk.Context, sdk.AccAddress) (uint64, error)
|
||||
|
||||
// Fetch the next account number, and increment the internal counter.
|
||||
GetNextAccountNumber(sdk.Context) uint64
|
||||
}
|
||||
```
|
||||
@ -1,15 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The auth module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
| ---------------------- | --------------- | ------- |
|
||||
| MaxMemoCharacters | uint64 | 256 |
|
||||
| TxSigLimit | uint64 | 7 |
|
||||
| TxSizeCostPerByte | uint64 | 10 |
|
||||
| SigVerifyCostED25519 | uint64 | 590 |
|
||||
| SigVerifyCostSecp256k1 | uint64 | 1000 |
|
||||
@ -1,421 +0,0 @@
|
||||
<!--
|
||||
order: 7
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
# Auth
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `auth` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `auth` state.
|
||||
|
||||
```bash
|
||||
simd query auth --help
|
||||
```
|
||||
|
||||
#### account
|
||||
|
||||
The `account` command allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
simd query auth account [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth account cosmos1...
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
'@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "0"
|
||||
address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2
|
||||
pub_key:
|
||||
'@type': /cosmos.crypto.secp256k1.PubKey
|
||||
key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD
|
||||
sequence: "1"
|
||||
```
|
||||
|
||||
#### accounts
|
||||
|
||||
The `accounts` command allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
simd query auth accounts [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth accounts
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
accounts:
|
||||
- '@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "0"
|
||||
address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2
|
||||
pub_key:
|
||||
'@type': /cosmos.crypto.secp256k1.PubKey
|
||||
key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD
|
||||
sequence: "1"
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "8"
|
||||
address: cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: transfer
|
||||
permissions:
|
||||
- minter
|
||||
- burner
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "4"
|
||||
address: cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: bonded_tokens_pool
|
||||
permissions:
|
||||
- burner
|
||||
- staking
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "5"
|
||||
address: cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: not_bonded_tokens_pool
|
||||
permissions:
|
||||
- burner
|
||||
- staking
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "6"
|
||||
address: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: gov
|
||||
permissions:
|
||||
- burner
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "3"
|
||||
address: cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: distribution
|
||||
permissions: []
|
||||
- '@type': /cosmos.auth.v1beta1.BaseAccount
|
||||
account_number: "1"
|
||||
address: cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "7"
|
||||
address: cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: mint
|
||||
permissions:
|
||||
- minter
|
||||
- '@type': /cosmos.auth.v1beta1.ModuleAccount
|
||||
base_account:
|
||||
account_number: "2"
|
||||
address: cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta
|
||||
pub_key: null
|
||||
sequence: "0"
|
||||
name: fee_collector
|
||||
permissions: []
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
simd query auth params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query auth params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
max_memo_characters: "256"
|
||||
sig_verify_cost_ed25519: "590"
|
||||
sig_verify_cost_secp256k1: "1000"
|
||||
tx_sig_limit: "7"
|
||||
tx_size_cost_per_byte: "10"
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `auth` module using gRPC endpoints.
|
||||
|
||||
### Account
|
||||
|
||||
The `account` endpoint allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Account
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Account
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"account":{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2",
|
||||
"pubKey":{
|
||||
"@type":"/cosmos.crypto.secp256k1.PubKey",
|
||||
"key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD"
|
||||
},
|
||||
"sequence":"1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Accounts
|
||||
|
||||
The `accounts` endpoint allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Accounts
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Accounts
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"accounts":[
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2",
|
||||
"pubKey":{
|
||||
"@type":"/cosmos.crypto.secp256k1.PubKey",
|
||||
"key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD"
|
||||
},
|
||||
"sequence":"1"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr",
|
||||
"accountNumber":"8"
|
||||
},
|
||||
"name":"transfer",
|
||||
"permissions":[
|
||||
"minter",
|
||||
"burner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
|
||||
"accountNumber":"4"
|
||||
},
|
||||
"name":"bonded_tokens_pool",
|
||||
"permissions":[
|
||||
"burner",
|
||||
"staking"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r",
|
||||
"accountNumber":"5"
|
||||
},
|
||||
"name":"not_bonded_tokens_pool",
|
||||
"permissions":[
|
||||
"burner",
|
||||
"staking"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
|
||||
"accountNumber":"6"
|
||||
},
|
||||
"name":"gov",
|
||||
"permissions":[
|
||||
"burner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl",
|
||||
"accountNumber":"3"
|
||||
},
|
||||
"name":"distribution"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.BaseAccount",
|
||||
"accountNumber":"1",
|
||||
"address":"cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j"
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q",
|
||||
"accountNumber":"7"
|
||||
},
|
||||
"name":"mint",
|
||||
"permissions":[
|
||||
"minter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type":"/cosmos.auth.v1beta1.ModuleAccount",
|
||||
"baseAccount":{
|
||||
"address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta",
|
||||
"accountNumber":"2"
|
||||
},
|
||||
"name":"fee_collector"
|
||||
}
|
||||
],
|
||||
"pagination":{
|
||||
"total":"9"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `params` endpoint allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
cosmos.auth.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.auth.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"params": {
|
||||
"maxMemoCharacters": "256",
|
||||
"txSigLimit": "7",
|
||||
"txSizeCostPerByte": "10",
|
||||
"sigVerifyCostEd25519": "590",
|
||||
"sigVerifyCostSecp256k1": "1000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `auth` module using REST endpoints.
|
||||
|
||||
### Account
|
||||
|
||||
The `account` endpoint allow users to query for an account by it's address.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/account?address={address}
|
||||
```
|
||||
|
||||
### Accounts
|
||||
|
||||
The `accounts` endpoint allow users to query all the available accounts.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/accounts
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `params` endpoint allow users to query the current auth parameters.
|
||||
|
||||
```bash
|
||||
/cosmos/auth/v1beta1/params
|
||||
```
|
||||
|
||||
# Vesting
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `vesting` module using the CLI.
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `vesting` module.
|
||||
|
||||
```bash
|
||||
simd tx vesting --help
|
||||
```
|
||||
|
||||
#### create-periodic-vesting-account
|
||||
|
||||
The `create-periodic-vesting-account` command creates a new vesting account funded with an allocation of tokens, where a sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation.
|
||||
|
||||
```bash
|
||||
simd tx vesting create-periodic-vesting-account [to_address] [periods_json_file] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx vesting create-periodic-vesting-account cosmos1.. periods.json
|
||||
```
|
||||
|
||||
#### create-vesting-account
|
||||
|
||||
The `create-vesting-account` command creates a new vesting account funded with an allocation of tokens. The account can either be a delayed or continuous vesting account, which is determined by the '--delayed' flag. All vesting accouts created will have their start time set by the committed block's time. The end_time must be provided as a UNIX epoch timestamp.
|
||||
|
||||
```bash
|
||||
simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx vesting create-vesting-account cosmos1.. 100stake 2592000
|
||||
```
|
||||
@ -1,45 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: "Auth Overview"
|
||||
parent:
|
||||
title: "auth"
|
||||
-->
|
||||
|
||||
# `auth`
|
||||
|
||||
## Abstract
|
||||
|
||||
This document specifies the auth module of the Cosmos SDK.
|
||||
|
||||
The auth module is responsible for specifying the base transaction and account types
|
||||
for an application, since the SDK itself is agnostic to these particulars. It contains
|
||||
the middlewares, where all basic transaction validity checks (signatures, nonces, auxiliary fields)
|
||||
are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts.
|
||||
|
||||
This module is used in the Cosmos Hub.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
* [Gas & Fees](01_concepts.md#gas-&-fees)
|
||||
2. **[State](02_state.md)**
|
||||
* [Accounts](02_state.md#accounts)
|
||||
3. **[AnteHandlers](03_antehandlers.md)**
|
||||
4. **[Keepers](04_keepers.md)**
|
||||
* [Account Keeper](04_keepers.md#account-keeper)
|
||||
5. **[Vesting](05_vesting.md)**
|
||||
* [Intro and Requirements](05_vesting.md#intro-and-requirements)
|
||||
* [Vesting Account Types](05_vesting.md#vesting-account-types)
|
||||
* [Vesting Account Specification](05_vesting.md#vesting-account-specification)
|
||||
* [Keepers & Handlers](05_vesting.md#keepers-&-handlers)
|
||||
* [Genesis Initialization](05_vesting.md#genesis-initialization)
|
||||
* [Examples](05_vesting.md#examples)
|
||||
* [Glossary](05_vesting.md#glossary)
|
||||
6. **[Parameters](06_params.md)**
|
||||
7. **[Client](07_client.md)**
|
||||
* **[Auth](07_client.md#auth)**
|
||||
* [CLI](07_client.md#cli)
|
||||
* [gRPC](07_client.md#grpc)
|
||||
* [REST](07_client.md#rest)
|
||||
* **[Vesting](07_client.md#vesting)**
|
||||
* [CLI](07_client.md#vesting#cli)
|
||||
@ -1,5 +1,8 @@
|
||||
<!--
|
||||
order: 5
|
||||
order: 0
|
||||
title: "Vesting Overview"
|
||||
parent:
|
||||
title: "vesting"
|
||||
-->
|
||||
|
||||
# Vesting
|
||||
@ -32,6 +35,8 @@ order: 5
|
||||
* [Slashing](#slashing)
|
||||
* [Periodic Vesting](#periodic-vesting)
|
||||
* [Glossary](#glossary)
|
||||
* [Client](#client)
|
||||
* [CLI](#vesting#cli)
|
||||
|
||||
## Intro and Requirements
|
||||
|
||||
@ -628,3 +633,44 @@ all coins at a given time.
|
||||
according to a custom vesting schedule.
|
||||
* PermanentLockedAccount: It does not ever release coins, locking them indefinitely.
|
||||
Coins in this account can still be used for delegating and for governance votes even while locked.
|
||||
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `vesting` module using the CLI.
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `vesting` module.
|
||||
|
||||
```bash
|
||||
simd tx vesting --help
|
||||
```
|
||||
|
||||
#### create-periodic-vesting-account
|
||||
|
||||
The `create-periodic-vesting-account` command creates a new vesting account funded with an allocation of tokens, where a sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation.
|
||||
|
||||
```bash
|
||||
simd tx vesting create-periodic-vesting-account [to_address] [periods_json_file] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx vesting create-periodic-vesting-account cosmos1.. periods.json
|
||||
```
|
||||
|
||||
#### create-vesting-account
|
||||
|
||||
The `create-vesting-account` command creates a new vesting account funded with an allocation of tokens. The account can either be a delayed or continuous vesting account, which is determined by the '--delayed' flag. All vesting accouts created will have their start time set by the committed block's time. The end_time must be provided as a UNIX epoch timestamp.
|
||||
|
||||
```bash
|
||||
simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx vesting create-vesting-account cosmos1.. 100stake 2592000
|
||||
```
|
||||
@ -1,7 +1,334 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Authz Overview
|
||||
parent:
|
||||
title: "authz"
|
||||
-->
|
||||
|
||||
# Authz
|
||||
# `x/authz`
|
||||
|
||||
* [Authz](spec/README.md) - Authorization for accounts to perform actions on behalf of other accounts.
|
||||
## Abstract
|
||||
|
||||
`x/authz` is an implementation of a Cosmos SDK module, per [ADR 30](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md), that allows
|
||||
granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the `Authorization` interface.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [Authorization and Grant](#authorization-and-grant)
|
||||
* [Built-in Authorizations](#built-in-authorizations)
|
||||
* [Gas](#gas)
|
||||
* [State](#state)
|
||||
* [Grant](#grant)
|
||||
* [GrantQueue](#grantqueue)
|
||||
* [Messages](#messages)
|
||||
* [MsgGrant](#msggrant)
|
||||
* [MsgRevoke](#msgrevoke)
|
||||
* [MsgExec](#msgexec)
|
||||
* [Events](#events)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
* [REST](#rest)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Authorization and Grant
|
||||
|
||||
The `x/authz` module defines interfaces and messages grant authorizations to perform actions
|
||||
on behalf of one account to other accounts. The design is defined in the [ADR 030](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md).
|
||||
|
||||
A *grant* is an allowance to execute a Msg by the grantee on behalf of the granter.
|
||||
Authorization is an interface that must be implemented by a concrete authorization logic to validate and execute grants. Authorizations are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details.
|
||||
|
||||
**Note:** The authz module is different from the [auth (authentication)](../modules/auth/) module that is responsible for specifying the base transaction and account types.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/authorizations.go#L11-L25
|
||||
|
||||
## Built-in Authorizations
|
||||
|
||||
The Cosmos SDK `x/authz` module comes with following authorization types:
|
||||
|
||||
### GenericAuthorization
|
||||
|
||||
`GenericAuthorization` implements the `Authorization` interface that gives unrestricted permission to execute the provided Msg on behalf of granter's account.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L13-L20
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/generic_authorization.go#L16-L29
|
||||
|
||||
* `msg` stores Msg type URL.
|
||||
|
||||
### SendAuthorization
|
||||
|
||||
`SendAuthorization` implements the `Authorization` interface for the `cosmos.bank.v1beta1.MsgSend` Msg. It takes a (positive) `SpendLimit` that specifies the maximum amount of tokens the grantee can spend. The `SpendLimit` is updated as the tokens are spent.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/authz.proto#L10-L19
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/bank/types/send_authorization.go#L23-L38
|
||||
|
||||
* `spend_limit` keeps track of how many coins are left in the authorization.
|
||||
|
||||
### StakeAuthorization
|
||||
|
||||
`StakeAuthorization` implements the `Authorization` interface for messages in the [staking module](https://docs.cosmos.network/v0.44/modules/staking/). It takes an `AuthorizationType` to specify whether you want to authorise delegating, undelegating or redelegating (i.e. these have to be authorised seperately). It also takes a required `MaxTokens` that keeps track of a limit to the amount of tokens that can be delegated/undelegated/redelegated. If left empty, the amount is unlimited. Additionally, this Msg takes an `AllowList` or a `DenyList`, which allows you to select which validators you allow or deny grantees to stake with.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/authz.proto#L10-L33
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/staking/types/authz.go#L15-L35
|
||||
|
||||
## Gas
|
||||
|
||||
In order to prevent DoS attacks, granting `StakeAuthorization`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK iterates over these lists and charge 10 gas for each validator in both of the lists.
|
||||
|
||||
Since the state maintaining a list for granter, grantee pair with same expiration, we are iterating over the list to remove the grant (incase of any revoke of paritcular `msgType`) from the list and we are charging 20 gas per iteration.
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
## Grant
|
||||
|
||||
Grants are identified by combining granter address (the address bytes of the granter), grantee address (the address bytes of the grantee) and Authorization type (its type URL). Hence we only allow one grant for the (granter, grantee, Authorization) triple.
|
||||
|
||||
* Grant: `0x01 | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes | msgType_bytes -> ProtocolBuffer(AuthorizationGrant)`
|
||||
|
||||
The grant object encapsulates an `Authorization` type and an expiration timestamp:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L22-L30
|
||||
|
||||
## GrantQueue
|
||||
|
||||
We are maintaining a queue for authz pruning. Whenever a grant is created, an item will be added to `GrantQueue` with a key of expiration, granter, grantee.
|
||||
|
||||
* GrantQueue: `0x02 | expiration_bytes | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes -> ProtocalBuffer(GrantQueueItem)`
|
||||
|
||||
The `expiration_bytes` are the expiration date in UTC with the format `"2006-01-02T15:04:05.000000000"`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/keeper/keys.go#L78-L93
|
||||
|
||||
The `GrantQueueItem` object contains the list of type urls between granter and grantee that expire at the time indicated in the key.
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Messages
|
||||
|
||||
In this section we describe the processing of messages for the authz module.
|
||||
|
||||
## MsgGrant
|
||||
|
||||
An authorization grant is created using the `MsgGrant` message.
|
||||
If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant overwrites the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L32-L41
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* both granter and grantee have the same address.
|
||||
* provided `Expiration` time is less than current unix timestamp (but a grant will be created if no `expiration` time is provided since `expiration` is optional).
|
||||
* provided `Grant.Authorization` is not implemented.
|
||||
* `Authorization.MsgTypeURL()` is not defined in the router (there is no defined handler in the app router to handle that Msg types).
|
||||
|
||||
## MsgRevoke
|
||||
|
||||
A grant can be removed with the `MsgRevoke` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L66-L72
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* both granter and grantee have the same address.
|
||||
* provided `MsgTypeUrl` is empty.
|
||||
|
||||
NOTE: The `MsgExec` message removes a grant if the grant has expired.
|
||||
|
||||
## MsgExec
|
||||
|
||||
When a grantee wants to execute a transaction on behalf of a granter, they must send `MsgExec`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L51-L59
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* provided `Authorization` is not implemented.
|
||||
* grantee doesn't have permission to run the transaction.
|
||||
* if granted authorization is expired.
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Events
|
||||
|
||||
The authz module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main/cosmos.authz.v1beta1#cosmos.authz.v1beta1.EventGrant).
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `authz` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `authz` state.
|
||||
|
||||
```bash
|
||||
simd query authz --help
|
||||
```
|
||||
|
||||
#### grants
|
||||
|
||||
The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type.
|
||||
|
||||
```bash
|
||||
simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query authz grants cosmos1.. cosmos1.. /cosmos.bank.v1beta1.MsgSend
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
grants:
|
||||
- authorization:
|
||||
'@type': /cosmos.bank.v1beta1.SendAuthorization
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
expiration: "2022-01-01T00:00:00Z"
|
||||
pagination: null
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `authz` module.
|
||||
|
||||
```bash
|
||||
simd tx authz --help
|
||||
```
|
||||
|
||||
#### exec
|
||||
|
||||
The `exec` command allows a grantee to execute a transaction on behalf of granter.
|
||||
|
||||
```bash
|
||||
simd tx authz exec [tx-json-file] --from [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz exec tx.json --from=cosmos1..
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows a granter to grant an authorization to a grantee.
|
||||
|
||||
```bash
|
||||
simd tx authz grant <grantee> <authorization_type="send"|"generic"|"delegate"|"unbond"|"redelegate"> --from <granter> [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz grant cosmos1.. send --spend-limit=100stake --from=cosmos1..
|
||||
```
|
||||
|
||||
#### revoke
|
||||
|
||||
The `revoke` command allows a granter to revoke an authorization from a grantee.
|
||||
|
||||
```bash
|
||||
simd tx authz revoke [grantee] [msg-type-url] --from=[granter] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz revoke cosmos1.. /cosmos.bank.v1beta1.MsgSend --from=cosmos1..
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `authz` module using gRPC endpoints.
|
||||
|
||||
### Grants
|
||||
|
||||
The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type.
|
||||
|
||||
```bash
|
||||
cosmos.authz.v1beta1.Query/Grants
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
-d '{"granter":"cosmos1..","grantee":"cosmos1..","msg_type_url":"/cosmos.bank.v1beta1.MsgSend"}' \
|
||||
localhost:9090 \
|
||||
cosmos.authz.v1beta1.Query/Grants
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"grants": [
|
||||
{
|
||||
"authorization": {
|
||||
"@type": "/cosmos.bank.v1beta1.SendAuthorization",
|
||||
"spendLimit": [
|
||||
{
|
||||
"denom":"stake",
|
||||
"amount":"100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expiration": "2022-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `authz` module using REST endpoints.
|
||||
|
||||
```bash
|
||||
/cosmos/authz/v1beta1/grants
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl "localhost:1317/cosmos/authz/v1beta1/grants?granter=cosmos1..&grantee=cosmos1..&msg_type_url=/cosmos.bank.v1beta1.MsgSend"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"grants": [
|
||||
{
|
||||
"authorization": {
|
||||
"@type": "/cosmos.bank.v1beta1.SendAuthorization",
|
||||
"spend_limit": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expiration": "2022-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": null
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Authorization and Grant
|
||||
|
||||
The `x/authz` module defines interfaces and messages grant authorizations to perform actions
|
||||
on behalf of one account to other accounts. The design is defined in the [ADR 030](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md).
|
||||
|
||||
A *grant* is an allowance to execute a Msg by the grantee on behalf of the granter.
|
||||
Authorization is an interface that must be implemented by a concrete authorization logic to validate and execute grants. Authorizations are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details.
|
||||
|
||||
**Note:** The authz module is different from the [auth (authentication)](../modules/auth/) module that is responsible for specifying the base transaction and account types.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/authorizations.go#L11-L25
|
||||
|
||||
## Built-in Authorizations
|
||||
|
||||
The Cosmos SDK `x/authz` module comes with following authorization types:
|
||||
|
||||
### GenericAuthorization
|
||||
|
||||
`GenericAuthorization` implements the `Authorization` interface that gives unrestricted permission to execute the provided Msg on behalf of granter's account.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L13-L20
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/generic_authorization.go#L16-L29
|
||||
|
||||
* `msg` stores Msg type URL.
|
||||
|
||||
### SendAuthorization
|
||||
|
||||
`SendAuthorization` implements the `Authorization` interface for the `cosmos.bank.v1beta1.MsgSend` Msg. It takes a (positive) `SpendLimit` that specifies the maximum amount of tokens the grantee can spend. The `SpendLimit` is updated as the tokens are spent.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/authz.proto#L10-L19
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/bank/types/send_authorization.go#L23-L38
|
||||
|
||||
* `spend_limit` keeps track of how many coins are left in the authorization.
|
||||
|
||||
### StakeAuthorization
|
||||
|
||||
`StakeAuthorization` implements the `Authorization` interface for messages in the [staking module](https://docs.cosmos.network/v0.44/modules/staking/). It takes an `AuthorizationType` to specify whether you want to authorise delegating, undelegating or redelegating (i.e. these have to be authorised seperately). It also takes a required `MaxTokens` that keeps track of a limit to the amount of tokens that can be delegated/undelegated/redelegated. If left empty, the amount is unlimited. Additionally, this Msg takes an `AllowList` or a `DenyList`, which allows you to select which validators you allow or deny grantees to stake with.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/authz.proto#L10-L33
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/staking/types/authz.go#L15-L35
|
||||
|
||||
## Gas
|
||||
|
||||
In order to prevent DoS attacks, granting `StakeAuthorization`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK iterates over these lists and charge 10 gas for each validator in both of the lists.
|
||||
|
||||
Since the state maintaining a list for granter, grantee pair with same expiration, we are iterating over the list to remove the grant (incase of any revoke of paritcular `msgType`) from the list and we are charging 20 gas per iteration.
|
||||
@ -1,27 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## Grant
|
||||
|
||||
Grants are identified by combining granter address (the address bytes of the granter), grantee address (the address bytes of the grantee) and Authorization type (its type URL). Hence we only allow one grant for the (granter, grantee, Authorization) triple.
|
||||
|
||||
* Grant: `0x01 | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes | msgType_bytes -> ProtocolBuffer(AuthorizationGrant)`
|
||||
|
||||
The grant object encapsulates an `Authorization` type and an expiration timestamp:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L22-L30
|
||||
|
||||
## GrantQueue
|
||||
|
||||
We are maintaining a queue for authz pruning. Whenever a grant is created, an item will be added to `GrantQueue` with a key of expiration, granter, grantee.
|
||||
|
||||
* GrantQueue: `0x02 | expiration_bytes | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes -> ProtocalBuffer(GrantQueueItem)`
|
||||
|
||||
The `expiration_bytes` are the expiration date in UTC with the format `"2006-01-02T15:04:05.000000000"`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/keeper/keys.go#L78-L93
|
||||
|
||||
The `GrantQueueItem` object contains the list of type urls between granter and grantee that expire at the time indicated in the key.
|
||||
@ -1,46 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
In this section we describe the processing of messages for the authz module.
|
||||
|
||||
## MsgGrant
|
||||
|
||||
An authorization grant is created using the `MsgGrant` message.
|
||||
If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant overwrites the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L32-L41
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* both granter and grantee have the same address.
|
||||
* provided `Expiration` time is less than current unix timestamp (but a grant will be created if no `expiration` time is provided since `expiration` is optional).
|
||||
* provided `Grant.Authorization` is not implemented.
|
||||
* `Authorization.MsgTypeURL()` is not defined in the router (there is no defined handler in the app router to handle that Msg types).
|
||||
|
||||
## MsgRevoke
|
||||
|
||||
A grant can be removed with the `MsgRevoke` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L66-L72
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* both granter and grantee have the same address.
|
||||
* provided `MsgTypeUrl` is empty.
|
||||
|
||||
NOTE: The `MsgExec` message removes a grant if the grant has expired.
|
||||
|
||||
## MsgExec
|
||||
|
||||
When a grantee wants to execute a transaction on behalf of a granter, they must send `MsgExec`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L51-L59
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* provided `Authorization` is not implemented.
|
||||
* grantee doesn't have permission to run the transaction.
|
||||
* if granted authorization is expired.
|
||||
@ -1,7 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The authz module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main/cosmos.authz.v1beta1#cosmos.authz.v1beta1.EventGrant).
|
||||
@ -1,172 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `authz` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `authz` state.
|
||||
|
||||
```bash
|
||||
simd query authz --help
|
||||
```
|
||||
|
||||
#### grants
|
||||
|
||||
The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type.
|
||||
|
||||
```bash
|
||||
simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query authz grants cosmos1.. cosmos1.. /cosmos.bank.v1beta1.MsgSend
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
grants:
|
||||
- authorization:
|
||||
'@type': /cosmos.bank.v1beta1.SendAuthorization
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
expiration: "2022-01-01T00:00:00Z"
|
||||
pagination: null
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `authz` module.
|
||||
|
||||
```bash
|
||||
simd tx authz --help
|
||||
```
|
||||
|
||||
#### exec
|
||||
|
||||
The `exec` command allows a grantee to execute a transaction on behalf of granter.
|
||||
|
||||
```bash
|
||||
simd tx authz exec [tx-json-file] --from [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz exec tx.json --from=cosmos1..
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows a granter to grant an authorization to a grantee.
|
||||
|
||||
```bash
|
||||
simd tx authz grant <grantee> <authorization_type="send"|"generic"|"delegate"|"unbond"|"redelegate"> --from <granter> [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz grant cosmos1.. send --spend-limit=100stake --from=cosmos1..
|
||||
```
|
||||
|
||||
#### revoke
|
||||
|
||||
The `revoke` command allows a granter to revoke an authorization from a grantee.
|
||||
|
||||
```bash
|
||||
simd tx authz revoke [grantee] [msg-type-url] --from=[granter] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx authz revoke cosmos1.. /cosmos.bank.v1beta1.MsgSend --from=cosmos1..
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `authz` module using gRPC endpoints.
|
||||
|
||||
### Grants
|
||||
|
||||
The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type.
|
||||
|
||||
```bash
|
||||
cosmos.authz.v1beta1.Query/Grants
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext \
|
||||
-d '{"granter":"cosmos1..","grantee":"cosmos1..","msg_type_url":"/cosmos.bank.v1beta1.MsgSend"}' \
|
||||
localhost:9090 \
|
||||
cosmos.authz.v1beta1.Query/Grants
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"grants": [
|
||||
{
|
||||
"authorization": {
|
||||
"@type": "/cosmos.bank.v1beta1.SendAuthorization",
|
||||
"spendLimit": [
|
||||
{
|
||||
"denom":"stake",
|
||||
"amount":"100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expiration": "2022-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `authz` module using REST endpoints.
|
||||
|
||||
```bash
|
||||
/cosmos/authz/v1beta1/grants
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl "localhost:1317/cosmos/authz/v1beta1/grants?granter=cosmos1..&grantee=cosmos1..&msg_type_url=/cosmos.bank.v1beta1.MsgSend"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"grants": [
|
||||
{
|
||||
"authorization": {
|
||||
"@type": "/cosmos.bank.v1beta1.SendAuthorization",
|
||||
"spend_limit": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expiration": "2022-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": null
|
||||
}
|
||||
```
|
||||
@ -1,30 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Authz Overview
|
||||
parent:
|
||||
title: "authz"
|
||||
-->
|
||||
|
||||
# `authz`
|
||||
|
||||
## Contents
|
||||
|
||||
## Abstract
|
||||
|
||||
`x/authz` is an implementation of a Cosmos SDK module, per [ADR 30](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md), that allows
|
||||
granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the `Authorization` interface.
|
||||
|
||||
1. **[Concept](01_concepts.md)**
|
||||
* [Authorization and Grant](01_concepts.md#Authorization-and-Grant)
|
||||
* [Built-in Authorizations](01_concepts.md#Built-in-Authorizations)
|
||||
* [Gas](01_concepts.md#gas)
|
||||
2. **[State](02_state.md)**
|
||||
3. **[Messages](03_messages.md)**
|
||||
* [MsgGrant](03_messages.md#MsgGrant)
|
||||
* [MsgRevoke](03_messages.md#MsgRevoke)
|
||||
* [MsgExec](03_messages.md#MsgExec)
|
||||
4. **[Events](04_events.md)**
|
||||
5. **[Client](05_client.md)**
|
||||
* [CLI](05_client.md#cli)
|
||||
* [gRPC](05_client.md#grpc)
|
||||
* [REST](05_client.md#rest)
|
||||
938
x/bank/README.md
938
x/bank/README.md
@ -1,7 +1,941 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Bank Overview
|
||||
parent:
|
||||
title: "bank"
|
||||
-->
|
||||
|
||||
# Bank
|
||||
# `x/bank`
|
||||
|
||||
* [Bank](spec/README.md) - Token transfer functionalities.
|
||||
## 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](#supply)
|
||||
* [Total Supply](#total-supply)
|
||||
* [Module Accounts](#module-accounts)
|
||||
* [Permissions](#permissions)
|
||||
* [State](#state)
|
||||
* [Params](#params)
|
||||
* [Keepers](#keepers)
|
||||
* [Messages](#messages)
|
||||
* [Events](#events)
|
||||
* [Message Events](#message-events)
|
||||
* [Keeper Events](#keeper-events)
|
||||
* [Parameters](#parameters)
|
||||
* [SendEnabled](#sendenabled)
|
||||
* [DefaultSendEnabled](#defaultsendenabled)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [Query](#query)
|
||||
* [Transactions](#transactions)
|
||||
* [gRPC](#grpc)
|
||||
|
||||
## 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:
|
||||
|
||||
```go
|
||||
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.
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
## State
|
||||
|
||||
The `x/bank` module keeps state of the following primary objects:
|
||||
|
||||
1. Account balances
|
||||
2. Denomination metadata
|
||||
3. The total supply of all balances
|
||||
4. 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
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
## 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](https://ibc.cosmos.network).
|
||||
|
||||
### Common Types
|
||||
|
||||
#### Input
|
||||
|
||||
An input of a multiparty transfer
|
||||
|
||||
```protobuf
|
||||
// Input models transaction input.
|
||||
message Input {
|
||||
string address = 1;
|
||||
repeated cosmos.base.v1beta1.Coin coins = 2;
|
||||
}
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
An output of a multiparty transfer.
|
||||
|
||||
```protobuf
|
||||
// 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).
|
||||
|
||||
```go
|
||||
// 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).
|
||||
|
||||
```go
|
||||
// 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)`.
|
||||
|
||||
```go
|
||||
// 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))
|
||||
}
|
||||
```
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
## 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.
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
## 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
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "coinbase",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "minter",
|
||||
"value": "{{sdk.AccAddress of the module minting coins}}",
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "{{sdk.Coins being minted}}",
|
||||
"index": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "burn",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "burner",
|
||||
"value": "{{sdk.AccAddress of the module burning coins}}",
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "{{sdk.Coins being burned}}",
|
||||
"index": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
## 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.
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
## 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.
|
||||
|
||||
```sh
|
||||
simd query bank --help
|
||||
```
|
||||
|
||||
#### balances
|
||||
|
||||
The `balances` command allows users to query account balances by address.
|
||||
|
||||
```sh
|
||||
simd query bank balances [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank balances cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
balances:
|
||||
- amount: "1000000000"
|
||||
denom: stake
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
#### denom-metadata
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd query bank denom-metadata [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank denom-metadata --denom stake
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd query bank total [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank total --denom stake
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
amount: "10000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### send-enabled
|
||||
|
||||
The `send-enabled` command allows users to query for all or some SendEnabled entries.
|
||||
|
||||
```sh
|
||||
simd query bank send-enabled [denom1 ...] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank send-enabled
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```yml
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd tx bank --help
|
||||
```
|
||||
|
||||
#### send
|
||||
|
||||
The `send` command allows users to send funds from one account to another.
|
||||
|
||||
```sh
|
||||
simd tx bank send [from_key_or_address] [to_address] [amount] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/Balance
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1..","denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/Balance
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"balance": {
|
||||
"denom": "stake",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AllBalances
|
||||
|
||||
The `AllBalances` endpoint allows users to query account balance by address for all denominations.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/AllBalances
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/AllBalances
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"balances": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DenomMetadata
|
||||
|
||||
The `DenomMetadata` endpoint allows users to query metadata for a single coin denomination.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomMetadata
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomMetadata
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"description": "native staking token of simulation app",
|
||||
"denomUnits": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"aliases": [
|
||||
"STAKE"
|
||||
]
|
||||
}
|
||||
],
|
||||
"base": "stake",
|
||||
"display": "stake",
|
||||
"name": "SimApp Token",
|
||||
"symbol": "STK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DenomsMetadata
|
||||
|
||||
The `DenomsMetadata` endpoint allows users to query metadata for all coin denominations.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomsMetadata
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomsMetadata
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomOwners
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomOwners
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/TotalSupply
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/TotalSupply
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"supply": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "10000000000"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SupplyOf
|
||||
|
||||
The `SupplyOf` endpoint allows users to query the total supply of a single coin.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/SupplyOf
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/SupplyOf
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": {
|
||||
"denom": "stake",
|
||||
"amount": "10000000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allows users to query the parameters of the `bank` module.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/SendEnabled
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/SendEnabled
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"send_enabled": [
|
||||
{
|
||||
"denom": "foocoin",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"denom": "barcoin"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"next-key": null,
|
||||
"total": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
The `x/bank` module keeps state of the following primary objects:
|
||||
|
||||
1. Account balances
|
||||
2. Denomination metadata
|
||||
3. The total supply of all balances
|
||||
4. 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
|
||||
@ -1,148 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# 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.
|
||||
|
||||
## Blocklisting 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](https://ibc.cosmos.network).
|
||||
|
||||
## Common Types
|
||||
|
||||
### Input
|
||||
|
||||
An input of a multiparty transfer
|
||||
|
||||
```protobuf
|
||||
// Input models transaction input.
|
||||
message Input {
|
||||
string address = 1;
|
||||
repeated cosmos.base.v1beta1.Coin coins = 2;
|
||||
}
|
||||
```
|
||||
|
||||
### Output
|
||||
|
||||
An output of a multiparty transfer.
|
||||
|
||||
```protobuf
|
||||
// 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).
|
||||
|
||||
```go
|
||||
// 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).
|
||||
|
||||
```go
|
||||
// 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)`.
|
||||
|
||||
```go
|
||||
// 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))
|
||||
}
|
||||
```
|
||||
@ -1,38 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# 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.
|
||||
@ -1,149 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The bank module emits the following events:
|
||||
|
||||
## Handlers
|
||||
|
||||
### 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 handlers events, the bank keeper will produce events when the following methods are called (or any method which ends up calling them)
|
||||
|
||||
### MintCoins
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "coinbase",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "minter",
|
||||
"value": "{{sdk.AccAddress of the module minting coins}}",
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "{{sdk.Coins being minted}}",
|
||||
"index": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "burn",
|
||||
"attributes": [
|
||||
{
|
||||
"key": "burner",
|
||||
"value": "{{sdk.AccAddress of the module burning coins}}",
|
||||
"index": true
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "{{sdk.Coins being burned}}",
|
||||
"index": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@ -1,24 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The bank module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
| ------------------ | ------------- |--------------|
|
||||
| SendEnabled | []SendEnabled | (deprecated) |
|
||||
| DefaultSendEnabled | bool | true |
|
||||
|
||||
## 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.
|
||||
@ -1,454 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# 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.
|
||||
|
||||
```sh
|
||||
simd query bank --help
|
||||
```
|
||||
|
||||
#### balances
|
||||
|
||||
The `balances` command allows users to query account balances by address.
|
||||
|
||||
```sh
|
||||
simd query bank balances [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank balances cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
balances:
|
||||
- amount: "1000000000"
|
||||
denom: stake
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
#### denom-metadata
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd query bank denom-metadata [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank denom-metadata --denom stake
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd query bank total [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank total --denom stake
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
amount: "10000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### send-enabled
|
||||
|
||||
The `send-enabled` command allows users to query for all or some SendEnabled entries.
|
||||
|
||||
```sh
|
||||
simd query bank send-enabled [denom1 ...] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query bank send-enabled
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```yml
|
||||
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.
|
||||
|
||||
```sh
|
||||
simd tx bank --help
|
||||
```
|
||||
|
||||
#### send
|
||||
|
||||
The `send` command allows users to send funds from one account to another.
|
||||
|
||||
```sh
|
||||
simd tx bank send [from_key_or_address] [to_address] [amount] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/Balance
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1..","denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/Balance
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"balance": {
|
||||
"denom": "stake",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AllBalances
|
||||
|
||||
The `AllBalances` endpoint allows users to query account balance by address for all denominations.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/AllBalances
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/AllBalances
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"balances": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DenomMetadata
|
||||
|
||||
The `DenomMetadata` endpoint allows users to query metadata for a single coin denomination.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomMetadata
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomMetadata
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"description": "native staking token of simulation app",
|
||||
"denomUnits": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"aliases": [
|
||||
"STAKE"
|
||||
]
|
||||
}
|
||||
],
|
||||
"base": "stake",
|
||||
"display": "stake",
|
||||
"name": "SimApp Token",
|
||||
"symbol": "STK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DenomsMetadata
|
||||
|
||||
The `DenomsMetadata` endpoint allows users to query metadata for all coin denominations.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomsMetadata
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomsMetadata
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/DenomOwners
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/DenomOwners
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/TotalSupply
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/TotalSupply
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"supply": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "10000000000"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SupplyOf
|
||||
|
||||
The `SupplyOf` endpoint allows users to query the total supply of a single coin.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/SupplyOf
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"denom":"stake"}' \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/SupplyOf
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": {
|
||||
"denom": "stake",
|
||||
"amount": "10000000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allows users to query the parameters of the `bank` module.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```sh
|
||||
cosmos.bank.v1beta1.Query/SendEnabled
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.bank.v1beta1.Query/SendEnabled
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"send_enabled": [
|
||||
{
|
||||
"denom": "foocoin",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"denom": "barcoin"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"next-key": null,
|
||||
"total": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,106 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Bank Overview
|
||||
parent:
|
||||
title: "bank"
|
||||
-->
|
||||
|
||||
# `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 will be used in the Cosmos Hub.
|
||||
|
||||
## 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:
|
||||
|
||||
```go
|
||||
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.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[State](01_state.md)**
|
||||
2. **[Keepers](02_keepers.md)**
|
||||
* [Common Types](02_keepers.md#common-types)
|
||||
* [BaseKeeper](02_keepers.md#basekeeper)
|
||||
* [SendKeeper](02_keepers.md#sendkeeper)
|
||||
* [ViewKeeper](02_keepers.md#viewkeeper)
|
||||
3. **[Messages](03_messages.md)**
|
||||
* [MsgSend](03_messages.md#msgsend)
|
||||
* [MsgMultiSend](03_messages.md#msgmultisend)
|
||||
4. **[Events](04_events.md)**
|
||||
* [Handlers](04_events.md#handlers)
|
||||
5. **[Parameters](05_params.md)**
|
||||
6. **[Client](06_client.md)**
|
||||
* [CLI](06_client.md#cli)
|
||||
* [gRPC](06_client.md#grpc)
|
||||
@ -1,7 +1,141 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Capability Overview
|
||||
parent:
|
||||
title: "capability"
|
||||
-->
|
||||
|
||||
# Capability
|
||||
# `x/capability`
|
||||
|
||||
* [Capability](spec/README.md) - Object capability implementation.
|
||||
## Overview
|
||||
|
||||
`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-003-dynamic-capability-store.md),
|
||||
that allows for provisioning, tracking, and authenticating multi-owner capabilities
|
||||
at runtime.
|
||||
|
||||
The keeper maintains two states: persistent and ephemeral in-memory. The persistent
|
||||
store maintains a globally unique auto-incrementing index and a mapping from
|
||||
capability index to a set of capability owners that are defined as a module and
|
||||
capability name tuple. The in-memory ephemeral state keeps track of the actual
|
||||
capabilities, represented as addresses in local memory, with both forward and reverse indexes.
|
||||
The forward index maps module name and capability tuples to the capability name. The
|
||||
reverse index maps between the module and capability name and the capability itself.
|
||||
|
||||
The keeper allows the creation of "scoped" sub-keepers which are tied to a particular
|
||||
module by name. Scoped keepers must be created at application initialization and
|
||||
passed to modules, which can then use them to claim capabilities they receive and
|
||||
retrieve capabilities which they own by name, in addition to creating new capabilities
|
||||
& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope,
|
||||
so a module cannot interfere with or inspect capabilities owned by other modules.
|
||||
|
||||
The keeper provides no other core functionality that can be found in other modules
|
||||
like queriers, REST and CLI handlers, and genesis state.
|
||||
|
||||
## Initialization
|
||||
|
||||
During application initialization, the keeper must be instantiated with a persistent
|
||||
store key and an in-memory store key.
|
||||
|
||||
```go
|
||||
type App struct {
|
||||
// ...
|
||||
|
||||
capabilityKeeper *capability.Keeper
|
||||
}
|
||||
|
||||
func NewApp(...) *App {
|
||||
// ...
|
||||
|
||||
app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey)
|
||||
}
|
||||
```
|
||||
|
||||
After the keeper is created, it can be used to create scoped sub-keepers which
|
||||
are passed to other modules that can create, authenticate, and claim capabilities.
|
||||
After all the necessary scoped keepers are created and the state is loaded, the
|
||||
main capability keeper must be sealed to prevent further scoped keepers from
|
||||
being created.
|
||||
|
||||
```go
|
||||
func NewApp(...) *App {
|
||||
// ...
|
||||
|
||||
// Creating a scoped keeper
|
||||
scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)
|
||||
|
||||
// Seal the capability keeper to prevent any further modules from creating scoped
|
||||
// sub-keepers.
|
||||
app.capabilityKeeper.Seal()
|
||||
|
||||
return app
|
||||
}
|
||||
```
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [Capabilities](#capabilities)
|
||||
* [Stores](#stores)
|
||||
* [State](#state)
|
||||
* [In persisted KV store](#in-persisted-kv-store)
|
||||
* [In-memory KV store](#in-memory-kv-store)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Capabilities
|
||||
|
||||
Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability`
|
||||
which creates a new unique, unforgeable object-capability reference. The newly
|
||||
created capability is automatically persisted; the calling module need not call
|
||||
`ClaimCapability`. Calling `NewCapability` will create the capability with the
|
||||
calling module and name as a tuple to be treated the capabilities first owner.
|
||||
|
||||
Capabilities can be claimed by other modules which add them as owners. `ClaimCapability`
|
||||
allows a module to claim a capability key which it has received from another
|
||||
module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST
|
||||
be called if a module which receives a capability wishes to access it by name in
|
||||
the future. Again, capabilities are multi-owner, so if multiple modules have a
|
||||
single Capability reference, they will all own it. If a module receives a capability
|
||||
from another module but does not call `ClaimCapability`, it may use it in the executing
|
||||
transaction but will not be able to access it afterwards.
|
||||
|
||||
`AuthenticateCapability` can be called by any module to check that a capability
|
||||
does in fact correspond to a particular name (the name can be un-trusted user input)
|
||||
with which the calling module previously associated it.
|
||||
|
||||
`GetCapability` allows a module to fetch a capability which it has previously
|
||||
claimed by name. The module is not allowed to retrieve capabilities which it does
|
||||
not own.
|
||||
|
||||
## Stores
|
||||
|
||||
* MemStore
|
||||
* KeyStore
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
## In persisted KV store
|
||||
|
||||
1. Global unique capability index
|
||||
2. Capability owners
|
||||
|
||||
Indexes:
|
||||
|
||||
* Unique index: `[]byte("index") -> []byte(currentGlobalIndex)`
|
||||
* Capability Index: `[]byte("capability_index") | []byte(index) -> ProtocolBuffer(CapabilityOwners)`
|
||||
|
||||
## In-memory KV store
|
||||
|
||||
1. Initialized flag
|
||||
2. Mapping between the module and capability tuple and the capability name
|
||||
3. Mapping between the module and capability name and its index
|
||||
|
||||
Indexes:
|
||||
|
||||
* Initialized flag: `[]byte("mem_initialized")`
|
||||
* RevCapabilityKey: `[]byte(moduleName + "/rev/" + capabilityName) -> []byte(index)`
|
||||
* FwdCapabilityKey: `[]byte(moduleName + "/fwd/" + capabilityPointerAddress) -> []byte(capabilityName)`
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Capabilities
|
||||
|
||||
Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability`
|
||||
which creates a new unique, unforgeable object-capability reference. The newly
|
||||
created capability is automatically persisted; the calling module need not call
|
||||
`ClaimCapability`. Calling `NewCapability` will create the capability with the
|
||||
calling module and name as a tuple to be treated the capabilities first owner.
|
||||
|
||||
Capabilities can be claimed by other modules which add them as owners. `ClaimCapability`
|
||||
allows a module to claim a capability key which it has received from another
|
||||
module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST
|
||||
be called if a module which receives a capability wishes to access it by name in
|
||||
the future. Again, capabilities are multi-owner, so if multiple modules have a
|
||||
single Capability reference, they will all own it. If a module receives a capability
|
||||
from another module but does not call `ClaimCapability`, it may use it in the executing
|
||||
transaction but will not be able to access it afterwards.
|
||||
|
||||
`AuthenticateCapability` can be called by any module to check that a capability
|
||||
does in fact correspond to a particular name (the name can be un-trusted user input)
|
||||
with which the calling module previously associated it.
|
||||
|
||||
`GetCapability` allows a module to fetch a capability which it has previously
|
||||
claimed by name. The module is not allowed to retrieve capabilities which it does
|
||||
not own.
|
||||
|
||||
## Stores
|
||||
|
||||
* MemStore
|
||||
* KeyStore
|
||||
@ -1,26 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
## In persisted KV store
|
||||
|
||||
1. Global unique capability index
|
||||
2. Capability owners
|
||||
|
||||
Indexes:
|
||||
|
||||
* Unique index: `[]byte("index") -> []byte(currentGlobalIndex)`
|
||||
* Capability Index: `[]byte("capability_index") | []byte(index) -> ProtocolBuffer(CapabilityOwners)`
|
||||
|
||||
## In-memory KV store
|
||||
|
||||
1. Initialized flag
|
||||
2. Mapping between the module and capability tuple and the capability name
|
||||
3. Mapping between the module and capability name and its index
|
||||
|
||||
Indexes:
|
||||
|
||||
* Initialized flag: `[]byte("mem_initialized")`
|
||||
* RevCapabilityKey: `[]byte(moduleName + "/rev/" + capabilityName) -> []byte(index)`
|
||||
* FwdCapabilityKey: `[]byte(moduleName + "/fwd/" + capabilityPointerAddress) -> []byte(capabilityName)`
|
||||
@ -1,77 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Capability Overview
|
||||
parent:
|
||||
title: "capability"
|
||||
-->
|
||||
|
||||
# `capability`
|
||||
|
||||
## Overview
|
||||
|
||||
`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-003-dynamic-capability-store.md),
|
||||
that allows for provisioning, tracking, and authenticating multi-owner capabilities
|
||||
at runtime.
|
||||
|
||||
The keeper maintains two states: persistent and ephemeral in-memory. The persistent
|
||||
store maintains a globally unique auto-incrementing index and a mapping from
|
||||
capability index to a set of capability owners that are defined as a module and
|
||||
capability name tuple. The in-memory ephemeral state keeps track of the actual
|
||||
capabilities, represented as addresses in local memory, with both forward and reverse indexes.
|
||||
The forward index maps module name and capability tuples to the capability name. The
|
||||
reverse index maps between the module and capability name and the capability itself.
|
||||
|
||||
The keeper allows the creation of "scoped" sub-keepers which are tied to a particular
|
||||
module by name. Scoped keepers must be created at application initialization and
|
||||
passed to modules, which can then use them to claim capabilities they receive and
|
||||
retrieve capabilities which they own by name, in addition to creating new capabilities
|
||||
& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope,
|
||||
so a module cannot interfere with or inspect capabilities owned by other modules.
|
||||
|
||||
The keeper provides no other core functionality that can be found in other modules
|
||||
like queriers, REST and CLI handlers, and genesis state.
|
||||
|
||||
## Initialization
|
||||
|
||||
During application initialization, the keeper must be instantiated with a persistent
|
||||
store key and an in-memory store key.
|
||||
|
||||
```go
|
||||
type App struct {
|
||||
// ...
|
||||
|
||||
capabilityKeeper *capability.Keeper
|
||||
}
|
||||
|
||||
func NewApp(...) *App {
|
||||
// ...
|
||||
|
||||
app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey)
|
||||
}
|
||||
```
|
||||
|
||||
After the keeper is created, it can be used to create scoped sub-keepers which
|
||||
are passed to other modules that can create, authenticate, and claim capabilities.
|
||||
After all the necessary scoped keepers are created and the state is loaded, the
|
||||
main capability keeper must be sealed to prevent further scoped keepers from
|
||||
being created.
|
||||
|
||||
```go
|
||||
func NewApp(...) *App {
|
||||
// ...
|
||||
|
||||
// Creating a scoped keeper
|
||||
scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)
|
||||
|
||||
// Seal the capability keeper to prevent any further modules from creating scoped
|
||||
// sub-keepers.
|
||||
app.capabilityKeeper.Seal()
|
||||
|
||||
return app
|
||||
}
|
||||
```
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
1. **[State](02_state.md)**
|
||||
@ -1,7 +1,119 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Crisis Overview
|
||||
parent:
|
||||
title: "crisis"
|
||||
-->
|
||||
|
||||
# Crisis
|
||||
# `x/crisis`
|
||||
|
||||
* [Crisis](spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken).
|
||||
## Overview
|
||||
|
||||
The crisis module halts the blockchain under the circumstance that a blockchain
|
||||
invariant is broken. Invariants can be registered with the application during the
|
||||
application initialization process.
|
||||
|
||||
## Contents
|
||||
|
||||
* [State](#state)
|
||||
* [Messages](#messages)
|
||||
* [Events](#events)
|
||||
* [Parameters](#parameters)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# State
|
||||
|
||||
## ConstantFee
|
||||
|
||||
Due to the anticipated large gas cost requirement to verify an invariant (and
|
||||
potential to exceed the maximum allowable block gas limit) a constant fee is
|
||||
used instead of the standard gas consumption method. The constant fee is
|
||||
intended to be larger than the anticipated gas cost of running the invariant
|
||||
with the standard gas consumption method.
|
||||
|
||||
The ConstantFee param is stored in the module params state with the prefix of `0x01`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `mint/params -> legacy_amino(sdk.Coin)`
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# Messages
|
||||
|
||||
In this section we describe the processing of the crisis messages and the
|
||||
corresponding updates to the state.
|
||||
|
||||
## MsgVerifyInvariant
|
||||
|
||||
Blockchain invariants can be checked using the `MsgVerifyInvariant` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/crisis/v1beta1/tx.proto#L16-L26
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
* the sender does not have enough coins for the constant fee
|
||||
* the invariant route is not registered
|
||||
|
||||
This message checks the invariant provided, and if the invariant is broken it
|
||||
panics, halting the blockchain. If the invariant is broken, the constant fee is
|
||||
never deducted as the transaction is never committed to a block (equivalent to
|
||||
being refunded). However, if the invariant is not broken, the constant fee will
|
||||
not be refunded.
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Events
|
||||
|
||||
The crisis module emits the following events:
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgVerifyInvariance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|-----------|---------------|------------------|
|
||||
| invariant | route | {invariantRoute} |
|
||||
| message | module | crisis |
|
||||
| message | action | verify_invariant |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
# Parameters
|
||||
|
||||
The crisis module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
|-------------|---------------|-----------------------------------|
|
||||
| ConstantFee | object (coin) | {"denom":"uatom","amount":"1000"} |
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `crisis` module using the CLI.
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `crisis` module.
|
||||
|
||||
```bash
|
||||
simd tx crisis --help
|
||||
```
|
||||
|
||||
#### invariant-broken
|
||||
|
||||
The `invariant-broken` command submits proof when an invariant was broken to halt the chain
|
||||
|
||||
```bash
|
||||
simd tx crisis invariant-broken [module-name] [invariant-route] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx crisis invariant-broken bank total-supply --from=[keyname or address]
|
||||
```
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## ConstantFee
|
||||
|
||||
Due to the anticipated large gas cost requirement to verify an invariant (and
|
||||
potential to exceed the maximum allowable block gas limit) a constant fee is
|
||||
used instead of the standard gas consumption method. The constant fee is
|
||||
intended to be larger than the anticipated gas cost of running the invariant
|
||||
with the standard gas consumption method.
|
||||
|
||||
The ConstantFee param is stored in the module params state with the prefix of `0x01`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `mint/params -> legacy_amino(sdk.Coin)`
|
||||
@ -1,25 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
In this section we describe the processing of the crisis messages and the
|
||||
corresponding updates to the state.
|
||||
|
||||
## MsgVerifyInvariant
|
||||
|
||||
Blockchain invariants can be checked using the `MsgVerifyInvariant` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/crisis/v1beta1/tx.proto#L16-L26
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
* the sender does not have enough coins for the constant fee
|
||||
* the invariant route is not registered
|
||||
|
||||
This message checks the invariant provided, and if the invariant is broken it
|
||||
panics, halting the blockchain. If the invariant is broken, the constant fee is
|
||||
never deducted as the transaction is never committed to a block (equivalent to
|
||||
being refunded). However, if the invariant is not broken, the constant fee will
|
||||
not be refunded.
|
||||
@ -1,18 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The crisis module emits the following events:
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgVerifyInvariance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|-----------|---------------|------------------|
|
||||
| invariant | route | {invariantRoute} |
|
||||
| message | module | crisis |
|
||||
| message | action | verify_invariant |
|
||||
| message | sender | {senderAddress} |
|
||||
@ -1,11 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The crisis module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
|-------------|---------------|-----------------------------------|
|
||||
| ConstantFee | object (coin) | {"denom":"uatom","amount":"1000"} |
|
||||
@ -1,31 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `crisis` module using the CLI.
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `crisis` module.
|
||||
|
||||
```bash
|
||||
simd tx crisis --help
|
||||
```
|
||||
|
||||
#### invariant-broken
|
||||
|
||||
The `invariant-broken` command submits proof when an invariant was broken to halt the chain
|
||||
|
||||
```bash
|
||||
simd tx crisis invariant-broken [module-name] [invariant-route] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd tx crisis invariant-broken bank total-supply --from=[keyname or address]
|
||||
```
|
||||
@ -1,26 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Crisis Overview
|
||||
parent:
|
||||
title: "crisis"
|
||||
-->
|
||||
|
||||
# `crisis`
|
||||
|
||||
## Overview
|
||||
|
||||
The crisis module halts the blockchain under the circumstance that a blockchain
|
||||
invariant is broken. Invariants can be registered with the application during the
|
||||
application initialization process.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[State](01_state.md)**
|
||||
* [ConstantFee](01_state.md#constantfee)
|
||||
2. **[Messages](02_messages.md)**
|
||||
* [MsgVerifyInvariant](02_messages.md#msgverifyinvariant)
|
||||
3. **[Events](03_events.md)**
|
||||
* [Handlers](03_events.md#handlers)
|
||||
4. **[Parameters](04_params.md)**
|
||||
5. **[Client](05_client.md)**
|
||||
* [CLI](05_client.md#cli)
|
||||
@ -1,7 +1,997 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Distribution Overview
|
||||
parent:
|
||||
title: "distribution"
|
||||
-->
|
||||
|
||||
# Distribution
|
||||
# `x/distribution`
|
||||
|
||||
* [Distribution](spec/README.md) - Fee distribution, and staking token provision distribution.
|
||||
## Overview
|
||||
|
||||
This _simple_ distribution mechanism describes a functional way to passively
|
||||
distribute rewards between validators and delegators. Note that this mechanism does
|
||||
not distribute funds in as precisely as active reward distribution mechanisms and
|
||||
will therefore be upgraded in the future.
|
||||
|
||||
The mechanism operates as follows. Collected rewards are pooled globally and
|
||||
divided out passively to validators and delegators. Each validator has the
|
||||
opportunity to charge commission to the delegators on the rewards collected on
|
||||
behalf of the delegators. Fees are collected directly into a global reward pool
|
||||
and validator proposer-reward pool. Due to the nature of passive accounting,
|
||||
whenever changes to parameters which affect the rate of reward distribution
|
||||
occurs, withdrawal of rewards must also occur.
|
||||
|
||||
* Whenever withdrawing, one must withdraw the maximum amount they are entitled
|
||||
to, leaving nothing in the pool.
|
||||
* Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
|
||||
full withdrawal of the rewards must occur (as the rules for lazy accounting
|
||||
change).
|
||||
* Whenever a validator chooses to change the commission on rewards, all accumulated
|
||||
commission rewards must be simultaneously withdrawn.
|
||||
|
||||
The above scenarios are covered in `hooks.md`.
|
||||
|
||||
The distribution mechanism outlined herein is used to lazily distribute the
|
||||
following rewards between validators and associated delegators:
|
||||
|
||||
* multi-token fees to be socially distributed
|
||||
* inflated staked asset provisions
|
||||
* validator commission on all rewards earned by their delegators stake
|
||||
|
||||
Fees are pooled within a global pool. The mechanisms used allow for validators
|
||||
and delegators to independently and lazily withdraw their rewards.
|
||||
|
||||
## Shortcomings
|
||||
|
||||
As a part of the lazy computations, each delegator holds an accumulation term
|
||||
specific to each validator which is used to estimate what their approximate
|
||||
fair portion of tokens held in the global fee pool is owed to them.
|
||||
|
||||
```text
|
||||
entitlement = delegator-accumulation / all-delegators-accumulation
|
||||
```
|
||||
|
||||
Under the circumstance that there was constant and equal flow of incoming
|
||||
reward tokens every block, this distribution mechanism would be equal to the
|
||||
active distribution (distribute individually to all delegators each block).
|
||||
However, this is unrealistic so deviations from the active distribution will
|
||||
occur based on fluctuations of incoming reward tokens as well as timing of
|
||||
reward withdrawal by other delegators.
|
||||
|
||||
If you happen to know that incoming rewards are about to significantly increase,
|
||||
you are incentivized to not withdraw until after this event, increasing the
|
||||
worth of your existing _accum_. See [#2764](https://github.com/cosmos/cosmos-sdk/issues/2764)
|
||||
for further details.
|
||||
|
||||
## Effect on Staking
|
||||
|
||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||
problematic within BPoS. Fundamentally, these two mechanisms are mutually
|
||||
exclusive. If both commission and auto-bonding mechanisms are simultaneously
|
||||
applied to the staking-token then the distribution of staking-tokens between
|
||||
any validator and its delegators will change with each block. This then
|
||||
necessitates a calculation for each delegation records for each block -
|
||||
which is considered computationally expensive.
|
||||
|
||||
In conclusion, we can only have Atom commission and unbonded atoms
|
||||
provisions or bonded atom provisions with no Atom commission, and we elect to
|
||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||
to set up a script to periodically withdraw and rebond rewards.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [State](#state)
|
||||
* [FeePool](#feepool)
|
||||
* [Validator Distribution](#validator-distribution)
|
||||
* [Delegation Distribution](#delegation-distribution)
|
||||
* [Params](#params)
|
||||
* [Begin Block](#begin-block)
|
||||
* [Messages](#messages)
|
||||
* [Hooks](#hooks)
|
||||
* [Events](#events)
|
||||
* [Parameters](#parameters)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
In Proof of Stake (PoS) blockchains, rewards gained from transaction fees are paid to validators. The fee distribution module fairly distributes the rewards to the validators' constituent delegators.
|
||||
|
||||
Rewards are calculated per period. The period is updated each time a validator's delegation changes, for example, when the validator receives a new delegation.
|
||||
The rewards for a single validator can then be calculated by taking the total rewards for the period before the delegation started, minus the current total rewards.
|
||||
To learn more, see the [F1 Fee Distribution paper](/docs/spec/fee_distribution/f1_fee_distr.pdf).
|
||||
|
||||
The commission to the validator is paid when the validator is removed or when the validator requests a withdrawal.
|
||||
The commission is calculated and incremented at every `BeginBlock` operation to update accumulated fee amounts.
|
||||
|
||||
The rewards to a delegator are distributed when the delegation is changed or removed, or a withdrawal is requested.
|
||||
Before rewards are distributed, all slashes to the validator that occurred during the current delegation are applied.
|
||||
|
||||
## Reference Counting in F1 Fee Distribution
|
||||
|
||||
In F1 fee distribution, the rewards a delegator receives are calculated when their delegation is withdrawn. This calculation must read the terms of the summation of rewards divided by the share of tokens from the period which they ended when they delegated, and the final period that was created for the withdrawal.
|
||||
|
||||
Additionally, as slashes change the amount of tokens a delegation will have (but we calculate this lazily,
|
||||
only when a delegator un-delegates), we must calculate rewards in separate periods before / after any slashes
|
||||
which occurred in between when a delegator delegated and when they withdrew their rewards. Thus slashes, like
|
||||
delegations, reference the period which was ended by the slash event.
|
||||
|
||||
All stored historical rewards records for periods which are no longer referenced by any delegations
|
||||
or any slashes can thus be safely removed, as they will never be read (future delegations and future
|
||||
slashes will always reference future periods). This is implemented by tracking a `ReferenceCount`
|
||||
along with each historical reward storage entry. Each time a new object (delegation or slash)
|
||||
is created which might need to reference the historical record, the reference count is incremented.
|
||||
Each time one object which previously needed to reference the historical record is deleted, the reference
|
||||
count is decremented. If the reference count hits zero, the historical record is deleted.
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
## FeePool
|
||||
|
||||
All globally tracked parameters for distribution are stored within
|
||||
`FeePool`. Rewards are collected and added to the reward pool and
|
||||
distributed to validators/delegators from here.
|
||||
|
||||
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||
for fractions of coins to be received from operations like inflation.
|
||||
When coins are distributed from the pool they are truncated back to
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
* FeePool: `0x00 -> ProtocolBuffer(FeePool)`
|
||||
|
||||
```go
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
type DecCoin struct {
|
||||
Amount sdk.Dec
|
||||
Denom string
|
||||
}
|
||||
```
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L92-L96
|
||||
|
||||
## Validator Distribution
|
||||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
|
||||
1. delegation amount to a validator is updated,
|
||||
2. any delegator withdraws from a validator, or
|
||||
3. the validator withdraws its commission.
|
||||
|
||||
* ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)`
|
||||
|
||||
```go
|
||||
type ValidatorDistInfo struct {
|
||||
OperatorAddress sdk.AccAddress
|
||||
SelfBondRewards sdk.DecCoins
|
||||
ValidatorCommission types.ValidatorAccumulatedCommission
|
||||
}
|
||||
```
|
||||
|
||||
## Delegation Distribution
|
||||
|
||||
Each delegation distribution only needs to record the height at which it last
|
||||
withdrew fees. Because a delegation must withdraw fees each time it's
|
||||
properties change (aka bonded tokens etc.) its properties will remain constant
|
||||
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||
only the height of the last withdrawal and its current properties.
|
||||
|
||||
* DelegationDistInfo: `0x02 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(delegatorDist)`
|
||||
|
||||
```go
|
||||
type DelegationDistInfo struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
}
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
The distribution module stores it's params in state with the prefix of `0x09`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `0x09 | ProtocolBuffer(Params)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L11-L30
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Begin Block
|
||||
|
||||
At each `BeginBlock`, all fees received in the previous block are transferred to
|
||||
the distribution `ModuleAccount` account. When a delegator or validator
|
||||
withdraws their rewards, they are taken out of the `ModuleAccount`. During begin
|
||||
block, the different claims on the fees collected are updated as follows:
|
||||
|
||||
* The reserve community tax is charged.
|
||||
* The remainder is distributed proportionally by voting power to all bonded validators
|
||||
|
||||
## The Distribution Scheme
|
||||
|
||||
See [params](07_params.md) for description of parameters.
|
||||
|
||||
Let `fees` be the total fees collected in the previous block, including
|
||||
inflationary rewards to the stake. All fees are collected in a specific module
|
||||
account during the block. During `BeginBlock`, they are sent to the
|
||||
`"distribution"` `ModuleAccount`. No other sending of tokens occurs. Instead, the
|
||||
rewards each account is entitled to are stored, and withdrawals can be triggered
|
||||
through the messages `FundCommunityPool`, `WithdrawValidatorCommission` and
|
||||
`WithdrawDelegatorReward`.
|
||||
|
||||
### Reward to the Community Pool
|
||||
|
||||
The community pool gets `community_tax * fees`, plus any remaining dust after
|
||||
validators get their rewards that are always rounded down to the nearest
|
||||
integer value.
|
||||
|
||||
### Reward To the Validators
|
||||
|
||||
The proposer receives no extra rewards. All fees are distributed among all the
|
||||
bonded validators, including the proposer, in proportion to their consensus power.
|
||||
|
||||
```text
|
||||
powFrac = validator power / total bonded validator power
|
||||
voteMul = 1 - community_tax
|
||||
```
|
||||
|
||||
All validators receive `fees * voteMul * powFrac`.
|
||||
|
||||
### Rewards to Delegators
|
||||
|
||||
Each validator's rewards are distributed to its delegators. The validator also
|
||||
has a self-delegation that is treated like a regular delegation in
|
||||
distribution calculations.
|
||||
|
||||
The validator sets a commission rate. The commission rate is flexible, but each
|
||||
validator sets a maximum rate and a maximum daily increase. These maximums cannot be exceeded and protect delegators from sudden increases of validator commission rates to prevent validators from taking all of the rewards.
|
||||
|
||||
The outstanding rewards that the operator is entitled to are stored in
|
||||
`ValidatorAccumulatedCommission`, while the rewards the delegators are entitled
|
||||
to are stored in `ValidatorCurrentRewards`. The [F1 fee distribution
|
||||
scheme](01_concepts.md) is used to calculate the rewards per delegator as they
|
||||
withdraw or update their delegation, and is thus not handled in `BeginBlock`.
|
||||
|
||||
### Example Distribution
|
||||
|
||||
For this example distribution, the underlying consensus engine selects block proposers in
|
||||
proportion to their power relative to the entire bonded power.
|
||||
|
||||
All validators are equally performant at including pre-commits in their proposed
|
||||
blocks. Then hold `(pre_commits included) / (total bonded validator power)`
|
||||
constant so that the amortized block reward for the validator is `( validator power / total bonded power) * (1 - community tax rate)` of
|
||||
the total rewards. Consequently, the reward for a single delegator is:
|
||||
|
||||
```text
|
||||
(delegator proportion of the validator power / validator power) * (validator power / total bonded power)
|
||||
* (1 - community tax rate) * (1 - validator commission rate)
|
||||
= (delegator proportion of the validator power / total bonded power) * (1 -
|
||||
community tax rate) * (1 - validator commission rate)
|
||||
```
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Messages
|
||||
|
||||
## MsgSetWithdrawAddress
|
||||
|
||||
By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message.
|
||||
Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`.
|
||||
|
||||
The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization.
|
||||
|
||||
Response:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L31-L41
|
||||
|
||||
```go
|
||||
func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error
|
||||
if k.blockedAddrs[withdrawAddr.String()] {
|
||||
fail with "`{withdrawAddr}` is not allowed to receive external funds"
|
||||
}
|
||||
|
||||
if !k.GetWithdrawAddrEnabled(ctx) {
|
||||
fail with `ErrSetWithdrawAddrDisabled`
|
||||
}
|
||||
|
||||
k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
|
||||
```
|
||||
|
||||
## MsgWithdrawDelegatorReward
|
||||
|
||||
A delegator can withdraw its rewards.
|
||||
Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value.
|
||||
The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address.
|
||||
Any remainder (truncated decimals) are sent to the community pool.
|
||||
The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented.
|
||||
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
||||
|
||||
In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator.
|
||||
In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way.
|
||||
Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`.
|
||||
Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`.
|
||||
However, these calculated rewards don't account for slashing.
|
||||
|
||||
Taking the slashes into account requires iteration.
|
||||
Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`.
|
||||
If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows:
|
||||
|
||||
```go
|
||||
stake := initial stake
|
||||
rewards := 0
|
||||
previous := A
|
||||
for P in P1, ..., PN`:
|
||||
rewards = (R(P) - previous) * stake
|
||||
stake = stake * F(P)
|
||||
previous = P
|
||||
rewards = rewards + (R(B) - R(PN)) * stake
|
||||
```
|
||||
|
||||
The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step.
|
||||
The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors.
|
||||
|
||||
Response:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L46-L56
|
||||
|
||||
## WithdrawValidatorCommission
|
||||
|
||||
The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission.
|
||||
The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw.
|
||||
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
||||
Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later.
|
||||
|
||||
## FundCommunityPool
|
||||
|
||||
This message sends coins directly from the sender to the community pool.
|
||||
|
||||
The transaction fails if the amount cannot be transferred from the sender to the distribution module account.
|
||||
|
||||
```go
|
||||
func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error {
|
||||
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feePool := k.GetFeePool(ctx)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...)
|
||||
k.SetFeePool(ctx, feePool)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## Common distribution operations
|
||||
|
||||
These operations take place during many different messages.
|
||||
|
||||
### Initialize delegation
|
||||
|
||||
Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized.
|
||||
Initializing a delegation increments the validator period and keeps track of the starting period of the delegation.
|
||||
|
||||
```go
|
||||
// initialize starting info for a new delegation
|
||||
func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) {
|
||||
// period has already been incremented - we want to store the period ended by this delegation action
|
||||
previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1
|
||||
|
||||
// increment reference count for the period we're going to track
|
||||
k.incrementReferenceCount(ctx, val, previousPeriod)
|
||||
|
||||
validator := k.stakingKeeper.Validator(ctx, val)
|
||||
delegation := k.stakingKeeper.Delegation(ctx, del, val)
|
||||
|
||||
// calculate delegation stake in tokens
|
||||
// we don't store directly, so multiply delegation shares * (tokens per share)
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
stake := validator.TokensFromSharesTruncated(delegation.GetShares())
|
||||
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
|
||||
}
|
||||
```
|
||||
|
||||
## MsgUpdateParams
|
||||
|
||||
Distribution module params can be updated through `MsgUpdateParams`, which can be done using governance proposal and the signer will always be gov module account address.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/8822ef2695a1eb8cb30b7432f58f631c73951f1d/proto/cosmos/distribution/v1beta1/tx.proto#L106-L119
|
||||
|
||||
The message handling can fail if:
|
||||
|
||||
* signer is not the gov module account address.
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Hooks
|
||||
|
||||
Available hooks that can be called by and from this module.
|
||||
|
||||
## Create or modify delegation distribution
|
||||
|
||||
* triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate`
|
||||
|
||||
### Before
|
||||
|
||||
* The delegation rewards are withdrawn to the withdraw address of the delegator.
|
||||
The rewards include the current period and exclude the starting period.
|
||||
* The validator period is incremented.
|
||||
The validator period is incremented because the validator's power and share distribution might have changed.
|
||||
* The reference count for the delegator's starting period is decremented.
|
||||
|
||||
### After
|
||||
|
||||
The starting height of the delegation is set to the previous period.
|
||||
Because of the `Before`-hook, this period is the last period for which the delegator was rewarded.
|
||||
|
||||
## Validator created
|
||||
|
||||
* triggered-by: `staking.MsgCreateValidator`
|
||||
|
||||
When a validator is created, the following validator variables are initialized:
|
||||
|
||||
* Historical rewards
|
||||
* Current accumulated rewards
|
||||
* Accumulated commission
|
||||
* Total outstanding rewards
|
||||
* Period
|
||||
|
||||
By default, all values are set to a `0`, except period, which is set to `1`.
|
||||
|
||||
## Validator removed
|
||||
|
||||
* triggered-by: `staking.RemoveValidator`
|
||||
|
||||
Outstanding commission is sent to the validator's self-delegation withdrawal address.
|
||||
Remaining delegator rewards get sent to the community fee pool.
|
||||
|
||||
Note: The validator gets removed only when it has no remaining delegations.
|
||||
At that time, all outstanding delegator rewards will have been withdrawn.
|
||||
Any remaining rewards are dust amounts.
|
||||
|
||||
## Validator is slashed
|
||||
|
||||
* triggered-by: `staking.Slash`
|
||||
|
||||
* The current validator period reference count is incremented.
|
||||
The reference count is incremented because the slash event has created a reference to it.
|
||||
* The validator period is incremented.
|
||||
* The slash event is stored for later use.
|
||||
The slash event will be referenced when calculating delegator rewards.
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
# Events
|
||||
|
||||
The distribution module emits the following events:
|
||||
|
||||
## BeginBlocker
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|-----------------|---------------|--------------------|
|
||||
| proposer_reward | validator | {validatorAddress} |
|
||||
| proposer_reward | reward | {proposerReward} |
|
||||
| commission | amount | {commissionAmount} |
|
||||
| commission | validator | {validatorAddress} |
|
||||
| rewards | amount | {rewardAmount} |
|
||||
| rewards | validator | {validatorAddress} |
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgSetWithdrawAddress
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|----------------------|------------------|----------------------|
|
||||
| set_withdraw_address | withdraw_address | {withdrawAddress} |
|
||||
| message | module | distribution |
|
||||
| message | action | set_withdraw_address |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgWithdrawDelegatorReward
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|---------|---------------|---------------------------|
|
||||
| withdraw_rewards | amount | {rewardAmount} |
|
||||
| withdraw_rewards | validator | {validatorAddress} |
|
||||
| message | module | distribution |
|
||||
| message | action | withdraw_delegator_reward |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgWithdrawValidatorCommission
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|------------|---------------|-------------------------------|
|
||||
| withdraw_commission | amount | {commissionAmount} |
|
||||
| message | module | distribution |
|
||||
| message | action | withdraw_validator_commission |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
<!-- order: 7 -->
|
||||
|
||||
# Parameters
|
||||
|
||||
The distribution module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
| ------------------- | ------------ | -------------------------- |
|
||||
| communitytax | string (dec) | "0.020000000000000000" [0] |
|
||||
| baseproposerreward | string (dec) | "0.010000000000000000" [0] |
|
||||
| bonusproposerreward | string (dec) | "0.040000000000000000" [0] |
|
||||
| withdrawaddrenabled | bool | true |
|
||||
|
||||
* [0] `communitytax`, `baseproposerreward` and `bonusproposerreward` must be
|
||||
positive and their sum cannot exceed 1.00.
|
||||
|
||||
<!-- order: 8 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `distribution` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `distribution` state.
|
||||
|
||||
```sh
|
||||
simd query distribution --help
|
||||
```
|
||||
|
||||
#### commission
|
||||
|
||||
The `commission` command allows users to query validator commission rewards by address.
|
||||
|
||||
```sh
|
||||
simd query distribution commission [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution commission cosmosvaloper1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
commission:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### community-pool
|
||||
|
||||
The `community-pool` command allows users to query all coin balances within the community pool.
|
||||
|
||||
```sh
|
||||
simd query distribution community-pool [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution community-pool
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
pool:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allows users to query the parameters of the `distribution` module.
|
||||
|
||||
```sh
|
||||
simd query distribution params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
base_proposer_reward: "0.010000000000000000"
|
||||
bonus_proposer_reward: "0.040000000000000000"
|
||||
community_tax: "0.020000000000000000"
|
||||
withdraw_addr_enabled: true
|
||||
```
|
||||
|
||||
#### rewards
|
||||
|
||||
The `rewards` command allows users to query delegator rewards. Users can optionally include the validator address to query rewards earned from a specific validator.
|
||||
|
||||
```sh
|
||||
simd query distribution rewards [delegator-addr] [validator-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution rewards cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
rewards:
|
||||
- reward:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
validator_address: cosmosvaloper1..
|
||||
total:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### slashes
|
||||
|
||||
The `slashes` command allows users to query all slashes for a given block range.
|
||||
|
||||
```sh
|
||||
simd query distribution slashes [validator] [start-height] [end-height] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution slashes cosmosvaloper1.. 1 1000
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
slashes:
|
||||
- validator_period: 20,
|
||||
fraction: "0.009999999999999999"
|
||||
```
|
||||
|
||||
#### validator-outstanding-rewards
|
||||
|
||||
The `validator-outstanding-rewards` command allows users to query all outstanding (un-withdrawn) rewards for a validator and all their delegations.
|
||||
|
||||
```sh
|
||||
simd query distribution validator-outstanding-rewards [validator] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution validator-outstanding-rewards cosmosvaloper1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
rewards:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `distribution` module.
|
||||
|
||||
```sh
|
||||
simd tx distribution --help
|
||||
```
|
||||
|
||||
#### fund-community-pool
|
||||
|
||||
The `fund-community-pool` command allows users to send funds to the community pool.
|
||||
|
||||
```sh
|
||||
simd tx distribution fund-community-pool [amount] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution fund-community-pool 100stake --from cosmos1..
|
||||
```
|
||||
|
||||
#### set-withdraw-addr
|
||||
|
||||
The `set-withdraw-addr` command allows users to set the withdraw address for rewards associated with a delegator address.
|
||||
|
||||
```sh
|
||||
simd tx distribution set-withdraw-addr [withdraw-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution set-withdraw-addr cosmos1.. --from cosmos1..
|
||||
```
|
||||
|
||||
#### withdraw-all-rewards
|
||||
|
||||
The `withdraw-all-rewards` command allows users to withdraw all rewards for a delegator.
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-all-rewards [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-all-rewards --from cosmos1..
|
||||
```
|
||||
|
||||
#### withdraw-rewards
|
||||
|
||||
The `withdraw-rewards` command allows users to withdraw all rewards from a given delegation address,
|
||||
and optionally withdraw validator commission if the delegation address given is a validator operator and the user proves the `--commision` flag.
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-rewards [validator-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-rewards cosmosvaloper1.. --from cosmos1.. --commision
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `distribution` module using gRPC endpoints.
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allows users to query parameters of the `distribution` module.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"communityTax": "20000000000000000",
|
||||
"baseProposerReward": "10000000000000000",
|
||||
"bonusProposerReward": "40000000000000000",
|
||||
"withdrawAddrEnabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorOutstandingRewards
|
||||
|
||||
The `ValidatorOutstandingRewards` endpoint allows users to query rewards of a validator address.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": {
|
||||
"rewards": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorCommission
|
||||
|
||||
The `ValidatorCommission` endpoint allows users to query accumulated commission for a validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorCommission
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"commission": {
|
||||
"commission": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorSlashes
|
||||
|
||||
The `ValidatorSlashes` endpoint allows users to query slash events of a validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorSlashes
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"slashes": [
|
||||
{
|
||||
"validator_period": "20",
|
||||
"fraction": "0.009999999999999999"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DelegationRewards
|
||||
|
||||
The `DelegationRewards` endpoint allows users to query the total rewards accrued by a delegation.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1..","validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegationRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegationTotalRewards
|
||||
|
||||
The `DelegationTotalRewards` endpoint allows users to query the total rewards accrued by each validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegationTotalRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": [
|
||||
{
|
||||
"validatorAddress": "cosmosvaloper1..",
|
||||
"reward": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegatorValidators
|
||||
|
||||
The `DelegatorValidators` endpoint allows users to query all validators for given delegator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegatorValidators
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"validators": [
|
||||
"cosmosvaloper1.."
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegatorWithdrawAddress
|
||||
|
||||
The `DelegatorWithdrawAddress` endpoint allows users to query the withdraw address of a delegator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"withdrawAddress": "cosmos1.."
|
||||
}
|
||||
```
|
||||
|
||||
### CommunityPool
|
||||
|
||||
The `CommunityPool` endpoint allows users to query the community pool coins.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/CommunityPool
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"pool": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
In Proof of Stake (PoS) blockchains, rewards gained from transaction fees are paid to validators. The fee distribution module fairly distributes the rewards to the validators' constituent delegators.
|
||||
|
||||
Rewards are calculated per period. The period is updated each time a validator's delegation changes, for example, when the validator receives a new delegation.
|
||||
The rewards for a single validator can then be calculated by taking the total rewards for the period before the delegation started, minus the current total rewards.
|
||||
To learn more, see the [F1 Fee Distribution paper](/docs/spec/fee_distribution/f1_fee_distr.pdf).
|
||||
|
||||
The commission to the validator is paid when the validator is removed or when the validator requests a withdrawal.
|
||||
The commission is calculated and incremented at every `BeginBlock` operation to update accumulated fee amounts.
|
||||
|
||||
The rewards to a delegator are distributed when the delegation is changed or removed, or a withdrawal is requested.
|
||||
Before rewards are distributed, all slashes to the validator that occurred during the current delegation are applied.
|
||||
|
||||
## Reference Counting in F1 Fee Distribution
|
||||
|
||||
In F1 fee distribution, the rewards a delegator receives are calculated when their delegation is withdrawn. This calculation must read the terms of the summation of rewards divided by the share of tokens from the period which they ended when they delegated, and the final period that was created for the withdrawal.
|
||||
|
||||
Additionally, as slashes change the amount of tokens a delegation will have (but we calculate this lazily,
|
||||
only when a delegator un-delegates), we must calculate rewards in separate periods before / after any slashes
|
||||
which occurred in between when a delegator delegated and when they withdrew their rewards. Thus slashes, like
|
||||
delegations, reference the period which was ended by the slash event.
|
||||
|
||||
All stored historical rewards records for periods which are no longer referenced by any delegations
|
||||
or any slashes can thus be safely removed, as they will never be read (future delegations and future
|
||||
slashes will always reference future periods). This is implemented by tracking a `ReferenceCount`
|
||||
along with each historical reward storage entry. Each time a new object (delegation or slash)
|
||||
is created which might need to reference the historical record, the reference count is incremented.
|
||||
Each time one object which previously needed to reference the historical record is deleted, the reference
|
||||
count is decremented. If the reference count hits zero, the historical record is deleted.
|
||||
@ -1,73 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## FeePool
|
||||
|
||||
All globally tracked parameters for distribution are stored within
|
||||
`FeePool`. Rewards are collected and added to the reward pool and
|
||||
distributed to validators/delegators from here.
|
||||
|
||||
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||
for fractions of coins to be received from operations like inflation.
|
||||
When coins are distributed from the pool they are truncated back to
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
* FeePool: `0x00 -> ProtocolBuffer(FeePool)`
|
||||
|
||||
```go
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
type DecCoin struct {
|
||||
Amount sdk.Dec
|
||||
Denom string
|
||||
}
|
||||
```
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L92-L96
|
||||
|
||||
## Validator Distribution
|
||||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
|
||||
1. delegation amount to a validator is updated,
|
||||
2. any delegator withdraws from a validator, or
|
||||
3. the validator withdraws its commission.
|
||||
|
||||
* ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)`
|
||||
|
||||
```go
|
||||
type ValidatorDistInfo struct {
|
||||
OperatorAddress sdk.AccAddress
|
||||
SelfBondRewards sdk.DecCoins
|
||||
ValidatorCommission types.ValidatorAccumulatedCommission
|
||||
}
|
||||
```
|
||||
|
||||
## Delegation Distribution
|
||||
|
||||
Each delegation distribution only needs to record the height at which it last
|
||||
withdrew fees. Because a delegation must withdraw fees each time it's
|
||||
properties change (aka bonded tokens etc.) its properties will remain constant
|
||||
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||
only the height of the last withdrawal and its current properties.
|
||||
|
||||
* DelegationDistInfo: `0x02 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(delegatorDist)`
|
||||
|
||||
```go
|
||||
type DelegationDistInfo struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
}
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
The distribution module stores it's params in state with the prefix of `0x09`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `0x09 | ProtocolBuffer(Params)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L11-L30
|
||||
@ -1,75 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Begin Block
|
||||
|
||||
At each `BeginBlock`, all fees received in the previous block are transferred to
|
||||
the distribution `ModuleAccount` account. When a delegator or validator
|
||||
withdraws their rewards, they are taken out of the `ModuleAccount`. During begin
|
||||
block, the different claims on the fees collected are updated as follows:
|
||||
|
||||
* The reserve community tax is charged.
|
||||
* The remainder is distributed proportionally by voting power to all bonded validators
|
||||
|
||||
## The Distribution Scheme
|
||||
|
||||
See [params](07_params.md) for description of parameters.
|
||||
|
||||
Let `fees` be the total fees collected in the previous block, including
|
||||
inflationary rewards to the stake. All fees are collected in a specific module
|
||||
account during the block. During `BeginBlock`, they are sent to the
|
||||
`"distribution"` `ModuleAccount`. No other sending of tokens occurs. Instead, the
|
||||
rewards each account is entitled to are stored, and withdrawals can be triggered
|
||||
through the messages `FundCommunityPool`, `WithdrawValidatorCommission` and
|
||||
`WithdrawDelegatorReward`.
|
||||
|
||||
### Reward to the Community Pool
|
||||
|
||||
The community pool gets `community_tax * fees`, plus any remaining dust after
|
||||
validators get their rewards that are always rounded down to the nearest
|
||||
integer value.
|
||||
|
||||
### Reward To the Validators
|
||||
|
||||
The proposer receives no extra rewards. All fees are distributed among all the
|
||||
bonded validators, including the proposer, in proportion to their consensus power.
|
||||
|
||||
```text
|
||||
powFrac = validator power / total bonded validator power
|
||||
voteMul = 1 - community_tax
|
||||
```
|
||||
|
||||
All validators receive `fees * voteMul * powFrac`.
|
||||
|
||||
### Rewards to Delegators
|
||||
|
||||
Each validator's rewards are distributed to its delegators. The validator also
|
||||
has a self-delegation that is treated like a regular delegation in
|
||||
distribution calculations.
|
||||
|
||||
The validator sets a commission rate. The commission rate is flexible, but each
|
||||
validator sets a maximum rate and a maximum daily increase. These maximums cannot be exceeded and protect delegators from sudden increases of validator commission rates to prevent validators from taking all of the rewards.
|
||||
|
||||
The outstanding rewards that the operator is entitled to are stored in
|
||||
`ValidatorAccumulatedCommission`, while the rewards the delegators are entitled
|
||||
to are stored in `ValidatorCurrentRewards`. The [F1 fee distribution
|
||||
scheme](01_concepts.md) is used to calculate the rewards per delegator as they
|
||||
withdraw or update their delegation, and is thus not handled in `BeginBlock`.
|
||||
|
||||
### Example Distribution
|
||||
|
||||
For this example distribution, the underlying consensus engine selects block proposers in
|
||||
proportion to their power relative to the entire bonded power.
|
||||
|
||||
All validators are equally performant at including pre-commits in their proposed
|
||||
blocks. Then hold `(pre_commits included) / (total bonded validator power)`
|
||||
constant so that the amortized block reward for the validator is `( validator power / total bonded power) * (1 - community tax rate)` of
|
||||
the total rewards. Consequently, the reward for a single delegator is:
|
||||
|
||||
```text
|
||||
(delegator proportion of the validator power / validator power) * (validator power / total bonded power)
|
||||
* (1 - community tax rate) * (1 - validator commission rate)
|
||||
= (delegator proportion of the validator power / total bonded power) * (1 -
|
||||
community tax rate) * (1 - validator commission rate)
|
||||
```
|
||||
@ -1,132 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
## MsgSetWithdrawAddress
|
||||
|
||||
By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message.
|
||||
Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`.
|
||||
|
||||
The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization.
|
||||
|
||||
Response:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L31-L41
|
||||
|
||||
```go
|
||||
func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error
|
||||
if k.blockedAddrs[withdrawAddr.String()] {
|
||||
fail with "`{withdrawAddr}` is not allowed to receive external funds"
|
||||
}
|
||||
|
||||
if !k.GetWithdrawAddrEnabled(ctx) {
|
||||
fail with `ErrSetWithdrawAddrDisabled`
|
||||
}
|
||||
|
||||
k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
|
||||
```
|
||||
|
||||
## MsgWithdrawDelegatorReward
|
||||
|
||||
A delegator can withdraw its rewards.
|
||||
Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value.
|
||||
The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address.
|
||||
Any remainder (truncated decimals) are sent to the community pool.
|
||||
The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented.
|
||||
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
||||
|
||||
In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator.
|
||||
In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way.
|
||||
Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`.
|
||||
Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`.
|
||||
However, these calculated rewards don't account for slashing.
|
||||
|
||||
Taking the slashes into account requires iteration.
|
||||
Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`.
|
||||
If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows:
|
||||
|
||||
```go
|
||||
stake := initial stake
|
||||
rewards := 0
|
||||
previous := A
|
||||
for P in P1, ..., PN`:
|
||||
rewards = (R(P) - previous) * stake
|
||||
stake = stake * F(P)
|
||||
previous = P
|
||||
rewards = rewards + (R(B) - R(PN)) * stake
|
||||
```
|
||||
|
||||
The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step.
|
||||
The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors.
|
||||
|
||||
Response:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L46-L56
|
||||
|
||||
## WithdrawValidatorCommission
|
||||
|
||||
The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission.
|
||||
The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw.
|
||||
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
||||
Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later.
|
||||
|
||||
## FundCommunityPool
|
||||
|
||||
This message sends coins directly from the sender to the community pool.
|
||||
|
||||
The transaction fails if the amount cannot be transferred from the sender to the distribution module account.
|
||||
|
||||
```go
|
||||
func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error {
|
||||
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feePool := k.GetFeePool(ctx)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...)
|
||||
k.SetFeePool(ctx, feePool)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## Common distribution operations
|
||||
|
||||
These operations take place during many different messages.
|
||||
|
||||
### Initialize delegation
|
||||
|
||||
Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized.
|
||||
Initializing a delegation increments the validator period and keeps track of the starting period of the delegation.
|
||||
|
||||
```go
|
||||
// initialize starting info for a new delegation
|
||||
func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) {
|
||||
// period has already been incremented - we want to store the period ended by this delegation action
|
||||
previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1
|
||||
|
||||
// increment reference count for the period we're going to track
|
||||
k.incrementReferenceCount(ctx, val, previousPeriod)
|
||||
|
||||
validator := k.stakingKeeper.Validator(ctx, val)
|
||||
delegation := k.stakingKeeper.Delegation(ctx, del, val)
|
||||
|
||||
// calculate delegation stake in tokens
|
||||
// we don't store directly, so multiply delegation shares * (tokens per share)
|
||||
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
||||
stake := validator.TokensFromSharesTruncated(delegation.GetShares())
|
||||
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
|
||||
}
|
||||
```
|
||||
|
||||
## MsgUpdateParams
|
||||
|
||||
Distribution module params can be updated through `MsgUpdateParams`, which can be done using governance proposal and the signer will always be gov module account address.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/8822ef2695a1eb8cb30b7432f58f631c73951f1d/proto/cosmos/distribution/v1beta1/tx.proto#L106-L119
|
||||
|
||||
The message handling can fail if:
|
||||
|
||||
* signer is not the gov module account address.
|
||||
@ -1,59 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Hooks
|
||||
|
||||
Available hooks that can be called by and from this module.
|
||||
|
||||
## Create or modify delegation distribution
|
||||
|
||||
* triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate`
|
||||
|
||||
### Before
|
||||
|
||||
* The delegation rewards are withdrawn to the withdraw address of the delegator.
|
||||
The rewards include the current period and exclude the starting period.
|
||||
* The validator period is incremented.
|
||||
The validator period is incremented because the validator's power and share distribution might have changed.
|
||||
* The reference count for the delegator's starting period is decremented.
|
||||
|
||||
### After
|
||||
|
||||
The starting height of the delegation is set to the previous period.
|
||||
Because of the `Before`-hook, this period is the last period for which the delegator was rewarded.
|
||||
|
||||
## Validator created
|
||||
|
||||
* triggered-by: `staking.MsgCreateValidator`
|
||||
|
||||
When a validator is created, the following validator variables are initialized:
|
||||
|
||||
* Historical rewards
|
||||
* Current accumulated rewards
|
||||
* Accumulated commission
|
||||
* Total outstanding rewards
|
||||
* Period
|
||||
|
||||
By default, all values are set to a `0`, except period, which is set to `1`.
|
||||
|
||||
## Validator removed
|
||||
|
||||
* triggered-by: `staking.RemoveValidator`
|
||||
|
||||
Outstanding commission is sent to the validator's self-delegation withdrawal address.
|
||||
Remaining delegator rewards get sent to the community fee pool.
|
||||
|
||||
Note: The validator gets removed only when it has no remaining delegations.
|
||||
At that time, all outstanding delegator rewards will have been withdrawn.
|
||||
Any remaining rewards are dust amounts.
|
||||
|
||||
## Validator is slashed
|
||||
|
||||
* triggered-by: `staking.Slash`
|
||||
|
||||
* The current validator period reference count is incremented.
|
||||
The reference count is incremented because the slash event has created a reference to it.
|
||||
* The validator period is incremented.
|
||||
* The slash event is stored for later use.
|
||||
The slash event will be referenced when calculating delegator rewards.
|
||||
@ -1,48 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The distribution module emits the following events:
|
||||
|
||||
## BeginBlocker
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|-----------------|---------------|--------------------|
|
||||
| proposer_reward | validator | {validatorAddress} |
|
||||
| proposer_reward | reward | {proposerReward} |
|
||||
| commission | amount | {commissionAmount} |
|
||||
| commission | validator | {validatorAddress} |
|
||||
| rewards | amount | {rewardAmount} |
|
||||
| rewards | validator | {validatorAddress} |
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgSetWithdrawAddress
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|----------------------|------------------|----------------------|
|
||||
| set_withdraw_address | withdraw_address | {withdrawAddress} |
|
||||
| message | module | distribution |
|
||||
| message | action | set_withdraw_address |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgWithdrawDelegatorReward
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|---------|---------------|---------------------------|
|
||||
| withdraw_rewards | amount | {rewardAmount} |
|
||||
| withdraw_rewards | validator | {validatorAddress} |
|
||||
| message | module | distribution |
|
||||
| message | action | withdraw_delegator_reward |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgWithdrawValidatorCommission
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|------------|---------------|-------------------------------|
|
||||
| withdraw_commission | amount | {commissionAmount} |
|
||||
| message | module | distribution |
|
||||
| message | action | withdraw_validator_commission |
|
||||
| message | sender | {senderAddress} |
|
||||
@ -1,17 +0,0 @@
|
||||
<!--
|
||||
order: 7
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The distribution module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
| ------------------- | ------------ | -------------------------- |
|
||||
| communitytax | string (dec) | "0.020000000000000000" [0] |
|
||||
| baseproposerreward | string (dec) | "0.010000000000000000" [0] |
|
||||
| bonusproposerreward | string (dec) | "0.040000000000000000" [0] |
|
||||
| withdrawaddrenabled | bool | true |
|
||||
|
||||
* [0] `communitytax`, `baseproposerreward` and `bonusproposerreward` must be
|
||||
positive and their sum cannot exceed 1.00.
|
||||
@ -1,469 +0,0 @@
|
||||
<!--
|
||||
order: 8
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `distribution` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `distribution` state.
|
||||
|
||||
```sh
|
||||
simd query distribution --help
|
||||
```
|
||||
|
||||
#### commission
|
||||
|
||||
The `commission` command allows users to query validator commission rewards by address.
|
||||
|
||||
```sh
|
||||
simd query distribution commission [address] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution commission cosmosvaloper1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
commission:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### community-pool
|
||||
|
||||
The `community-pool` command allows users to query all coin balances within the community pool.
|
||||
|
||||
```sh
|
||||
simd query distribution community-pool [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution community-pool
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
pool:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allows users to query the parameters of the `distribution` module.
|
||||
|
||||
```sh
|
||||
simd query distribution params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
base_proposer_reward: "0.010000000000000000"
|
||||
bonus_proposer_reward: "0.040000000000000000"
|
||||
community_tax: "0.020000000000000000"
|
||||
withdraw_addr_enabled: true
|
||||
```
|
||||
|
||||
#### rewards
|
||||
|
||||
The `rewards` command allows users to query delegator rewards. Users can optionally include the validator address to query rewards earned from a specific validator.
|
||||
|
||||
```sh
|
||||
simd query distribution rewards [delegator-addr] [validator-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution rewards cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
rewards:
|
||||
- reward:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
validator_address: cosmosvaloper1..
|
||||
total:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
#### slashes
|
||||
|
||||
The `slashes` command allows users to query all slashes for a given block range.
|
||||
|
||||
```sh
|
||||
simd query distribution slashes [validator] [start-height] [end-height] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution slashes cosmosvaloper1.. 1 1000
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
slashes:
|
||||
- validator_period: 20,
|
||||
fraction: "0.009999999999999999"
|
||||
```
|
||||
|
||||
#### validator-outstanding-rewards
|
||||
|
||||
The `validator-outstanding-rewards` command allows users to query all outstanding (un-withdrawn) rewards for a validator and all their delegations.
|
||||
|
||||
```sh
|
||||
simd query distribution validator-outstanding-rewards [validator] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query distribution validator-outstanding-rewards cosmosvaloper1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
rewards:
|
||||
- amount: "1000000.000000000000000000"
|
||||
denom: stake
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `distribution` module.
|
||||
|
||||
```sh
|
||||
simd tx distribution --help
|
||||
```
|
||||
|
||||
#### fund-community-pool
|
||||
|
||||
The `fund-community-pool` command allows users to send funds to the community pool.
|
||||
|
||||
```sh
|
||||
simd tx distribution fund-community-pool [amount] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution fund-community-pool 100stake --from cosmos1..
|
||||
```
|
||||
|
||||
#### set-withdraw-addr
|
||||
|
||||
The `set-withdraw-addr` command allows users to set the withdraw address for rewards associated with a delegator address.
|
||||
|
||||
```sh
|
||||
simd tx distribution set-withdraw-addr [withdraw-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution set-withdraw-addr cosmos1.. --from cosmos1..
|
||||
```
|
||||
|
||||
#### withdraw-all-rewards
|
||||
|
||||
The `withdraw-all-rewards` command allows users to withdraw all rewards for a delegator.
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-all-rewards [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-all-rewards --from cosmos1..
|
||||
```
|
||||
|
||||
#### withdraw-rewards
|
||||
|
||||
The `withdraw-rewards` command allows users to withdraw all rewards from a given delegation address,
|
||||
and optionally withdraw validator commission if the delegation address given is a validator operator and the user proves the `--commision` flag.
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-rewards [validator-addr] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx distribution withdraw-rewards cosmosvaloper1.. --from cosmos1.. --commision
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `distribution` module using gRPC endpoints.
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allows users to query parameters of the `distribution` module.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"communityTax": "20000000000000000",
|
||||
"baseProposerReward": "10000000000000000",
|
||||
"bonusProposerReward": "40000000000000000",
|
||||
"withdrawAddrEnabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorOutstandingRewards
|
||||
|
||||
The `ValidatorOutstandingRewards` endpoint allows users to query rewards of a validator address.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": {
|
||||
"rewards": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorCommission
|
||||
|
||||
The `ValidatorCommission` endpoint allows users to query accumulated commission for a validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorCommission
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"commission": {
|
||||
"commission": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ValidatorSlashes
|
||||
|
||||
The `ValidatorSlashes` endpoint allows users to query slash events of a validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/ValidatorSlashes
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"slashes": [
|
||||
{
|
||||
"validator_period": "20",
|
||||
"fraction": "0.009999999999999999"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DelegationRewards
|
||||
|
||||
The `DelegationRewards` endpoint allows users to query the total rewards accrued by a delegation.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1..","validator_address":"cosmosvalop1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegationRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegationTotalRewards
|
||||
|
||||
The `DelegationTotalRewards` endpoint allows users to query the total rewards accrued by each validator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegationTotalRewards
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewards": [
|
||||
{
|
||||
"validatorAddress": "cosmosvaloper1..",
|
||||
"reward": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegatorValidators
|
||||
|
||||
The `DelegatorValidators` endpoint allows users to query all validators for given delegator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegatorValidators
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"validators": [
|
||||
"cosmosvaloper1.."
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### DelegatorWithdrawAddress
|
||||
|
||||
The `DelegatorWithdrawAddress` endpoint allows users to query the withdraw address of a delegator.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"delegator_address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"withdrawAddress": "cosmos1.."
|
||||
}
|
||||
```
|
||||
|
||||
### CommunityPool
|
||||
|
||||
The `CommunityPool` endpoint allows users to query the community pool coins.
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
localhost:9090 \
|
||||
cosmos.distribution.v1beta1.Query/CommunityPool
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"pool": [
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "1000000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@ -1,104 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Distribution Overview
|
||||
parent:
|
||||
title: "distribution"
|
||||
-->
|
||||
|
||||
# `distribution`
|
||||
|
||||
## Overview
|
||||
|
||||
This _simple_ distribution mechanism describes a functional way to passively
|
||||
distribute rewards between validators and delegators. Note that this mechanism does
|
||||
not distribute funds in as precisely as active reward distribution mechanisms and
|
||||
will therefore be upgraded in the future.
|
||||
|
||||
The mechanism operates as follows. Collected rewards are pooled globally and
|
||||
divided out passively to validators and delegators. Each validator has the
|
||||
opportunity to charge commission to the delegators on the rewards collected on
|
||||
behalf of the delegators. Fees are collected directly into a global reward pool
|
||||
and validator proposer-reward pool. Due to the nature of passive accounting,
|
||||
whenever changes to parameters which affect the rate of reward distribution
|
||||
occurs, withdrawal of rewards must also occur.
|
||||
|
||||
* Whenever withdrawing, one must withdraw the maximum amount they are entitled
|
||||
to, leaving nothing in the pool.
|
||||
* Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
|
||||
full withdrawal of the rewards must occur (as the rules for lazy accounting
|
||||
change).
|
||||
* Whenever a validator chooses to change the commission on rewards, all accumulated
|
||||
commission rewards must be simultaneously withdrawn.
|
||||
|
||||
The above scenarios are covered in `hooks.md`.
|
||||
|
||||
The distribution mechanism outlined herein is used to lazily distribute the
|
||||
following rewards between validators and associated delegators:
|
||||
|
||||
* multi-token fees to be socially distributed
|
||||
* inflated staked asset provisions
|
||||
* validator commission on all rewards earned by their delegators stake
|
||||
|
||||
Fees are pooled within a global pool. The mechanisms used allow for validators
|
||||
and delegators to independently and lazily withdraw their rewards.
|
||||
|
||||
## Shortcomings
|
||||
|
||||
As a part of the lazy computations, each delegator holds an accumulation term
|
||||
specific to each validator which is used to estimate what their approximate
|
||||
fair portion of tokens held in the global fee pool is owed to them.
|
||||
|
||||
```text
|
||||
entitlement = delegator-accumulation / all-delegators-accumulation
|
||||
```
|
||||
|
||||
Under the circumstance that there was constant and equal flow of incoming
|
||||
reward tokens every block, this distribution mechanism would be equal to the
|
||||
active distribution (distribute individually to all delegators each block).
|
||||
However, this is unrealistic so deviations from the active distribution will
|
||||
occur based on fluctuations of incoming reward tokens as well as timing of
|
||||
reward withdrawal by other delegators.
|
||||
|
||||
If you happen to know that incoming rewards are about to significantly increase,
|
||||
you are incentivized to not withdraw until after this event, increasing the
|
||||
worth of your existing _accum_. See [#2764](https://github.com/cosmos/cosmos-sdk/issues/2764)
|
||||
for further details.
|
||||
|
||||
## Effect on Staking
|
||||
|
||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||
problematic within BPoS. Fundamentally, these two mechanisms are mutually
|
||||
exclusive. If both commission and auto-bonding mechanisms are simultaneously
|
||||
applied to the staking-token then the distribution of staking-tokens between
|
||||
any validator and its delegators will change with each block. This then
|
||||
necessitates a calculation for each delegation records for each block -
|
||||
which is considered computationally expensive.
|
||||
|
||||
In conclusion, we can only have Atom commission and unbonded atoms
|
||||
provisions or bonded atom provisions with no Atom commission, and we elect to
|
||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||
to set up a script to periodically withdraw and rebond rewards.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
* [Reference Counting in F1 Fee Distribution](01_concepts.md#reference-counting-in-f1-fee-distribution)
|
||||
2. **[State](02_state.md)**
|
||||
3. **[Begin Block](03_begin_block.md)**
|
||||
4. **[Messages](04_messages.md)**
|
||||
* [MsgSetWithdrawAddress](04_messages.md#msgsetwithdrawaddress)
|
||||
* [MsgWithdrawDelegatorReward](04_messages.md#msgwithdrawdelegatorreward)
|
||||
* [Withdraw Validator Rewards All](04_messages.md#withdraw-validator-rewards-all)
|
||||
* [Common calculations](04_messages.md#common-calculations-)
|
||||
5. **[Hooks](05_hooks.md)**
|
||||
* [Create or modify delegation distribution](05_hooks.md#create-or-modify-delegation-distribution)
|
||||
* [Commission rate change](05_hooks.md#commission-rate-change)
|
||||
* [Change in Validator State](05_hooks.md#change-in-validator-state)
|
||||
6. **[Events](06_events.md)**
|
||||
* [BeginBlocker](06_events.md#beginblocker)
|
||||
* [Handlers](06_events.md#handlers)
|
||||
7. **[Parameters](07_params.md)**
|
||||
8. **[Client](08_client.md)**
|
||||
* [CLI](08_client.md#cli)
|
||||
* [gRPC](08_client.md#grpc)
|
||||
@ -1,7 +1,94 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Epoching Overview
|
||||
parent:
|
||||
title: "epoching"
|
||||
-->
|
||||
|
||||
# Epoching
|
||||
# `x/epoching`
|
||||
|
||||
* [Epoching](epoching/spec/README.md) - Allows modules to queue messages for execution at a certain block height.
|
||||
## Abstract
|
||||
|
||||
The epoching module allows modules to queue messages for execution at a certain block height. Each module will have its own instance of the epoching module, this allows each module to have its own message queue and own duration for epochs.
|
||||
|
||||
## Example
|
||||
|
||||
In this example, we are creating an epochkeeper for a module that will be used by the module to queue messages to be executed at a later point in time.
|
||||
|
||||
```go
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc codec.BinaryMarshaler
|
||||
epochKeeper epochkeeper.Keeper
|
||||
}
|
||||
|
||||
// NewKeeper creates a new staking Keeper instance
|
||||
func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey) Keeper {
|
||||
return Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
epochKeeper: epochkeeper.NewKeeper(cdc, key),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Contents
|
||||
|
||||
* [State](#state)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# State
|
||||
|
||||
## Messages queue
|
||||
|
||||
Messages are queued to run at the end of each epoch. Queued messages have an epoch number and for each epoch number, the queues are iterated over and each message is executed.
|
||||
|
||||
### Message queues
|
||||
|
||||
Each module has one unique message queue that is specific to that module.
|
||||
|
||||
## Actions
|
||||
|
||||
A module will add a message that implements the `sdk.Msg` interface. These message will be executed at a later time (end of the next epoch).
|
||||
|
||||
```go
|
||||
type Msg interface {
|
||||
proto.Message
|
||||
|
||||
// Return the message type.
|
||||
// Must be alphanumeric or empty.
|
||||
Route() string
|
||||
|
||||
// Returns a human-readable string for the message, intended for utilization
|
||||
// within tags
|
||||
Type() string
|
||||
|
||||
// ValidateBasic does a simple validation check that
|
||||
// doesn't require access to any other information.
|
||||
ValidateBasic() error
|
||||
|
||||
// Get the canonical byte representation of the Msg.
|
||||
GetSignBytes() []byte
|
||||
|
||||
// Signers returns the addrs of signers that must sign.
|
||||
// CONTRACT: All signatures must be present to be valid.
|
||||
// CONTRACT: Returns addrs in some deterministic order.
|
||||
GetSigners() []AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
## Buffered Messages Export / Import
|
||||
|
||||
For now, the `x/epoching` module is implemented to export all buffered messages without epoch numbers. When state is imported, buffered messages are stored on current epoch to run at the end of current epoch.
|
||||
|
||||
## Genesis Transactions
|
||||
|
||||
We execute epoch after execution of genesis transactions to see the changes instantly before node start.
|
||||
|
||||
## Execution on epochs
|
||||
|
||||
* Try executing the message for the epoch
|
||||
* If success, make changes as it is
|
||||
* If failure, try making revert extra actions done on handlers (e.g. EpochDelegationPool deposit)
|
||||
* If revert fail, panic
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## Messages queue
|
||||
|
||||
Messages are queued to run at the end of each epoch. Queued messages have an epoch number and for each epoch number, the queues are iterated over and each message is executed.
|
||||
|
||||
### Message queues
|
||||
|
||||
Each module has one unique message queue that is specific to that module.
|
||||
|
||||
## Actions
|
||||
|
||||
A module will add a message that implements the `sdk.Msg` interface. These message will be executed at a later time (end of the next epoch).
|
||||
|
||||
```go
|
||||
type Msg interface {
|
||||
proto.Message
|
||||
|
||||
// Return the message type.
|
||||
// Must be alphanumeric or empty.
|
||||
Route() string
|
||||
|
||||
// Returns a human-readable string for the message, intended for utilization
|
||||
// within tags
|
||||
Type() string
|
||||
|
||||
// ValidateBasic does a simple validation check that
|
||||
// doesn't require access to any other information.
|
||||
ValidateBasic() error
|
||||
|
||||
// Get the canonical byte representation of the Msg.
|
||||
GetSignBytes() []byte
|
||||
|
||||
// Signers returns the addrs of signers that must sign.
|
||||
// CONTRACT: All signatures must be present to be valid.
|
||||
// CONTRACT: Returns addrs in some deterministic order.
|
||||
GetSigners() []AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
## Buffered Messages Export / Import
|
||||
|
||||
For now, the `x/epoching` module is implemented to export all buffered messages without epoch numbers. When state is imported, buffered messages are stored on current epoch to run at the end of current epoch.
|
||||
|
||||
## Genesis Transactions
|
||||
|
||||
We execute epoch after execution of genesis transactions to see the changes instantly before node start.
|
||||
|
||||
## Execution on epochs
|
||||
|
||||
* Try executing the message for the epoch
|
||||
* If success, make changes as it is
|
||||
* If failure, try making revert extra actions done on handlers (e.g. EpochDelegationPool deposit)
|
||||
* If revert fail, panic
|
||||
@ -1,44 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Changes to make
|
||||
|
||||
## Validator self-unbonding (which exceed minimum self delegation) could be required to start instantly
|
||||
|
||||
Cases that trigger unbonding process
|
||||
|
||||
* Validator undelegate can unbond more tokens than his minimum_self_delegation and it will automatically turn the validator into unbonding
|
||||
In this case, unbonding should start instantly.
|
||||
* Validator miss blocks and get slashed
|
||||
* Validator get slashed for double sign
|
||||
|
||||
**Note:** When a validator begins the unbonding process, it could be required to turn the validator into unbonding state instantly.
|
||||
This is different than a specific delegator beginning to unbond. A validator beginning to unbond means that it's not in the set any more.
|
||||
A delegator unbonding from a validator removes their delegation from the validator.
|
||||
|
||||
## Pending development
|
||||
|
||||
```go
|
||||
// Changes to make
|
||||
// — Implement correct next epoch time calculation
|
||||
// — For validator self undelegation, it could be required to do start on end blocker
|
||||
// — Implement TODOs on the PR #46
|
||||
// Implement CLI commands for querying
|
||||
// — BufferedValidators
|
||||
// — BufferedMsgCreateValidatorQueue, BufferedMsgEditValidatorQueue
|
||||
// — BufferedMsgUnjailQueue, BufferedMsgDelegateQueue, BufferedMsgRedelegationQueue, BufferedMsgUndelegateQueue
|
||||
// Write epoch related tests with new scenarios
|
||||
// — Simulation test is important for finding bugs [Ask Dev for questions)
|
||||
// — Can easily add a simulator check to make sure all delegation amounts in queue add up to the same amount that’s in the EpochUnbondedPool
|
||||
// — I’d like it added as an invariant test for the simulator
|
||||
// — the simulator should check that the sum of all the queued delegations always equals the amount kept track in the data
|
||||
// — Staking/Slashing/Distribution module params are being modified by governance based on vote result instantly. We should test the effect.
|
||||
// — — Should test to see what would happen if max_validators is changed though, in the middle of an epoch
|
||||
// — we should define some new invariants that help check that everything is working smoothly with these new changes for 3 modules e.g. https://github.com/cosmos/cosmos-sdk/blob/main/x/staking/keeper/invariants.go
|
||||
// — — Within Epoch, ValidationPower = ValidationPower - SlashAmount
|
||||
// — — When epoch actions queue is empty, EpochDelegationPool balance should be zero
|
||||
// — we should count all the delegation changes that happen during the epoch, and then make sure that the resulting change at the end of the epoch is actually correct
|
||||
// — If the validator that I delegated to double signs at block 16, I should still get slashed instantly because even though I asked to unbond at 14, they still used my power at block 16, I should only be not liable for slashes once my power is stopped being used
|
||||
// — On the converse of this, I should still be getting rewards while my power is being used. I shouldn’t stop receiving rewards until block 20
|
||||
```
|
||||
@ -1,37 +0,0 @@
|
||||
<!--
|
||||
order: 20
|
||||
title: Epoching Overview
|
||||
parent:
|
||||
title: "epoching"
|
||||
-->
|
||||
|
||||
# `x/epoching`
|
||||
|
||||
## Abstract
|
||||
|
||||
The epoching module allows modules to queue messages for execution at a certain block height. Each module will have its own instance of the epoching module, this allows each module to have its own message queue and own duration for epochs.
|
||||
|
||||
## Example
|
||||
|
||||
In this example, we are creating an epochkeeper for a module that will be used by the module to queue messages to be executed at a later point in time.
|
||||
|
||||
```go
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc codec.BinaryMarshaler
|
||||
epochKeeper epochkeeper.Keeper
|
||||
}
|
||||
|
||||
// NewKeeper creates a new staking Keeper instance
|
||||
func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey) Keeper {
|
||||
return Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
epochKeeper: epochkeeper.NewKeeper(cdc, key),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Contents
|
||||
|
||||
1. **[State](01_state.md)**
|
||||
@ -1,7 +1,554 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Evidence Overview
|
||||
parent:
|
||||
title: "evidence"
|
||||
-->
|
||||
|
||||
# Evidence
|
||||
# `x/evidence`
|
||||
|
||||
* [Evidence](spec/README.md) - Evidence handling for double signing, misbehaviour, etc.
|
||||
* [Concepts](#concepts)
|
||||
* [State](#state)
|
||||
* [Messages](#messages)
|
||||
* [Events](#events)
|
||||
* [Parameters](#parameters)
|
||||
* [BeginBlock](#beginblock)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [REST](#rest)
|
||||
* [gRPC](#grpc)
|
||||
|
||||
## Abstract
|
||||
|
||||
`x/evidence` is an implementation of a Cosmos SDK module, per [ADR 009](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-009-evidence-module.md),
|
||||
that allows for the submission and handling of arbitrary evidence of misbehavior such
|
||||
as equivocation and counterfactual signing.
|
||||
|
||||
The evidence module differs from standard evidence handling which typically expects the
|
||||
underlying consensus engine, e.g. Tendermint, to automatically submit evidence when
|
||||
it is discovered by allowing clients and foreign chains to submit more complex evidence
|
||||
directly.
|
||||
|
||||
All concrete evidence types must implement the `Evidence` interface contract. Submitted
|
||||
`Evidence` is first routed through the evidence module's `Router` in which it attempts
|
||||
to find a corresponding registered `Handler` for that specific `Evidence` type.
|
||||
Each `Evidence` type must have a `Handler` registered with the evidence module's
|
||||
keeper in order for it to be successfully routed and executed.
|
||||
|
||||
Each corresponding handler must also fulfill the `Handler` interface contract. The
|
||||
`Handler` for a given `Evidence` type can perform any arbitrary state transitions
|
||||
such as slashing, jailing, and tombstoning.
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Evidence
|
||||
|
||||
Any concrete type of evidence submitted to the `x/evidence` module must fulfill the
|
||||
`Evidence` contract outlined below. Not all concrete types of evidence will fulfill
|
||||
this contract in the same way and some data may be entirely irrelevant to certain
|
||||
types of evidence. An additional `ValidatorEvidence`, which extends `Evidence`,
|
||||
has also been created to define a contract for evidence against malicious validators.
|
||||
|
||||
```go
|
||||
// Evidence defines the contract which concrete evidence types of misbehavior
|
||||
// must implement.
|
||||
type Evidence interface {
|
||||
proto.Message
|
||||
|
||||
Route() string
|
||||
Type() string
|
||||
String() string
|
||||
Hash() tmbytes.HexBytes
|
||||
ValidateBasic() error
|
||||
|
||||
// Height at which the infraction occurred
|
||||
GetHeight() int64
|
||||
}
|
||||
|
||||
// ValidatorEvidence extends Evidence interface to define contract
|
||||
// for evidence against malicious validators
|
||||
type ValidatorEvidence interface {
|
||||
Evidence
|
||||
|
||||
// The consensus address of the malicious validator at time of infraction
|
||||
GetConsensusAddress() sdk.ConsAddress
|
||||
|
||||
// The total power of the malicious validator at time of infraction
|
||||
GetValidatorPower() int64
|
||||
|
||||
// The total validator set power at time of infraction
|
||||
GetTotalPower() int64
|
||||
}
|
||||
```
|
||||
|
||||
## Registration & Handling
|
||||
|
||||
The `x/evidence` module must first know about all types of evidence it is expected
|
||||
to handle. This is accomplished by registering the `Route` method in the `Evidence`
|
||||
contract with what is known as a `Router` (defined below). The `Router` accepts
|
||||
`Evidence` and attempts to find the corresponding `Handler` for the `Evidence`
|
||||
via the `Route` method.
|
||||
|
||||
```go
|
||||
type Router interface {
|
||||
AddRoute(r string, h Handler) Router
|
||||
HasRoute(r string) bool
|
||||
GetRoute(path string) Handler
|
||||
Seal()
|
||||
Sealed() bool
|
||||
}
|
||||
```
|
||||
|
||||
The `Handler` (defined below) is responsible for executing the entirety of the
|
||||
business logic for handling `Evidence`. This typically includes validating the
|
||||
evidence, both stateless checks via `ValidateBasic` and stateful checks via any
|
||||
keepers provided to the `Handler`. In addition, the `Handler` may also perform
|
||||
capabilities such as slashing and jailing a validator. All `Evidence` handled
|
||||
by the `Handler` should be persisted.
|
||||
|
||||
```go
|
||||
// Handler defines an agnostic Evidence handler. The handler is responsible
|
||||
// for executing all corresponding business logic necessary for verifying the
|
||||
// evidence as valid. In addition, the Handler may execute any necessary
|
||||
// slashing and potential jailing.
|
||||
type Handler func(sdk.Context, Evidence) error
|
||||
```
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
Currently the `x/evidence` module only stores valid submitted `Evidence` in state.
|
||||
The evidence state is also stored and exported in the `x/evidence` module's `GenesisState`.
|
||||
|
||||
```protobuf
|
||||
// GenesisState defines the evidence module's genesis state.
|
||||
message GenesisState {
|
||||
// evidence defines all the evidence at genesis.
|
||||
repeated google.protobuf.Any evidence = 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
All `Evidence` is retrieved and stored via a prefix `KVStore` using prefix `0x00` (`KeyPrefixEvidence`).
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Messages
|
||||
|
||||
## MsgSubmitEvidence
|
||||
|
||||
Evidence is submitted through a `MsgSubmitEvidence` message:
|
||||
|
||||
```protobuf
|
||||
// MsgSubmitEvidence represents a message that supports submitting arbitrary
|
||||
// Evidence of misbehavior such as equivocation or counterfactual signing.
|
||||
message MsgSubmitEvidence {
|
||||
string submitter = 1;
|
||||
google.protobuf.Any evidence = 2;
|
||||
}
|
||||
```
|
||||
|
||||
Note, the `Evidence` of a `MsgSubmitEvidence` message must have a corresponding
|
||||
`Handler` registered with the `x/evidence` module's `Router` in order to be processed
|
||||
and routed correctly.
|
||||
|
||||
Given the `Evidence` is registered with a corresponding `Handler`, it is processed
|
||||
as follows:
|
||||
|
||||
```go
|
||||
func SubmitEvidence(ctx Context, evidence Evidence) error {
|
||||
if _, ok := GetEvidence(ctx, evidence.Hash()); ok {
|
||||
return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String())
|
||||
}
|
||||
if !router.HasRoute(evidence.Route()) {
|
||||
return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route())
|
||||
}
|
||||
|
||||
handler := router.GetRoute(evidence.Route())
|
||||
if err := handler(ctx, evidence); err != nil {
|
||||
return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error())
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeSubmitEvidence,
|
||||
sdk.NewAttribute(types.AttributeKeyEvidenceHash, evidence.Hash().String()),
|
||||
),
|
||||
)
|
||||
|
||||
SetEvidence(ctx, evidence)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
First, there must not already exist valid submitted `Evidence` of the exact same
|
||||
type. Secondly, the `Evidence` is routed to the `Handler` and executed. Finally,
|
||||
if there is no error in handling the `Evidence`, an event is emitted and it is persisted to state.
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Events
|
||||
|
||||
The `x/evidence` module emits the following events:
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgSubmitEvidence
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| --------------- | ------------- | --------------- |
|
||||
| submit_evidence | evidence_hash | {evidenceHash} |
|
||||
| message | module | evidence |
|
||||
| message | sender | {senderAddress} |
|
||||
| message | action | submit_evidence |
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Parameters
|
||||
|
||||
The evidence module does not contain any parameters.
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
# BeginBlock
|
||||
|
||||
## Evidence Handling
|
||||
|
||||
Tendermint blocks can include
|
||||
[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly.
|
||||
|
||||
### Equivocation
|
||||
|
||||
The Cosmos SDK handles two types of evidence inside the ABCI `BeginBlock`:
|
||||
|
||||
* `DuplicateVoteEvidence`,
|
||||
* `LightClientAttackEvidence`.
|
||||
|
||||
The evidence module handles these two evidence types the same way. First, the Cosmos SDK converts the Tendermint concrete evidence type to an SDK `Evidence` interface using `Equivocation` as the concrete type.
|
||||
|
||||
```proto
|
||||
// Equivocation implements the Evidence interface.
|
||||
message Equivocation {
|
||||
int64 height = 1;
|
||||
google.protobuf.Timestamp time = 2;
|
||||
int64 power = 3;
|
||||
string consensus_address = 4;
|
||||
}
|
||||
```
|
||||
|
||||
For some `Equivocation` submitted in `block` to be valid, it must satisfy:
|
||||
|
||||
`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge`
|
||||
|
||||
Where:
|
||||
|
||||
* `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height`
|
||||
* `block.Timestamp` is the current block timestamp.
|
||||
|
||||
If valid `Equivocation` evidence is included in a block, the validator's stake is
|
||||
reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module
|
||||
of what their stake was when the infraction occurred, rather than when the evidence was discovered.
|
||||
We want to "follow the stake", i.e., the stake that contributed to the infraction
|
||||
should be slashed, even if it has since been redelegated or started unbonding.
|
||||
|
||||
In addition, the validator is permanently jailed and tombstoned to make it impossible for that
|
||||
validator to ever re-enter the validator set.
|
||||
|
||||
The `Equivocation` evidence is handled as follows:
|
||||
|
||||
```go
|
||||
func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) {
|
||||
logger := k.Logger(ctx)
|
||||
consAddr := evidence.GetConsensusAddress()
|
||||
|
||||
if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil {
|
||||
// Ignore evidence that cannot be handled.
|
||||
//
|
||||
// NOTE: We used to panic with:
|
||||
// `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`,
|
||||
// but this couples the expectations of the app to both Tendermint and
|
||||
// the simulator. Both are expected to provide the full range of
|
||||
// allowable but none of the disallowed evidence types. Instead of
|
||||
// getting this coordination right, it is easier to relax the
|
||||
// constraints and ignore evidence that cannot be handled.
|
||||
return
|
||||
}
|
||||
|
||||
// calculate the age of the evidence
|
||||
infractionHeight := evidence.GetHeight()
|
||||
infractionTime := evidence.GetTime()
|
||||
ageDuration := ctx.BlockHeader().Time.Sub(infractionTime)
|
||||
ageBlocks := ctx.BlockHeader().Height - infractionHeight
|
||||
|
||||
// Reject evidence if the double-sign is too old. Evidence is considered stale
|
||||
// if the difference in time and number of blocks is greater than the allowed
|
||||
// parameters defined.
|
||||
cp := ctx.ConsensusParams()
|
||||
if cp != nil && cp.Evidence != nil {
|
||||
if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks {
|
||||
logger.Info(
|
||||
"ignored equivocation; evidence too old",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks,
|
||||
"infraction_time", infractionTime,
|
||||
"max_age_duration", cp.Evidence.MaxAgeDuration,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr)
|
||||
if validator == nil || validator.IsUnbonded() {
|
||||
// Defensive: Simulation doesn't take unbonding periods into account, and
|
||||
// Tendermint might break this assumption at some point.
|
||||
return
|
||||
}
|
||||
|
||||
if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok {
|
||||
panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr))
|
||||
}
|
||||
|
||||
// ignore if the validator is already tombstoned
|
||||
if k.slashingKeeper.IsTombstoned(ctx, consAddr) {
|
||||
logger.Info(
|
||||
"ignored equivocation; validator already tombstoned",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"infraction_time", infractionTime,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info(
|
||||
"confirmed equivocation",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"infraction_time", infractionTime,
|
||||
)
|
||||
|
||||
// We need to retrieve the stake distribution which signed the block, so we
|
||||
// subtract ValidatorUpdateDelay from the evidence height.
|
||||
// Note, that this *can* result in a negative "distributionHeight", up to
|
||||
// -ValidatorUpdateDelay, i.e. at the end of the
|
||||
// pre-genesis block (none) = at the beginning of the genesis block.
|
||||
// That's fine since this is just used to filter unbonding delegations & redelegations.
|
||||
distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay
|
||||
|
||||
// Slash validator. The `power` is the int64 power of the validator as provided
|
||||
// to/by Tendermint. This value is validator.Tokens as sent to Tendermint via
|
||||
// ABCI, and now received as evidence. The fraction is passed in to separately
|
||||
// to slash unbonding and rebonding delegations.
|
||||
k.slashingKeeper.Slash(
|
||||
ctx,
|
||||
consAddr,
|
||||
k.slashingKeeper.SlashFractionDoubleSign(ctx),
|
||||
evidence.GetValidatorPower(), distributionHeight,
|
||||
)
|
||||
|
||||
// Jail the validator if not already jailed. This will begin unbonding the
|
||||
// validator if not already unbonding (tombstoned).
|
||||
if !validator.IsJailed() {
|
||||
k.slashingKeeper.Jail(ctx, consAddr)
|
||||
}
|
||||
|
||||
k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime)
|
||||
k.slashingKeeper.Tombstone(ctx, consAddr)
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module
|
||||
that emits informative events and finally delegates calls to the `x/staking` module. See documentation
|
||||
on slashing and jailing in [State Transitions](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md).
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `evidence` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allows users to query `evidence` state.
|
||||
|
||||
```bash
|
||||
simd query evidence --help
|
||||
```
|
||||
|
||||
### evidence
|
||||
|
||||
The `evidence` command allows users to list all evidence or evidence by hash.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
simd query evidence [flags]
|
||||
```
|
||||
|
||||
To query evidence by hash
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
evidence:
|
||||
consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
|
||||
height: 11
|
||||
power: 100
|
||||
time: "2021-10-20T16:08:38.194017624Z"
|
||||
```
|
||||
|
||||
To get all evidence
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query evidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
evidence:
|
||||
consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
|
||||
height: 11
|
||||
power: 100
|
||||
time: "2021-10-20T16:08:38.194017624Z"
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "1"
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `evidence` module using REST endpoints.
|
||||
|
||||
### Evidence
|
||||
|
||||
Get evidence by hash
|
||||
|
||||
```bash
|
||||
/cosmos/evidence/v1beta1/evidence/{evidence_hash}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": {
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### All evidence
|
||||
|
||||
Get all evidence
|
||||
|
||||
```bash
|
||||
/cosmos/evidence/v1beta1/evidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": [
|
||||
{
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `evidence` module using gRPC endpoints.
|
||||
|
||||
### Evidence
|
||||
|
||||
Get evidence by hash
|
||||
|
||||
```bash
|
||||
cosmos.evidence.v1beta1.Query/Evidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": {
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### All evidence
|
||||
|
||||
Get all evidence
|
||||
|
||||
```bash
|
||||
cosmos.evidence.v1beta1.Query/AllEvidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": [
|
||||
{
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,78 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Evidence
|
||||
|
||||
Any concrete type of evidence submitted to the `x/evidence` module must fulfill the
|
||||
`Evidence` contract outlined below. Not all concrete types of evidence will fulfill
|
||||
this contract in the same way and some data may be entirely irrelevant to certain
|
||||
types of evidence. An additional `ValidatorEvidence`, which extends `Evidence`,
|
||||
has also been created to define a contract for evidence against malicious validators.
|
||||
|
||||
```go
|
||||
// Evidence defines the contract which concrete evidence types of misbehavior
|
||||
// must implement.
|
||||
type Evidence interface {
|
||||
proto.Message
|
||||
|
||||
Route() string
|
||||
Type() string
|
||||
String() string
|
||||
Hash() tmbytes.HexBytes
|
||||
ValidateBasic() error
|
||||
|
||||
// Height at which the infraction occurred
|
||||
GetHeight() int64
|
||||
}
|
||||
|
||||
// ValidatorEvidence extends Evidence interface to define contract
|
||||
// for evidence against malicious validators
|
||||
type ValidatorEvidence interface {
|
||||
Evidence
|
||||
|
||||
// The consensus address of the malicious validator at time of infraction
|
||||
GetConsensusAddress() sdk.ConsAddress
|
||||
|
||||
// The total power of the malicious validator at time of infraction
|
||||
GetValidatorPower() int64
|
||||
|
||||
// The total validator set power at time of infraction
|
||||
GetTotalPower() int64
|
||||
}
|
||||
```
|
||||
|
||||
## Registration & Handling
|
||||
|
||||
The `x/evidence` module must first know about all types of evidence it is expected
|
||||
to handle. This is accomplished by registering the `Route` method in the `Evidence`
|
||||
contract with what is known as a `Router` (defined below). The `Router` accepts
|
||||
`Evidence` and attempts to find the corresponding `Handler` for the `Evidence`
|
||||
via the `Route` method.
|
||||
|
||||
```go
|
||||
type Router interface {
|
||||
AddRoute(r string, h Handler) Router
|
||||
HasRoute(r string) bool
|
||||
GetRoute(path string) Handler
|
||||
Seal()
|
||||
Sealed() bool
|
||||
}
|
||||
```
|
||||
|
||||
The `Handler` (defined below) is responsible for executing the entirety of the
|
||||
business logic for handling `Evidence`. This typically includes validating the
|
||||
evidence, both stateless checks via `ValidateBasic` and stateful checks via any
|
||||
keepers provided to the `Handler`. In addition, the `Handler` may also perform
|
||||
capabilities such as slashing and jailing a validator. All `Evidence` handled
|
||||
by the `Handler` should be persisted.
|
||||
|
||||
```go
|
||||
// Handler defines an agnostic Evidence handler. The handler is responsible
|
||||
// for executing all corresponding business logic necessary for verifying the
|
||||
// evidence as valid. In addition, the Handler may execute any necessary
|
||||
// slashing and potential jailing.
|
||||
type Handler func(sdk.Context, Evidence) error
|
||||
```
|
||||
@ -1,19 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
Currently the `x/evidence` module only stores valid submitted `Evidence` in state.
|
||||
The evidence state is also stored and exported in the `x/evidence` module's `GenesisState`.
|
||||
|
||||
```protobuf
|
||||
// GenesisState defines the evidence module's genesis state.
|
||||
message GenesisState {
|
||||
// evidence defines all the evidence at genesis.
|
||||
repeated google.protobuf.Any evidence = 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
All `Evidence` is retrieved and stored via a prefix `KVStore` using prefix `0x00` (`KeyPrefixEvidence`).
|
||||
@ -1,55 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
## MsgSubmitEvidence
|
||||
|
||||
Evidence is submitted through a `MsgSubmitEvidence` message:
|
||||
|
||||
```protobuf
|
||||
// MsgSubmitEvidence represents a message that supports submitting arbitrary
|
||||
// Evidence of misbehavior such as equivocation or counterfactual signing.
|
||||
message MsgSubmitEvidence {
|
||||
string submitter = 1;
|
||||
google.protobuf.Any evidence = 2;
|
||||
}
|
||||
```
|
||||
|
||||
Note, the `Evidence` of a `MsgSubmitEvidence` message must have a corresponding
|
||||
`Handler` registered with the `x/evidence` module's `Router` in order to be processed
|
||||
and routed correctly.
|
||||
|
||||
Given the `Evidence` is registered with a corresponding `Handler`, it is processed
|
||||
as follows:
|
||||
|
||||
```go
|
||||
func SubmitEvidence(ctx Context, evidence Evidence) error {
|
||||
if _, ok := GetEvidence(ctx, evidence.Hash()); ok {
|
||||
return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String())
|
||||
}
|
||||
if !router.HasRoute(evidence.Route()) {
|
||||
return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route())
|
||||
}
|
||||
|
||||
handler := router.GetRoute(evidence.Route())
|
||||
if err := handler(ctx, evidence); err != nil {
|
||||
return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error())
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeSubmitEvidence,
|
||||
sdk.NewAttribute(types.AttributeKeyEvidenceHash, evidence.Hash().String()),
|
||||
),
|
||||
)
|
||||
|
||||
SetEvidence(ctx, evidence)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
First, there must not already exist valid submitted `Evidence` of the exact same
|
||||
type. Secondly, the `Evidence` is routed to the `Handler` and executed. Finally,
|
||||
if there is no error in handling the `Evidence`, an event is emitted and it is persisted to state.
|
||||
@ -1,18 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The `x/evidence` module emits the following events:
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgSubmitEvidence
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| --------------- | ------------- | --------------- |
|
||||
| submit_evidence | evidence_hash | {evidenceHash} |
|
||||
| message | module | evidence |
|
||||
| message | sender | {senderAddress} |
|
||||
| message | action | submit_evidence |
|
||||
@ -1,7 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The evidence module does not contain any parameters.
|
||||
@ -1,154 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# BeginBlock
|
||||
|
||||
## Evidence Handling
|
||||
|
||||
Tendermint blocks can include
|
||||
[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly.
|
||||
|
||||
### Equivocation
|
||||
|
||||
The Cosmos SDK handles two types of evidence inside the ABCI `BeginBlock`:
|
||||
|
||||
* `DuplicateVoteEvidence`,
|
||||
* `LightClientAttackEvidence`.
|
||||
|
||||
The evidence module handles these two evidence types the same way. First, the Cosmos SDK converts the Tendermint concrete evidence type to an SDK `Evidence` interface using `Equivocation` as the concrete type.
|
||||
|
||||
```proto
|
||||
// Equivocation implements the Evidence interface.
|
||||
message Equivocation {
|
||||
int64 height = 1;
|
||||
google.protobuf.Timestamp time = 2;
|
||||
int64 power = 3;
|
||||
string consensus_address = 4;
|
||||
}
|
||||
```
|
||||
|
||||
For some `Equivocation` submitted in `block` to be valid, it must satisfy:
|
||||
|
||||
`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge`
|
||||
|
||||
Where:
|
||||
|
||||
* `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height`
|
||||
* `block.Timestamp` is the current block timestamp.
|
||||
|
||||
If valid `Equivocation` evidence is included in a block, the validator's stake is
|
||||
reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module
|
||||
of what their stake was when the infraction occurred, rather than when the evidence was discovered.
|
||||
We want to "follow the stake", i.e., the stake that contributed to the infraction
|
||||
should be slashed, even if it has since been redelegated or started unbonding.
|
||||
|
||||
In addition, the validator is permanently jailed and tombstoned to make it impossible for that
|
||||
validator to ever re-enter the validator set.
|
||||
|
||||
The `Equivocation` evidence is handled as follows:
|
||||
|
||||
```go
|
||||
func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) {
|
||||
logger := k.Logger(ctx)
|
||||
consAddr := evidence.GetConsensusAddress()
|
||||
|
||||
if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil {
|
||||
// Ignore evidence that cannot be handled.
|
||||
//
|
||||
// NOTE: We used to panic with:
|
||||
// `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`,
|
||||
// but this couples the expectations of the app to both Tendermint and
|
||||
// the simulator. Both are expected to provide the full range of
|
||||
// allowable but none of the disallowed evidence types. Instead of
|
||||
// getting this coordination right, it is easier to relax the
|
||||
// constraints and ignore evidence that cannot be handled.
|
||||
return
|
||||
}
|
||||
|
||||
// calculate the age of the evidence
|
||||
infractionHeight := evidence.GetHeight()
|
||||
infractionTime := evidence.GetTime()
|
||||
ageDuration := ctx.BlockHeader().Time.Sub(infractionTime)
|
||||
ageBlocks := ctx.BlockHeader().Height - infractionHeight
|
||||
|
||||
// Reject evidence if the double-sign is too old. Evidence is considered stale
|
||||
// if the difference in time and number of blocks is greater than the allowed
|
||||
// parameters defined.
|
||||
cp := ctx.ConsensusParams()
|
||||
if cp != nil && cp.Evidence != nil {
|
||||
if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks {
|
||||
logger.Info(
|
||||
"ignored equivocation; evidence too old",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks,
|
||||
"infraction_time", infractionTime,
|
||||
"max_age_duration", cp.Evidence.MaxAgeDuration,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr)
|
||||
if validator == nil || validator.IsUnbonded() {
|
||||
// Defensive: Simulation doesn't take unbonding periods into account, and
|
||||
// Tendermint might break this assumption at some point.
|
||||
return
|
||||
}
|
||||
|
||||
if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok {
|
||||
panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr))
|
||||
}
|
||||
|
||||
// ignore if the validator is already tombstoned
|
||||
if k.slashingKeeper.IsTombstoned(ctx, consAddr) {
|
||||
logger.Info(
|
||||
"ignored equivocation; validator already tombstoned",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"infraction_time", infractionTime,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info(
|
||||
"confirmed equivocation",
|
||||
"validator", consAddr,
|
||||
"infraction_height", infractionHeight,
|
||||
"infraction_time", infractionTime,
|
||||
)
|
||||
|
||||
// We need to retrieve the stake distribution which signed the block, so we
|
||||
// subtract ValidatorUpdateDelay from the evidence height.
|
||||
// Note, that this *can* result in a negative "distributionHeight", up to
|
||||
// -ValidatorUpdateDelay, i.e. at the end of the
|
||||
// pre-genesis block (none) = at the beginning of the genesis block.
|
||||
// That's fine since this is just used to filter unbonding delegations & redelegations.
|
||||
distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay
|
||||
|
||||
// Slash validator. The `power` is the int64 power of the validator as provided
|
||||
// to/by Tendermint. This value is validator.Tokens as sent to Tendermint via
|
||||
// ABCI, and now received as evidence. The fraction is passed in to separately
|
||||
// to slash unbonding and rebonding delegations.
|
||||
k.slashingKeeper.Slash(
|
||||
ctx,
|
||||
consAddr,
|
||||
k.slashingKeeper.SlashFractionDoubleSign(ctx),
|
||||
evidence.GetValidatorPower(), distributionHeight,
|
||||
)
|
||||
|
||||
// Jail the validator if not already jailed. This will begin unbonding the
|
||||
// validator if not already unbonding (tombstoned).
|
||||
if !validator.IsJailed() {
|
||||
k.slashingKeeper.Jail(ctx, consAddr)
|
||||
}
|
||||
|
||||
k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime)
|
||||
k.slashingKeeper.Tombstone(ctx, consAddr)
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module
|
||||
that emits informative events and finally delegates calls to the `x/staking` module. See documentation
|
||||
on slashing and jailing in [State Transitions](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md).
|
||||
@ -1,188 +0,0 @@
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `evidence` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allows users to query `evidence` state.
|
||||
|
||||
```bash
|
||||
simd query evidence --help
|
||||
```
|
||||
|
||||
### evidence
|
||||
|
||||
The `evidence` command allows users to list all evidence or evidence by hash.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
simd query evidence [flags]
|
||||
```
|
||||
|
||||
To query evidence by hash
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
evidence:
|
||||
consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
|
||||
height: 11
|
||||
power: 100
|
||||
time: "2021-10-20T16:08:38.194017624Z"
|
||||
```
|
||||
|
||||
To get all evidence
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
simd query evidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
evidence:
|
||||
consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
|
||||
height: 11
|
||||
power: 100
|
||||
time: "2021-10-20T16:08:38.194017624Z"
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "1"
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `evidence` module using REST endpoints.
|
||||
|
||||
### Evidence
|
||||
|
||||
Get evidence by hash
|
||||
|
||||
```bash
|
||||
/cosmos/evidence/v1beta1/evidence/{evidence_hash}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": {
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### All evidence
|
||||
|
||||
Get all evidence
|
||||
|
||||
```bash
|
||||
/cosmos/evidence/v1beta1/evidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": [
|
||||
{
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `evidence` module using gRPC endpoints.
|
||||
|
||||
### Evidence
|
||||
|
||||
Get evidence by hash
|
||||
|
||||
```bash
|
||||
cosmos.evidence.v1beta1.Query/Evidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": {
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### All evidence
|
||||
|
||||
Get all evidence
|
||||
|
||||
```bash
|
||||
cosmos.evidence.v1beta1.Query/AllEvidence
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
{
|
||||
"evidence": [
|
||||
{
|
||||
"consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
|
||||
"height": "11",
|
||||
"power": "100",
|
||||
"time": "2021-10-20T16:08:38.194017624Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,40 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Evidence Overview
|
||||
parent:
|
||||
title: "evidence"
|
||||
-->
|
||||
|
||||
# `x/evidence`
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
2. **[State](02_state.md)**
|
||||
3. **[Messages](03_messages.md)**
|
||||
4. **[Events](04_events.md)**
|
||||
5. **[Params](05_params.md)**
|
||||
6. **[BeginBlock](06_begin_block.md)**
|
||||
|
||||
## Abstract
|
||||
|
||||
`x/evidence` is an implementation of a Cosmos SDK module, per [ADR 009](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-009-evidence-module.md),
|
||||
that allows for the submission and handling of arbitrary evidence of misbehavior such
|
||||
as equivocation and counterfactual signing.
|
||||
|
||||
The evidence module differs from standard evidence handling which typically expects the
|
||||
underlying consensus engine, e.g. Tendermint, to automatically submit evidence when
|
||||
it is discovered by allowing clients and foreign chains to submit more complex evidence
|
||||
directly.
|
||||
|
||||
All concrete evidence types must implement the `Evidence` interface contract. Submitted
|
||||
`Evidence` is first routed through the evidence module's `Router` in which it attempts
|
||||
to find a corresponding registered `Handler` for that specific `Evidence` type.
|
||||
Each `Evidence` type must have a `Handler` registered with the evidence module's
|
||||
keeper in order for it to be successfully routed and executed.
|
||||
|
||||
Each corresponding handler must also fulfill the `Handler` interface contract. The
|
||||
`Handler` for a given `Evidence` type can perform any arbitrary state transitions
|
||||
such as slashing, jailing, and tombstoning.
|
||||
@ -1,7 +1,377 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Fee grant Overview
|
||||
parent:
|
||||
title: "feegrant"
|
||||
-->
|
||||
|
||||
# Fee Grant
|
||||
# `x/feegrant`
|
||||
|
||||
* [Fee Grant](spec/README.md) - Grant fee allowances for executing transactions.
|
||||
## Abstract
|
||||
|
||||
This document specifies the fee grant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-029-fee-grant-module.md).
|
||||
|
||||
This module allows accounts to grant fee allowances and to use fees from their accounts. Grantees can execute any transaction without the need to maintain sufficient fees.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [State](#state)
|
||||
* [FeeAllowance](#feeallowance)
|
||||
* [FeeAllowanceQueue](#feeallowancequeue)
|
||||
* [Messages](#messages)
|
||||
* [Msg/GrantAllowance](#msggrantallowance)
|
||||
* [Msg/RevokeAllowance](#msgrevokeallowance)
|
||||
* [Events](#events)
|
||||
* [Msg Server](#msg-server)
|
||||
* [MsgGrantAllowance](#msggrantallowance-1)
|
||||
* [MsgRevokeAllowance](#msgrevokeallowance-1)
|
||||
* [Exec fee allowance](#exec-fee-allowance)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Grant
|
||||
|
||||
`Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L76-L77
|
||||
|
||||
`FeeAllowanceI` looks like:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/fees.go#L9-L32
|
||||
|
||||
## Fee Allowance types
|
||||
|
||||
There are two types of fee allowances present at the moment:
|
||||
|
||||
* `BasicAllowance`
|
||||
* `PeriodicAllowance`
|
||||
* `AllowedMsgAllowance`
|
||||
|
||||
## BasicAllowance
|
||||
|
||||
`BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26
|
||||
|
||||
* `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available coins from `granter` account address before the expiration.
|
||||
|
||||
* `expiration` specifies an optional time when this allowance expires. If the value is left empty, there is no expiry for the grant.
|
||||
|
||||
* When a grant is created with empty values for `spend_limit` and `expiration`, it is still a valid grant. It won't restrict the `grantee` to use any number of coins from `granter` and it won't have any expiration. The only way to restrict the `grantee` is by revoking the grant.
|
||||
|
||||
## PeriodicAllowance
|
||||
|
||||
`PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L29-L54
|
||||
|
||||
* `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`.
|
||||
|
||||
* `period` is the specific period of time, after each period passes, `period_can_spend` will be reset.
|
||||
|
||||
* `period_spend_limit` specifies the maximum number of coins that can be spent in the period.
|
||||
|
||||
* `period_can_spend` is the number of coins left to be spent before the period_reset time.
|
||||
|
||||
* `period_reset` keeps track of when a next period reset should happen.
|
||||
|
||||
## AllowedMsgAllowance
|
||||
|
||||
`AllowedMsgAllowance` is a fee allowance, it can be any of `BasicFeeAllowance`, `PeriodicAllowance` but restricted only to the allowed messages mentioned by the granter.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L56-L66
|
||||
|
||||
* `allowance` is either `BasicAllowance` or `PeriodicAllowance`.
|
||||
|
||||
* `allowed_messages` is array of messages allowed to execute the given allowance.
|
||||
|
||||
## FeeGranter flag
|
||||
|
||||
`feegrant` module introduces a `FeeGranter` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/cmd.go#L236-L246
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/tx/tx.go#L109-L109
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/auth/tx/builder.go#L270-L279
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/tx/v1beta1/tx.proto#L196-L217
|
||||
|
||||
Example cmd:
|
||||
|
||||
```go
|
||||
./simd tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake"
|
||||
```
|
||||
|
||||
## Granted Fee Deductions
|
||||
|
||||
Fees are deducted from grants in the `x/auth` ante handler. To learn more about how ante handlers work, read the [Auth Module AnteHandlers Guide](../../auth/spec/03_antehandlers.md).
|
||||
|
||||
## Gas
|
||||
|
||||
In order to prevent DoS attacks, using a filtered `x/feegrant` incurs gas. The SDK must assure that the `grantee`'s transactions all conform to the filter set by the `granter`. The SDK does this by iterating over the allowed messages in the filter and charging 10 gas per filtered message. The SDK will then iterate over the messages being sent by the `grantee` to ensure the messages adhere to the filter, also charging 10 gas per message. The SDK will stop iterating and fail the transaction if it finds a message that does not conform to the filter.
|
||||
|
||||
**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance.
|
||||
|
||||
## Pruning
|
||||
|
||||
A queue in the state maintained with the prefix of expiration of the grants and checks them on EndBlock with the current block time for every block to prune.
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
## FeeAllowance
|
||||
|
||||
Fee Allowances are identified by combining `Grantee` (the account address of fee allowance grantee) with the `Granter` (the account address of fee allowance granter).
|
||||
|
||||
Fee allowance grants are stored in the state as follows:
|
||||
|
||||
* Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/feegrant.pb.go#L221-L229
|
||||
|
||||
## FeeAllowanceQueue
|
||||
|
||||
Fee Allowances queue items are identified by combining the `FeeAllowancePrefixQueue` (i.e., 0x01), `expiration`, `grantee` (the account address of fee allowance grantee), `granter` (the account address of fee allowance granter). Endblocker checks `FeeAllowanceQueue` state for the expired grants and prunes them from `FeeAllowance` if there are any found.
|
||||
|
||||
Fee allowance queue keys are stored in the state as follows:
|
||||
|
||||
* Grant: `0x01 | expiration_bytes | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> EmptyBytes`
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Messages
|
||||
|
||||
## Msg/GrantAllowance
|
||||
|
||||
A fee allowance grant will be created with the `MsgGrantAllowance` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L23-L36
|
||||
|
||||
## Msg/RevokeAllowance
|
||||
|
||||
An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L41-L50
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Events
|
||||
|
||||
The feegrant module emits the following events:
|
||||
|
||||
# Msg Server
|
||||
|
||||
## MsgGrantAllowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | set_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
|
||||
## MsgRevokeAllowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | revoke_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
|
||||
## Exec fee allowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | use_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `feegrant` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `feegrant` state.
|
||||
|
||||
```sh
|
||||
simd query feegrant --help
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows users to query a grant for a given granter-grantee pair.
|
||||
|
||||
```sh
|
||||
simd query feegrant grant [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query feegrant grant cosmos1.. cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
allowance:
|
||||
'@type': /cosmos.feegrant.v1beta1.BasicAllowance
|
||||
expiration: null
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
grantee: cosmos1..
|
||||
granter: cosmos1..
|
||||
```
|
||||
|
||||
#### grants
|
||||
|
||||
The `grants` command allows users to query all grants for a given grantee.
|
||||
|
||||
```sh
|
||||
simd query feegrant grants [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query feegrant grants cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
allowances:
|
||||
- allowance:
|
||||
'@type': /cosmos.feegrant.v1beta1.BasicAllowance
|
||||
expiration: null
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
grantee: cosmos1..
|
||||
granter: cosmos1..
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `feegrant` module.
|
||||
|
||||
```sh
|
||||
simd tx feegrant --help
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit.
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example (one-time spend limit):
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake
|
||||
```
|
||||
|
||||
Example (periodic spend limit):
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake
|
||||
```
|
||||
|
||||
#### revoke
|
||||
|
||||
The `revoke` command allows users to revoke a granted fee allowance.
|
||||
|
||||
```sh
|
||||
simd tx feegrant revoke [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx feegrant revoke cosmos1.. cosmos1..
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `feegrant` module using gRPC endpoints.
|
||||
|
||||
### Allowance
|
||||
|
||||
The `Allowance` endpoint allows users to query a granted fee allowance.
|
||||
|
||||
```sh
|
||||
cosmos.feegrant.v1beta1.Query/Allowance
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"grantee":"cosmos1..","granter":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.feegrant.v1beta1.Query/Allowance
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"allowance": {
|
||||
"granter": "cosmos1..",
|
||||
"grantee": "cosmos1..",
|
||||
"allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Allowances
|
||||
|
||||
The `Allowances` endpoint allows users to query all granted fee allowances for a given grantee.
|
||||
|
||||
```sh
|
||||
cosmos.feegrant.v1beta1.Query/Allowances
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.feegrant.v1beta1.Query/Allowances
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"allowances": [
|
||||
{
|
||||
"granter": "cosmos1..",
|
||||
"grantee": "cosmos1..",
|
||||
"allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]}
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Grant
|
||||
|
||||
`Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L76-L77
|
||||
|
||||
`FeeAllowanceI` looks like:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/fees.go#L9-L32
|
||||
|
||||
## Fee Allowance types
|
||||
|
||||
There are two types of fee allowances present at the moment:
|
||||
|
||||
* `BasicAllowance`
|
||||
* `PeriodicAllowance`
|
||||
* `AllowedMsgAllowance`
|
||||
|
||||
## BasicAllowance
|
||||
|
||||
`BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26
|
||||
|
||||
* `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available coins from `granter` account address before the expiration.
|
||||
|
||||
* `expiration` specifies an optional time when this allowance expires. If the value is left empty, there is no expiry for the grant.
|
||||
|
||||
* When a grant is created with empty values for `spend_limit` and `expiration`, it is still a valid grant. It won't restrict the `grantee` to use any number of coins from `granter` and it won't have any expiration. The only way to restrict the `grantee` is by revoking the grant.
|
||||
|
||||
## PeriodicAllowance
|
||||
|
||||
`PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L29-L54
|
||||
|
||||
* `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`.
|
||||
|
||||
* `period` is the specific period of time, after each period passes, `period_can_spend` will be reset.
|
||||
|
||||
* `period_spend_limit` specifies the maximum number of coins that can be spent in the period.
|
||||
|
||||
* `period_can_spend` is the number of coins left to be spent before the period_reset time.
|
||||
|
||||
* `period_reset` keeps track of when a next period reset should happen.
|
||||
|
||||
## AllowedMsgAllowance
|
||||
|
||||
`AllowedMsgAllowance` is a fee allowance, it can be any of `BasicFeeAllowance`, `PeriodicAllowance` but restricted only to the allowed messages mentioned by the granter.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L56-L66
|
||||
|
||||
* `allowance` is either `BasicAllowance` or `PeriodicAllowance`.
|
||||
|
||||
* `allowed_messages` is array of messages allowed to execute the given allowance.
|
||||
|
||||
## FeeGranter flag
|
||||
|
||||
`feegrant` module introduces a `FeeGranter` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/cmd.go#L236-L246
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/tx/tx.go#L109-L109
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/auth/tx/builder.go#L270-L279
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/tx/v1beta1/tx.proto#L196-L217
|
||||
|
||||
Example cmd:
|
||||
|
||||
```go
|
||||
./simd tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake"
|
||||
```
|
||||
|
||||
## Granted Fee Deductions
|
||||
|
||||
Fees are deducted from grants in the `x/auth` ante handler. To learn more about how ante handlers work, read the [Auth Module AnteHandlers Guide](../../auth/spec/03_antehandlers.md).
|
||||
|
||||
## Gas
|
||||
|
||||
In order to prevent DoS attacks, using a filtered `x/feegrant` incurs gas. The SDK must assure that the `grantee`'s transactions all conform to the filter set by the `granter`. The SDK does this by iterating over the allowed messages in the filter and charging 10 gas per filtered message. The SDK will then iterate over the messages being sent by the `grantee` to ensure the messages adhere to the filter, also charging 10 gas per message. The SDK will stop iterating and fail the transaction if it finds a message that does not conform to the filter.
|
||||
|
||||
**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance.
|
||||
|
||||
## Pruning
|
||||
|
||||
A queue in the state maintained with the prefix of expiration of the grants and checks them on EndBlock with the current block time for every block to prune.
|
||||
@ -1,23 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## FeeAllowance
|
||||
|
||||
Fee Allowances are identified by combining `Grantee` (the account address of fee allowance grantee) with the `Granter` (the account address of fee allowance granter).
|
||||
|
||||
Fee allowance grants are stored in the state as follows:
|
||||
|
||||
* Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/feegrant.pb.go#L221-L229
|
||||
|
||||
## FeeAllowanceQueue
|
||||
|
||||
Fee Allowances queue items are identified by combining the `FeeAllowancePrefixQueue` (i.e., 0x01), `expiration`, `grantee` (the account address of fee allowance grantee), `granter` (the account address of fee allowance granter). Endblocker checks `FeeAllowanceQueue` state for the expired grants and prunes them from `FeeAllowance` if there are any found.
|
||||
|
||||
Fee allowance queue keys are stored in the state as follows:
|
||||
|
||||
* Grant: `0x01 | expiration_bytes | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> EmptyBytes`
|
||||
@ -1,17 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
## Msg/GrantAllowance
|
||||
|
||||
A fee allowance grant will be created with the `MsgGrantAllowance` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L23-L36
|
||||
|
||||
## Msg/RevokeAllowance
|
||||
|
||||
An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L41-L50
|
||||
@ -1,33 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The feegrant module emits the following events:
|
||||
|
||||
# Msg Server
|
||||
|
||||
## MsgGrantAllowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | set_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
|
||||
## MsgRevokeAllowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | revoke_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
|
||||
## Exec fee allowance
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| message | action | use_feegrant |
|
||||
| message | granter | {granterAddress} |
|
||||
| message | grantee | {granteeAddress} |
|
||||
@ -1,184 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `feegrant` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `feegrant` state.
|
||||
|
||||
```sh
|
||||
simd query feegrant --help
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows users to query a grant for a given granter-grantee pair.
|
||||
|
||||
```sh
|
||||
simd query feegrant grant [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query feegrant grant cosmos1.. cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
allowance:
|
||||
'@type': /cosmos.feegrant.v1beta1.BasicAllowance
|
||||
expiration: null
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
grantee: cosmos1..
|
||||
granter: cosmos1..
|
||||
```
|
||||
|
||||
#### grants
|
||||
|
||||
The `grants` command allows users to query all grants for a given grantee.
|
||||
|
||||
```sh
|
||||
simd query feegrant grants [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query feegrant grants cosmos1..
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```yml
|
||||
allowances:
|
||||
- allowance:
|
||||
'@type': /cosmos.feegrant.v1beta1.BasicAllowance
|
||||
expiration: null
|
||||
spend_limit:
|
||||
- amount: "100"
|
||||
denom: stake
|
||||
grantee: cosmos1..
|
||||
granter: cosmos1..
|
||||
pagination:
|
||||
next_key: null
|
||||
total: "0"
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
The `tx` commands allow users to interact with the `feegrant` module.
|
||||
|
||||
```sh
|
||||
simd tx feegrant --help
|
||||
```
|
||||
|
||||
#### grant
|
||||
|
||||
The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit.
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example (one-time spend limit):
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake
|
||||
```
|
||||
|
||||
Example (periodic spend limit):
|
||||
|
||||
```sh
|
||||
simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake
|
||||
```
|
||||
|
||||
#### revoke
|
||||
|
||||
The `revoke` command allows users to revoke a granted fee allowance.
|
||||
|
||||
```sh
|
||||
simd tx feegrant revoke [granter] [grantee] [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd tx feegrant revoke cosmos1.. cosmos1..
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `feegrant` module using gRPC endpoints.
|
||||
|
||||
### Allowance
|
||||
|
||||
The `Allowance` endpoint allows users to query a granted fee allowance.
|
||||
|
||||
```sh
|
||||
cosmos.feegrant.v1beta1.Query/Allowance
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"grantee":"cosmos1..","granter":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.feegrant.v1beta1.Query/Allowance
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"allowance": {
|
||||
"granter": "cosmos1..",
|
||||
"grantee": "cosmos1..",
|
||||
"allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Allowances
|
||||
|
||||
The `Allowances` endpoint allows users to query all granted fee allowances for a given grantee.
|
||||
|
||||
```sh
|
||||
cosmos.feegrant.v1beta1.Query/Allowances
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext \
|
||||
-d '{"address":"cosmos1.."}' \
|
||||
localhost:9090 \
|
||||
cosmos.feegrant.v1beta1.Query/Allowances
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"allowances": [
|
||||
{
|
||||
"granter": "cosmos1..",
|
||||
"grantee": "cosmos1..",
|
||||
"allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]}
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,37 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Fee grant
|
||||
parent:
|
||||
title: "feegrant"
|
||||
-->
|
||||
|
||||
# Fee grant
|
||||
|
||||
## Abstract
|
||||
|
||||
This document specifies the fee grant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-029-fee-grant-module.md).
|
||||
|
||||
This module allows accounts to grant fee allowances and to use fees from their accounts. Grantees can execute any transaction without the need to maintain sufficient fees.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
* [Grant](01_concepts.md#grant)
|
||||
* [Fee Allowance types](01_concepts.md#fee-allowance-types)
|
||||
* [BasicAllowance](01_concepts.md#basicallowance)
|
||||
* [PeriodicAllowance](01_concepts.md#periodicallowance)
|
||||
* [FeeAccount flag](01_concepts.md#feeaccount-flag)
|
||||
* [Granted Fee Deductions](01_concepts.md#granted-fee-deductions)
|
||||
* [Gas](01_concepts.md#gas)
|
||||
2. **[State](02_state.md)**
|
||||
* [FeeAllowance](02_state.md#feeallowance)
|
||||
3. **[Messages](03_messages.md)**
|
||||
* [Msg/GrantAllowance](03_messages.md#msggrantallowance)
|
||||
* [Msg/RevokeAllowance](03_messages.md#msgrevokeallowance)
|
||||
4. **[Events](04_events.md)**
|
||||
* [MsgGrantAllowance](04_events.md#msggrantallowance)
|
||||
* [MsgRevokeAllowance](04_events.md#msgrevokeallowance)
|
||||
* [Exec fee allowance](04_events.md#exec-fee-allowance)
|
||||
5. **[Client](05_client.md)**
|
||||
* [CLI](05_client.md#cli)
|
||||
* [gRPC](05_client.md#grpc)
|
||||
2625
x/gov/README.md
2625
x/gov/README.md
File diff suppressed because it is too large
Load Diff
@ -1,203 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
_Disclaimer: This is work in progress. Mechanisms are susceptible to change._
|
||||
|
||||
The governance process is divided in a few steps that are outlined below:
|
||||
|
||||
* **Proposal submission:** Proposal is submitted to the blockchain with a
|
||||
deposit.
|
||||
* **Vote:** Once deposit reaches a certain value (`MinDeposit`), proposal is
|
||||
confirmed and vote opens. Bonded Atom holders can then send `TxGovVote`
|
||||
transactions to vote on the proposal.
|
||||
* **Execution** After a period of time, the votes are tallied and depending
|
||||
on the result, the messages in the proposal will be executed.
|
||||
|
||||
## Proposal submission
|
||||
|
||||
### Right to submit a proposal
|
||||
|
||||
Every account can submit proposals by sending a `MsgSubmitProposal` transaction.
|
||||
Once a proposal is submitted, it is identified by its unique `proposalID`.
|
||||
|
||||
### Proposal Messages
|
||||
|
||||
A proposal includes an array of `sdk.Msg`s which are executed automatically if the
|
||||
proposal passes. The messages are executed by the governance `ModuleAccount` itself. Modules
|
||||
such as `x/upgrade`, that want to allow certain messages to be executed by governance
|
||||
only should add a whitelist within the respective msg server, granting the governance
|
||||
module the right to execute the message once a quorum has been reached. The governance
|
||||
module uses the `MsgServiceRouter` to check that these messages are correctly constructed
|
||||
and have a respective path to execute on but do not perform a full validity check.
|
||||
|
||||
## Deposit
|
||||
|
||||
To prevent spam, proposals must be submitted with a deposit in the coins defined by
|
||||
the `MinDeposit` param.
|
||||
|
||||
When a proposal is submitted, it has to be accompanied with a deposit that must be
|
||||
strictly positive, but can be inferior to `MinDeposit`. The submitter doesn't need
|
||||
to pay for the entire deposit on their own. The newly created proposal is stored in
|
||||
an _inactive proposal queue_ and stays there until its deposit passes the `MinDeposit`.
|
||||
Other token holders can increase the proposal's deposit by sending a `Deposit`
|
||||
transaction. If a proposal doesn't pass the `MinDeposit` before the deposit end time
|
||||
(the time when deposits are no longer accepted), the proposal will be destroyed: the
|
||||
proposal will be removed from state and the deposit will be burned (see x/gov `EndBlocker`).
|
||||
When a proposal deposit passes the `MinDeposit` threshold (even during the proposal
|
||||
submission) before the deposit end time, the proposal will be moved into the
|
||||
_active proposal queue_ and the voting period will begin.
|
||||
|
||||
The deposit is kept in escrow and held by the governance `ModuleAccount` until the
|
||||
proposal is finalized (passed or rejected).
|
||||
|
||||
### Deposit refund and burn
|
||||
|
||||
When a proposal is finalized, the coins from the deposit are either refunded or burned
|
||||
according to the final tally of the proposal:
|
||||
|
||||
* If the proposal is approved or rejected but _not_ vetoed, each deposit will be
|
||||
automatically refunded to its respective depositor (transferred from the governance
|
||||
`ModuleAccount`).
|
||||
* When the proposal is vetoed with greater than 1/3, deposits will be burned from the
|
||||
governance `ModuleAccount` and the proposal information along with its deposit
|
||||
information will be removed from state.
|
||||
* All refunded or burned deposits are removed from the state. Events are issued when
|
||||
burning or refunding a deposit.
|
||||
|
||||
## Vote
|
||||
|
||||
### Participants
|
||||
|
||||
_Participants_ are users that have the right to vote on proposals. On the
|
||||
Cosmos Hub, participants are bonded Atom holders. Unbonded Atom holders and
|
||||
other users do not get the right to participate in governance. However, they
|
||||
can submit and deposit on proposals.
|
||||
|
||||
Note that some _participants_ can be forbidden to vote on a proposal under a
|
||||
certain validator if:
|
||||
|
||||
* _participant_ bonded or unbonded Atoms to said validator after proposal
|
||||
entered voting period.
|
||||
* _participant_ became validator after proposal entered voting period.
|
||||
|
||||
This does not prevent _participant_ to vote with Atoms bonded to other
|
||||
validators. For example, if a _participant_ bonded some Atoms to validator A
|
||||
before a proposal entered voting period and other Atoms to validator B after
|
||||
proposal entered voting period, only the vote under validator B will be
|
||||
forbidden.
|
||||
|
||||
### Voting period
|
||||
|
||||
Once a proposal reaches `MinDeposit`, it immediately enters `Voting period`. We
|
||||
define `Voting period` as the interval between the moment the vote opens and
|
||||
the moment the vote closes. `Voting period` should always be shorter than
|
||||
`Unbonding period` to prevent double voting. The initial value of
|
||||
`Voting period` is 2 weeks.
|
||||
|
||||
### Option set
|
||||
|
||||
The option set of a proposal refers to the set of choices a participant can
|
||||
choose from when casting its vote.
|
||||
|
||||
The initial option set includes the following options:
|
||||
|
||||
* `Yes`
|
||||
* `No`
|
||||
* `NoWithVeto`
|
||||
* `Abstain`
|
||||
|
||||
`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option
|
||||
allows voters to signal that they do not intend to vote in favor or against the
|
||||
proposal but accept the result of the vote.
|
||||
|
||||
_Note: from the UI, for urgent proposals we should maybe add a ‘Not Urgent’
|
||||
option that casts a `NoWithVeto` vote._
|
||||
|
||||
### Weighted Votes
|
||||
|
||||
[ADR-037](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md) introduces the weighted vote feature which allows a staker to split their votes into several voting options. For example, it could use 70% of its voting power to vote Yes and 30% of its voting power to vote No.
|
||||
|
||||
Often times the entity owning that address might not be a single individual. For example, a company might have different stakeholders who want to vote differently, and so it makes sense to allow them to split their voting power. Currently, it is not possible for them to do "passthrough voting" and giving their users voting rights over their tokens. However, with this system, exchanges can poll their users for voting preferences, and then vote on-chain proportionally to the results of the poll.
|
||||
|
||||
To represent weighted vote on chain, we use the following Protobuf message.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L33-L43
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L136-L150
|
||||
|
||||
For a weighted vote to be valid, the `options` field must not contain duplicate vote options, and the sum of weights of all options must be equal to 1.
|
||||
|
||||
### Quorum
|
||||
|
||||
Quorum is defined as the minimum percentage of voting power that needs to be
|
||||
cast on a proposal for the result to be valid.
|
||||
|
||||
### Threshold
|
||||
|
||||
Threshold is defined as the minimum proportion of `Yes` votes (excluding
|
||||
`Abstain` votes) for the proposal to be accepted.
|
||||
|
||||
Initially, the threshold is set at 50% of `Yes` votes, excluding `Abstain`
|
||||
votes. A possibility to veto exists if more than 1/3rd of all votes are
|
||||
`NoWithVeto` votes. Note, both of these values are derived from the `TallyParams`
|
||||
on-chain parameter, which is modifiable by governance.
|
||||
This means that proposals are accepted iff:
|
||||
|
||||
* There exist bonded tokens.
|
||||
* Quorum has been achieved.
|
||||
* The proportion of `Abstain` votes is inferior to 1/1.
|
||||
* The proportion of `NoWithVeto` votes is inferior to 1/3, including
|
||||
`Abstain` votes.
|
||||
* The proportion of `Yes` votes, excluding `Abstain` votes, at the end of
|
||||
the voting period is superior to 1/2.
|
||||
|
||||
### Inheritance
|
||||
|
||||
If a delegator does not vote, it will inherit its validator vote.
|
||||
|
||||
* If the delegator votes before its validator, it will not inherit from the
|
||||
validator's vote.
|
||||
* If the delegator votes after its validator, it will override its validator
|
||||
vote with its own. If the proposal is urgent, it is possible
|
||||
that the vote will close before delegators have a chance to react and
|
||||
override their validator's vote. This is not a problem, as proposals require more than 2/3rd of the total voting power to pass before the end of the voting period. Because as little as 1/3 + 1 validation power could collude to censor transactions, non-collusion is already assumed for ranges exceeding this threshold.
|
||||
|
||||
### Validator’s punishment for non-voting
|
||||
|
||||
At present, validators are not punished for failing to vote.
|
||||
|
||||
### Governance address
|
||||
|
||||
Later, we may add permissioned keys that could only sign txs from certain modules. For the MVP, the `Governance address` will be the main validator address generated at account creation. This address corresponds to a different PrivKey than the Tendermint PrivKey which is responsible for signing consensus messages. Validators thus do not have to sign governance transactions with the sensitive Tendermint PrivKey.
|
||||
|
||||
## Software Upgrade
|
||||
|
||||
If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade
|
||||
their software to the new version that was voted. This process is divided into
|
||||
two steps:
|
||||
|
||||
### Signal
|
||||
|
||||
After a `SoftwareUpgradeProposal` is accepted, validators are expected to
|
||||
download and install the new version of the software while continuing to run
|
||||
the previous version. Once a validator has downloaded and installed the
|
||||
upgrade, it will start signaling to the network that it is ready to switch by
|
||||
including the proposal's `proposalID` in its _precommits_.(_Note: Confirmation
|
||||
that we want it in the precommit?_)
|
||||
|
||||
Note: There is only one signal slot per _precommit_. If several
|
||||
`SoftwareUpgradeProposals` are accepted in a short timeframe, a pipeline will
|
||||
form and they will be implemented one after the other in the order that they
|
||||
were accepted.
|
||||
|
||||
### Switch
|
||||
|
||||
Once a block contains more than 2/3rd _precommits_ where a common
|
||||
`SoftwareUpgradeProposal` is signaled, all the nodes (including validator
|
||||
nodes, non-validating full nodes and light-nodes) are expected to switch to the
|
||||
new version of the software.
|
||||
|
||||
Validators and full nodes can use an automation tool, such as [Cosmovisor](https://github.com/cosmos/cosmos-sdk/blob/main/cosmovisor/README.md), for automatically switching version of the chain.
|
||||
@ -1,219 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## Proposals
|
||||
|
||||
`Proposal` objects are used to tally votes and generally track the proposal's state.
|
||||
They contain an array of arbitrary `sdk.Msg`'s which the governance module will attempt
|
||||
to resolve and then execute if the proposal passes. `Proposal`'s are identified by a
|
||||
unique id and contains a series of timestamps: `submit_time`, `deposit_end_time`,
|
||||
`voting_start_time`, `voting_end_time` which track the lifecycle of a proposal
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L42-L59
|
||||
|
||||
A proposal will generally require more than just a set of messages to explain its
|
||||
purpose but need some greater justification and allow a means for interested participants
|
||||
to discuss and debate the proposal.
|
||||
In most cases, **it is encouraged to have an off-chain system that supports the on-chain governance process**.
|
||||
To accommodate for this, a proposal contains a special **`metadata`** field, a string,
|
||||
which can be used to add context to the proposal. The `metadata` field allows custom use for networks,
|
||||
however, it is expected that the field contains a URL or some form of CID using a system such as
|
||||
[IPFS](https://docs.ipfs.io/concepts/content-addressing/). To support the case of
|
||||
interoperability across networks, the SDK recommends that the `metadata` represents
|
||||
the following `JSON` template:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "...",
|
||||
"description": "...",
|
||||
"forum": "...", // a link to the discussion platform (i.e. Discord)
|
||||
"other": "..." // any extra data that doesn't correspond to the other fields
|
||||
}
|
||||
```
|
||||
|
||||
This makes it far easier for clients to support multiple networks.
|
||||
|
||||
The metadata has a maximum length that is chosen by the app developer, and
|
||||
passed into the gov keeper as a config. The default maximum length in the SDK is 255 characters.
|
||||
|
||||
### Writing a module that uses governance
|
||||
|
||||
There are many aspects of a chain, or of the individual modules that you may want to
|
||||
use governance to perform such as changing various parameters. This is very simple
|
||||
to do. First, write out your message types and `MsgServer` implementation. Add an
|
||||
`authority` field to the keeper which will be populated in the constructor with the
|
||||
governance module account: `govKeeper.GetGovernanceAccount().GetAddress()`. Then for
|
||||
the methods in the `msg_server.go`, perform a check on the message that the signer
|
||||
matches `authority`. This will prevent any user from executing that message.
|
||||
|
||||
## Parameters and base types
|
||||
|
||||
`Parameters` define the rules according to which votes are run. There can only
|
||||
be one active parameter set at any given time. If governance wants to change a
|
||||
parameter set, either to modify a value or add/remove a parameter field, a new
|
||||
parameter set has to be created and the previous one rendered inactive.
|
||||
|
||||
### DepositParams
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L102-L112
|
||||
|
||||
### VotingParams
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L114-L118
|
||||
|
||||
### TallyParams
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L120-L132
|
||||
|
||||
Parameters are stored in a global `GlobalParams` KVStore.
|
||||
|
||||
Additionally, we introduce some basic types:
|
||||
|
||||
```go
|
||||
type Vote byte
|
||||
|
||||
const (
|
||||
VoteYes = 0x1
|
||||
VoteNo = 0x2
|
||||
VoteNoWithVeto = 0x3
|
||||
VoteAbstain = 0x4
|
||||
)
|
||||
|
||||
type ProposalType string
|
||||
|
||||
const (
|
||||
ProposalTypePlainText = "Text"
|
||||
ProposalTypeSoftwareUpgrade = "SoftwareUpgrade"
|
||||
)
|
||||
|
||||
type ProposalStatus byte
|
||||
|
||||
|
||||
const (
|
||||
StatusNil ProposalStatus = 0x00
|
||||
StatusDepositPeriod ProposalStatus = 0x01 // Proposal is submitted. Participants can deposit on it but not vote
|
||||
StatusVotingPeriod ProposalStatus = 0x02 // MinDeposit is reached, participants can vote
|
||||
StatusPassed ProposalStatus = 0x03 // Proposal passed and successfully executed
|
||||
StatusRejected ProposalStatus = 0x04 // Proposal has been rejected
|
||||
StatusFailed ProposalStatus = 0x05 // Proposal passed but failed execution
|
||||
)
|
||||
```
|
||||
|
||||
## Deposit
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L34-L40
|
||||
|
||||
## ValidatorGovInfo
|
||||
|
||||
This type is used in a temp map when tallying
|
||||
|
||||
```go
|
||||
type ValidatorGovInfo struct {
|
||||
Minus sdk.Dec
|
||||
Vote Vote
|
||||
}
|
||||
```
|
||||
|
||||
## Stores
|
||||
|
||||
_Note: Stores are KVStores in the multi-store. The key to find the store is the first parameter in the list_
|
||||
|
||||
We will use one KVStore `Governance` to store two mappings:
|
||||
|
||||
* A mapping from `proposalID|'proposal'` to `Proposal`.
|
||||
* A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows
|
||||
us to query all addresses that voted on the proposal along with their vote by
|
||||
doing a range query on `proposalID:addresses`.
|
||||
* A mapping from `ParamsKey|'Params'` to `Params`. This map allows to query all
|
||||
x/gov params.
|
||||
|
||||
For pseudocode purposes, here are the two function we will use to read or write in stores:
|
||||
|
||||
* `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore
|
||||
* `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore
|
||||
|
||||
## Proposal Processing Queue
|
||||
|
||||
**Store:**
|
||||
|
||||
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
|
||||
`ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`,
|
||||
all the proposals that have reached the end of their voting period are processed.
|
||||
To process a finished proposal, the application tallies the votes, computes the
|
||||
votes of each validator and checks if every validator in the validator set has
|
||||
voted. If the proposal is accepted, deposits are refunded. Finally, the proposal
|
||||
content `Handler` is executed.
|
||||
|
||||
And the pseudocode for the `ProposalProcessingQueue`:
|
||||
|
||||
```go
|
||||
in EndBlock do
|
||||
|
||||
for finishedProposalID in GetAllFinishedProposalIDs(block.Time)
|
||||
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
|
||||
|
||||
validators = Keeper.getAllValidators()
|
||||
tmpValMap := map(sdk.AccAddress)ValidatorGovInfo
|
||||
|
||||
// Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes
|
||||
for each validator in validators
|
||||
tmpValMap(validator.OperatorAddr).Minus = 0
|
||||
|
||||
// Tally
|
||||
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
|
||||
for each (voterAddress, vote) in voterIterator
|
||||
delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter
|
||||
|
||||
for each delegation in delegations
|
||||
// make sure delegation.Shares does NOT include shares being unbonded
|
||||
tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares
|
||||
proposal.updateTally(vote, delegation.Shares)
|
||||
|
||||
_, isVal = stakingKeeper.getValidator(voterAddress)
|
||||
if (isVal)
|
||||
tmpValMap(voterAddress).Vote = vote
|
||||
|
||||
tallyingParam = load(GlobalParams, 'TallyingParam')
|
||||
|
||||
// Update tally if validator voted
|
||||
for each validator in validators
|
||||
if tmpValMap(validator).HasVoted
|
||||
proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus))
|
||||
|
||||
|
||||
|
||||
// Check if proposal is accepted or rejected
|
||||
totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes
|
||||
if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto)
|
||||
// proposal was accepted at the end of the voting period
|
||||
// refund deposits (non-voters already punished)
|
||||
for each (amount, depositor) in proposal.Deposits
|
||||
depositor.AtomBalance += amount
|
||||
|
||||
stateWriter, err := proposal.Handler()
|
||||
if err != nil
|
||||
// proposal passed but failed during state execution
|
||||
proposal.CurrentStatus = ProposalStatusFailed
|
||||
else
|
||||
// proposal pass and state is persisted
|
||||
proposal.CurrentStatus = ProposalStatusAccepted
|
||||
stateWriter.save()
|
||||
else
|
||||
// proposal was rejected
|
||||
proposal.CurrentStatus = ProposalStatusRejected
|
||||
|
||||
store(Governance, <proposalID|'proposal'>, proposal)
|
||||
```
|
||||
|
||||
## Legacy Proposal
|
||||
|
||||
A legacy proposal is the old implementation of governance proposal.
|
||||
Contrary to proposal that can contain any messages, a legacy proposal allows to submit a set of pre-defined proposals.
|
||||
These proposal are defined by their types.
|
||||
|
||||
While proposals should use the new implementation of the governance proposal, we need still to use legacy proposal in order to submit a `software-upgrade` and a `cancel-software-upgrade` proposal.
|
||||
|
||||
More information on how to submit proposals in the [client section](07_client.md).
|
||||
@ -1,183 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Messages
|
||||
|
||||
## Proposal Submission
|
||||
|
||||
Proposals can be submitted by any account via a `MsgSubmitProposal`
|
||||
transaction.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L33-L43
|
||||
|
||||
All `sdk.Msgs` passed into the `messages` field of a `MsgSubmitProposal` message
|
||||
must be registered in the app's `MsgServiceRouter`. Each of these messages must
|
||||
have one signer, namely the gov module account. And finally, the metadata length
|
||||
must not be larger than the `maxMetadataLen` config passed into the gov keeper.
|
||||
|
||||
**State modifications:**
|
||||
|
||||
* Generate new `proposalID`
|
||||
* Create new `Proposal`
|
||||
* Initialise `Proposal`'s attributes
|
||||
* Decrease balance of sender by `InitialDeposit`
|
||||
* If `MinDeposit` is reached:
|
||||
* Push `proposalID` in `ProposalProcessingQueue`
|
||||
* Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount`
|
||||
|
||||
A `MsgSubmitProposal` transaction can be handled according to the following
|
||||
pseudocode.
|
||||
|
||||
```go
|
||||
// PSEUDOCODE //
|
||||
// Check if MsgSubmitProposal is valid. If it is, create proposal //
|
||||
|
||||
upon receiving txGovSubmitProposal from sender do
|
||||
|
||||
if !correctlyFormatted(txGovSubmitProposal)
|
||||
// check if proposal is correctly formatted and the messages have routes to other modules. Includes fee payment.
|
||||
// check if all messages' unique Signer is the gov acct.
|
||||
// check if the metadata is not too long.
|
||||
throw
|
||||
|
||||
initialDeposit = txGovSubmitProposal.InitialDeposit
|
||||
if (initialDeposit.Atoms <= 0) OR (sender.AtomBalance < initialDeposit.Atoms)
|
||||
// InitialDeposit is negative or null OR sender has insufficient funds
|
||||
throw
|
||||
|
||||
if (txGovSubmitProposal.Type != ProposalTypePlainText) OR (txGovSubmitProposal.Type != ProposalTypeSoftwareUpgrade)
|
||||
|
||||
sender.AtomBalance -= initialDeposit.Atoms
|
||||
|
||||
depositParam = load(GlobalParams, 'DepositParam')
|
||||
|
||||
proposalID = generate new proposalID
|
||||
proposal = NewProposal()
|
||||
|
||||
proposal.Messages = txGovSubmitProposal.Messages
|
||||
proposal.Metadata = txGovSubmitProposal.Metadata
|
||||
proposal.TotalDeposit = initialDeposit
|
||||
proposal.SubmitTime = <CurrentTime>
|
||||
proposal.DepositEndTime = <CurrentTime>.Add(depositParam.MaxDepositPeriod)
|
||||
proposal.Deposits.append({initialDeposit, sender})
|
||||
proposal.Submitter = sender
|
||||
proposal.YesVotes = 0
|
||||
proposal.NoVotes = 0
|
||||
proposal.NoWithVetoVotes = 0
|
||||
proposal.AbstainVotes = 0
|
||||
proposal.CurrentStatus = ProposalStatusOpen
|
||||
|
||||
store(Proposals, <proposalID|'proposal'>, proposal) // Store proposal in Proposals mapping
|
||||
return proposalID
|
||||
```
|
||||
|
||||
## Deposit
|
||||
|
||||
Once a proposal is submitted, if
|
||||
`Proposal.TotalDeposit < ActiveParam.MinDeposit`, Atom holders can send
|
||||
`MsgDeposit` transactions to increase the proposal's deposit.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L90-L97
|
||||
|
||||
**State modifications:**
|
||||
|
||||
* Decrease balance of sender by `deposit`
|
||||
* Add `deposit` of sender in `proposal.Deposits`
|
||||
* Increase `proposal.TotalDeposit` by sender's `deposit`
|
||||
* If `MinDeposit` is reached:
|
||||
* Push `proposalID` in `ProposalProcessingQueueEnd`
|
||||
* Transfer `Deposit` from the `proposer` to the governance `ModuleAccount`
|
||||
|
||||
A `MsgDeposit` transaction has to go through a number of checks to be valid.
|
||||
These checks are outlined in the following pseudocode.
|
||||
|
||||
```go
|
||||
// PSEUDOCODE //
|
||||
// Check if MsgDeposit is valid. If it is, increase deposit and check if MinDeposit is reached
|
||||
|
||||
upon receiving txGovDeposit from sender do
|
||||
// check if proposal is correctly formatted. Includes fee payment.
|
||||
|
||||
if !correctlyFormatted(txGovDeposit)
|
||||
throw
|
||||
|
||||
proposal = load(Proposals, <txGovDeposit.ProposalID|'proposal'>) // proposal is a const key, proposalID is variable
|
||||
|
||||
if (proposal == nil)
|
||||
// There is no proposal for this proposalID
|
||||
throw
|
||||
|
||||
if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.CurrentStatus != ProposalStatusOpen)
|
||||
|
||||
// deposit is negative or null
|
||||
// OR sender has insufficient funds
|
||||
// OR proposal is not open for deposit anymore
|
||||
|
||||
throw
|
||||
|
||||
depositParam = load(GlobalParams, 'DepositParam')
|
||||
|
||||
if (CurrentBlock >= proposal.SubmitBlock + depositParam.MaxDepositPeriod)
|
||||
proposal.CurrentStatus = ProposalStatusClosed
|
||||
|
||||
else
|
||||
// sender can deposit
|
||||
sender.AtomBalance -= txGovDeposit.Deposit.Atoms
|
||||
|
||||
proposal.Deposits.append({txGovVote.Deposit, sender})
|
||||
proposal.TotalDeposit.Plus(txGovDeposit.Deposit)
|
||||
|
||||
if (proposal.TotalDeposit >= depositParam.MinDeposit)
|
||||
// MinDeposit is reached, vote opens
|
||||
|
||||
proposal.VotingStartBlock = CurrentBlock
|
||||
proposal.CurrentStatus = ProposalStatusActive
|
||||
ProposalProcessingQueue.push(txGovDeposit.ProposalID)
|
||||
|
||||
store(Proposals, <txGovVote.ProposalID|'proposal'>, proposal)
|
||||
```
|
||||
|
||||
## Vote
|
||||
|
||||
Once `ActiveParam.MinDeposit` is reached, voting period starts. From there,
|
||||
bonded Atom holders are able to send `MsgVote` transactions to cast their
|
||||
vote on the proposal.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L64-L72
|
||||
|
||||
**State modifications:**
|
||||
|
||||
* Record `Vote` of sender
|
||||
|
||||
_Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker._
|
||||
|
||||
Next is a pseudocode outline of the way `MsgVote` transactions are
|
||||
handled:
|
||||
|
||||
```go
|
||||
// PSEUDOCODE //
|
||||
// Check if MsgVote is valid. If it is, count vote//
|
||||
|
||||
upon receiving txGovVote from sender do
|
||||
// check if proposal is correctly formatted. Includes fee payment.
|
||||
|
||||
if !correctlyFormatted(txGovDeposit)
|
||||
throw
|
||||
|
||||
proposal = load(Proposals, <txGovDeposit.ProposalID|'proposal'>)
|
||||
|
||||
if (proposal == nil)
|
||||
// There is no proposal for this proposalID
|
||||
throw
|
||||
|
||||
|
||||
if (proposal.CurrentStatus == ProposalStatusActive)
|
||||
|
||||
|
||||
// Sender can vote if
|
||||
// Proposal is active
|
||||
// Sender has some bonds
|
||||
|
||||
store(Governance, <txGovVote.ProposalID|'addresses'|sender>, txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end.
|
||||
```
|
||||
@ -1,65 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The governance module emits the following events:
|
||||
|
||||
## EndBlocker
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ----------------- | --------------- | ---------------- |
|
||||
| inactive_proposal | proposal_id | {proposalID} |
|
||||
| inactive_proposal | proposal_result | {proposalResult} |
|
||||
| active_proposal | proposal_id | {proposalID} |
|
||||
| active_proposal | proposal_result | {proposalResult} |
|
||||
|
||||
## Handlers
|
||||
|
||||
### MsgSubmitProposal
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------- | ------------------- | --------------- |
|
||||
| submit_proposal | proposal_id | {proposalID} |
|
||||
| submit_proposal [0] | voting_period_start | {proposalID} |
|
||||
| proposal_deposit | amount | {depositAmount} |
|
||||
| proposal_deposit | proposal_id | {proposalID} |
|
||||
| message | module | governance |
|
||||
| message | action | submit_proposal |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
* [0] Event only emitted if the voting period starts during the submission.
|
||||
|
||||
### MsgVote
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------- | ------------- | --------------- |
|
||||
| proposal_vote | option | {voteOption} |
|
||||
| proposal_vote | proposal_id | {proposalID} |
|
||||
| message | module | governance |
|
||||
| message | action | vote |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgVoteWeighted
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------- | ------------- | ------------------------ |
|
||||
| proposal_vote | option | {weightedVoteOptions} |
|
||||
| proposal_vote | proposal_id | {proposalID} |
|
||||
| message | module | governance |
|
||||
| message | action | vote |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
### MsgDeposit
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------- | ------------------- | --------------- |
|
||||
| proposal_deposit | amount | {depositAmount} |
|
||||
| proposal_deposit | proposal_id | {proposalID} |
|
||||
| proposal_deposit [0] | voting_period_start | {proposalID} |
|
||||
| message | module | governance |
|
||||
| message | action | deposit |
|
||||
| message | sender | {senderAddress} |
|
||||
|
||||
* [0] Event only emitted if the voting period starts during the submission.
|
||||
@ -1,30 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Future Improvements
|
||||
|
||||
The current documentation only describes the minimum viable product for the
|
||||
governance module. Future improvements may include:
|
||||
|
||||
* **`BountyProposals`:** If accepted, a `BountyProposal` creates an open
|
||||
bounty. The `BountyProposal` specifies how many Atoms will be given upon
|
||||
completion. These Atoms will be taken from the `reserve pool`. After a
|
||||
`BountyProposal` is accepted by governance, anybody can submit a
|
||||
`SoftwareUpgradeProposal` with the code to claim the bounty. Note that once a
|
||||
`BountyProposal` is accepted, the corresponding funds in the `reserve pool`
|
||||
are locked so that payment can always be honored. In order to link a
|
||||
`SoftwareUpgradeProposal` to an open bounty, the submitter of the
|
||||
`SoftwareUpgradeProposal` will use the `Proposal.LinkedProposal` attribute.
|
||||
If a `SoftwareUpgradeProposal` linked to an open bounty is accepted by
|
||||
governance, the funds that were reserved are automatically transferred to the
|
||||
submitter.
|
||||
* **Complex delegation:** Delegators could choose other representatives than
|
||||
their validators. Ultimately, the chain of representatives would always end
|
||||
up to a validator, but delegators could inherit the vote of their chosen
|
||||
representative before they inherit the vote of their validator. In other
|
||||
words, they would only inherit the vote of their validator if their other
|
||||
appointed representative did not vote.
|
||||
* **Better process for proposal review:** There would be two parts to
|
||||
`proposal.Deposit`, one for anti-spam (same as in MVP) and an other one to
|
||||
reward third party auditors.
|
||||
@ -1,28 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The governance module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
|---------------|--------|----------------------------------------------------------------------------------------------------|
|
||||
| depositparams | object | {"min_deposit":[{"denom":"uatom","amount":"10000000"}],"max_deposit_period":"172800000000000"} |
|
||||
| votingparams | object | {"voting_period":"172800000000000"} |
|
||||
| tallyparams | object | {"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto":"0.334000000000000000"} |
|
||||
|
||||
## SubKeys
|
||||
|
||||
| Key | Type | Example |
|
||||
|--------------------|------------------|-----------------------------------------|
|
||||
| min_deposit | array (coins) | [{"denom":"uatom","amount":"10000000"}] |
|
||||
| max_deposit_period | string (time ns) | "172800000000000" |
|
||||
| voting_period | string (time ns) | "172800000000000" |
|
||||
| quorum | string (dec) | "0.334000000000000000" |
|
||||
| threshold | string (dec) | "0.500000000000000000" |
|
||||
| veto | string (dec) | "0.334000000000000000" |
|
||||
|
||||
__NOTE__: The governance module contains parameters that are objects unlike other
|
||||
modules. If only a subset of parameters are desired to be changed, only they need
|
||||
to be included and not the entire parameter object structure.
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,30 +0,0 @@
|
||||
<!--
|
||||
order: 8
|
||||
-->
|
||||
|
||||
# Metadata
|
||||
|
||||
The gov module has two locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the gov and group modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains.
|
||||
|
||||
## Proposal
|
||||
Location: off-chain as json object stored on IPFS (mirrors [group proposal](../../group/spec/06_metadata.md#proposal))
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "",
|
||||
"authors": "",
|
||||
"summary": "",
|
||||
"details": "",
|
||||
"proposalForumURL": "",
|
||||
"voteOptionContext": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Vote
|
||||
Location: on-chain as json within 255 character limit (mirrors [group vote](../../group/spec/06_metadata.md#vote))
|
||||
|
||||
```json
|
||||
{
|
||||
"justification": "",
|
||||
}
|
||||
```
|
||||
@ -1,65 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Gov Overview
|
||||
parent:
|
||||
title: "gov"
|
||||
-->
|
||||
|
||||
# `gov`
|
||||
|
||||
## Abstract
|
||||
|
||||
This paper specifies the Governance module of the Cosmos-SDK, which was first
|
||||
described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in
|
||||
June 2016.
|
||||
|
||||
The module enables Cosmos-SDK based blockchain to support an on-chain governance
|
||||
system. In this system, holders of the native staking token of the chain can vote
|
||||
on proposals on a 1 token 1 vote basis. Next is a list of features the module
|
||||
currently supports:
|
||||
|
||||
* **Proposal submission:** Users can submit proposals with a deposit. Once the
|
||||
minimum deposit is reached, proposal enters voting period
|
||||
* **Vote:** Participants can vote on proposals that reached MinDeposit
|
||||
* **Inheritance and penalties:** Delegators inherit their validator's vote if
|
||||
they don't vote themselves.
|
||||
* **Claiming deposit:** Users that deposited on proposals can recover their
|
||||
deposits if the proposal was accepted OR if the proposal never entered voting period.
|
||||
|
||||
This module will be used in the Cosmos Hub, the first Hub in the Cosmos network.
|
||||
Features that may be added in the future are described in [Future Improvements](05_future_improvements.md).
|
||||
|
||||
## Contents
|
||||
|
||||
The following specification uses *ATOM* as the native staking token. The module
|
||||
can be adapted to any Proof-Of-Stake blockchain by replacing *ATOM* with the native
|
||||
staking token of the chain.
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
* [Proposal submission](01_concepts.md#proposal-submission)
|
||||
* [Deposit](01_concepts.md#Deposit)
|
||||
* [Vote](01_concepts.md#vote)
|
||||
* [Software Upgrade](01_concepts.md#software-upgrade)
|
||||
2. **[State](02_state.md)**
|
||||
* [Parameters and base types](02_state.md#parameters-and-base-types)
|
||||
* [Deposit](02_state.md#deposit)
|
||||
* [ValidatorGovInfo](02_state.md#validatorgovinfo)
|
||||
* [Proposals](02_state.md#proposals)
|
||||
* [Stores](02_state.md#stores)
|
||||
* [Proposal Processing Queue](02_state.md#proposal-processing-queue)
|
||||
3. **[Messages](03_messages.md)**
|
||||
* [Proposal Submission](03_messages.md#proposal-submission)
|
||||
* [Deposit](03_messages.md#deposit)
|
||||
* [Vote](03_messages.md#vote)
|
||||
4. **[Events](04_events.md)**
|
||||
* [EndBlocker](04_events.md#endblocker)
|
||||
* [Handlers](04_events.md#handlers)
|
||||
5. **[Future Improvements](05_future_improvements.md)**
|
||||
6. **[Parameters](06_params.md)**
|
||||
7. **[Client](07_client.md)**
|
||||
* [CLI](07_client.md#cli)
|
||||
* [gRPC](07_client.md#grpc)
|
||||
* [REST](07_client.md#rest)
|
||||
8. **[Metadata](08_metadata.md)**
|
||||
* [Proposal](08_metadata.md#proposal)
|
||||
* [Vote](08_metadata.md#vote)
|
||||
@ -1,7 +1,554 @@
|
||||
<!--
|
||||
order: 5
|
||||
order: 0
|
||||
title: Group Overview
|
||||
parent:
|
||||
title: "group"
|
||||
-->
|
||||
|
||||
# Group Module
|
||||
|
||||
## Abstract
|
||||
|
||||
The following documents specify the group module.
|
||||
|
||||
This module allows the creation and management of on-chain multisig accounts and enables voting for message execution based on configurable decision policies.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Concepts](#concepts)
|
||||
* [Group](#group)
|
||||
* [Group Policy](#group-policy)
|
||||
* [Decision Policy](#decision-policy)
|
||||
* [Proposal](#proposal)
|
||||
* [Pruning](#pruning)
|
||||
* [State](#state)
|
||||
* [Group Table](#group-table)
|
||||
* [Group Member Table](#group-member-table)
|
||||
* [Group Policy Table](#group-policy-table)
|
||||
* [Proposal Table](#proposal-table)
|
||||
* [Vote Table](#vote-table)
|
||||
* [Msg Service](#msg-service)
|
||||
* [Msg/CreateGroup](#msgcreategroup)
|
||||
* [Msg/UpdateGroupMembers](#msgupdategroupmembers)
|
||||
* [Msg/UpdateGroupAdmin](#msgupdategroupadmin)
|
||||
* [Msg/UpdateGroupMetadata](#msgupdategroupmetadata)
|
||||
* [Msg/CreateGroupPolicy](#msgcreategrouppolicy)
|
||||
* [Msg/CreateGroupWithPolicy](#msgcreategroupwithpolicy)
|
||||
* [Msg/UpdateGroupPolicyAdmin](#msgupdategrouppolicyadmin)
|
||||
* [Msg/UpdateGroupPolicyDecisionPolicy](#msgupdategrouppolicydecisionpolicy)
|
||||
* [Msg/UpdateGroupPolicyMetadata](#msgupdategrouppolicymetadata)
|
||||
* [Msg/SubmitProposal](#msgsubmitproposal)
|
||||
* [Msg/WithdrawProposal](#msgwithdrawproposal)
|
||||
* [Msg/Vote](#msgvote)
|
||||
* [Msg/Exec](#msgexec)
|
||||
* [Msg/LeaveGroup](#msgleavegroup)
|
||||
* [Events](#events)
|
||||
* [EventCreateGroup](#eventcreategroup)
|
||||
* [EventUpdateGroup](#eventupdategroup)
|
||||
* [EventCreateGroupPolicy](#eventcreategrouppolicy)
|
||||
* [EventUpdateGroupPolicy](#eventupdategrouppolicy)
|
||||
* [EventCreateProposal](#eventcreateproposal)
|
||||
* [EventWithdrawProposal](#eventwithdrawproposal)
|
||||
* [EventVote](#eventvote)
|
||||
* [EventExec](#eventexec)
|
||||
* [EventLeaveGroup](#eventleavegroup)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
* [REST](#rest)
|
||||
* [Metadata](#metadata)
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Group
|
||||
|
||||
A group is simply an aggregation of accounts with associated weights. It is not
|
||||
an account and doesn't have a balance. It doesn't in and of itself have any
|
||||
sort of voting or decision weight. It does have an "administrator" which has
|
||||
the ability to add, remove and update members in the group. Note that a
|
||||
group policy account could be an administrator of a group, and that the
|
||||
administrator doesn't necessarily have to be a member of the group.
|
||||
|
||||
## Group Policy
|
||||
|
||||
A group policy is an account associated with a group and a decision policy.
|
||||
Group policies are abstracted from groups because a single group may have
|
||||
multiple decision policies for different types of actions. Managing group
|
||||
membership separately from decision policies results in the least overhead
|
||||
and keeps membership consistent across different policies. The pattern that
|
||||
is recommended is to have a single master group policy for a given group,
|
||||
and then to create separate group policies with different decision policies
|
||||
and delegate the desired permissions from the master account to
|
||||
those "sub-accounts" using the `x/authz` module.
|
||||
|
||||
## Decision Policy
|
||||
|
||||
A decision policy is the mechanism by which members of a group can vote on
|
||||
proposals, as well as the rules that dictate whether a proposal should pass
|
||||
or not based on its tally outcome.
|
||||
|
||||
All decision policies generally would have a mininum execution period and a
|
||||
maximum voting window. The minimum execution period is the minimum amount of time
|
||||
that must pass after submission in order for a proposal to potentially be executed, and it may
|
||||
be set to 0. The maximum voting window is the maximum time after submission that a proposal may
|
||||
be voted on before it is tallied.
|
||||
|
||||
The chain developer also defines an app-wide maximum execution period, which is
|
||||
the maximum amount of time after a proposal's voting period end where users are
|
||||
allowed to execute a proposal.
|
||||
|
||||
The current group module comes shipped with two decision policies: threshold
|
||||
and percentage. Any chain developer can extend upon these two, by creating
|
||||
custom decision policies, as long as they adhere to the `DecisionPolicy`
|
||||
interface:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/types.go#L27-L41
|
||||
|
||||
### Threshold decision policy
|
||||
|
||||
A threshold decision policy defines a threshold of yes votes (based on a tally
|
||||
of voter weights) that must be achieved in order for a proposal to pass. For
|
||||
this decision policy, abstain and veto are simply treated as no's.
|
||||
|
||||
### Percentage decision policy
|
||||
|
||||
A percentage decision policy is similar to a threshold decision policy, except
|
||||
that the threshold is not defined as a constant weight, but as a percentage.
|
||||
It's more suited for groups where the group members' weights can be updated, as
|
||||
the percentage threshold stays the same, and doesn't depend on how those member
|
||||
weights get updated.
|
||||
|
||||
## Proposal
|
||||
|
||||
Any member(s) of a group can submit a proposal for a group policy account to decide upon.
|
||||
A proposal consists of a set of messages that will be executed if the proposal
|
||||
passes as well as any metadata associated with the proposal.
|
||||
|
||||
### Voting
|
||||
|
||||
There are four choices to choose while voting - yes, no, abstain and veto. Not
|
||||
all decision policies will take the four choices into account. Votes can contain some optional metadata.
|
||||
In the current implementation, the voting window begins as soon as a proposal
|
||||
is submitted, and the end is defined by the group policy's decision policy.
|
||||
|
||||
### Withdrawing Proposals
|
||||
|
||||
Proposals can be withdrawn any time before the voting period end, either by the
|
||||
admin of the group policy or by one of the proposers. Once withdrawn, it is
|
||||
marked as `PROPOSAL_STATUS_WITHDRAWN`, and no more voting or execution is
|
||||
allowed on it.
|
||||
|
||||
### Aborted Proposals
|
||||
|
||||
If the group policy is updated during the voting period of the proposal, then
|
||||
the proposal is marked as `PROPOSAL_STATUS_ABORTED`, and no more voting or
|
||||
execution is allowed on it. This is because the group policy defines the rules
|
||||
of proposal voting and execution, so if those rules change during the lifecycle
|
||||
of a proposal, then the proposal should be marked as stale.
|
||||
|
||||
### Tallying
|
||||
|
||||
Tallying is the counting of all votes on a proposal. It happens only once in
|
||||
the lifecycle of a proposal, but can be triggered by two factors, whichever
|
||||
happens first:
|
||||
|
||||
* either someone tries to execute the proposal (see next section), which can
|
||||
happen on a `Msg/Exec` transaction, or a `Msg/{SubmitProposal,Vote}`
|
||||
transaction with the `Exec` field set. When a proposal execution is attempted,
|
||||
a tally is done first to make sure the proposal passes.
|
||||
* or on `EndBlock` when the proposal's voting period end just passed.
|
||||
|
||||
If the tally result passes the decision policy's rules, then the proposal is
|
||||
marked as `PROPOSAL_STATUS_ACCEPTED`, or else it is marked as
|
||||
`PROPOSAL_STATUS_REJECTED`. In any case, no more voting is allowed anymore, and the tally
|
||||
result is persisted to state in the proposal's `FinalTallyResult`.
|
||||
|
||||
### Executing Proposals
|
||||
|
||||
Proposals are executed only when the tallying is done, and the group account's
|
||||
decision policy allows the proposal to pass based on the tally outcome. They
|
||||
are marked by the status `PROPOSAL_STATUS_ACCEPTED`. Execution must happen
|
||||
before a duration of `MaxExecutionPeriod` (set by the chain developer) after
|
||||
each proposal's voting period end.
|
||||
|
||||
Proposals will not be automatically executed by the chain in this current design,
|
||||
but rather a user must submit a `Msg/Exec` transaction to attempt to execute the
|
||||
proposal based on the current votes and decision policy. Any user (not only the
|
||||
group members) can execute proposals that have been accepted, and execution fees are
|
||||
paid by the proposal executor.
|
||||
It's also possible to try to execute a proposal immediately on creation or on
|
||||
new votes using the `Exec` field of `Msg/SubmitProposal` and `Msg/Vote` requests.
|
||||
In the former case, proposers signatures are considered as yes votes.
|
||||
In these cases, if the proposal can't be executed (i.e. it didn't pass the
|
||||
decision policy's rules), it will still be opened for new votes and
|
||||
could be tallied and executed later on.
|
||||
|
||||
A successful proposal execution will have its `ExecutorResult` marked as
|
||||
`PROPOSAL_EXECUTOR_RESULT_SUCCESS`. The proposal will be automatically pruned
|
||||
after execution. On the other hand, a failed proposal execution will be marked
|
||||
as `PROPOSAL_EXECUTOR_RESULT_FAILURE`. Such a proposal can be re-executed
|
||||
multiple times, until it expires after `MaxExecutionPeriod` after voting period
|
||||
end.
|
||||
|
||||
## Pruning
|
||||
|
||||
Proposals and votes are automatically pruned to avoid state bloat.
|
||||
|
||||
Votes are pruned:
|
||||
|
||||
* either after a successful tally, i.e. a tally whose result passes the decision
|
||||
policy's rules, which can be trigged by a `Msg/Exec` or a
|
||||
`Msg/{SubmitProposal,Vote}` with the `Exec` field set,
|
||||
* or on `EndBlock` right after the proposal's voting period end. This applies to proposals with status `aborted` or `withdrawn` too.
|
||||
|
||||
whichever happens first.
|
||||
|
||||
Proposals are pruned:
|
||||
|
||||
* on `EndBlock` whose proposal status is `withdrawn` or `aborted` on proposal's voting period end before tallying,
|
||||
* and either after a successful proposal execution,
|
||||
* or on `EndBlock` right after the proposal's `voting_period_end` +
|
||||
`max_execution_period` (defined as an app-wide configuration) is passed,
|
||||
|
||||
whichever happens first.
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# State
|
||||
|
||||
The `group` module uses the `orm` package which provides table storage with support for
|
||||
primary keys and secondary indexes. `orm` also defines `Sequence` which is a persistent unique key generator based on a counter that can be used along with `Table`s.
|
||||
|
||||
Here's the list of tables and associated sequences and indexes stored as part of the `group` module.
|
||||
|
||||
## Group Table
|
||||
|
||||
The `groupTable` stores `GroupInfo`: `0x0 | BigEndian(GroupId) -> ProtocolBuffer(GroupInfo)`.
|
||||
|
||||
### groupSeq
|
||||
|
||||
The value of `groupSeq` is incremented when creating a new group and corresponds to the new `GroupId`: `0x1 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### groupByAdminIndex
|
||||
|
||||
`groupByAdminIndex` allows to retrieve groups by admin address:
|
||||
`0x2 | len([]byte(group.Admin)) | []byte(group.Admin) | BigEndian(GroupId) -> []byte()`.
|
||||
|
||||
## Group Member Table
|
||||
|
||||
The `groupMemberTable` stores `GroupMember`s: `0x10 | BigEndian(GroupId) | []byte(member.Address) -> ProtocolBuffer(GroupMember)`.
|
||||
|
||||
The `groupMemberTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`BigEndian(GroupId) | []byte(member.Address)` which is used by the following indexes.
|
||||
|
||||
### groupMemberByGroupIndex
|
||||
|
||||
`groupMemberByGroupIndex` allows to retrieve group members by group id:
|
||||
`0x11 | BigEndian(GroupId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### groupMemberByMemberIndex
|
||||
|
||||
`groupMemberByMemberIndex` allows to retrieve group members by member address:
|
||||
`0x12 | len([]byte(member.Address)) | []byte(member.Address) | PrimaryKey -> []byte()`.
|
||||
|
||||
## Group Policy Table
|
||||
|
||||
The `groupPolicyTable` stores `GroupPolicyInfo`: `0x20 | len([]byte(Address)) | []byte(Address) -> ProtocolBuffer(GroupPolicyInfo)`.
|
||||
|
||||
The `groupPolicyTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`len([]byte(Address)) | []byte(Address)` which is used by the following indexes.
|
||||
|
||||
### groupPolicySeq
|
||||
|
||||
The value of `groupPolicySeq` is incremented when creating a new group policy and is used to generate the new group policy account `Address`:
|
||||
`0x21 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### groupPolicyByGroupIndex
|
||||
|
||||
`groupPolicyByGroupIndex` allows to retrieve group policies by group id:
|
||||
`0x22 | BigEndian(GroupId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### groupPolicyByAdminIndex
|
||||
|
||||
`groupPolicyByAdminIndex` allows to retrieve group policies by admin address:
|
||||
`0x23 | len([]byte(Address)) | []byte(Address) | PrimaryKey -> []byte()`.
|
||||
|
||||
## Proposal Table
|
||||
|
||||
The `proposalTable` stores `Proposal`s: `0x30 | BigEndian(ProposalId) -> ProtocolBuffer(Proposal)`.
|
||||
|
||||
### proposalSeq
|
||||
|
||||
The value of `proposalSeq` is incremented when creating a new proposal and corresponds to the new `ProposalId`: `0x31 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### proposalByGroupPolicyIndex
|
||||
|
||||
`proposalByGroupPolicyIndex` allows to retrieve proposals by group policy account address:
|
||||
`0x32 | len([]byte(account.Address)) | []byte(account.Address) | BigEndian(ProposalId) -> []byte()`.
|
||||
|
||||
### ProposalsByVotingPeriodEndIndex
|
||||
|
||||
`proposalsByVotingPeriodEndIndex` allows to retrieve proposals sorted by chronological `voting_period_end`:
|
||||
`0x33 | sdk.FormatTimeBytes(proposal.VotingPeriodEnd) | BigEndian(ProposalId) -> []byte()`.
|
||||
|
||||
This index is used when tallying the proposal votes at the end of the voting period, and for pruning proposals at `VotingPeriodEnd + MaxExecutionPeriod`.
|
||||
|
||||
## Vote Table
|
||||
|
||||
The `voteTable` stores `Vote`s: `0x40 | BigEndian(ProposalId) | []byte(voter.Address) -> ProtocolBuffer(Vote)`.
|
||||
|
||||
The `voteTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`BigEndian(ProposalId) | []byte(voter.Address)` which is used by the following indexes.
|
||||
|
||||
### voteByProposalIndex
|
||||
|
||||
`voteByProposalIndex` allows to retrieve votes by proposal id:
|
||||
`0x41 | BigEndian(ProposalId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### voteByVoterIndex
|
||||
|
||||
`voteByVoterIndex` allows to retrieve votes by voter address:
|
||||
`0x42 | len([]byte(voter.Address)) | []byte(voter.Address) | PrimaryKey -> []byte()`.
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Msg Service
|
||||
|
||||
## Msg/CreateGroup
|
||||
|
||||
A new group can be created with the `MsgCreateGroup`, which has an admin address, a list of members and some optional metadata.
|
||||
|
||||
The metadata has a maximum length that is chosen by the app developer, and
|
||||
passed into the group keeper as a config.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L66-L78
|
||||
|
||||
It's expected to fail if
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen`
|
||||
config
|
||||
* members are not correctly set (e.g. wrong address format, duplicates, or with 0 weight).
|
||||
|
||||
## Msg/UpdateGroupMembers
|
||||
|
||||
Group members can be updated with the `UpdateGroupMembers`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L87-L100
|
||||
|
||||
In the list of `MemberUpdates`, an existing member can be removed by setting its weight to 0.
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group.
|
||||
* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group.
|
||||
|
||||
## Msg/UpdateGroupAdmin
|
||||
|
||||
The `UpdateGroupAdmin` can be used to update a group admin.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L105-L117
|
||||
|
||||
It's expected to fail if the signer is not the admin of the group.
|
||||
|
||||
## Msg/UpdateGroupMetadata
|
||||
|
||||
The `UpdateGroupMetadata` can be used to update a group metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L122-L134
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* new metadata length is greater than `MaxMetadataLen` config.
|
||||
* the signer is not the admin of the group.
|
||||
|
||||
## Msg/CreateGroupPolicy
|
||||
|
||||
A new group policy can be created with the `MsgCreateGroupPolicy`, which has an admin address, a group id, a decision policy and some optional metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L143-L160
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group.
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* the decision policy's `Validate()` method doesn't pass against the group.
|
||||
|
||||
## Msg/CreateGroupWithPolicy
|
||||
|
||||
A new group with policy can be created with the `MsgCreateGroupWithPolicy`, which has an admin address, a list of members, a decision policy, a `group_policy_as_admin` field to optionally set group and group policy admin with group policy address and some optional metadata for group and group policy.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L183-L206
|
||||
|
||||
It's expected to fail for the same reasons as `Msg/CreateGroup` and `Msg/CreateGroupPolicy`.
|
||||
|
||||
## Msg/UpdateGroupPolicyAdmin
|
||||
|
||||
The `UpdateGroupPolicyAdmin` can be used to update a group policy admin.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L169-L181
|
||||
|
||||
It's expected to fail if the signer is not the admin of the group policy.
|
||||
|
||||
## Msg/UpdateGroupPolicyDecisionPolicy
|
||||
|
||||
The `UpdateGroupPolicyDecisionPolicy` can be used to update a decision policy.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L219-L235
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group policy.
|
||||
* the new decision policy's `Validate()` method doesn't pass against the group.
|
||||
|
||||
## Msg/UpdateGroupPolicyMetadata
|
||||
|
||||
The `UpdateGroupPolicyMetadata` can be used to update a group policy metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L240-L252
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* new metadata length is greater than `MaxMetadataLen` config.
|
||||
* the signer is not the admin of the group.
|
||||
|
||||
## Msg/SubmitProposal
|
||||
|
||||
A new proposal can be created with the `MsgSubmitProposal`, which has a group policy account address, a list of proposers addresses, a list of messages to execute if the proposal is accepted and some optional metadata.
|
||||
An optional `Exec` value can be provided to try to execute the proposal immediately after proposal creation. Proposers signatures are considered as yes votes in this case.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L275-L298
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* if any of the proposers is not a group member.
|
||||
|
||||
## Msg/WithdrawProposal
|
||||
|
||||
A proposal can be withdrawn using `MsgWithdrawProposal` which has an `address` (can be either a proposer or the group policy admin) and a `proposal_id` (which has to be withdrawn).
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L307-L316
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is neither the group policy admin nor proposer of the proposal.
|
||||
* the proposal is already closed or aborted.
|
||||
|
||||
## Msg/Vote
|
||||
|
||||
A new vote can be created with the `MsgVote`, given a proposal id, a voter address, a choice (yes, no, veto or abstain) and some optional metadata.
|
||||
An optional `Exec` value can be provided to try to execute the proposal immediately after voting.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L321-L339
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* the proposal is not in voting period anymore.
|
||||
|
||||
## Msg/Exec
|
||||
|
||||
A proposal can be executed with the `MsgExec`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L341-L353
|
||||
|
||||
The messages that are part of this proposal won't be executed if:
|
||||
|
||||
* the proposal has not been accepted by the group policy.
|
||||
* the proposal has already been successfully executed.
|
||||
|
||||
## Msg/LeaveGroup
|
||||
|
||||
The `MsgLeaveGroup` allows group member to leave a group.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L362-L370
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the group member is not part of the group.
|
||||
* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group.
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Events
|
||||
|
||||
The group module emits the following events:
|
||||
|
||||
## EventCreateGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------- | ------------- | -------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateGroup |
|
||||
| cosmos.group.v1.EventCreateGroup | group_id | {groupId} |
|
||||
|
||||
## EventUpdateGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------- | ------------- | ---------------------------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/UpdateGroup{Admin\|Metadata\|Members} |
|
||||
| cosmos.group.v1.EventUpdateGroup | group_id | {groupId} |
|
||||
|
||||
## EventCreateGroupPolicy
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------------- | ------------- | -------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateGroupPolicy |
|
||||
| cosmos.group.v1.EventCreateGroupPolicy | address | {groupPolicyAddress} |
|
||||
|
||||
## EventUpdateGroupPolicy
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------------- | ------------- | ----------------------------------------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/UpdateGroupPolicy{Admin\|Metadata\|DecisionPolicy} |
|
||||
| cosmos.group.v1.EventUpdateGroupPolicy | address | {groupPolicyAddress} |
|
||||
|
||||
## EventCreateProposal
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ----------------------------------- | ------------- | ----------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateProposal |
|
||||
| cosmos.group.v1.EventCreateProposal | proposal_id | {proposalId} |
|
||||
|
||||
## EventWithdrawProposal
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------------------- | ------------- | ------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/WithdrawProposal |
|
||||
| cosmos.group.v1.EventWithdrawProposal | proposal_id | {proposalId} |
|
||||
|
||||
## EventVote
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------- | ------------- | ------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/Vote |
|
||||
| cosmos.group.v1.EventVote | proposal_id | {proposalId} |
|
||||
|
||||
## EventExec
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------- | ------------- | ------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/Exec |
|
||||
| cosmos.group.v1.EventExec | proposal_id | {proposalId} |
|
||||
| cosmos.group.v1.EventExec | logs | {logs_string} |
|
||||
|
||||
## EventLeaveGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------------- | ------------- | ------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/LeaveGroup |
|
||||
| cosmos.group.v1.EventLeaveGroup | proposal_id | {proposalId} |
|
||||
| cosmos.group.v1.EventLeaveGroup | address | {address} |
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
@ -1509,3 +2056,58 @@ Example Output:
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- order: 6 -->
|
||||
|
||||
# Metadata
|
||||
|
||||
The group module has four locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the group and gov modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains.
|
||||
|
||||
## Proposal
|
||||
|
||||
Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../../gov/spec/08_metadata.md#proposal))
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "",
|
||||
"authors": "",
|
||||
"summary": "",
|
||||
"details": "",
|
||||
"proposalForumURL": "",
|
||||
"voteOptionContext": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Vote
|
||||
|
||||
Location: on-chain as json within 255 character limit (mirrors [gov vote](../../gov/spec/08_metadata.md#vote))
|
||||
|
||||
```json
|
||||
{
|
||||
"justification": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Group
|
||||
|
||||
Location: off-chain as json object stored on IPFS
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "",
|
||||
"description": "",
|
||||
"groupWebsiteURL": "",
|
||||
"groupForumURL": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Decision policy
|
||||
|
||||
Location: on-chain as json within 255 character limit
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "",
|
||||
"description": "",
|
||||
}
|
||||
```
|
||||
119
x/group/internal/orm/README.md
Normal file
119
x/group/internal/orm/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# Abstract
|
||||
|
||||
The orm package provides a framework for creating relational database tables with primary and secondary keys.
|
||||
|
||||
## Contents
|
||||
|
||||
* [Table](#table)
|
||||
* [AutoUInt64Table](#autouint64table)
|
||||
* [PrimaryKeyTable](#primarykeytable)
|
||||
* [PrimaryKeyed](#primarykeyed)
|
||||
* [Key codec](#key-codec)
|
||||
* [Secondary Index](#secondary-index)
|
||||
* [MultiKeyIndex](#multikeyindex)
|
||||
* [UniqueIndex](#uniqueindex)
|
||||
* [Iterator and Pagination](#iterator-and-pagination)
|
||||
* [Iterator](#iterator)
|
||||
* [Pagination](#pagination)
|
||||
|
||||
# Table
|
||||
|
||||
A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L30-L36
|
||||
|
||||
In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes.
|
||||
Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store.
|
||||
|
||||
The `table` struct does not:
|
||||
|
||||
* enforce uniqueness of the `RowID`
|
||||
* enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix of another
|
||||
* optimize Gas usage conditions
|
||||
|
||||
The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements.
|
||||
|
||||
`table` provides methods for exporting (using a [`PrefixScan` `Iterator`](03_iterator_pagination.md#iterator)) and importing genesis data. For the import to be successful, objects have to be aware of their primary key by implementing the [`PrimaryKeyed`](#primarykeyed) interface.
|
||||
|
||||
## AutoUInt64Table
|
||||
|
||||
`AutoUInt64Table` is a table type with an auto incrementing `uint64` ID.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/auto_uint64.go#L15-L18
|
||||
|
||||
It's based on the `Sequence` struct which is a persistent unique key generator based on a counter encoded using 8 byte big endian.
|
||||
|
||||
## PrimaryKeyTable
|
||||
|
||||
`PrimaryKeyTable` provides simpler object style orm methods where are persisted and loaded with a reference to their unique primary key.
|
||||
|
||||
### PrimaryKeyed
|
||||
|
||||
The model provided for creating a `PrimaryKeyTable` should implement the `PrimaryKeyed` interface:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/primary_key.go#L30-L44
|
||||
|
||||
`PrimaryKeyFields()` method returns the list of key parts for a given object.
|
||||
The primary key parts can be []byte, string, and `uint64` types.
|
||||
|
||||
### Key codec
|
||||
|
||||
Key parts, except the last part, follow these rules:
|
||||
|
||||
* []byte is encoded with a single byte length prefix (which means the max []byte length is 255)
|
||||
* strings are null-terminated
|
||||
* `uint64` are encoded using 8 byte big endian.
|
||||
|
||||
# Secondary Index
|
||||
|
||||
Secondary indexes can be used on `Indexable` [tables](01_table.md). Indeed, those tables implement the `Indexable` interface that provides a set of functions that can be called by indexes to register and interact with the tables, like callback functions that are called on entries creation, update or deletion to create, update or remove corresponding entries in the table secondary indexes.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L88-L93
|
||||
|
||||
## MultiKeyIndex
|
||||
|
||||
A `MultiKeyIndex` is an index where multiple entries can point to the same underlying object.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L26-L32
|
||||
|
||||
Internally, it uses an `Indexer` that manages the persistence of the index based on searchable keys and create/update/delete operations.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L15-L20
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/indexer.go#L15-L19
|
||||
|
||||
The currently used implementation of an `indexer`, `Indexer`, relies on an `IndexerFunc` that should be provided when instantiating the index. Based on the source object, this function returns one or multiple index keys as `[]interface{}`. Such secondary index keys should be bytes, string or `uint64` in order to be handled properly by the [key codec](01_table.md#key-codec) which defines specific encoding for those types.
|
||||
In the index prefix store, the keys are built based on the source object's `RowID` and its secondary index key(s) using the key codec and the values are set as empty bytes.
|
||||
|
||||
## UniqueIndex
|
||||
|
||||
As opposed to `MultiKeyIndex`, `UniqueIndex` is an index where duplicate keys are prohibited.
|
||||
|
||||
# Iterator and Pagination
|
||||
|
||||
Both [tables](01_table.md) and [secondary indexes](02_secondary_index.md) support iterating over a domain of keys, through `PrefixScan` or `ReversePrefixScan`, as well pagination.
|
||||
|
||||
## Iterator
|
||||
|
||||
An `Iterator` allows iteration through a sequence of key value pairs.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L77-L85
|
||||
|
||||
Tables rely on a `typeSafeIterator` that is used by `PrefixScan` and `ReversePrefixScan` `table` methods to iterate through a range of `RowID`s.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L285-L290
|
||||
|
||||
Secondary indexes rely on an `indexIterator` that can strip the `RowID` from the full index key in order to get the underlying value in the table prefix store.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L232-L238
|
||||
|
||||
Under the hood, both use a prefix store `Iterator` (alias for tm-db `Iterator`).
|
||||
|
||||
## Pagination
|
||||
|
||||
The `Paginate` function does pagination given an [`Iterator`](#iterator) and a `query.PageRequest`, and returns a `query.PageResponse`.
|
||||
It unmarshals the results into the provided dest interface that should be a pointer to a slice of models.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/iterator.go#L102-L220
|
||||
|
||||
Secondary indexes have a `GetPaginated` method that returns an `Iterator` for the given searched secondary index key, starting from the `query.PageRequest` key if provided. It's important to note that this `query.PageRequest` key should be a `RowID` (that could have been returned by a previous paginated request). The returned `Iterator` can then be used with the `Paginate` function and the same `query.PageRequest`.
|
||||
@ -1,47 +0,0 @@
|
||||
# Table
|
||||
|
||||
A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L30-L36
|
||||
|
||||
In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes.
|
||||
Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store.
|
||||
|
||||
The `table` struct does not:
|
||||
|
||||
* enforce uniqueness of the `RowID`
|
||||
* enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix of another
|
||||
* optimize Gas usage conditions
|
||||
|
||||
The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements.
|
||||
|
||||
`table` provides methods for exporting (using a [`PrefixScan` `Iterator`](03_iterator_pagination.md#iterator)) and importing genesis data. For the import to be successful, objects have to be aware of their primary key by implementing the [`PrimaryKeyed`](#primarykeyed) interface.
|
||||
|
||||
## AutoUInt64Table
|
||||
|
||||
`AutoUInt64Table` is a table type with an auto incrementing `uint64` ID.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/auto_uint64.go#L15-L18
|
||||
|
||||
It's based on the `Sequence` struct which is a persistent unique key generator based on a counter encoded using 8 byte big endian.
|
||||
|
||||
## PrimaryKeyTable
|
||||
|
||||
`PrimaryKeyTable` provides simpler object style orm methods where are persisted and loaded with a reference to their unique primary key.
|
||||
|
||||
### PrimaryKeyed
|
||||
|
||||
The model provided for creating a `PrimaryKeyTable` should implement the `PrimaryKeyed` interface:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/primary_key.go#L30-L44
|
||||
|
||||
`PrimaryKeyFields()` method returns the list of key parts for a given object.
|
||||
The primary key parts can be []byte, string, and `uint64` types.
|
||||
|
||||
### Key codec
|
||||
|
||||
Key parts, except the last part, follow these rules:
|
||||
|
||||
* []byte is encoded with a single byte length prefix (which means the max []byte length is 255)
|
||||
* strings are null-terminated
|
||||
* `uint64` are encoded using 8 byte big endian.
|
||||
@ -1,24 +0,0 @@
|
||||
# Secondary Index
|
||||
|
||||
Secondary indexes can be used on `Indexable` [tables](01_table.md). Indeed, those tables implement the `Indexable` interface that provides a set of functions that can be called by indexes to register and interact with the tables, like callback functions that are called on entries creation, update or deletion to create, update or remove corresponding entries in the table secondary indexes.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L88-L93
|
||||
|
||||
## MultiKeyIndex
|
||||
|
||||
A `MultiKeyIndex` is an index where multiple entries can point to the same underlying object.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L26-L32
|
||||
|
||||
Internally, it uses an `Indexer` that manages the persistence of the index based on searchable keys and create/update/delete operations.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L15-L20
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/indexer.go#L15-L19
|
||||
|
||||
The currently used implementation of an `indexer`, `Indexer`, relies on an `IndexerFunc` that should be provided when instantiating the index. Based on the source object, this function returns one or multiple index keys as `[]interface{}`. Such secondary index keys should be bytes, string or `uint64` in order to be handled properly by the [key codec](01_table.md#key-codec) which defines specific encoding for those types.
|
||||
In the index prefix store, the keys are built based on the source object's `RowID` and its secondary index key(s) using the key codec and the values are set as empty bytes.
|
||||
|
||||
## UniqueIndex
|
||||
|
||||
As opposed to `MultiKeyIndex`, `UniqueIndex` is an index where duplicate keys are prohibited.
|
||||
@ -1,28 +0,0 @@
|
||||
# Iterator and Pagination
|
||||
|
||||
Both [tables](01_table.md) and [secondary indexes](02_secondary_index.md) support iterating over a domain of keys, through `PrefixScan` or `ReversePrefixScan`, as well pagination.
|
||||
|
||||
## Iterator
|
||||
|
||||
An `Iterator` allows iteration through a sequence of key value pairs.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L77-L85
|
||||
|
||||
Tables rely on a `typeSafeIterator` that is used by `PrefixScan` and `ReversePrefixScan` `table` methods to iterate through a range of `RowID`s.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L285-L290
|
||||
|
||||
Secondary indexes rely on an `indexIterator` that can strip the `RowID` from the full index key in order to get the underlying value in the table prefix store.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L232-L238
|
||||
|
||||
Under the hood, both use a prefix store `Iterator` (alias for tm-db `Iterator`).
|
||||
|
||||
## Pagination
|
||||
|
||||
The `Paginate` function does pagination given an [`Iterator`](#iterator) and a `query.PageRequest`, and returns a `query.PageResponse`.
|
||||
It unmarshals the results into the provided dest interface that should be a pointer to a slice of models.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/iterator.go#L102-L220
|
||||
|
||||
Secondary indexes have a `GetPaginated` method that returns an `Iterator` for the given searched secondary index key, starting from the `query.PageRequest` key if provided. It's important to note that this `query.PageRequest` key should be a `RowID` (that could have been returned by a previous paginated request). The returned `Iterator` can then be used with the `Paginate` function and the same `query.PageRequest`.
|
||||
@ -1,15 +0,0 @@
|
||||
# Abstract
|
||||
|
||||
The orm package provides a framework for creating relational database tables with primary and secondary keys.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Table](01_table.md)**
|
||||
* [AutoUInt64Table](01_table.md#autouint64table)
|
||||
* [PrimaryKeyTable](01_table.md#primarykeytable)
|
||||
2. **[Secondary Index](02_secondary_index.md)**
|
||||
* [MultiKeyIndex](02_secondary_index.md#multikeyindex)
|
||||
* [UniqueIndex](02_secondary_index.md#uniqueindex)
|
||||
3. **[Iterator and Pagination](03_iterator_pagination.md)**
|
||||
* [Iterator](03_iterator_pagination.md#iterator)
|
||||
* [Pagination](03_iterator_pagination.md#pagination)
|
||||
@ -1,157 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Group
|
||||
|
||||
A group is simply an aggregation of accounts with associated weights. It is not
|
||||
an account and doesn't have a balance. It doesn't in and of itself have any
|
||||
sort of voting or decision weight. It does have an "administrator" which has
|
||||
the ability to add, remove and update members in the group. Note that a
|
||||
group policy account could be an administrator of a group, and that the
|
||||
administrator doesn't necessarily have to be a member of the group.
|
||||
|
||||
## Group Policy
|
||||
|
||||
A group policy is an account associated with a group and a decision policy.
|
||||
Group policies are abstracted from groups because a single group may have
|
||||
multiple decision policies for different types of actions. Managing group
|
||||
membership separately from decision policies results in the least overhead
|
||||
and keeps membership consistent across different policies. The pattern that
|
||||
is recommended is to have a single master group policy for a given group,
|
||||
and then to create separate group policies with different decision policies
|
||||
and delegate the desired permissions from the master account to
|
||||
those "sub-accounts" using the `x/authz` module.
|
||||
|
||||
## Decision Policy
|
||||
|
||||
A decision policy is the mechanism by which members of a group can vote on
|
||||
proposals, as well as the rules that dictate whether a proposal should pass
|
||||
or not based on its tally outcome.
|
||||
|
||||
All decision policies generally would have a mininum execution period and a
|
||||
maximum voting window. The minimum execution period is the minimum amount of time
|
||||
that must pass after submission in order for a proposal to potentially be executed, and it may
|
||||
be set to 0. The maximum voting window is the maximum time after submission that a proposal may
|
||||
be voted on before it is tallied.
|
||||
|
||||
The chain developer also defines an app-wide maximum execution period, which is
|
||||
the maximum amount of time after a proposal's voting period end where users are
|
||||
allowed to execute a proposal.
|
||||
|
||||
The current group module comes shipped with two decision policies: threshold
|
||||
and percentage. Any chain developer can extend upon these two, by creating
|
||||
custom decision policies, as long as they adhere to the `DecisionPolicy`
|
||||
interface:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/types.go#L27-L41
|
||||
|
||||
### Threshold decision policy
|
||||
|
||||
A threshold decision policy defines a threshold of yes votes (based on a tally
|
||||
of voter weights) that must be achieved in order for a proposal to pass. For
|
||||
this decision policy, abstain and veto are simply treated as no's.
|
||||
|
||||
### Percentage decision policy
|
||||
|
||||
A percentage decision policy is similar to a threshold decision policy, except
|
||||
that the threshold is not defined as a constant weight, but as a percentage.
|
||||
It's more suited for groups where the group members' weights can be updated, as
|
||||
the percentage threshold stays the same, and doesn't depend on how those member
|
||||
weights get updated.
|
||||
|
||||
## Proposal
|
||||
|
||||
Any member(s) of a group can submit a proposal for a group policy account to decide upon.
|
||||
A proposal consists of a set of messages that will be executed if the proposal
|
||||
passes as well as any metadata associated with the proposal.
|
||||
|
||||
### Voting
|
||||
|
||||
There are four choices to choose while voting - yes, no, abstain and veto. Not
|
||||
all decision policies will take the four choices into account. Votes can contain some optional metadata.
|
||||
In the current implementation, the voting window begins as soon as a proposal
|
||||
is submitted, and the end is defined by the group policy's decision policy.
|
||||
|
||||
### Withdrawing Proposals
|
||||
|
||||
Proposals can be withdrawn any time before the voting period end, either by the
|
||||
admin of the group policy or by one of the proposers. Once withdrawn, it is
|
||||
marked as `PROPOSAL_STATUS_WITHDRAWN`, and no more voting or execution is
|
||||
allowed on it.
|
||||
|
||||
### Aborted Proposals
|
||||
|
||||
If the group policy is updated during the voting period of the proposal, then
|
||||
the proposal is marked as `PROPOSAL_STATUS_ABORTED`, and no more voting or
|
||||
execution is allowed on it. This is because the group policy defines the rules
|
||||
of proposal voting and execution, so if those rules change during the lifecycle
|
||||
of a proposal, then the proposal should be marked as stale.
|
||||
|
||||
### Tallying
|
||||
|
||||
Tallying is the counting of all votes on a proposal. It happens only once in
|
||||
the lifecycle of a proposal, but can be triggered by two factors, whichever
|
||||
happens first:
|
||||
|
||||
* either someone tries to execute the proposal (see next section), which can
|
||||
happen on a `Msg/Exec` transaction, or a `Msg/{SubmitProposal,Vote}`
|
||||
transaction with the `Exec` field set. When a proposal execution is attempted,
|
||||
a tally is done first to make sure the proposal passes.
|
||||
* or on `EndBlock` when the proposal's voting period end just passed.
|
||||
|
||||
If the tally result passes the decision policy's rules, then the proposal is
|
||||
marked as `PROPOSAL_STATUS_ACCEPTED`, or else it is marked as
|
||||
`PROPOSAL_STATUS_REJECTED`. In any case, no more voting is allowed anymore, and the tally
|
||||
result is persisted to state in the proposal's `FinalTallyResult`.
|
||||
|
||||
### Executing Proposals
|
||||
|
||||
Proposals are executed only when the tallying is done, and the group account's
|
||||
decision policy allows the proposal to pass based on the tally outcome. They
|
||||
are marked by the status `PROPOSAL_STATUS_ACCEPTED`. Execution must happen
|
||||
before a duration of `MaxExecutionPeriod` (set by the chain developer) after
|
||||
each proposal's voting period end.
|
||||
|
||||
Proposals will not be automatically executed by the chain in this current design,
|
||||
but rather a user must submit a `Msg/Exec` transaction to attempt to execute the
|
||||
proposal based on the current votes and decision policy. Any user (not only the
|
||||
group members) can execute proposals that have been accepted, and execution fees are
|
||||
paid by the proposal executor.
|
||||
It's also possible to try to execute a proposal immediately on creation or on
|
||||
new votes using the `Exec` field of `Msg/SubmitProposal` and `Msg/Vote` requests.
|
||||
In the former case, proposers signatures are considered as yes votes.
|
||||
In these cases, if the proposal can't be executed (i.e. it didn't pass the
|
||||
decision policy's rules), it will still be opened for new votes and
|
||||
could be tallied and executed later on.
|
||||
|
||||
A successful proposal execution will have its `ExecutorResult` marked as
|
||||
`PROPOSAL_EXECUTOR_RESULT_SUCCESS`. The proposal will be automatically pruned
|
||||
after execution. On the other hand, a failed proposal execution will be marked
|
||||
as `PROPOSAL_EXECUTOR_RESULT_FAILURE`. Such a proposal can be re-executed
|
||||
multiple times, until it expires after `MaxExecutionPeriod` after voting period
|
||||
end.
|
||||
|
||||
## Pruning
|
||||
|
||||
Proposals and votes are automatically pruned to avoid state bloat.
|
||||
|
||||
Votes are pruned:
|
||||
|
||||
* either after a successful tally, i.e. a tally whose result passes the decision
|
||||
policy's rules, which can be trigged by a `Msg/Exec` or a
|
||||
`Msg/{SubmitProposal,Vote}` with the `Exec` field set,
|
||||
* or on `EndBlock` right after the proposal's voting period end. This applies to proposals with status `aborted` or `withdrawn` too.
|
||||
|
||||
whichever happens first.
|
||||
|
||||
Proposals are pruned:
|
||||
|
||||
* on `EndBlock` whose proposal status is `withdrawn` or `aborted` on proposal's voting period end before tallying,
|
||||
* and either after a successful proposal execution,
|
||||
* or on `EndBlock` right after the proposal's `voting_period_end` +
|
||||
`max_execution_period` (defined as an app-wide configuration) is passed,
|
||||
|
||||
whichever happens first.
|
||||
@ -1,105 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
The `group` module uses the `orm` package which provides table storage with support for
|
||||
primary keys and secondary indexes. `orm` also defines `Sequence` which is a persistent unique key generator based on a counter that can be used along with `Table`s.
|
||||
|
||||
Here's the list of tables and associated sequences and indexes stored as part of the `group` module.
|
||||
|
||||
## Group Table
|
||||
|
||||
The `groupTable` stores `GroupInfo`: `0x0 | BigEndian(GroupId) -> ProtocolBuffer(GroupInfo)`.
|
||||
|
||||
### groupSeq
|
||||
|
||||
The value of `groupSeq` is incremented when creating a new group and corresponds to the new `GroupId`: `0x1 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### groupByAdminIndex
|
||||
|
||||
`groupByAdminIndex` allows to retrieve groups by admin address:
|
||||
`0x2 | len([]byte(group.Admin)) | []byte(group.Admin) | BigEndian(GroupId) -> []byte()`.
|
||||
|
||||
## Group Member Table
|
||||
|
||||
The `groupMemberTable` stores `GroupMember`s: `0x10 | BigEndian(GroupId) | []byte(member.Address) -> ProtocolBuffer(GroupMember)`.
|
||||
|
||||
The `groupMemberTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`BigEndian(GroupId) | []byte(member.Address)` which is used by the following indexes.
|
||||
|
||||
### groupMemberByGroupIndex
|
||||
|
||||
`groupMemberByGroupIndex` allows to retrieve group members by group id:
|
||||
`0x11 | BigEndian(GroupId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### groupMemberByMemberIndex
|
||||
|
||||
`groupMemberByMemberIndex` allows to retrieve group members by member address:
|
||||
`0x12 | len([]byte(member.Address)) | []byte(member.Address) | PrimaryKey -> []byte()`.
|
||||
|
||||
## Group Policy Table
|
||||
|
||||
The `groupPolicyTable` stores `GroupPolicyInfo`: `0x20 | len([]byte(Address)) | []byte(Address) -> ProtocolBuffer(GroupPolicyInfo)`.
|
||||
|
||||
The `groupPolicyTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`len([]byte(Address)) | []byte(Address)` which is used by the following indexes.
|
||||
|
||||
### groupPolicySeq
|
||||
|
||||
The value of `groupPolicySeq` is incremented when creating a new group policy and is used to generate the new group policy account `Address`:
|
||||
`0x21 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### groupPolicyByGroupIndex
|
||||
|
||||
`groupPolicyByGroupIndex` allows to retrieve group policies by group id:
|
||||
`0x22 | BigEndian(GroupId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### groupPolicyByAdminIndex
|
||||
|
||||
`groupPolicyByAdminIndex` allows to retrieve group policies by admin address:
|
||||
`0x23 | len([]byte(Address)) | []byte(Address) | PrimaryKey -> []byte()`.
|
||||
|
||||
## Proposal Table
|
||||
|
||||
The `proposalTable` stores `Proposal`s: `0x30 | BigEndian(ProposalId) -> ProtocolBuffer(Proposal)`.
|
||||
|
||||
### proposalSeq
|
||||
|
||||
The value of `proposalSeq` is incremented when creating a new proposal and corresponds to the new `ProposalId`: `0x31 | 0x1 -> BigEndian`.
|
||||
|
||||
The second `0x1` corresponds to the ORM `sequenceStorageKey`.
|
||||
|
||||
### proposalByGroupPolicyIndex
|
||||
|
||||
`proposalByGroupPolicyIndex` allows to retrieve proposals by group policy account address:
|
||||
`0x32 | len([]byte(account.Address)) | []byte(account.Address) | BigEndian(ProposalId) -> []byte()`.
|
||||
|
||||
### ProposalsByVotingPeriodEndIndex
|
||||
|
||||
`proposalsByVotingPeriodEndIndex` allows to retrieve proposals sorted by chronological `voting_period_end`:
|
||||
`0x33 | sdk.FormatTimeBytes(proposal.VotingPeriodEnd) | BigEndian(ProposalId) -> []byte()`.
|
||||
|
||||
This index is used when tallying the proposal votes at the end of the voting period, and for pruning proposals at `VotingPeriodEnd + MaxExecutionPeriod`.
|
||||
|
||||
## Vote Table
|
||||
|
||||
The `voteTable` stores `Vote`s: `0x40 | BigEndian(ProposalId) | []byte(voter.Address) -> ProtocolBuffer(Vote)`.
|
||||
|
||||
The `voteTable` is a primary key table and its `PrimaryKey` is given by
|
||||
`BigEndian(ProposalId) | []byte(voter.Address)` which is used by the following indexes.
|
||||
|
||||
### voteByProposalIndex
|
||||
|
||||
`voteByProposalIndex` allows to retrieve votes by proposal id:
|
||||
`0x41 | BigEndian(ProposalId) | PrimaryKey -> []byte()`.
|
||||
|
||||
### voteByVoterIndex
|
||||
|
||||
`voteByVoterIndex` allows to retrieve votes by voter address:
|
||||
`0x42 | len([]byte(voter.Address)) | []byte(voter.Address) | PrimaryKey -> []byte()`.
|
||||
@ -1,159 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Msg Service
|
||||
|
||||
## Msg/CreateGroup
|
||||
|
||||
A new group can be created with the `MsgCreateGroup`, which has an admin address, a list of members and some optional metadata.
|
||||
|
||||
The metadata has a maximum length that is chosen by the app developer, and
|
||||
passed into the group keeper as a config.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L66-L78
|
||||
|
||||
It's expected to fail if
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen`
|
||||
config
|
||||
* members are not correctly set (e.g. wrong address format, duplicates, or with 0 weight).
|
||||
|
||||
## Msg/UpdateGroupMembers
|
||||
|
||||
Group members can be updated with the `UpdateGroupMembers`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L87-L100
|
||||
|
||||
In the list of `MemberUpdates`, an existing member can be removed by setting its weight to 0.
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group.
|
||||
* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group.
|
||||
|
||||
## Msg/UpdateGroupAdmin
|
||||
|
||||
The `UpdateGroupAdmin` can be used to update a group admin.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L105-L117
|
||||
|
||||
It's expected to fail if the signer is not the admin of the group.
|
||||
|
||||
## Msg/UpdateGroupMetadata
|
||||
|
||||
The `UpdateGroupMetadata` can be used to update a group metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L122-L134
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* new metadata length is greater than `MaxMetadataLen` config.
|
||||
* the signer is not the admin of the group.
|
||||
|
||||
## Msg/CreateGroupPolicy
|
||||
|
||||
A new group policy can be created with the `MsgCreateGroupPolicy`, which has an admin address, a group id, a decision policy and some optional metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L143-L160
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group.
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* the decision policy's `Validate()` method doesn't pass against the group.
|
||||
|
||||
## Msg/CreateGroupWithPolicy
|
||||
|
||||
A new group with policy can be created with the `MsgCreateGroupWithPolicy`, which has an admin address, a list of members, a decision policy, a `group_policy_as_admin` field to optionally set group and group policy admin with group policy address and some optional metadata for group and group policy.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L183-L206
|
||||
|
||||
It's expected to fail for the same reasons as `Msg/CreateGroup` and `Msg/CreateGroupPolicy`.
|
||||
|
||||
## Msg/UpdateGroupPolicyAdmin
|
||||
|
||||
The `UpdateGroupPolicyAdmin` can be used to update a group policy admin.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L169-L181
|
||||
|
||||
It's expected to fail if the signer is not the admin of the group policy.
|
||||
|
||||
## Msg/UpdateGroupPolicyDecisionPolicy
|
||||
|
||||
The `UpdateGroupPolicyDecisionPolicy` can be used to update a decision policy.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L219-L235
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is not the admin of the group policy.
|
||||
* the new decision policy's `Validate()` method doesn't pass against the group.
|
||||
|
||||
## Msg/UpdateGroupPolicyMetadata
|
||||
|
||||
The `UpdateGroupPolicyMetadata` can be used to update a group policy metadata.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L240-L252
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* new metadata length is greater than `MaxMetadataLen` config.
|
||||
* the signer is not the admin of the group.
|
||||
|
||||
## Msg/SubmitProposal
|
||||
|
||||
A new proposal can be created with the `MsgSubmitProposal`, which has a group policy account address, a list of proposers addresses, a list of messages to execute if the proposal is accepted and some optional metadata.
|
||||
An optional `Exec` value can be provided to try to execute the proposal immediately after proposal creation. Proposers signatures are considered as yes votes in this case.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L275-L298
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* if any of the proposers is not a group member.
|
||||
|
||||
## Msg/WithdrawProposal
|
||||
|
||||
A proposal can be withdrawn using `MsgWithdrawProposal` which has an `address` (can be either a proposer or the group policy admin) and a `proposal_id` (which has to be withdrawn).
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L307-L316
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the signer is neither the group policy admin nor proposer of the proposal.
|
||||
* the proposal is already closed or aborted.
|
||||
|
||||
## Msg/Vote
|
||||
|
||||
A new vote can be created with the `MsgVote`, given a proposal id, a voter address, a choice (yes, no, veto or abstain) and some optional metadata.
|
||||
An optional `Exec` value can be provided to try to execute the proposal immediately after voting.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L321-L339
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* metadata length is greater than `MaxMetadataLen` config.
|
||||
* the proposal is not in voting period anymore.
|
||||
|
||||
## Msg/Exec
|
||||
|
||||
A proposal can be executed with the `MsgExec`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L341-L353
|
||||
|
||||
The messages that are part of this proposal won't be executed if:
|
||||
|
||||
* the proposal has not been accepted by the group policy.
|
||||
* the proposal has already been successfully executed.
|
||||
|
||||
## Msg/LeaveGroup
|
||||
|
||||
The `MsgLeaveGroup` allows group member to leave a group.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L362-L370
|
||||
|
||||
It's expected to fail if:
|
||||
|
||||
* the group member is not part of the group.
|
||||
* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group.
|
||||
@ -1,72 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The group module emits the following events:
|
||||
|
||||
## EventCreateGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------- | ------------- | -------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateGroup |
|
||||
| cosmos.group.v1.EventCreateGroup | group_id | {groupId} |
|
||||
|
||||
## EventUpdateGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------- | ------------- | ---------------------------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/UpdateGroup{Admin\|Metadata\|Members} |
|
||||
| cosmos.group.v1.EventUpdateGroup | group_id | {groupId} |
|
||||
|
||||
## EventCreateGroupPolicy
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------------- | ------------- | -------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateGroupPolicy |
|
||||
| cosmos.group.v1.EventCreateGroupPolicy | address | {groupPolicyAddress} |
|
||||
|
||||
## EventUpdateGroupPolicy
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| -------------------------------------- | ------------- | ----------------------------------------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/UpdateGroupPolicy{Admin\|Metadata\|DecisionPolicy} |
|
||||
| cosmos.group.v1.EventUpdateGroupPolicy | address | {groupPolicyAddress} |
|
||||
|
||||
## EventCreateProposal
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ----------------------------------- | ------------- | ----------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/CreateProposal |
|
||||
| cosmos.group.v1.EventCreateProposal | proposal_id | {proposalId} |
|
||||
|
||||
## EventWithdrawProposal
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------------------- | ------------- | ------------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/WithdrawProposal |
|
||||
| cosmos.group.v1.EventWithdrawProposal | proposal_id | {proposalId} |
|
||||
|
||||
## EventVote
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------- | ------------- | ------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/Vote |
|
||||
| cosmos.group.v1.EventVote | proposal_id | {proposalId} |
|
||||
|
||||
## EventExec
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------- | ------------- | ------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/Exec |
|
||||
| cosmos.group.v1.EventExec | proposal_id | {proposalId} |
|
||||
| cosmos.group.v1.EventExec | logs | {logs_string} |
|
||||
|
||||
## EventLeaveGroup
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
| ------------------------------- | ------------- | ------------------------------- |
|
||||
| message | action | /cosmos.group.v1.Msg/LeaveGroup |
|
||||
| cosmos.group.v1.EventLeaveGroup | proposal_id | {proposalId} |
|
||||
| cosmos.group.v1.EventLeaveGroup | address | {address} |
|
||||
@ -1,52 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Metadata
|
||||
|
||||
The group module has four locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the group and gov modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains.
|
||||
|
||||
## Proposal
|
||||
Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../../gov/spec/08_metadata.md#proposal))
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "",
|
||||
"authors": "",
|
||||
"summary": "",
|
||||
"details": "",
|
||||
"proposalForumURL": "",
|
||||
"voteOptionContext": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Vote
|
||||
Location: on-chain as json within 255 character limit (mirrors [gov vote](../../gov/spec/08_metadata.md#vote))
|
||||
|
||||
```json
|
||||
{
|
||||
"justification": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Group
|
||||
Location: off-chain as json object stored on IPFS
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "",
|
||||
"description": "",
|
||||
"groupWebsiteURL": "",
|
||||
"groupForumURL": "",
|
||||
}
|
||||
```
|
||||
|
||||
## Decision policy
|
||||
Location: on-chain as json within 255 character limit
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "",
|
||||
"description": "",
|
||||
}
|
||||
```
|
||||
@ -1,63 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Group Overview
|
||||
parent:
|
||||
title: "group"
|
||||
-->
|
||||
|
||||
# Group Module
|
||||
|
||||
## Abstract
|
||||
|
||||
The following documents specify the group module.
|
||||
|
||||
This module allows the creation and management of on-chain multisig accounts and enables voting for message execution based on configurable decision policies.
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concepts](01_concepts.md)**
|
||||
- [Group](01_concepts.md#group)
|
||||
- [Group Policy](01_concepts.md#group-policy)
|
||||
- [Group With Policy](01_concepts.md#group-with-policy)
|
||||
- [Decision Policy](01_concepts.md#decision-policy)
|
||||
- [Proposal](01_concepts.md#proposal)
|
||||
- [Voting](01_concepts.md#voting)
|
||||
- [Executing Proposals](01_concepts.md#executing-proposals)
|
||||
2. **[State](02_state.md)**
|
||||
* [Group Table](02_state.md#group-table)
|
||||
* [Group Member Table](02_state.md#group-member-table)
|
||||
* [Group Policy Table](02_state.md#group-policy-table)
|
||||
* [Proposal](02_state.md#proposal-table)
|
||||
* [Vote Table](02_state.md#vote-table)
|
||||
3. **[Msg Service](03_messages.md)**
|
||||
- [Msg/CreateGroup](03_messages.md#msgcreategroup)
|
||||
- [Msg/UpdateGroupMembers](03_messages.md#msgupdategroupmembers)
|
||||
- [Msg/UpdateGroupAdmin](03_messages.md#msgupdategroupadmin)
|
||||
- [Msg/UpdateGroupMetadata](03_messages.md#msgupdategroupmetadata)
|
||||
- [Msg/CreateGroupPolicy](03_messages.md#msgcreategrouppolicy)
|
||||
- [Msg/CreateGroupWithPolicy](03_messages.md#msgcreategroupwithpolicy)
|
||||
- [Msg/UpdateGroupPolicyAdmin](03_messages.md#msgupdategrouppolicyadmin)
|
||||
- [Msg/UpdateGroupPolicyDecisionPolicy](03_messages.md#msgupdategrouppolicydecisionpolicy)
|
||||
- [Msg/UpdateGroupPolicyMetadata](03_messages.md#msgupdategrouppolicymetadata)
|
||||
- [Msg/CreateProposal](03_messages.md#msgcreateproposal)
|
||||
- [Msg/WithdrawProposal](03_messages.md#msgwithdrawproposal)
|
||||
- [Msg/Vote](03_messages.md#msgvote)
|
||||
- [Msg/Exec](03_messages.md#msgexec)
|
||||
4. **[Events](04_events.md)**
|
||||
* [EventCreateGroup](04_events.md#eventcreategroup)
|
||||
* [EventUpdateGroup](04_events.md#eventupdategroup)
|
||||
* [EventCreateGroupPolicy](04_events.md#eventcreategrouppolicy)
|
||||
* [EventUpdateGroupPolicy](04_events.md#eventupdategrouppolicy)
|
||||
* [EventCreateProposal](04_events.md#eventcreateproposal)
|
||||
* [EventWithdrawProposal](04_events.md#eventwithdrawproposal)
|
||||
* [EventVote](04_events.md#eventvote)
|
||||
* [EventExec](04_events.md#eventexec)
|
||||
5. **[Client](05_client.md)**
|
||||
* [CLI](05_client.md#cli)
|
||||
* [gRPC](05_client.md#grpc)
|
||||
* [REST](05_client.md#rest)
|
||||
6. **[Metadata](06_metadata.md)**
|
||||
* [Proposal](06_metadata.md#proposal)
|
||||
* [Vote](06_metadata.md#vote)
|
||||
* [Group](06_metadata.md#group)
|
||||
* [Decision policy](06_metadata.md#decision%20policy)
|
||||
386
x/mint/README.md
386
x/mint/README.md
@ -1,7 +1,389 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Mint Overview
|
||||
parent:
|
||||
title: "mint"
|
||||
-->
|
||||
|
||||
# Mint
|
||||
# `x/mint`
|
||||
|
||||
* [Mint](spec/README.md) - Creation of new units of staking token.
|
||||
## Contents
|
||||
|
||||
* [State](#state)
|
||||
* [Minter](#minter)
|
||||
* [Params](#params)
|
||||
* [Begin-Block](#begin-block)
|
||||
* [NextInflationRate](#nextinflationrate)
|
||||
* [NextAnnualProvisions](#nextannualprovisions)
|
||||
* [BlockProvision](#blockprovision)
|
||||
* [Parameters](#parameters)
|
||||
* [Events](#events)
|
||||
* [BeginBlocker](#beginblocker)
|
||||
* [Client](#client)
|
||||
* [CLI](#cli)
|
||||
* [gRPC](#grpc)
|
||||
* [REST](#rest)
|
||||
|
||||
# Concepts
|
||||
|
||||
## The Minting Mechanism
|
||||
|
||||
The minting mechanism was designed to:
|
||||
|
||||
* allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio
|
||||
* effect a balance between market liquidity and staked supply
|
||||
|
||||
In order to best determine the appropriate market rate for inflation rewards, a
|
||||
moving change rate is used. The moving change rate mechanism ensures that if
|
||||
the % bonded is either over or under the goal %-bonded, the inflation rate will
|
||||
adjust to further incentivize or disincentivize being bonded, respectively. Setting the goal
|
||||
%-bonded at less than 100% encourages the network to maintain some non-staked tokens
|
||||
which should help provide some liquidity.
|
||||
|
||||
It can be broken down in the following way:
|
||||
|
||||
* If the inflation rate is below the goal %-bonded the inflation rate will
|
||||
increase until a maximum value is reached
|
||||
* If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation
|
||||
rate will stay constant
|
||||
* If the inflation rate is above the goal %-bonded the inflation rate will
|
||||
decrease until a minimum value is reached
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# State
|
||||
|
||||
## Minter
|
||||
|
||||
The minter is a space for holding current inflation information.
|
||||
|
||||
* Minter: `0x00 -> ProtocolBuffer(minter)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L9-L23
|
||||
|
||||
## Params
|
||||
|
||||
The mint module stores it's params in state with the prefix of `0x01`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `mint/params -> legacy_amino(params)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L25-L57
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# Begin-Block
|
||||
|
||||
Minting parameters are recalculated and inflation
|
||||
paid at the beginning of each block.
|
||||
|
||||
## Inflation rate calculation
|
||||
|
||||
Inflation rate is calculated using an "inflation calculation function" that's
|
||||
passed to the `NewAppModule` function. If no function is passed, then the SDK's
|
||||
default inflation function will be used (`NextInflationRate`). In case a custom
|
||||
inflation calculation logic is needed, this can be achieved by defining and
|
||||
passing a function that matches `InflationCalculationFn`'s signature.
|
||||
|
||||
```go
|
||||
type InflationCalculationFn func(ctx sdk.Context, minter Minter, params Params, bondedRatio sdk.Dec) sdk.Dec
|
||||
```
|
||||
|
||||
### NextInflationRate
|
||||
|
||||
The target annual inflation rate is recalculated each block.
|
||||
The inflation is also subject to a rate change (positive or negative)
|
||||
depending on the distance from the desired ratio (67%). The maximum rate change
|
||||
possible is defined to be 13% per year, however the annual inflation is capped
|
||||
as between 7% and 20%.
|
||||
|
||||
```go
|
||||
NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
||||
inflationRateChange = inflationRateChangePerYear/blocksPerYr
|
||||
|
||||
// increase the new annual inflation for this next cycle
|
||||
inflation += inflationRateChange
|
||||
if inflation > params.InflationMax {
|
||||
inflation = params.InflationMax
|
||||
}
|
||||
if inflation < params.InflationMin {
|
||||
inflation = params.InflationMin
|
||||
}
|
||||
|
||||
return inflation
|
||||
}
|
||||
```
|
||||
|
||||
## NextAnnualProvisions
|
||||
|
||||
Calculate the annual provisions based on current total supply and inflation
|
||||
rate. This parameter is calculated once per block.
|
||||
|
||||
```go
|
||||
NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) {
|
||||
return Inflation * totalSupply
|
||||
```
|
||||
|
||||
## BlockProvision
|
||||
|
||||
Calculate the provisions generated for each block based on current annual provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount` and then transferred to the `auth`'s `FeeCollector` `ModuleAccount`.
|
||||
|
||||
```go
|
||||
BlockProvision(params Params) sdk.Coin {
|
||||
provisionAmt = AnnualProvisions/ params.BlocksPerYear
|
||||
return sdk.NewCoin(params.MintDenom, provisionAmt.Truncate())
|
||||
```
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Parameters
|
||||
|
||||
The minting module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
|---------------------|-----------------|------------------------|
|
||||
| MintDenom | string | "uatom" |
|
||||
| InflationRateChange | string (dec) | "0.130000000000000000" |
|
||||
| InflationMax | string (dec) | "0.200000000000000000" |
|
||||
| InflationMin | string (dec) | "0.070000000000000000" |
|
||||
| GoalBonded | string (dec) | "0.670000000000000000" |
|
||||
| BlocksPerYear | string (uint64) | "6311520" |
|
||||
|
||||
<!-- order: 4 -->
|
||||
|
||||
# Events
|
||||
|
||||
The minting module emits the following events:
|
||||
|
||||
## BeginBlocker
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|------|-------------------|--------------------|
|
||||
| mint | bonded_ratio | {bondedRatio} |
|
||||
| mint | inflation | {inflation} |
|
||||
| mint | annual_provisions | {annualProvisions} |
|
||||
| mint | amount | {amount} |
|
||||
|
||||
<!-- order: 5 -->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `mint` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `mint` state.
|
||||
|
||||
```sh
|
||||
simd query mint --help
|
||||
```
|
||||
|
||||
#### annual-provisions
|
||||
|
||||
The `annual-provisions` command allow users to query the current minting annual provisions value
|
||||
|
||||
```sh
|
||||
simd query mint annual-provisions [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query mint annual-provisions
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```sh
|
||||
22268504368893.612100895088410693
|
||||
```
|
||||
|
||||
#### inflation
|
||||
|
||||
The `inflation` command allow users to query the current minting inflation value
|
||||
|
||||
```sh
|
||||
simd query mint inflation [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query mint inflation
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```sh
|
||||
0.199200302563256955
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allow users to query the current minting parameters
|
||||
|
||||
```sh
|
||||
simd query mint params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```yml
|
||||
blocks_per_year: "4360000"
|
||||
goal_bonded: "0.670000000000000000"
|
||||
inflation_max: "0.200000000000000000"
|
||||
inflation_min: "0.070000000000000000"
|
||||
inflation_rate_change: "0.130000000000000000"
|
||||
mint_denom: stake
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `mint` module using gRPC endpoints.
|
||||
|
||||
### AnnualProvisions
|
||||
|
||||
The `AnnualProvisions` endpoint allow users to query the current minting annual provisions value
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/AnnualProvisions
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/AnnualProvisions
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"annualProvisions": "1432452520532626265712995618"
|
||||
}
|
||||
```
|
||||
|
||||
### Inflation
|
||||
|
||||
The `Inflation` endpoint allow users to query the current minting inflation value
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/Inflation
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Inflation
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"inflation": "130197115720711261"
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allow users to query the current minting parameters
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"mintDenom": "stake",
|
||||
"inflationRateChange": "130000000000000000",
|
||||
"inflationMax": "200000000000000000",
|
||||
"inflationMin": "70000000000000000",
|
||||
"goalBonded": "670000000000000000",
|
||||
"blocksPerYear": "6311520"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `mint` module using REST endpoints.
|
||||
|
||||
### annual-provisions
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/annual_provisions
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/annual_provisions"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"annualProvisions": "1432452520532626265712995618"
|
||||
}
|
||||
```
|
||||
|
||||
### inflation
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/inflation
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/inflation"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"inflation": "130197115720711261"
|
||||
}
|
||||
```
|
||||
|
||||
### params
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/params"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"mintDenom": "stake",
|
||||
"inflationRateChange": "130000000000000000",
|
||||
"inflationMax": "200000000000000000",
|
||||
"inflationMin": "70000000000000000",
|
||||
"goalBonded": "670000000000000000",
|
||||
"blocksPerYear": "6311520"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## The Minting Mechanism
|
||||
|
||||
The minting mechanism was designed to:
|
||||
|
||||
* allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio
|
||||
* effect a balance between market liquidity and staked supply
|
||||
|
||||
In order to best determine the appropriate market rate for inflation rewards, a
|
||||
moving change rate is used. The moving change rate mechanism ensures that if
|
||||
the % bonded is either over or under the goal %-bonded, the inflation rate will
|
||||
adjust to further incentivize or disincentivize being bonded, respectively. Setting the goal
|
||||
%-bonded at less than 100% encourages the network to maintain some non-staked tokens
|
||||
which should help provide some liquidity.
|
||||
|
||||
It can be broken down in the following way:
|
||||
|
||||
* If the inflation rate is below the goal %-bonded the inflation rate will
|
||||
increase until a maximum value is reached
|
||||
* If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation
|
||||
rate will stay constant
|
||||
* If the inflation rate is above the goal %-bonded the inflation rate will
|
||||
decrease until a minimum value is reached
|
||||
@ -1,22 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# State
|
||||
|
||||
## Minter
|
||||
|
||||
The minter is a space for holding current inflation information.
|
||||
|
||||
* Minter: `0x00 -> ProtocolBuffer(minter)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L9-L23
|
||||
|
||||
## Params
|
||||
|
||||
The mint module stores it's params in state with the prefix of `0x01`,
|
||||
it can be updated with governance or the address with authority.
|
||||
|
||||
* Params: `mint/params -> legacy_amino(params)`
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L25-L57
|
||||
@ -1,66 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Begin-Block
|
||||
|
||||
Minting parameters are recalculated and inflation
|
||||
paid at the beginning of each block.
|
||||
|
||||
## Inflation rate calculation
|
||||
|
||||
Inflation rate is calculated using an "inflation calculation function" that's
|
||||
passed to the `NewAppModule` function. If no function is passed, then the SDK's
|
||||
default inflation function will be used (`NextInflationRate`). In case a custom
|
||||
inflation calculation logic is needed, this can be achieved by defining and
|
||||
passing a function that matches `InflationCalculationFn`'s signature.
|
||||
|
||||
```go
|
||||
type InflationCalculationFn func(ctx sdk.Context, minter Minter, params Params, bondedRatio sdk.Dec) sdk.Dec
|
||||
```
|
||||
|
||||
### NextInflationRate
|
||||
|
||||
The target annual inflation rate is recalculated each block.
|
||||
The inflation is also subject to a rate change (positive or negative)
|
||||
depending on the distance from the desired ratio (67%). The maximum rate change
|
||||
possible is defined to be 13% per year, however the annual inflation is capped
|
||||
as between 7% and 20%.
|
||||
|
||||
```go
|
||||
NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
||||
inflationRateChange = inflationRateChangePerYear/blocksPerYr
|
||||
|
||||
// increase the new annual inflation for this next cycle
|
||||
inflation += inflationRateChange
|
||||
if inflation > params.InflationMax {
|
||||
inflation = params.InflationMax
|
||||
}
|
||||
if inflation < params.InflationMin {
|
||||
inflation = params.InflationMin
|
||||
}
|
||||
|
||||
return inflation
|
||||
}
|
||||
```
|
||||
|
||||
## NextAnnualProvisions
|
||||
|
||||
Calculate the annual provisions based on current total supply and inflation
|
||||
rate. This parameter is calculated once per block.
|
||||
|
||||
```go
|
||||
NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) {
|
||||
return Inflation * totalSupply
|
||||
```
|
||||
|
||||
## BlockProvision
|
||||
|
||||
Calculate the provisions generated for each block based on current annual provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount` and then transferred to the `auth`'s `FeeCollector` `ModuleAccount`.
|
||||
|
||||
```go
|
||||
BlockProvision(params Params) sdk.Coin {
|
||||
provisionAmt = AnnualProvisions/ params.BlocksPerYear
|
||||
return sdk.NewCoin(params.MintDenom, provisionAmt.Truncate())
|
||||
```
|
||||
@ -1,16 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Parameters
|
||||
|
||||
The minting module contains the following parameters:
|
||||
|
||||
| Key | Type | Example |
|
||||
|---------------------|-----------------|------------------------|
|
||||
| MintDenom | string | "uatom" |
|
||||
| InflationRateChange | string (dec) | "0.130000000000000000" |
|
||||
| InflationMax | string (dec) | "0.200000000000000000" |
|
||||
| InflationMin | string (dec) | "0.070000000000000000" |
|
||||
| GoalBonded | string (dec) | "0.670000000000000000" |
|
||||
| BlocksPerYear | string (uint64) | "6311520" |
|
||||
@ -1,16 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Events
|
||||
|
||||
The minting module emits the following events:
|
||||
|
||||
## BeginBlocker
|
||||
|
||||
| Type | Attribute Key | Attribute Value |
|
||||
|------|-------------------|--------------------|
|
||||
| mint | bonded_ratio | {bondedRatio} |
|
||||
| mint | inflation | {inflation} |
|
||||
| mint | annual_provisions | {annualProvisions} |
|
||||
| mint | amount | {amount} |
|
||||
@ -1,224 +0,0 @@
|
||||
<!--
|
||||
order: 6
|
||||
-->
|
||||
|
||||
# Client
|
||||
|
||||
## CLI
|
||||
|
||||
A user can query and interact with the `mint` module using the CLI.
|
||||
|
||||
### Query
|
||||
|
||||
The `query` commands allow users to query `mint` state.
|
||||
|
||||
```sh
|
||||
simd query mint --help
|
||||
```
|
||||
|
||||
#### annual-provisions
|
||||
|
||||
The `annual-provisions` command allow users to query the current minting annual provisions value
|
||||
|
||||
```sh
|
||||
simd query mint annual-provisions [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query mint annual-provisions
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```sh
|
||||
22268504368893.612100895088410693
|
||||
```
|
||||
|
||||
#### inflation
|
||||
|
||||
The `inflation` command allow users to query the current minting inflation value
|
||||
|
||||
```sh
|
||||
simd query mint inflation [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
simd query mint inflation
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```sh
|
||||
0.199200302563256955
|
||||
```
|
||||
|
||||
#### params
|
||||
|
||||
The `params` command allow users to query the current minting parameters
|
||||
|
||||
```sh
|
||||
simd query mint params [flags]
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```yml
|
||||
blocks_per_year: "4360000"
|
||||
goal_bonded: "0.670000000000000000"
|
||||
inflation_max: "0.200000000000000000"
|
||||
inflation_min: "0.070000000000000000"
|
||||
inflation_rate_change: "0.130000000000000000"
|
||||
mint_denom: stake
|
||||
```
|
||||
|
||||
## gRPC
|
||||
|
||||
A user can query the `mint` module using gRPC endpoints.
|
||||
|
||||
### AnnualProvisions
|
||||
|
||||
The `AnnualProvisions` endpoint allow users to query the current minting annual provisions value
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/AnnualProvisions
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/AnnualProvisions
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"annualProvisions": "1432452520532626265712995618"
|
||||
}
|
||||
```
|
||||
|
||||
### Inflation
|
||||
|
||||
The `Inflation` endpoint allow users to query the current minting inflation value
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/Inflation
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Inflation
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"inflation": "130197115720711261"
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
The `Params` endpoint allow users to query the current minting parameters
|
||||
|
||||
```sh
|
||||
/cosmos.mint.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Params
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"mintDenom": "stake",
|
||||
"inflationRateChange": "130000000000000000",
|
||||
"inflationMax": "200000000000000000",
|
||||
"inflationMin": "70000000000000000",
|
||||
"goalBonded": "670000000000000000",
|
||||
"blocksPerYear": "6311520"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## REST
|
||||
|
||||
A user can query the `mint` module using REST endpoints.
|
||||
|
||||
### annual-provisions
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/annual_provisions
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/annual_provisions"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"annualProvisions": "1432452520532626265712995618"
|
||||
}
|
||||
```
|
||||
|
||||
### inflation
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/inflation
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/inflation"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"inflation": "130197115720711261"
|
||||
}
|
||||
```
|
||||
|
||||
### params
|
||||
|
||||
```sh
|
||||
/cosmos/mint/v1beta1/params
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
curl "localhost:1317/cosmos/mint/v1beta1/params"
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"params": {
|
||||
"mintDenom": "stake",
|
||||
"inflationRateChange": "130000000000000000",
|
||||
"inflationMax": "200000000000000000",
|
||||
"inflationMin": "70000000000000000",
|
||||
"goalBonded": "670000000000000000",
|
||||
"blocksPerYear": "6311520"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,26 +0,0 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: Mint Overview
|
||||
parent:
|
||||
title: "mint"
|
||||
-->
|
||||
|
||||
# `mint`
|
||||
|
||||
## Contents
|
||||
|
||||
1. **[Concept](01_concepts.md)**
|
||||
2. **[State](02_state.md)**
|
||||
* [Minter](02_state.md#minter)
|
||||
* [Params](02_state.md#params)
|
||||
3. **[Begin-Block](03_begin_block.md)**
|
||||
* [NextInflationRate](03_begin_block.md#nextinflationrate)
|
||||
* [NextAnnualProvisions](03_begin_block.md#nextannualprovisions)
|
||||
* [BlockProvision](03_begin_block.md#blockprovision)
|
||||
4. **[Parameters](04_params.md)**
|
||||
5. **[Events](05_events.md)**
|
||||
* [BeginBlocker](05_events.md#beginblocker)
|
||||
6. **[Client](06_client.md)**
|
||||
* [CLI](06_client.md#cli)
|
||||
* [gRPC](06_client.md#grpc)
|
||||
* [REST](06_client.md#rest)
|
||||
88
x/nft/README.md
Normal file
88
x/nft/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
<!--
|
||||
order: 0
|
||||
title: NFT Overview
|
||||
parent:
|
||||
title: "nft"
|
||||
-->
|
||||
|
||||
# `x/nft`
|
||||
|
||||
## Contents
|
||||
|
||||
## Abstract
|
||||
|
||||
`x/nft` is an implementation of a Cosmos SDK module, per [ADR 43](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md), that allows you to create nft classification, create nft, transfer nft, update nft, and support various queries by integrating the module. It is fully compatible with the ERC721 specification.
|
||||
|
||||
* [Concept](#concepts)
|
||||
* [Class](#class)
|
||||
* [NFT](#nft)
|
||||
*[State](#state)
|
||||
*[Messages](#messages)
|
||||
* [MsgSend](#msgsend)
|
||||
*[Events](#events)
|
||||
|
||||
# Concepts
|
||||
|
||||
## Class
|
||||
|
||||
`x/nft` module defines a struct `Class` to describe the common characteristics of a class of nft, under this class, you can create a variety of nft, which is equivalent to an erc721 contract for Ethereum. The design is defined in the [ADR 043](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md).
|
||||
|
||||
## NFT
|
||||
|
||||
The full name of NFT is Non-Fungible Tokens. Because of the irreplaceable nature of NFT, it means that it can be used to represent unique things. The nft implemented by this module is fully compatible with Ethereum ERC721 standard.
|
||||
|
||||
<!-- order: 1 -->
|
||||
|
||||
# State
|
||||
|
||||
## Class
|
||||
|
||||
Class is mainly composed of `id`, `name`, `symbol`, `description`, `uri`, `uri_hash`,`data` where `id` is the unique identifier of the class, similar to the Ethereum ERC721 contract address, the others are optional.
|
||||
|
||||
* Class: `0x01 | classID | -> ProtocolBuffer(Class)`
|
||||
|
||||
## NFT
|
||||
|
||||
NFT is mainly composed of `class_id`, `id`, `uri`, `uri_hash` and `data`. Among them, `class_id` and `id` are two-tuples that identify the uniqueness of nft, `uri` and `uri_hash` is optional, which identifies the off-chain storage location of the nft, and `data` is an Any type. Use Any chain of `x/nft` modules can be customized by extending this field
|
||||
|
||||
* NFT: `0x02 | classID | 0x00 | nftID |-> ProtocolBuffer(NFT)`
|
||||
|
||||
## NFTOfClassByOwner
|
||||
|
||||
NFTOfClassByOwner is mainly to realize the function of querying all nfts using classID and owner, without other redundant functions.
|
||||
|
||||
* NFTOfClassByOwner: `0x03 | owner | 0x00 | classID | 0x00 | nftID |-> 0x01`
|
||||
|
||||
## Owner
|
||||
|
||||
Since there is no extra field in NFT to indicate the owner of nft, an additional key-value pair is used to save the ownership of nft. With the transfer of nft, the key-value pair is updated synchronously.
|
||||
|
||||
* OwnerKey: `0x04 | classID | 0x00 | nftID |-> owner`
|
||||
|
||||
## TotalSupply
|
||||
|
||||
TotalSupply is responsible for tracking the number of all nfts under a certain class. Mint operation is performed under the changed class, supply increases by one, burn operation, and supply decreases by one.
|
||||
|
||||
* OwnerKey: `0x05 | classID |-> totalSupply`
|
||||
|
||||
<!-- order: 2 -->
|
||||
|
||||
# Messages
|
||||
|
||||
In this section we describe the processing of messages for the nft module.
|
||||
|
||||
## MsgSend
|
||||
|
||||
You can use the `MsgSend` message to transfer the ownership of nft. This is a function provided by the `x/nft` module. Of course, you can use the `Transfer` method to implement your own transfer logic, but you need to pay extra attention to the transfer permissions.
|
||||
|
||||
The message handling should fail if:
|
||||
|
||||
* provided `ClassID` is not exist.
|
||||
* provided `Id` is not exist.
|
||||
* provided `Sender` is not the owner of nft.
|
||||
|
||||
<!-- order: 3 -->
|
||||
|
||||
# Events
|
||||
|
||||
The nft module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main:cosmos.nft.v1beta1).
|
||||
@ -1,13 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# Concepts
|
||||
|
||||
## Class
|
||||
|
||||
`x/nft` module defines a struct `Class` to describe the common characteristics of a class of nft, under this class, you can create a variety of nft, which is equivalent to an erc721 contract for Ethereum. The design is defined in the [ADR 043](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md).
|
||||
|
||||
## NFT
|
||||
|
||||
The full name of NFT is Non-Fungible Tokens. Because of the irreplaceable nature of NFT, it means that it can be used to represent unique things. The nft implemented by this module is fully compatible with Ethereum ERC721 standard.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user