Token
1. Summary
The PWN Token governance is based on the Aragon's token voting plugin. The main changes we've made to the plugin are to use our Epoch Clock instead of block numbers, remove VotingMode functionality and use only Standard by default, and we added the assignment of voting rewards on proposal creation.
Aragon OSx VotingMode allows for EarlyExecution and VoteReplacement features. In Standard mode, early execution and vote replacement are disabled.
2. Important links
3. Contract details
- PWNTokenGovernancePlugin.sol is written in Solidity version 0.8.17
Features
- Create and Execute Token governance proposals
- Vote for a proposal
Inherited contracts, implemented Interfaces and ERCs
- IPWNTokenGovernance
- IMembership
- Initializable
- ERC165Upgradeable
- PluginUUPSUpgradeable
- ProposalUpgradeable
Functions
createProposal
Overview
Function to create a new token voting proposal.
This function takes five arguments:
bytes calldata_metadata- Metadata of the proposalIDAO.Action[] calldata_actions- Actions to be executed after the proposal passes. (Learn more about IDAO.Action struct)uint256_allowFailureMap- Allows proposal to succeed even if an action reverts. Uses bitmap representation. If the bit at indexxis 1, the tx succeeds even if the action atxfailed. Passing 0 will be treated as atomic execution.uint64_startDate- The start date of the proposal vote. If 0, the current timestamp is used and the vote starts immediately.uint64_endDate- The end date of the proposal vote. If 0,_startDate + minDurationis used.VoteOption_voteOption- Chosen vote option (VoteOption Enum) to be casted on proposal creation.
Implementation
function createProposal(
bytes calldata _metadata,
IDAO.Action[] calldata _actions,
uint256 _allowFailureMap,
uint64 _startDate,
uint64 _endDate,
VoteOption _voteOption
) external returns (uint256 proposalId) {
// check that `_msgSender` has enough voting power
{
uint256 minProposerVotingPower_ = minProposerVotingPower();
if (minProposerVotingPower_ != 0) {
if (votingToken.getVotes(_msgSender()) < minProposerVotingPower_) {
revert ProposalCreationForbidden(_msgSender());
}
}
}
uint256 snapshotEpoch = epochClock.currentEpoch();
uint256 totalVotingPower_ = totalVotingPower(snapshotEpoch);
if (totalVotingPower_ == 0) {
revert NoVotingPower();
}
(_startDate, _endDate) = _validateProposalDates(_startDate, _endDate);
proposalId = _createProposal({
_creator: _msgSender(),
_metadata: _metadata,
_startDate: _startDate,
_endDate: _endDate,
_actions: _actions,
_allowFailureMap: _allowFailureMap
});
// store proposal related information
Proposal storage proposal_ = proposals[proposalId];
proposal_.parameters.startDate = _startDate;
proposal_.parameters.endDate = _endDate;
proposal_.parameters.snapshotEpoch = snapshotEpoch.toUint64();
proposal_.parameters.supportThreshold = supportThreshold();
proposal_.parameters.minVotingPower = _applyRatioCeiled(totalVotingPower_, minParticipation());
// reduce costs
if (_allowFailureMap != 0) {
proposal_.allowFailureMap = _allowFailureMap;
}
for (uint256 i; i < _actions.length;) {
proposal_.actions.push(_actions[i]);
unchecked {
++i;
}
}
// assign voting reward
rewardToken.assignProposalReward(proposalId);
if (_voteOption != VoteOption.None) {
vote(proposalId, _voteOption);
}
}
vote
Overview
Function to vote the choosen option. Optionally, this function can also execute the proposal.
This function takes two arguments:
uint256proposalIdVoteOptionvoteOption- VoteOption Enum
Implementation
function vote(uint256 _proposalId, VoteOption _voteOption) public {
address _voter = _msgSender();
(bool canVote_, uint256 votingPower) = _canVote(_proposalId, _voter, _voteOption);
if (!canVote_) {
revert VoteCastForbidden({ proposalId: _proposalId, account: _voter, voteOption: _voteOption });
}
_vote(_proposalId, _voteOption, _voter, votingPower);
}
execute
Events
event VoteCast(uint256 indexed proposalId, address indexed voter, VoteOption voteOption, uint256 votingPower);
event TokenGovernanceSettingsUpdated(uint32 supportThreshold, uint32 minParticipation, uint64 minDuration, uint256 minProposerVotingPower);
VoteCast
VoteCast event is emitted when a vote is cast by a voter.
This event has four parameters:
uint256 indexedproposalIdaddress indexedvoterVoteOptionvoteOption- VoteOption Enumuint256votingPower- Voting power behind the vote
TokenGovernanceSettingsUpdated
TokenGovernanceSettingsUpdated event is emitted when the token governance settings are updated.
This event has four parameters:
uint32supportThresholduint32minParticipationuint64minDuration- Minimum duration of the proposal vote in secondsuint256minProposerVotingPower- Minimum voting power required to create a proposal
Errors
error NoVotingPower();
error DateOutOfBounds(uint64 limit, uint64 actual);
error MinDurationOutOfBounds(uint64 limit, uint64 actual);
error ProposalCreationForbidden(address sender);
error VoteCastForbidden(uint256 proposalId, address account, VoteOption voteOption);
error ProposalExecutionForbidden(uint256 proposalId);
NoVotingPower
NoVotingPower error is thrown if the voting power is zero.
DateOutOfBounds
DateOutOfBounds error is thrown when a date is out of bounds.
This error has two parameters:
uint64limituint64actual
MinDurationOutOfBounds
MinDurationOutOfBounds error is thrown when the minimum duration value is out of bounds (less than 1 hour or greater than 1 year).
This error has two parameters:
uint64limituint64actual
ProposalCreationForbidden
ProposalCreationForbidden error is thrown when a sender is not allowed to create a proposal.
This error has one parameter:
addresssender
VoteCastForbidden
VoteCastForbidden error is thrown when an account is not allowed to cast a vote. This happens when the vote:
- has not started
- has ended
- was executed
- the account doesn't have voting powers
This error has three parameters:
uint256proposalIdaddressaccountVoteOptionvoteOption- VoteOption Enum
ProposalExecutionForbidden
ProposalExecutionForbidden error is thrown when a proposal execution is forbidden.
This error has one parameter:
uint256proposalId
VoteOption Enum
enum VoteOption {
None, Abstain, Yes, No
}