Abstract
This paper specifies the Governance module of the Cosmos SDK, which was first described in the Cosmos 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, the proposal enters voting period. The minimum deposit can be reached by collecting deposits from different users (including proposer) within deposit period.
- Vote: Participants can vote on proposals that reached MinDeposit and entered voting period.
- 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 rejected. If the proposal was vetoed, or never entered voting period (minimum deposit not reached within deposit period), the deposit is burned.
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.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 sendTxGovVotetransactions 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 aMsgSubmitProposal transaction.
Once a proposal is submitted, it is identified by its unique proposalID.
Proposal Messages
A proposal includes an array ofsdk.Msgs 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 theMinDeposit 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 ModuleAccountand 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 when participants have bonded and unbonded Atoms, their voting power is calculated from their bonded Atom holdings only.Voting period
Once a proposal reachesMinDeposit, it immediately enters Voting period. We
define Voting period as the interval between the moment the vote opens and
the moment the vote closes. 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 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.options field must not contain duplicate vote options, and the sum of weights of all options must be equal to 1.
Custom Vote Calculation
Cosmos SDK v0.53.0 introduced an option for developers to define a custom vote result and voting power calculation function.- Quadratic Voting
- Time-weighted Voting
- Reputation-Based voting
Example
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.Expedited Proposals
A proposal can be expedited, making the proposal use shorter voting duration and a higher tally threshold by its default. If an expedited proposal fails to meet the threshold within the scope of shorter voting duration, the expedited proposal is then converted to a regular proposal and restarts voting under regular voting conditions.Threshold
Threshold is defined as the minimum proportion ofYes 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 Abstainvotes is inferior to 1/1.
- The proportion of NoWithVetovotes is inferior to 1/3, includingAbstainvotes.
- The proportion of Yesvotes, excludingAbstainvotes, 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, when tallied at 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, theGovernance address will be the main validator address generated at account creation. This address corresponds to a different PrivKey than the CometBFT PrivKey which is responsible for signing consensus messages. Validators thus do not have to sign governance transactions with the sensitive CometBFT PrivKey.
Burnable Params
There are three parameters that define if the deposit of a proposal should be burned or returned to the depositors.- BurnVoteVetoburns the proposal deposit if the proposal gets vetoed.
- BurnVoteQuorumburns the proposal deposit if the proposal deposit if the vote does not reach quorum.
- BurnProposalDepositPrevoteburns the proposal deposit if it does not enter the voting phase.
Note: These parameters are modifiable via governance.
State
Constitution
Constitution is found in the genesis state.  It is a string field intended to be used to descibe the purpose of a particular blockchain, and its expected norms.  A few examples of how the constitution field can be used:
- define the purpose of the chain, laying a foundation for its future development
- set expectations for delegators
- set expectations for validators
- define the chain’s relationship to “meatspace” entities, like a foundation or corporation
- What limitations on governance exist, if any?
- is it okay for the community to slash the wallet of a whale that they no longer feel that they want around? (viz: Juno Proposal 4 and 16)
- can governance “socially slash” a validator who is using unapproved MEV? (viz: commonwealth.im/osmosis)
- In the event of an economic emergency, what should validators do?
- Terra crash of May, 2022, saw validators choose to run a new binary with code that had not been approved by governance, because the governance token had been inflated to nothing.
 
 
- What is the purpose of the chain, specifically?
- best example of this is the Cosmos hub, where different founding groups, have different interpertations of the purpose of the network.
 
- validators
- token holders
- developers (yourself)
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
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. To support the case of
interoperability across networks, the SDK recommends that the metadata represents
the following JSON template:
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 andMsgServer 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
VotingParams
TallyParams
GlobalParams KVStore.
Additionally, we introduce some basic types:
Deposit
ValidatorGovInfo
This type is used in a temp map when tallyingStores
Stores are KVStores in the multi-store. The key to find the store is the first parameter in the list
Governance to store four mappings:
- A mapping from proposalID|'proposal'toProposal.
- A mapping from proposalID|'addresses'|addresstoVote. This mapping allows us to query all addresses that voted on the proposal along with their vote by doing a range query onproposalID:addresses.
- A mapping from ParamsKey|'Params'toParams. This map allows to query all x/gov params.
- A mapping from VotingPeriodProposalKeyPrefix|proposalIDto a single byte. This allows us to know if a proposal is in the voting period or not with very low gas cost.
- load(StoreKey, Key): Retrieve item stored at key- Keyin store found at key- StoreKeyin the multistore
- store(StoreKey, Key, value): Write value- Valueat key- Keyin store found at key- StoreKeyin the multistore
Proposal Processing Queue
Store:- ProposalProcessingQueue: A queue- queue[proposalID]containing all the- ProposalIDsof 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- Handleris executed.
ProposalProcessingQueue:
Legacy Proposal
Legacy proposals are deprecated. Use the new proposal flow by granting the governance module the right to execute the message.
Messages
Proposal Submission
Proposals can be submitted by any account via aMsgSubmitProposal transaction.
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.
The initialDeposit must be strictly positive and conform to the accepted denom of the MinDeposit param.
State modifications:
- Generate new proposalID
- Create new Proposal
- Initialise Proposal’s attributes
- Decrease balance of sender by InitialDeposit
- If MinDepositis reached:- Push proposalIDinProposalProcessingQueue
 
- Push 
- Transfer InitialDepositfrom theProposerto the governanceModuleAccount
Deposit
Once a proposal is submitted, ifProposal.TotalDeposit < ActiveParam.MinDeposit, Atom holders can send
MsgDeposit transactions to increase the proposal’s deposit.
A deposit is accepted iff:
- The proposal exists
- The proposal is not in the voting period
- The deposited coins are conform to the accepted denom from the MinDepositparam
- Decrease balance of sender by deposit
- Add depositof sender inproposal.Deposits
- Increase proposal.TotalDepositby sender’sdeposit
- If MinDepositis reached:- Push proposalIDinProposalProcessingQueueEnd
 
- Push 
- Transfer Depositfrom theproposerto the governanceModuleAccount
Vote
OnceActiveParam.MinDeposit is reached, voting period starts. From there,
bonded Atom holders are able to send MsgVote transactions to cast their
vote on the proposal.
- Record Voteof sender
Gas cost for this message has to take into account the future tallying of the vote in EndBlocker.
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.
Parameters
The governance module contains the following parameters:| Key | Type | Example | 
|---|---|---|
| min_deposit | array (coins) | [ {"denom":"uatom","amount":"10000000"}] | 
| max_deposit_period | string (time ns) | “172800000000000” (17280s) | 
| voting_period | string (time ns) | “172800000000000” (17280s) | 
| quorum | string (dec) | “0.334000000000000000” | 
| threshold | string (dec) | “0.500000000000000000” | 
| veto | string (dec) | “0.334000000000000000” | 
| expedited_threshold | string (time ns) | “0.667000000000000000” | 
| expedited_voting_period | string (time ns) | “86400000000000” (8600s) | 
| expedited_min_deposit | array (coins) | [ {"denom":"uatom","amount":"50000000"}] | 
| burn_proposal_deposit_prevote | bool | false | 
| burn_vote_quorum | bool | false | 
| burn_vote_veto | bool | true | 
| min_initial_deposit_ratio | string | ”0.1” | 
Client
CLI
A user can query and interact with thegov module using the CLI.
Query
Thequery commands allow users to query gov state.
deposit
Thedeposit command allows users to query a deposit for a given proposal from a given depositor.
deposits
Thedeposits command allows users to query all deposits for a given proposal.
param
Theparam command allows users to query a given parameter for the gov module.
params
Theparams command allows users to query all parameters for the gov module.
proposal
Theproposal command allows users to query a given proposal.
proposals
Theproposals command allows users to query all proposals with optional filters.
proposer
Theproposer command allows users to query the proposer for a given proposal.
tally
Thetally command allows users to query the tally of a given proposal vote.
vote
Thevote command allows users to query a vote for a given proposal.
votes
Thevotes command allows users to query all votes for a given proposal.
Transactions
Thetx commands allow users to interact with the gov module.
deposit
Thedeposit command allows users to deposit tokens for a given proposal.
draft-proposal
Thedraft-proposal command allows users to draft any type of proposal.
The command returns a draft_proposal.json, to be used by submit-proposal after being completed.
The draft_metadata.json is meant to be uploaded to IPFS.
submit-proposal
Thesubmit-proposal command allows users to submit a governance proposal along with some messages and metadata.
Messages, metadata and deposit are defined in a JSON file.
proposal.json contains:
By default the metadata, summary and title are both limited by 255 characters, this can be overridden by the application developer.
When metadata is not specified, the title is limited to 255 characters and the summary 40x the title length.
submit-legacy-proposal
Thesubmit-legacy-proposal command allows users to submit a governance legacy proposal along with an initial deposit.
param-change):
cancel-proposal
Once proposal is canceled, from the deposits of proposaldeposits * proposal_cancel_ratio will be burned or sent to ProposalCancelDest address , if ProposalCancelDest is empty then deposits will be burned. The remaining deposits will be sent to depositers.
vote
Thevote command allows users to submit a vote for a given governance proposal.
weighted-vote
Theweighted-vote command allows users to submit a weighted vote for a given governance proposal.
gRPC
A user can query thegov module using gRPC endpoints.
Proposal
TheProposal endpoint allows users to query a given proposal.
Using legacy v1beta1:
Proposals
TheProposals endpoint allows users to query all proposals with optional filters.
Using legacy v1beta1:
Vote
TheVote endpoint allows users to query a vote for a given proposal.
Using legacy v1beta1:
Votes
TheVotes endpoint allows users to query all votes for a given proposal.
Using legacy v1beta1:
Params
TheParams endpoint allows users to query all parameters for the gov module.
Using legacy v1beta1:
Deposit
TheDeposit endpoint allows users to query a deposit for a given proposal from a given depositor.
Using legacy v1beta1:
deposits
TheDeposits endpoint allows users to query all deposits for a given proposal.
Using legacy v1beta1:
TallyResult
TheTallyResult endpoint allows users to query the tally of a given proposal.
Using legacy v1beta1:
REST
A user can query thegov module using REST endpoints.
proposal
Theproposals endpoint allows users to query a given proposal.
Using legacy v1beta1:
proposals
Theproposals endpoint also allows users to query all proposals with optional filters.
Using legacy v1beta1:
voter vote
Thevotes endpoint allows users to query a vote for a given proposal.
Using legacy v1beta1:
votes
Thevotes endpoint allows users to query all votes for a given proposal.
Using legacy v1beta1:
params
Theparams endpoint allows users to query all parameters for the gov module.
Using legacy v1beta1:
deposits
Thedeposits endpoint allows users to query a deposit for a given proposal from a given depositor.
Using legacy v1beta1:
proposal deposits
Thedeposits endpoint allows users to query all deposits for a given proposal.
Using legacy v1beta1:
tally
Thetally endpoint allows users to query the tally of a given proposal.
Using legacy v1beta1:
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)The 
authors field is an array of strings, this is to allow for multiple authors to be listed in the metadata.
In v0.46, the authors field is a comma-separated string. Frontends are encouraged to support both formats for backwards compatibility.Vote
Location: on-chain as json within 255 character limit (mirrors group vote)Future Improvements
The current documentation only describes the minimum viable product for the governance module. Future improvements may include:- BountyProposals: If accepted, a- BountyProposalcreates an open bounty. The- BountyProposalspecifies how many Atoms will be given upon completion. These Atoms will be taken from the- reserve pool. After a- BountyProposalis accepted by governance, anybody can submit a- SoftwareUpgradeProposalwith the code to claim the bounty. Note that once a- BountyProposalis accepted, the corresponding funds in the- reserve poolare locked so that payment can always be honored. In order to link a- SoftwareUpgradeProposalto an open bounty, the submitter of the- SoftwareUpgradeProposalwill use the- Proposal.LinkedProposalattribute. If a- SoftwareUpgradeProposallinked 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.