EIP 2612 introduces the function
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) to the ERC20 ABI. This function takes in signature parameters generated through ECDSA, combined with the EIP 712 standard for typed data hashing, and recovers the author of the signature through
ecrecover(). It then sets
This method presents a new way of allocating allowances, as signatures can be computed off-chain and passed to a contract. It allows a relayer to pay the entire gas fee of the permit transaction in exchange for a fee, enabling completely gasless transactions for a user. Furthermore, this removes the typical
approve() -> transferFrom() pattern that forces users to send two transactions instead of just one through this new method.
Note that for the permit function to work, a valid signature is needed. This example will demonstrate how we can use
sign cheatcode to sign data with a private key. More generally, you can use this cheatcode to test anything that requires valid signatures.
We use Solmate’s implementation of the ERC20 standard that includes the permit function. Observe that there are also values for the
PERMIT_TYPEHASH and a
mapping(address -> uint256) public nonces. The former is part of the EIP712 standard, and the latter is used to prevent signature replay attacks.
TestDepositWithPermit contract, we need to have the signature signed by an owner for validation. To accomplish this, we can use
sign cheatcode, which takes in a message and a private key and creates a valid signature. For this example, we use the private key
0x02, and the following signed message representing the permit signature following the EIP 712:
keccak256( abi.encodePacked( "\x19\x01", asset.DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), owner, spender, assetAmount, asset.nonces(owner), block.timestamp ) ) ) );
The helper function
getSignature(address owner, address spender, uint256 assetAmount) returns a valid signature generated via the
sign cheatcode. Note that the sign cheatcode exposes the private key, so it is best to use dummy keys when testing. Our keypair data was taken from this site. To test the signature, we will mint a random amount to the
OWNER address, the address corresponding to the private key
0x02, which was the signer of the permit signature. We then check whether we can use that signature to transfer the owner’s tokens to ourselves.
First, we call
permit() on our Mock ERC20 token with the signature generated in
getSignature(), and then call
transferFrom(). If our permit request and transfer are successful, our balance of the mock ERC20 should increase by the amount permitted, and the
OWNER's balance should decrease as well. For simplicity, we'll transfer all the minted tokens so that the
OWNER's balance will be
0, and our balance will be
The complete example code can be found here.