SPP Plugin Compatibility
In the StagedProposalProcessor (SPP), each “body” within a stage can be configured as either automatic or manual. Automatic bodies simplify the user experience by having the SPP create sub-proposals on their behalf, while manual bodies require external intervention. Understanding how to set up and operate both types of bodies ensures smooth integration with the SPP.
Automatic vs. Manual Bodies
-
Automatic Bodies: If
isManual
is set tofalse
in the stage configuration, the SPP will automatically create sub-proposals on these bodies whenever a proposal enters their stage. This approach reduces the operational overhead, making governance processes more seamless. To qualify as an automatic body:-
The plugin must meet the compatibility requirements detailed below.
-
The SPP must have the necessary permission to call
createProposal
on the body.
-
-
Manual Bodies: If
isManual
is set totrue
, you must create and manage sub-proposals externally. In this case, the body is responsible for callingreportProposalResult
on the SPP to register approvals or vetoes. While this offers flexibility—useful if the body’s contract does not support the required interfaces—it can be more labor-intensive.
Requirements for Automatic Bodies
A plugin that fully integrates with the SPP as an automatic body must implement the IProposal interface and support ERC165. You can simplify this by inheriting from the Proposal or ProposalUpgradeable abstract contracts provided by Aragon, which handle ERC165 requirements automatically.
Key Functions:
createProposal
Automatic bodies must implement createProposal
to accept parameters from the SPP:
-
_startDate
/_endDate
: The time window for the sub-proposal. For a voting plugin, this defines the voting period. -
_data
: Custom parameters for scenarios where default inputs are insufficient. To support these, implementcustomProposalParamsABI
to declare the expected parameters, for example:
function customProposalParamsABI() external pure override returns (string memory) {
return "(uint256 allowFailureMap, uint8 voteOption, bool tryEarlyExecution)";
}
Do not add custom conditional logic in |
hasSucceeded
The SPP calls hasSucceeded
to determine if a sub-proposal has met its success criteria without triggering execution.
This should return true
if the sub-proposal passed at any point. Avoid time-based logic here — once true
, it should
remain true
, reflecting that the sub-proposal succeeded during its designated window, regardless of when SPP checks it.
If |
Manual Body Best Practices
For manual bodies, the SPP does not create sub-proposals automatically. Instead, you must manually call reportProposalResult
on the SPP to inform it of approval or veto outcomes. This might involve creating external transactions or leveraging another governance process to signal results.
Example Using a Safe:
-
Add the Safe’s address as a body with
isManual = true
. -
After creating a proposal in the SPP, note its
proposalId
and initiate a transaction on the Safe, where:-
to: SPP’s address
-
data:
abi.encodeCall(StagedProposalProcessor.reportProposalResult, (proposalId, stageId, resultType, tryAdvance))
-
resultType
can beApproval
orVeto
. -
stageId
must correspond to the stage where this body is registered. We require bodies to pass this explicitly as there could be the same body added in multiple stages. IfstageId
is passed in which this body has not been added, the resultType will not be used in SPP’s decision making process to advance(i.e it will have no effect other than for you, spending gas in vain). -
tryAdvance
if you know the result is enough to advance the proposal and body also hasADVANCE_PERMISSION_ID
, this can betrue
which will automatically advance the proposal to the next stage.
-
-
-
Once the transaction is executed, the SPP records the result. Ensure this transaction occurs before the
maxAdvance
time of the relevant stage.
If you are creating a new contract to act as a body, consider implementing |