Skip to content

Token Voting Plugin ​

The Token Voting Plugin is the "one token, one vote" governance plugin, the most common way an OSx DAO governs itself. Members' influence is proportional to the governance tokens they hold (or that others delegate to them), and a proposal passes when it meets a configurable majority-voting rule. It also puts the protocol's shared building blocks to work: it reuses the proposal, membership, and ratio primitives, adds token-based voting power, and is installed through the standard framework.

Start with the lifecycle and permissions below, then follow these related topics:

  • This page — what it is, the proposal lifecycle, and the permissions it sets up.
  • Voting power — where power comes from: the token, the snapshot, delegation, and who may propose.
  • Governance tokens — mint a new token, reuse an IVotes token, or wrap an existing ERC-20.
  • The shared voting model: majority voting (the thresholds) and voting modes (Standard / Early Execution / Vote Replacement).

Why it needs a special token ​

The problem any token vote must solve is double voting: hold tokens, vote, transfer them to a fresh address, and vote again, counting the same tokens twice. The plugin prevents this by only accepting tokens that support historical, per-account snapshots (IVotes / ERC20Votes). Every proposal fixes a snapshot block at creation and weighs each vote by the holder's balance at that block, so moving tokens after a proposal opens changes nothing. For this requirement and its consequences (delegation, snapshots, wrapping a plain ERC-20), see Voting power.

The proposal lifecycle ​

Create. A proposal records its snapshot block, freezes the voting settings and its execution target (where its approved actions are sent, normally the DAO), stores the actions to run if it passes, and its start and end dates (the end must be at least minDuration after the start). The creator may cast their vote in the same transaction ("propose and vote yes"). Who may create is gated, see gating proposal creation.

Vote. Eligible holders call vote with Yes, No, or Abstain, weighted by their snapshot power. Whether a voter can later change their vote depends on the voting mode. A voter may also ask to execute in the same call (tryEarlyExecution) if the mode and thresholds allow and they hold execute permission.

Execute. Once the proposal has passed (all thresholds met, and the timing allowed by the mode), anyone with EXECUTE_PROPOSAL_PERMISSION_ID calls execute. The plugin hands the approved actions to the DAO (via execute, which is why it holds EXECUTE_PERMISSION_ID on the DAO) and marks the proposal executed. A passed proposal stays executable until someone runs it; there's no expiry.

The DAO changes the voting mode, supportThreshold, minParticipation, minDuration, and minProposerVotingPower through updateVotingSettings, and minApproval through updateMinApprovals. Both methods require UPDATE_VOTING_SETTINGS_PERMISSION_ID, so changing governance rules is itself a governance decision. Changes apply to new proposals; existing proposals retain their recorded rules.

Permissions it sets up ​

TokenVotingSetup wires these on install:

PermissionOn (where)Granted to (who)ConditionGates
EXECUTE_PERMISSION_IDDAOpluginnonethe plugin calling dao.execute
CREATE_PROPOSAL_PERMISSION_IDpluginany addressVotingPowerConditioncreateProposal
EXECUTE_PROPOSAL_PERMISSION_IDpluginany addressnoneexecute
UPDATE_VOTING_SETTINGS_PERMISSION_IDpluginDAOnoneupdateVotingSettings, updateMinApprovals
SET_TARGET_CONFIG_PERMISSION_IDpluginDAOnonesetTargetConfig
SET_METADATA_PERMISSION_IDpluginDAOnonesetMetadata
MINT_PERMISSION_IDgovernance tokenDAOnonemint (only when a new token is minted)

The two any address grants are intentional: proposal creation is opened to everyone but narrowed by the VotingPowerCondition to holders above a minimum, and execution is opened to everyone because the threshold math already decides whether a proposal may execute, letting anyone trigger it just stops a passed proposal getting stuck.

Installing it ​

TokenVotingSetup handles installation without manual permission wiring. The plugin setup deploys the plugin proxy, arranges the governance token, deploys the VotingPowerCondition, and returns the permission set above for the PluginSetupProcessor to apply. Its helpers are the condition and the token, so an update or uninstall can find them again. Choosing the token is the main decision in this step; see Governance tokens.

Keep in mind ​

  • Delegate, or you have no power. Holding the token isn't enough; voting power is zero until delegated. The most common "why can't I vote?" is an undelegated balance. See voting power.
  • Power is fixed at the snapshot. Acquiring or delegating more tokens after a proposal opens does nothing for that proposal.
  • Identical proposals collide. The proposal id hashes the actions and metadata, so a byte-identical resubmission reverts; vary the metadata to resubmit.

See also ​