Skip to main content

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.

info

Aragon OSx VotingMode allows for EarlyExecution and VoteReplacement features. In Standard mode, early execution and vote replacement are disabled.

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

Functions

createProposal

Overview

Function to create a new token voting proposal.

This function takes five arguments:

  • bytes calldata_metadata - Metadata of the proposal
  • IDAO.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 index x is 1, the tx succeeds even if the action at x failed. 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 + minDuration is 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:

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

Overview

Function to execute the given proposal.

This function takes one argument:

  • uint256proposalId

Implementation

function execute(uint256 _proposalId) public {
if (!_canExecute(_proposalId)) {
revert ProposalExecutionForbidden(_proposalId);
}
_execute(_proposalId);
}

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 indexedproposalId
  • address indexedvoter
  • VoteOptionvoteOption - VoteOption Enum
  • uint256votingPower - Voting power behind the vote
TokenGovernanceSettingsUpdated

TokenGovernanceSettingsUpdated event is emitted when the token governance settings are updated.

This event has four parameters:

  • uint32supportThreshold
  • uint32minParticipation
  • uint64minDuration - Minimum duration of the proposal vote in seconds
  • uint256minProposerVotingPower - 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:

  • uint64limit
  • uint64actual
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:

  • uint64limit
  • uint64actual
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:

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
}