ERC-3009 enables ERC-20 transfers via signed authorizations instead of on-chain transactions. Unlike ERC-2612's sequential nonces, it uses random 32-byte nonces allowing multiple concurrent authorizations. The signature includes validity windows and can be submitted by any relayer.
Sequential nonces break when users sign multiple meta-transactions before they confirm. Random nonces allow users to pre-sign many transfers without coordination. Combined with time windows, this enables complex DeFi interactions where multiple authorizations need to execute in any order.
A set of functions to enable meta-transactions and atomic interactions with ERC-20 token contracts via signatures conforming to the EIP-712 typed message signing specification.
This enables the user to:
Please note that this ERC does not apply to smart contract accounts, as the transfer and approve/transferFrom functions from the ERC-20 standards can directly be used.
There is an existing spec, ERC-2612, that also allows meta-transactions, and it is encouraged that a contract implements both for maximum compatibility. The two primary differences between this spec and ERC-2612 are that:
approve/transferFrom ("ERC-20 allowance") pattern.The biggest issue with the use of sequential nonces is that it does not allow users to perform more than one transaction at a time without risking their transactions failing, because:
This can be especially problematic if the gas prices are very high and transactions often get queued up and remain unconfirmed for a long time. Non-sequential nonces allow users to create as many transactions as they want at the same time.
The ERC-20 allowance mechanism is susceptible to the /, and encourages antipatterns such as the use of the "infinite" allowance. The wide prevalence of upgradeable contracts has made the conditions favorable for these attacks to happen in the wild.
The deficiencies of the ERC-20 allowance pattern brought about the development of alternative token standards such as the ERC-777 and . However, they haven't been able to gain much adoption due to compatibility and potential security issues.
Optional:
The arguments v, r, and s must be obtained using the EIP-712 typed message signing spec.
Example:
With the domain separator, the typehash, which is used to identify the type of the EIP-712 message being used, and the values of the parameters, you are able to derive a Keccak-256 hash digest which can then be signed using the token holder's private key.
Example:
Smart contract functions that wrap receiveWithAuthorization call may choose to reduce the number of arguments by accepting the full ABI-encoded set of arguments for the receiveWithAuthorization call as a single argument of the type bytes.
Example:
The signature for an authorization can be obtained using a web3 provider with the eth_signTypedData{_v4} method.
Example:
One might say transaction ordering is one reason why sequential nonces are preferred. However, sequential nonces do not actually help achieve transaction ordering for meta transactions in practice:
verifyingContract and chainId are included.New contracts benefit from being able to directly utilize ERC-3009 in order to create atomic transactions, but existing contracts may still rely on the conventional ERC-20 allowance pattern (approve/transferFrom).
In order to add support for ERC-3009 to existing contracts ("parent contract") that use the ERC-20 allowance pattern, a forwarding contract ("forwarder") can be constructed that takes an authorization and does the following:
receiveWithAuthorization to transfer specified funds from the user to the forwarderExample:
EIP3009.solIERC20Transfer.solEIP712Domain.solEIP712.solA fully working implementation of ERC-3009 can be found in this repository. The repository also includes an implementation of ERC-2612 that uses the EIP-712 library code presented above.
Use receiveWithAuthorization instead of transferWithAuthorization when calling from other smart contracts. It is possible for an attacker watching the transaction pool to extract the transfer authorization and front-run the transferWithAuthorization call to execute the transfer without invoking the wrapper function. This could potentially result in unprocessed, locked up deposits. receiveWithAuthorization prevents this by performing an additional check that ensures that the caller is the payee. Additionally, if there are multiple contract functions accepting receive authorizations, the app developer could dedicate some leading bytes of the nonce as an identifier to prevent cross-use.
When submitting multiple transfers simultaneously, be mindful of the fact that relayers and miners will decide the order in which they are processed. This is generally not a problem if the transactions are not dependent on each other, but for transactions that are highly dependent on each other, it is recommended that the signed authorizations are submitted one at a time.
The zero address must be rejected when ecrecover is used to prevent unauthorized transfers and approvals of funds from the zero address. The built-in ecrecover returns the zero address when a malformed signature is provided.
Copyright and related rights waived via CC0.