In the proposal life cycle, the initial step is its creation. We have previously discussed the creation of proposals that alter the state of system contracts, but it's important to note that the executor can be any contract. Suppose we have the UnknownToken token, and ownership of this token has been transferred to the DAO.
You can also add specific validations that will be passed each time you create a proposal with your contract functioning as the main executor. To achieve this, you should implement the IProposalValidator interface. In this particular case, the validation ensures that the only action within the proposal is the minting of some amount of tokens. If the validate method returns false, the creation of the proposal will be reverted.
Once created, a proposal initially enters the Voting state, making it available for user to cast their votes. The voting period remains open as long as the quorum is not reached or the voting time hasn't elapsed. Users may also vote against proposals. If votes against the proposal reach a quorum, the status of the proposal becomes Defeated. Now we can pass the proposalId from the just-created proposal to the voting function and cast a vote in favor of it.
It's possible to cancel your entire vote on the proposal, including the delegated power, by simply calling the cancelVote method. After that, your assets will no longer be locked and you can withdraw them.
Assuming our proposal has reached the quorum and has exceeded duration if earlyCompletion is false, it can exist in one of three possible states. The first state is Locked in which case we only need to wait for the executionDelay. The second state is SucceededFor or SucceededAgainst indicating that it is ready for execution. In this case, we can simply call the execute method.
⚠️ SucceededAgainst status is reachable only in meta-governance proposals not covered in this chapter.
The WaitingForVotingTransfer state, indicating that validatorsVote is true, signifies that the proposal is ready to be moved to the second stage of voting. To initiate this, the moveProposalToValidators method should be called by any user. This method triggers the creation of the corresponding external proposal in the GovValidators contract. External proposals for the GovValidators contract have the same ids as those on the GovPool contract.
functionmoveProposalToValidators(IGovPool govPool,uint256 proposalId) external {require( govPool.getProposalState(proposalId) == IGovPool.ProposalState.WaitingForVotingTransfer,"Not waiting for transfer state" ); govPool.moveProposalToValidators(proposalId);}
Following the transition of the proposal to the validators, the validators will have the ability to cast their votes for it.
Once the external proposal has the Succeeded status on the GovValidators contract, it will also attain the SucceededFor or SucceededAgainst status on the GovPool contract, allowing it to be executed in the usual manner.
Well done! When you call the execute method, the tokens are minted to the address specified in the proposal. You can verify this by simply calling the balanceOf method on the token contract.