ERC-5247 Smart contract execution proposal interface (Smart Contract Executable Proposal Interface)
Review · Other · created 2022-07-13
A common interface that registers a list of desired contract calls onchain as a proposal, so they can be executed later once approved.
Why it is needed
In smart contracts, it is often necessary to separate deciding what code to run from actually executing that code. For example, in a decentralized autonomous organization (DAO), a proposer first submits the execution content as a proposal, and it is only executed after members vote to approve it. In trust relationships such as those involving a trustee or legal representative, a proposal is likewise drafted, discussed, and approved before being carried out. There are also cases where one party hands a conditional proposal to another, and it is executed only if the other party accepts it. However, without a common way to record and execute such proposals onchain, the proposal format and handling differ from service to service, forcing every voting or approval tool to build its own proposal-handling logic. This standard solves this by defining proposal creation and execution through a single interface.
What to implement
function executeProposal(uint256 proposalId, bytes calldata extraParams) external;: Executes the calls contained in the proposal with the given number.
In depth
Information contained in a proposal
A proposal is a bundle of function calls. Each call includes the target contract address (targets), the ether value to send (values), the gas limit (gasLimits), and the call data (calldatas), stored as arrays. Arrays are used so a single proposal can contain an arbitrary number of function calls. The caller supplies a proposalId, but the actual registered number is returned via createProposal's return value, registeredProposalId. This design lets implementations define their own proposal numbering scheme. extraParams is an additional parameter slot present in both creation and execution.
Separation from the voting standard
This interface was originally part of the voting standard ERC-1202. However, proposals themselves have many uses outside of voting, and voting does not necessarily need to presuppose a specific proposal format. For this reason, the voting interface and the proposal interface were separated. This lets the same interface be used not only for DAO voting but also for structures where a trustee or agent executes after approval, or conditional proposals that execute once the other party accepts.
Behavior of the reference implementation
In the reference implementation ProposalRegistry.sol, createProposal uses require to check that the four arrays, targets, values, gasLimits, and calldatas, all have the same length, then uses the internal counter proposalCount as the registeredProposalId and increments it by 1. The proposal content is stored along with the proposer (by), and a ProposalCreated event is emitted. executeProposal iterates through the stored proposal's targets in order, sends a call to each target with its value and calldata attached, verifies the call succeeded using Address.verifyCallResult, and then emits a ProposalExecuted event.
Usage as shown in a test case
In the test, two mint calls on an ERC-721 contract are registered as a single proposal. Immediately after calling createProposal with proposal number 0, the balance remains 0, and only after calling executeProposal(0, []) are two tokens minted, bringing the balance to 2. This shows that proposal registration and execution occur as separate transactions.
Proposal status and security discussion
This proposal's original status is Review, meaning its content may still change. The original Security Considerations section also simply states that it needs discussion, so security guidance has not been finalized.