---
eip: 5247
title: Smart Contract Executable Proposal Interface
description: An interface to create and execute proposals.
author: Zainan Victor Zhou (@xinbenlv)
discussions-to: https://ethereum-magicians.org/t/erc-5247-executable-proposal-standard/9938
status: Draft
type: Standards Track
category: ERC
created: 2022-07-13
---

## Abstract

This EIP presents an interface for "smart contract executable proposals": proposals that are submitted to, recorded on, and possibly executed on-chain. Such proposals include a series of information about
function calls including the target contract address, ether value to be transmitted, gas limits and calldatas.

## Motivation

It is oftentimes necessary to separate the code that is to be executed from the actual execution of the code.

A typical use case for this EIP is in a Decentralized Autonomous Organization (DAO). A proposer will create a smart proposal and advocate for it. Members will then choose whether or not to endorse the proposal and vote accordingly (see [EIP-1202](./eip-1202.md)). Finallym when consensus has been formed, the proposal is executed.

A second typical use-case is that one could have someone who they trust, such as a delegator, trustee, or an attorney-in-fact, or any bilateral collaboration format, where a smart proposal will be first composed, discussed, approved in some way, and then put into execution.

A third use-case is that a person could make an "offer" to a second person, potentially with conditions. The smart proposal can be presented as an offer and the second person can execute it if they choose to accept this proposal.

## Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC5247 {
    event ProposalCreated(
        address indexed proposer,
        uint256 indexed proposalId,
        address[] targets,
        uint256[] values,
        uint256[] gasLimits,
        bytes[] calldatas,
        bytes extraParams
    );

    event ProposalExecuted(
        address indexed executor,
        uint256 indexed proposalId,
        bytes extraParams
    );

    function createProposal(
        uint256 proposalId,
        address[] calldata targets,
        uint256[] calldata values,
        uint256[] calldata gasLimits,
        bytes[] calldata calldatas,
        bytes calldata extraParams
    ) external returns (uint256 registeredProposalId);

    function executeProposal(uint256 proposalId, bytes calldata extraParams) external;
}
```

## Rationale

* Originally, this interface was part of part of [EIP-1202](./eip-1202.md). However, the proposal itself can potentially have many use cases outside of voting. It is possible that voting may not need to be upon a proposal in any particular format. Hence, we decide to *decouple the voting interface and proposal interface*.
* Arrays were used for `target`s, `value`s, `calldata`s instead of single variables, allowing a proposal to carry arbitrarily long multiple functional calls.
* `registeredProposalId` is returned in `createProposal` so the standard can support implementation to decide their own format of proposal id.

## Test Cases

A simple test case can be found as

```ts
        it("Should work for a simple case", async function () {
            const { contract, erc721, owner } = await loadFixture(deployFixture);
            const callData1 = erc721.interface.encodeFunctionData("mint", [owner.address, 1]);
            const callData2 = erc721.interface.encodeFunctionData("mint", [owner.address, 2]);
            await contract.connect(owner)
                .createProposal(
                    0,
                    [erc721.address, erc721.address],
                    [0,0],
                    [0,0],
                    [callData1, callData2],
                    []);
            expect(await erc721.balanceOf(owner.address)).to.equal(0);
            await contract.connect(owner).executeProposal(0, []);
            expect(await erc721.balanceOf(owner.address)).to.equal(2);
        });
```

See [testProposalRegistry.ts](../assets/eip-5247/testProposalRegistry.ts) for the whole testset.

## Reference Implementation

A simple reference implementation can be found.

```solidity
    function createProposal(
        uint256 proposalId,
        address[] calldata targets,
        uint256[] calldata values,
        uint256[] calldata gasLimits,
        bytes[] calldata calldatas,
        bytes calldata extraParams
    ) external returns (uint256 registeredProposalId) {
        require(targets.length == values.length, "GeneralForwarder: targets and values length mismatch");
        require(targets.length == gasLimits.length, "GeneralForwarder: targets and gasLimits length mismatch");
        require(targets.length == calldatas.length, "GeneralForwarder: targets and calldatas length mismatch");
        registeredProposalId = proposalCount;
        proposalCount++;

        proposals[registeredProposalId] = Proposal({
            by: msg.sender,
            proposalId: proposalId,
            targets: targets,
            values: values,
            calldatas: calldatas,
            gasLimits: gasLimits
        });
        emit ProposalCreated(msg.sender, proposalId, targets, values, gasLimits, calldatas, extraParams);
        return registeredProposalId;
    }
    function executeProposal(uint256 proposalId, bytes calldata extraParams) external {
        Proposal storage proposal = proposals[proposalId];
        address[] memory targets = proposal.targets;
        string memory errorMessage = "Governor: call reverted without message";
        for (uint256 i = 0; i < targets.length; ++i) {
            (bool success, bytes memory returndata) = proposal.targets[i].call{value: proposal.values[i]}(proposal.calldatas[i]);
            Address.verifyCallResult(success, returndata, errorMessage);
        }
        emit ProposalExecuted(msg.sender, proposalId, extraParams);
    }
```

See [ProposalRegistry.sol](../assets/eip-5247/ProposalRegistry.sol) for more information.

## Security Considerations

Needs discussion.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
