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:

  1. Normal Stages: A stage can allow bodies to approve the proposal before advancing

  2. 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.

  3. 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.

  4. 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 supporting createProposal 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.

Configurations

StagedProposalProcessor supports updating stage configurations, allowing the DAO to evolve its governance rules over time.

Proposal Lifecycle

  1. Creation:

    • A user with CREATE_PROPOSAL_PERMISSION_ID calls createProposal 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.

  2. Evaluation at Each Stage:

    • Bodies at the current stage report Approval or Veto results via reportProposalResult. If the required advanceability criteria are met (see above), the proposal state becomes Advanceable.

  3. Advancing to Next Stages:

    • Proposal can be advanced by calling advanceProposal function, requiring the caller to have ADVANCE_PERMISSION_ID. This moves the proposal to the next stage, triggering sub-proposals on the new stage’s automatic bodies.

  4. Execution:

    • Once the proposal reaches the last stage and becomes Advanceable, it can be executed. A user with EXECUTE_PROPOSAL_PERMISSION_ID calls execute.

If allowed by the stage configuration, a user with EDIT_PERMISSION_ID can modify the proposal’s metadata and actions prior to being advanced. A user with CANCEL_PERMISSION_ID can cancel the proposal if the stage permits it.

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