Governance
JMES's Governance module inherits from Cosmos SDK's gov module. This document is a stub, and mainly covers important JMES-specific notes on how it is used.
The JMES protocol is a decentralized public blockchain governed by community members. Governance is the democratic process that allows users and validators to make changes to the JMES protocol. Community members submit, vote, and implement proposals.
The governance module maintains the logic for all governance activity.
If you are an advanced user and want to learn about submitting or voting on proposals using JMESd, visit the Governance section of the JMESd Reference.
Concepts
The following concepts describe the governance proposal procedure.
Drafting and submission
Proposals start as ideas within the community on JMES's Discord. After gaining support and feedback from the community, a proposer drafts and submits a proposal.
To learn more about the different types of proposals, see the Proposal types section below.
Deposit period
After a proposal is submitted, it enters the deposit period, where it must reach a total minimum deposit of 512 bJMES within 7 days from the time of its submission. The deposit threshold is reached when the sum of the initial deposit (from the proposer) and the deposits from all other interested network participants meet or exceed 512 bJMES.
Deposits protect against unnecessary proposals and spam.
Deposits get refunded if all of the following conditions are met:
- The minimum deposit of 512 bJMES is reached within the 7-day deposit period.
Quorumis met: all casted votes represent more than 30% of all staked bJMES.- The total number of
NoWithVetovotes is less than 33.4% of the total vote. - A vote returns a majority of
YesorNovotes.
Deposits are burned under any of the following conditions:
- The minimum deposit of 512 bJMES is not reached within the one-week deposit period.
Quorumis not met: the number of total votes after the one-week voting period is less than 30% of all staked bJMES.- The number of
NoWithVetovotes is above 33.4% of the total vote.
Voting period
If the minimum deposit has been reached before the end of the deposit period, then the proposal goes into a one-week voting period. While the proposal is in voting, holders of staked bJMES can cast votes for the proposal.
Voting options
The 4 voting options available are:
Yes: in favor.No: not in favor.NoWithVeto: not in favor, and the creator should lose their deposit.Abstain: neither for or against. An abstain vote counts toward meeting quorum but does not count toward thethreshold.
Delegators vote using their staked bJMES. One staked bJMES equals one vote.
If a delegator does not specify a vote with their staked bJMES, their vote defaults to the vote cast by the validator their bJMES is staked to. Delegators can override a validator's vote at any time during the voting period by voting with their staked bJMES.
Tallying
The logic for tallying votes can be found in the tally.go file of the Cosmos SDK.
For a proposal to pass, the following conditions must be met.
- Voter participation must be at least
quorum(). The currentquorumvalue is 30% of all staked bJMES.
- The ratio of
NoWithVetovotes must be less thanveto(). The currentvetovalue is 33%.
- The ratio of
Yesvotes must be greater thanthreshold(). The currentthresholdvalue is 50%. Abstain votes are not included in thethresholdtally.
If a proposal meets all of the previous conditions, it passes. If a proposal fails to meet any of the previous conditions, it fails. Proposals that get rejected with veto do not get their deposits refunded. The parameters quorum, veto, and threshold exist as blockchain parameters in the Governance module.
Deposits will not be refunded for proposals that are rejected with veto, do not meet quorum, or fail to reach the minimum deposit during the deposit period. Non-refunded deposits are burned.
Proposal Implementation
Once a governance proposal passes, the changes described are put into effect by the proposal handler. Generic proposals such as a TextProposal must be reviewed by JMES protocol developers and the community for decisions on how to manually implement them.
Although parameter changes get updated immediately, they generally are not put into effect until the next epoch operation. Epochs occur every 100800 blocks or roughly every 7.7 days, given a 6.6-second block time.
Data
Proposal
_14type Proposal struct {_14 Content `json:"content" yaml:"content"` // Proposal content interface_14_14 ProposalID uint64 `json:"id" yaml:"id"` // ID of the proposal_14 Status ProposalStatus `json:"proposal_status" yaml:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}_14 FinalTallyResult TallyResult `json:"final_tally_result" yaml:"final_tally_result"` // Result of Tallies_14_14 SubmitTime time.Time `json:"submit_time" yaml:"submit_time"` // Time of the block where TxGovSubmitProposal was included_14 DepositEndTime time.Time `json:"deposit_end_time" yaml:"deposit_end_time"` // Time that the Proposal would expire if deposit amount isn't met_14 TotalDeposit sdk.Coins `json:"total_deposit" yaml:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit_14_14 VotingStartTime time.Time `json:"voting_start_time" yaml:"voting_start_time"` // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached_14 VotingEndTime time.Time `json:"voting_end_time" yaml:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied_14}
A Proposal is a data structure representing a petition for a change that is submitted to the blockchain alongside a deposit. Once its deposit reaches a certain MinDeposit, the proposal is confirmed and voting opens. Bonded bJMES holders can then send TxGovVote transactions to vote on the proposal. JMES currently follows a simple voting scheme of 1 Bonded bJMES = 1 Vote.
The Content of a proposal is the interface that contains the information about the Proposal, such as the title, description, and any notable changes. A Content type can be implemented by any module. The ProposalRoute of the Content returns a string that must be used to route the handler of the Content in the Governance keeper. This process allows the governance keeper to execute proposal logic implemented by any module. If a proposal passes, the handler is executed. Only if the handler is successful does the state get persisted and the proposal finally pass. Otherwise, the proposal is rejected.
Message Types
MsgSubmitProposal
_5type MsgSubmitProposal struct {_5 Content Content `json:"content" yaml:"content"`_5 InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` // Initial deposit paid by sender. Must be strictly positive_5 Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` // Address of the proposer_5}
MsgDeposit
_5type MsgDeposit struct {_5 ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // ID of the proposal_5 Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor_5 Amount sdk.Coins `json:"amount" yaml:"amount"` // Coins to add to the proposal's deposit_5}
MsgVote
_5type MsgVote struct {_5 ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` // ID of the proposal_5 Voter sdk.AccAddress `json:"voter" yaml:"voter"` // Address of the voter_5 Option VoteOption `json:"option" yaml:"option"` // Option from OptionSet chosen by the voter_5}
Proposal types
Text Proposal
_4type TextProposal struct {_4 Title string `json:"title" yaml:"title"`_4 Description string `json:"description" yaml:"description"`_4}
Text Proposals are used to create general-purpose petitions, such as asking core developers or community members to implement a specific feature. The community can reference a passed Text Proposal to the core developers or community members to indicate that a feature that potentially requires a soft or hard fork is in significant demand.
Parameter Change Proposals
_12type ParameterChangeProposal struct {_12 Title string `json:"title" yaml:"title"`_12 Description string `json:"description" yaml:"description"`_12 Changes []ParamChange `json:"changes" yaml:"changes"`_12}_12_12type ParamChange struct {_12 Subspace string `json:"subspace" yaml:"subspace"`_12 Key string `json:"key" yaml:"key"`_12 Subkey string `json:"subkey,omitempty" yaml:"subkey,omitempty"`_12 Value string `json:"value" yaml:"value"`_12}
Parameter Change Proposals are a special type of proposal which, once passed, will automatically go into effect by directly altering the network's specified parameter.
Software Upgrade Proposals
This type of proposal requires validators to update their node software to a new version at a specified block height.
Software upgrade proposals can be difficult to execute. Exercise caution when using this proposal type, as you may lose your deposit due to an incorrect proposal.
Transitions
End-Block
This section was taken from the official Cosmos SDK docs and placed here for your convenience to understand the Governance process.
ProposalProcessingQueue is a queue (queue[proposalID]) containing all the ProposalIDs of proposals that reach MinDeposit. At the end of each block, 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.
_52for finishedProposalID in GetAllFinishedProposalIDs(block.Time)_52 proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key_52_52 validators = Keeper.getAllValidators()_52 tmpValMap := map(sdk.AccAddress)ValidatorGovInfo_52_52 // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes_52 for each validator in validators_52 tmpValMap(validator.OperatorAddr).Minus = 0_52_52 // Tally_52 voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal_52 for each (voterAddress, vote) in voterIterator_52 delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter_52_52 for each delegation in delegations_52 // make sure delegation.Shares does NOT include shares being unbonded_52 tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares_52 proposal.updateTally(vote, delegation.Shares)_52_52 _, isVal = stakingKeeper.getValidator(voterAddress)_52 if (isVal)_52 tmpValMap(voterAddress).Vote = vote_52_52 tallyingParam = load(GlobalParams, 'TallyingParam')_52_52 // Update tally if validator voted they voted_52 for each validator in validators_52 if tmpValMap(validator).HasVoted_52 proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus))_52_52 // Check if proposal is accepted or rejected_52 totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes_52 if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto)_52 // proposal was accepted at the end of the voting period_52 // refund deposits (non-voters already punished)_52 for each (amount, depositor) in proposal.Deposits_52 depositor.AtomBalance += amount_52_52 stateWriter, err := proposal.Handler()_52 if err != nil_52 // proposal passed but failed during state execution_52 proposal.CurrentStatus = ProposalStatusFailed_52 else_52 // proposal pass and state is persisted_52 proposal.CurrentStatus = ProposalStatusAccepted_52 stateWriter.save()_52 else_52 // proposal was rejected_52 proposal.CurrentStatus = ProposalStatusRejected_52_52 store(Governance, <proposalID|'proposal'>, proposal)
Parameters
The subspace for the Governance module is gov.
_14type DepositParams struct {_14 MinDeposit sdk.Coins `json:"min_deposit,omitempty" yaml:"min_deposit,omitempty"`_14 MaxDepositPeriod time.Duration `json:"max_deposit_period,omitempty" yaml:"max_deposit_period,omitempty"`_14}_14_14type TallyParams struct {_14 Quorum sdk.Dec `json:"quorum,omitempty" yaml:"quorum,omitempty"`_14 Threshold sdk.Dec `json:"threshold,omitempty" yaml:"threshold,omitempty"`_14 Veto sdk.Dec `json:"veto,omitempty" yaml:"veto,omitempty"`_14}_14_14type VotingParams struct {_14 VotingPeriod time.Duration `json:"voting_period,omitempty" yaml:"voting_period,omitempty"`_14}
MinDeposit
- type:
Coins - denom:
ubJMES - amount:
512000000
The minimum deposit amount for a proposal to enter a voting period. Currently 512 bJMES.
MaxDepositPeriod
- type:
time.Duration(seconds) "max_deposit_period": "604800s"
The maximum period of time for a proposal to meet the minimum deposit. Currently 1 week.
Quorum
- type:
Dec "quorum": "0.300000000000000000",
The minimum number of votes needed for a proposal to be valid. As of JMES governance prop 3547, 30% of all staked bJMES must vote to reach Quorum.
Threshold
- type:
Dec - value: 50%
The minimum number of Yes votes needed for a proposal to pass. Currently, 50% of all votes must be Yes. Abstain votes are excluded from this tally.
Veto
- type:
Dec - value:
0.334
The minimum value of NoWithVeto votes needed for a proposal to be vetoed. If 33.4% or more of the total votes cast are NoWithVeto, the proposal fails, and the creator's deposit is not returned.
VotingPeriod
- type:
time.Duration(seconds) "voting_period": "604800s"
The length of the voting period. Currently one week.