191 lines
5.8 KiB
Markdown
191 lines
5.8 KiB
Markdown
# Messages
|
||
|
||
## Proposal Submission
|
||
|
||
Proposals can be submitted by any Atom holder via a `TxGovSubmitProposal`
|
||
transaction.
|
||
|
||
```go
|
||
type TxGovSubmitProposal struct {
|
||
Content Content
|
||
InitialDeposit sdk.Coins
|
||
Proposer sdk.AccAddress
|
||
}
|
||
```
|
||
|
||
The `Content` of a `TxGovSubmitProposal` message must have an appropriate router
|
||
set in the governance module.
|
||
|
||
**State modifications:**
|
||
* Generate new `proposalID`
|
||
* Create new `Proposal`
|
||
* Initialise `Proposals` 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 `TxGovSubmitProposal` transaction can be handled according to the following
|
||
pseudocode.
|
||
|
||
```go
|
||
// PSEUDOCODE //
|
||
// Check if TxGovSubmitProposal is valid. If it is, create proposal //
|
||
|
||
upon receiving txGovSubmitProposal from sender do
|
||
|
||
if !correctlyFormatted(txGovSubmitProposal)
|
||
// check if proposal is correctly formatted. Includes fee payment.
|
||
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.Title = txGovSubmitProposal.Title
|
||
proposal.Description = txGovSubmitProposal.Description
|
||
proposal.Type = txGovSubmitProposal.Type
|
||
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
|
||
`TxGovDeposit` transactions to increase the proposal's deposit.
|
||
|
||
```go
|
||
type TxGovDeposit struct {
|
||
ProposalID int64 // ID of the proposal
|
||
Deposit sdk.Coins // Number of Atoms to add to the proposal's deposit
|
||
}
|
||
```
|
||
|
||
**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 `TxGovDeposit` transaction has to go through a number of checks to be valid.
|
||
These checks are outlined in the following pseudocode.
|
||
|
||
```go
|
||
// PSEUDOCODE //
|
||
// Check if TxGovDeposit 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 `TxGovVote` transactions to cast their
|
||
vote on the proposal.
|
||
|
||
```go
|
||
type TxGovVote struct {
|
||
ProposalID int64 // proposalID of the proposal
|
||
Vote byte // option from OptionSet chosen by the voter
|
||
}
|
||
```
|
||
|
||
**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 proposal of the way `TxGovVote` transactions are
|
||
handled:
|
||
|
||
```go
|
||
// PSEUDOCODE //
|
||
// Check if TxGovVote 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.
|
||
```
|