StagedProposalProcessor
This is a New plugin that uses 1.4 protocol version. Currently, these are being audited, we do NOT recommend using these latest versions in production until audit is finished. |
Description
StagedProposalProcessor is a governance plugin developed and maintained by the Aragon core team. It orchestrates proposals through a series of configurable stages, enabling complex decision-making processes where proposals progress through predefined stages with multiple “bodies” (other governance plugins or contracts) that report results such as approvals or vetoes. By chaining these bodies and applying thresholds, durations, and conditions, the plugin guides proposals from creation to execution in a flexible, modular manner, addressing the problems facing large monolithic DAOs stuck with one-size-fits-all governance processes.
Key Concepts
Staged Governance Processes
Rather than deciding proposals in a single step, StagedProposalProcessor breaks the decision-making process into sequential stages. Bodies within a stage approve or veto the proposal. Stages can impose timing constraints, thresholds for required number of approvals or vetoes, and rules for editing or canceling the proposal.
Depending on how a stage is configured, it can support different use cases. For example:
-
Normal Stages: A stage can allow bodies to approve the proposal before advancing
-
Optimistic Stages: A stage can allow any body to act as a vetoer rather than approver, effectively allowing any stage to act as an optimistic stage as desired, only passing if not vetoed.
-
Time-Locked Stages: If no bodies are added to a stage, it effectively acts as a timelock delay period, preventing a proposal from advancing until the period has passed.
-
Cancelable or Editable Stages: These allow addresses with permission to do so to either cancel a proposal or modify proposals’ metadata and list of actions prior to advancing to the next stage.
Bodies and Results
A “body” represents an external governance component—such as another plugin or any other address—that evaluates the proposal at a given stage.
Bodies call reportProposalResult
to indicate if they are approving or vetoing a proposal. Stages can have any number of bodies,
each reporting their own results. Stages have configurable thresholds to determine if it can be advanced to the next stage, based on
the governance results from the bodies.
Sub-proposals
When a stage starts, including upon when a proposal is initially created, the StagedProposalProcessor attempts to create a sub-proposal on each body in that stage. For example, if someone is voting within a body, they are voting whether or not they want to advance or veto the parent proposal, but not voting directly on the proposal itself.
Sub-proposals creation can only be “automatic” if both of the following are true:
-
body supports IERC165 and
IProposal
interface, thus supportingcreateProposal
and other necessary functions. -
body is added in a stage with
isManual
setting set to false.
If a body does not meet these criteria, it is “manual,” and the external body (an EOA or other smart contract) must report results explicitly.
Advanceability Criteria
For each stage, you must define the following in the configuration:
-
Approval Threshold: How many bodies must approve for the proposal to proceed.
-
Veto Threshold: How many vetoes are necessary to prevent the proposal from being advanced, regardless of the number of approvals. Vetoes always trump approvals.
-
minAdvance & maxAdvance: Minimum and maximum time windows controlling when the proposal can be advanced to the next stage.
-
voteDuration: Has two different effects:
-
Used to calculate the
endTime
for sub-proposals created on automatic bodies -
If and only if there are any vetoing bodies, used to extend the advance time window (potentially overriding
minAdvance
), ensuring they have enough time to veto it before it is advanced.
-
If all the above conditions are met before maxAdvance
, the proposal becomes Advanceable
. After maxAdvance
, it becomes Expired
and
can no longer be advanced.
When a proposal reaches its final stage and meets that stage’s advanceability criteria, the proposal’s actions can be executed. |
Proposal Lifecycle
-
Creation:
-
A user with
CREATE_PROPOSAL_PERMISSION_ID
callscreateProposal
providing metadata, actions, and start times. The proposal references the active configuration index and starts at stage 0, where sub-proposals are created on its automatic bodies.
-
-
Evaluation at Each Stage:
-
Bodies at the current stage report
Approval
orVeto
results viareportProposalResult
. If the required advanceability criteria are met (see above), the proposal state becomesAdvanceable
.
-
-
Advancing to Next Stages:
-
Proposal can be advanced by calling
advanceProposal
function, requiring the caller to haveADVANCE_PERMISSION_ID
. This moves the proposal to the next stage, triggering sub-proposals on the new stage’s automatic bodies.
-
-
Execution:
-
Once the proposal reaches the last stage and becomes
Advanceable
, it can be executed. A user withEXECUTE_PROPOSAL_PERMISSION_ID
callsexecute
.
-
If allowed by the stage configuration, a user with |
Plugin Setup
Deployed Contracts
During the plugin’s installation process, the setup contract deploys and configures the following contracts:
-
StagedProposalProcessor Proxy
-
A UUPS proxy instance of the main
StagedProposalProcessor
contract. This proxy is initialized with the chosen stages, metadata, and target configuration. It is the primary contract that users interact with to create, advance, and execute proposals through multiple stages. -
StagedProposalProcessor Implementation Contract
-
The underlying implementation referenced by the UUPS proxy. While you typically won’t interact with this contract directly, it provides the upgradable logic that the proxy delegates all calls to. As the DAO evolves, addresses with permission to do so can upgrade this logic.
-
SPPRuleCondition
-
A condition contract deployed to enforce rules for determining whether callers meet the necessary criteria to create proposals on the StagedProposalProcessor. The condition’s logic modularly inherits conditional logic from other conditions. For example, the condition can be configured to return true if the
msg.sender
is a member of a multisig plugin and/or tokenvoting plugin, using boolean operators.
Permissions: The following permissions are set up by default by the StagedProposalProcessorSetup:
Permission ID | Where (Granted By) | Who (Granted To) | Condition | Functions |
---|---|---|---|---|
UPDATE_STAGES_PERMISSION_ID |
Plugin |
DAO |
None |
updateStages |
CREATE_PROPOSAL_PERMISSION_ID |
Plugin |
Any Address |
SPPRuleCondition |
createProposal |
SET_TRUSTED_FORWARDER_PERMISSION_ID |
Plugin |
DAO |
None |
setTrustedForwarder |
SET_TARGET_CONFIG_PERMISSION_ID |
Plugin |
DAO |
None |
setTargetConfig |
SET_METADATA_PERMISSION_ID |
Plugin |
DAO |
None |
setMetadata |
EXECUTE_PROPOSAL_PERMISSION_ID |
Plugin |
Any Address |
None |
execute |
CANCEL_PERMISSION_ID |
Plugin |
Any Address |
None |
cancel |
ADVANCE_PERMISSION_ID |
Plugin |
Any Address |
None |
advanceProposal |
EXECUTE_PERMISSION_ID |
DAO |
Plugin |
None |
execute |
UPDATE_RULES_PERMISSION_ID |
SPPRuleCondition |
DAO |
None |
updateRules |