ERC-5453 Approving any function with a signature (Endorsement - Permit for Any Functions)

Last Call · Signatures & auth · created 2022-08-12

Unlike existing approaches that allow only one specific action to be authorized by signature, this is a common convention that lets any function call within a single transaction be approved by the signature(s) (endorsement) of one or more signers.

Why it is needed

Existing standards for authorizing actions via signature have narrow uses. ERC-2612 for ERC-20 tokens and ERC-4494 for ERC-721 NFTs can each authorize only one action (transfer or safeTransferFrom), allow only a single approver, and typically require two steps: sending a permit transaction first and then a transfer transaction. As a result, authorizing arbitrary functions by signature, aggregating approvals from multiple people to function like multisig or threshold signatures, or building flows where someone else submits the transaction on your behalf each required a separate design per function. ERC-5453 defines a general convention that carries approval data in a function's final bytes parameter (ERC-5750), allowing any function to be authorized within the same transaction by signatures from an arbitrary number of approvers. Use cases such as offline signing, joint-action approval, and cumulative voting are also cited as motivations.

What to implement

In depth

A convention layered on top of ERC-5750's extraData

A function following this standard MUST accept a final bytes extraData parameter per ERC-5750. The caller places the memory-encoded bytes of a GeneralExtensionDataStruct into this extraData. This struct consists of the fields erc5453MagicWord (an identifying magic word), erc5453Type (the approval data format), nonce, validSince and validBy (the validity period), and endorsementPayload (the signature bundle). Because this approach inserts approval data into the last parameter of an existing call rather than defining a new function signature, any function can receive signature-based approval under the same framework.

Magic word and types A and B

When interpreting extraData, erc5453MagicWord must be the value keccak256("ERC5453-ENDORSEMENT"), and erc5453Type must be one of the supported values. The original text defines ERC5453_TYPE_A = 1 and ERC5453_TYPE_B = 2. For type A, endorsementPayload must be the abi-encoded value of a single SingleEndorsementData (consisting of the approver address endorserAddress and a 65-byte signature sig); for type B, it must be the abi-encoded value of a dynamic array of SingleEndorsementData. According to the Rationale, type A serves single-approval uses such as ERC-2612 or ERC-4494, while type B serves multi-approval uses such as threshold approval, and more complex approval formats can be added by defining new type values.

The signed subject is the EIP-712 ValidityBound digest

Each signature sig must be an ECDSA (secp256k1) signature of validityDigest produced with the private key corresponding to endorserAddress. validityDigest is the hash of the ValidityBound struct (bytes32 functionParamStructHash, uint256 validSince, uint256 validBy, uint256 nonce), wrapped via EIP-712's hashTypedDataV4. functionParamStructHash is computed as keccak256(abi.encodePacked(keccak256(bytes(_functionStructure)), _functionParamPacked)), where _functionStructure is a function structure string of the form "function methodName(type1 param1, type2 param2, ...)" and _functionParamPacked is the concatenation of each parameter's encoding. Because which function is called with which arguments is bound entirely within the signature, a given signature is valid only for that specific call.

Validation rules and threshold

A single approval MUST be considered valid when either endorserAddress == ecrecover(validityDigest, signature) holds, or EIP1271(endorserAddress).isValidSignature(validityDigest, signature) returns ERC1271.MAGICVALUE. In other words, both signatures from externally owned accounts and signatures from contract accounts (via ERC-1271) can be accepted. For type B's endorsementPayload, an implementation MAY set a threshold for the number of approvals required to be valid. The reference implementation checks that the signature length is 65 bytes, then verifies it using OpenZeppelin's SignatureChecker, and performs this verification before executing the function body via the onlyEndorsed modifier.

The validity period: validSince and validBy

Both validSince and validBy are inclusive. Implementers MAY choose whether to use block numbers or timestamps, and SHOULD provide a way to determine which one is being used. The Rationale explains that both a start and an end value are included, not just an expiration point, in order to maximize flexibility in handling expiration. It notes that if ERC-5081 is adopted, the EVM could support this natively, but since that adoption is unlikely for the time being, these two values were built into the protocol to support it at the smart contract level.

Three reference implementations

The original text presents an abstract contract, AERC5453Endorsible, along with two examples that use it. EndorsableERC721 attaches the onlyEndorsed modifier to a mint(address _to, uint256 _tokenId, bytes calldata _extraData) function, implementing behavior similar to ERC-4494. ThresholdMultiSigForwarder demonstrates behavior similar to a Gnosis Safe wallet, calling a remote contract via forward(address _dest, uint256 _value, uint256 _gasLimit, bytes calldata _calldata, bytes calldata _extraData) after threshold multisig approval. Here the call data is included in the signed subject in the form of the hash keccak256(_calldata).

Backward compatibility and proposal status

This design rests on the assumption that a function accepts a final bytes calldata extraData parameter, which is compatible with many ERCs including ERC-721 and ERC-1155. Standards that are not compatible, such as ERC-20, can be adapted to support this via wrapper contracts or proxy upgrades. This proposal's status is Last Call (final comment period, deadline 2023-09-27), meaning that as of the original text it is at the review stage immediately before final confirmation.

Things to watch out for

Original ERC · ← ERCs