The Powers Protocol
Powers is a role-restricted governance protocol that provides a modular, flexible, decentralized, and efficient governance engine for DAOs. It is designed to be used in combination with implementations of Mandate.sol contracts.
The Role of Powers.sol
Powers.sol is the central engine of the protocol, acting as the unopinionated core of any organisation's governance structure. It is intentionally minimalistic and does not contain any specific governance logic itself. Instead, its primary responsibilities are to:
- Serve as the Governance Hub: All governance actions, from proposing a vote to executing a transaction, are initiated through
Powers.sol. It provides a single, secure entry point for all interactions. - Run checks: Before any action is executed,
Powers.solchecks the relevant Mandate conditions to validate the request. This ensures that all governance actions adhere to the rules defined by the organisation's mandates. - Manage State: It is the authoritative source for the organisation's state, including which mandates are active, which accounts hold which roles, and the status of all ongoing proposals and actions.
- Enforce Outcomes: After a
Mandate.solcontract has validated an action and returned the execution data,Powers.solis responsible for reliably executing the final transaction and updating the state accordingly.
In essence, Powers.sol acts as the immutable foundation of the organisation, providing the core mechanics for state management and execution, while the modular Mandate.sol contracts provide the flexible, adaptable governance logic. This separation makes the system both secure and highly extensible.
Roles: Assigning, Revoking and Labelling
The Powers protocol implements a role-based access control system that is fundamental to its governance mechanism.
Built-in Roles
ADMIN_ROLE(0): The highest privilege role, assigned to the contract deployer.PUBLIC_ROLE(type(uint256).max): A special role that everyone has by default.
Role Management
The process of managing roles involves a few key functions.
Assigning a Role
An admin uses assignRole() to grant a specific role to a user's account.
Revoking a Role
An admin uses revokeRole() to remove a role from a user's account.
Labelling a Role
To make roles easier to identify, an admin can use labelRole() to give it a human-readable name.
Mandates: Adopting and Revoking
Mandates are modular, role-restricted governance actions and the building blocks of the protocol's governance system.
Mandate Management
Managing the lifecycle of mandates is a core administrative task.
Initial Constitution
The organisation is born when an admin calls constitute() with the initial set of mandates. This can only be done once.
Adopting New Mandates
As the organisation evolves, new mandates can be added by an admin using adoptMandate().
Revoking Existing Mandates
If a mandate becomes obsolete, an admin can remove it using revokeMandate().
Actions: Proposing, Voting, and Executing
Proposing and Voting
Proposals are used when an action requires community consensus.
Creating a Proposal
A user calls propose() with the mandate details.
Voting Period
The proposal enters a voting period defined by the mandate.
Casting Votes
Eligible voters use castVote() or castVoteWithReason().
Resolution
The proposal can be Succeeded, Defeated, or Cancelled.
Executing Actions
The execution flow involves a request and callback logic between Powers.sol and the Mandate contracts.
Request Action
A user initiates an action by calling request() in Powers.sol.
Mandate Validation
Powers.sol calls executeMandate() on the target mandate contract, which validates the request and prepares the execution data.
Fulfill Action
The mandate calls back to Powers.sol's fulfill() function, which executes the transaction and marks the action as complete.
Technical Specifications
Source
See the github repo here.
Key Differences from OpenZeppelin's Governor.sol:
- DAO actions must be encoded in role-restricted external contracts (mandates) following the
IMandateinterface. - Proposing, voting, cancelling and executing actions are role-restricted along the target mandate.
- All DAO actions must run through the governance flow provided by
Powers.sol. - Uses a non-weighted voting mechanism: one account has one vote.
- Core protocol is intentionally minimalistic - complexity must be integrated through mandates.
State Variables
_actions:mapping(uint256 actionId => Action)_mandates:mapping(uint16 mandateId => AdoptedMandate)_roles:mapping(uint256 roleId => Role)_deposits:mapping(address account => Deposit[])
Functions
- Governance:
request,fulfill,propose,cancel,castVote,castVoteWithReason - Admin:
constitute,adoptMandate,revokeMandate,assignRole,revokeRole,labelRole
Structs
Action: Tracks a proposal's state and voting information.AdoptedMandate: Tracks an active mandate's address and status.Role: Tracks role assignments and membership.Deposit: Tracks a deposit's amount and block number.
Events
- Governance:
ActionRequested,ActionExecuted,ProposedActionCreated,ProposedActionCancelled,VoteCast - Admin:
RoleSet,RoleLabel,MandateAdopted,MandateRevoked