This EIP establish a general protocol for permitting approving function calls in the same transaction rely on ERC-5750.
Unlike a few prior art (ERC-2612 for ERC-20, ERC-4494 for ERC-721 that
usually only permit for a single behavior (transfer for ERC-20 and safeTransferFrom for ERC-721) and a single approver in two transactions (first a permit(...) TX, then a transfer-like TX), this EIP provides a way to permit arbitrary behaviors and aggregating multiple approvals from arbitrary number of approvers in the same transaction, allowing for Multi-Sig or Threshold Signing behavior.
Motivation
Support permit(approval) alongside a function call.
Support a second approval from another user.
Support pay-for-by another user
Support multi-sig
Support persons acting in concert by endorsements
Support accumulated voting
Support off-line signatures
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Interfaces
The interfaces and structure referenced here are as followed
As specified in ERC-5750 General Extensibility for Method Behaviors, any compliant method that has an bytes extraData as its
last method designated for extending behaviors can conform to ERC-5453 as the way to indicate a permit from certain user.
Any compliant method of this EIP MUST be a ERC-5750 compliant method.
Caller MUST pass in the last parameter bytes extraData conforming a solidity memory encoded layout bytes of GeneralExtensionDataStruct specified in Section Interfaces. The following descriptions are based on when decoding bytes extraData into a GeneralExtensionDataStruct
In the GeneralExtensionDataStruct-decoded extraData, caller MUST set the value of GeneralExtensionDataStruct.erc5453MagicWord to be the keccak256("ERC5453-ENDORSEMENT").
Caller MUST set the value of GeneralExtensionDataStruct.erc5453Type to be one of the supported values.
When the value of GeneralExtensionDataStruct.erc5453Type is set to be ERC5453_TYPE_A, GeneralExtensionDataStruct.endorsementPayload MUST be abi encoded bytes of a SingleEndorsementData.
When the value of GeneralExtensionDataStruct.erc5453Type is set to be ERC5453_TYPE_B, GeneralExtensionDataStruct.endorsementPayload MUST be abi encoded bytes of SingleEndorsementData[] (a dynamic array).
Each SingleEndorsementData MUST have a address endorserAddress; and a 65-bytes bytes sig signature.
Each bytes sig MUST be an ECDSA (secp256k1) signature using private key of signer whose corresponding address is endorserAddress signing validityDigest which is the a hashTypeDataV4 of EIP-712 of hashStruct of ValidityBound data structure as followed:
_functionStructure MUST be computed as function methodName(type1 param1, type2 param2, ...).
_functionParamPacked MUST be computed as enc(param1) || enco(param2) ...
Upon validating that endorserAddress == ecrecover(validityDigest, signature) or EIP1271(endorserAddress).isValidSignature(validityDigest, signature) == ERC1271.MAGICVALUE, the single endorsement MUST be deemed valid.
Compliant method MAY choose to impose a threshold for a number of endorsements needs to be valid in the same ERC5453_TYPE_B kind of endorsementPayload.
The validSince and validBy are both inclusive. Implementer MAY choose to use blocknumber or timestamp. Implementor SHOULD find away to indicate whether validSince and validBy is blocknumber or timestamp.
Rationale
We chose to have both ERC5453_TYPE_A(single-endorsement) and ERC5453_TYPE_B(multiple-endorsements, same nonce for entire contract) so we
could balance a wider range of use cases. E.g. the same use cases of ERC-2612 and ERC-4494 can be supported by ERC5453_TYPE_A. And threshold approvals can be done via ERC5453_TYPE_B. More complicated approval types can also be extended by defining new ERC5453_TYPE_?
We chose to include both validSince and validBy to allow maximum flexibility in expiration. This can be also be supported by EVM natively at if adopted ERC-5081 but ERC-5081 will not be adopted anytime soon, we choose to add these two numbers in our protocol to allow
smart contract level support.
Backwards Compatibility
The design assumes a bytes calldata extraData to maximize the flexibility of future extensions. This assumption is compatible with ERC-721, ERC-1155 and many other ERC-track EIPs. Those that aren’t, such as ERC-20, can also be updated to support it, such as using a wrapper contract or proxy upgrade.
Reference Implementation
In addition to the specified algorithm for validating endorser signatures, we also present the following reference implementations.
Reference Implementation of ThresholdMultiSigForwarder
Here is a reference implementation of ThresholdMultiSigForwarder that achieves similar behavior of multi-sig threshold approval
remote contract call like a Gnosis-Safe wallet.
A replay attack is a type of attack on cryptography authentication. In a narrow sense, it usually refers to a type of attack that circumvents the cryptographically signature verification by reusing an existing signature for a message being signed again. Any implementations relying on this EIP must realize that all smart endorsements described here are cryptographic signatures that are public and can be obtained by anyone. They must foresee the possibility of a replay of the transactions not only at the exact deployment of the same smart contract, but also other deployments of similar smart contracts, or of a version of the same contract on another chainId, or any other similar attack surfaces. The nonce, validSince, and validBy fields are meant to restrict the surface of attack but might not fully eliminate the risk of all such attacks, e.g. see the Phishing section.
Phishing
It’s worth pointing out a special form of replay attack by phishing. An adversary can design another smart contract in a way that the user be tricked into signing a smart endorsement for a seemingly legitimate purpose, but the data-to-designed matches the target application