TIP-1004: Permit for TIP-20
Protocol Version: T2
Status: In Review
Authors: Dan Robinson
Status: In Review
Authors: Dan Robinson
Abstract
TIP-1004 adds EIP-2612 compatiblepermit() functionality to TIP-20 tokens, enabling gasless approvals via off-chain signatures. This allows users to approve token spending without submitting an on-chain transaction, with the approval being executed by any third party who submits the signed permit.
Motivation
The standard ERC-20 approval flow requires users to submit a transaction to approve a spender before that spender can transfer tokens on their behalf. Among other things, this makes it difficult for a transaction to “sweep” tokens from multiple addresses that have never sent a transaction onchain. EIP-2612 introduced thepermit() function which allows approvals to be granted via a signed message rather than an on-chain transaction. This enables:
- Gasless approvals: Users can sign a permit off-chain, and a relayer or the spender can submit the transaction
- Single-transaction flows: DApps can batch the permit with the subsequent action (e.g., approve + swap) in one transaction
- Improved UX: Users don’t need to wait for or pay for a separate approval transaction
Alternatives
While Tempo transactions provide solutions for most of the common problems that are solved by account abstraction, they do not provide a way to transfer tokens from an address that has never sent a transaction onchain, which means it does not provide an easy way for a batched transaction to “sweep” tokens from many addresses. While we plan to have Permit2 deployed on the chain, it, too, requires an initial transaction from the address being transferred from. Adding a function fortransferWithAuthorization, which we are also considering, would also solve this problem. But permit is somewhat more flexible, and we think these functions are not mutually exclusive.
Specification
New Functions
The following functions are added to the TIP-20 interface:EIP-712 Typed Data
The permit signature must conform to EIP-712 typed structured data signing.Domain Separator
Permit Typehash
Signature Construction
Behavior
Nonces
Each address has an associated nonce that:- Starts at
0for all addresses - Increments by
1each time a permit is successfully executed for that address - Must be included in the permit signature to prevent replay attacks
Deadline
Thedeadline parameter is a Unix timestamp. The permit is only valid if block.timestamp <= deadline. This allows signers to limit the validity window of their permits.
Pause State
Thepermit() function follows the same pause behavior as approve(). Since setting an allowance does not move tokens, permit() is allowed to execute even when the token is paused.
TIP-403 Transfer Policy
Thepermit() function does not perform TIP-403 authorization checks, consistent with the behavior of approve(). Transfer policy checks are only enforced when tokens are actually transferred.
Signature Validation
The implementation must:- Verify that
block.timestamp <= deadline, otherwise revert withPermitExpired - Retrieve the current nonce for
ownerand use it to construct thestructHashanddigest - Increment
nonces[owner] - Validate the signature:
- The
vparameter must be27or28. Values of0or1are not normalized and will revert withInvalidSignature. - Use
ecrecoverto recover a signer address from the digest - If
ecrecoverreturns a non-zero address that equalsowner, the signature is valid (EOA case) - Otherwise, revert with
InvalidSignature
- The
- Set
allowance[owner][spender] = value - Emit an
Approval(owner, spender, value)event
The nonce is included in the signed digest, so nonce verification is implicit in signature validation—if the wrong nonce was signed,
ecrecover will return a different address.New Errors
New Events
None. Successful permit execution emits the existingApproval event from TIP-20.
Invariants
nonces(owner)must only ever increase, never decreasenonces(owner)must increment by exactly 1 on each successfulpermit()call for that owner- A permit signature can only be used once (enforced by nonce increment)
- A permit with a deadline in the past must always revert
- The recovered signer from a valid permit signature must exactly match the
ownerparameter - After a successful
permit(owner, spender, value, ...),allowance(owner, spender)must equalvalue DOMAIN_SEPARATOR()must be computed dynamically and reflect the currentblock.chainid