Approvals are confusing.
Off chain financial transfers at least appear atomic whereas the ERC20 token standard forces users call an additional function approve to allow applications to pull assets on your behalf.
Eco recently introduced Permit3: a new contract for cross-chain approvals.
It is a serious effort to bring multichain UX forward and I think it deserves a deeper look.
But before we start, we need to review the approval landscape today.
By the end of this post, you’ll be able to understand what everything means in this chart:
EIP-2612
The original sin of ERC20 was to mandate a impossible choice: either use a separate transaction for each approval and be gas inefficient or approve an “infinite” amount and be at risk if the app you interact with gets maliciously upgraded.
EIP-2612 made approvals more efficient by allowing token contracts to support signature based approvals.
Now, you didn't have to waste an additional transaction on an approval, you could provide a signature to the app instead and it could call permit on the token contract before pulling your tokens: all in one transaction.
Workflow
The author of a new ERC20 token adds support for 3 new functions: permit, nonces and DOMAIN_SEPARATOR.
The application developer now has to use permit() in addition to transferFrom to receive tokens from the user.
Example: application is a vault with a deposit function. The deposit function should also accept a signature as an argument and then call permit and transferFrom in that order.
The user provides the permit signature to the application alongside their transaction.
The permit call will successfully modify the user’s allowance before the tokens are pulled.
Unfortunately, the standard didn't get universally adopted and introduced three new problems…
PERMIT2
First, it couldn't be added to tokens retroactively and many popular tokens didn't support signature-based approvals (in fact many still don't).
Second, individual signatures were still required per approval.
Third, EIP-2612 didn't work well for smart wallets since the signatures had to be created off chain from an EOA.
Permit2 was the solution.
The original idea was developed here as part of the PermitEverywhere contract but the version that caught on was built by Uniswap Labs. The idea was to use a dedicated contract which would become the source of truth for all token approvals for all tokens, applications and users.
Users interact with the Permit2 contract to create an approval and applications call transferFrom on the Permit2 contract directly.
Workflow
Uniswap Labs deploys the Permit2 contract (once for each chain).
A user who wants to move a token first does an infinite approval for that token to the Permit2 contract. This only needs to be done once per token.
Now each application UI can ask users to specify the approval through the Permit2 contract. Smart wallets can directly modify the per-application approvals but EOAs can do so via off chain signatures, combining the best of 2 worlds.
Then the onchain application can request funds directly from the Permit2 contract which will release them in accordance with the pre-approved allowance.
Beyond creating the original approval at the best case (EOA), this requires the same number of steps as EIP-2612. In the worst case (smart wallet), this is no worse than doing a regular ERC20 approval.
PERMIT3
Now we are set up to understand Eco’s Permit3 contract.
Permit3 sets out to fix two main issues with Permit2:
Permit2 operates independently for each chain. While it does allow batching approvals per-chain in a single signature, it doesn't allow approvals to be batched across chains.
Permit2 uses a linear nonce system meaning that the approvals (or direct transactions) have to be sent in a set sequence.
Using Permit3, you can have one big signature containing approvals for multiple tokens, applications and even chains. For example you could approve Uniswap to spend your WETH on Unichain and approve Aerodrome to spend your USDC on Base using a single signature.
The workflow is very similar to Permit2. The primary difference is that the Permit3 contract uses Merkle trees to effectively store multiple approvals so when interacting with a chain you only need to specify that chain’s approvals and a Merkle proof that they are part of the overall signature.
Permit3 stores a salt for every single operation allowing it to only be executed once. This “async nonce” system is as safe as using linear nonces (which increment by one after every transaction) although less efficient.
It is very useful for automated transaction generation.
Consider an EOA that needs to communicate with 3 separate contracts. Without proper nonce management, there is a risk that transactions would fail. For example, if the nonce is 0 and you send a transaction that would set it to 1 and a transaction that would set it to 2. If the transactions get sequenced incorrectly, then the Permit2 contract would expect a nonce of 0 but see a nonce of 1 in the second transaction which would then fail. Only the first transaction would eventually get accepted.
In contrast, Permit3 would correctly accept both transactions, marking the salt value for each as spent.
WHAT IT MEANS
Permit3 plays into two significant changes in how we use blockchains.
The first direction is chain abstraction. Wallets already operate across chains (to access the best yields and the widest set of applications) but UX has been complicated. Chain abstraction aims to make the UX as easy as when interacting on a single chain. Having a single signature for multichain approvals does just that.
The second trend is increased automation or transactions being created by relayers, solvers, trading bots and curators.
When I built a keeper agent, nonce management was always tricky when using a single address to interface with multiple applications in parallel. I had to maintain the nonce internally in the app (even before transactions were approved) and then use that nonce for any new transactions being issued.
RISKS
The risk of bundling more complicated signatures is that it is harder for users to verify what they are signing. The good thing is that you still need to manually approve tokens for the Permit3 contract to spend on every chain which reduces the risk that you would be drained on a chain that you haven't interacted on.
Ultimately Permit2 changed the game by allowing applications to decide which approval flow to use. Unfortunately, applications have failed to realize that ERC2612 should still be used when possible for tokens that support it.
Adding another standard makes this more complicated for applications and integrators and they may integrate Permit3 on an inconsistent basis preventing users from reaping the full benefits. Many users would also need to fragment their approvals across Permit2 and Permit3 going forward resulting in more approvals overall.
There is always smart contract risk to consider with any contract especially one that expects you to use an infinite approval with. While Permit3 is audited and open source, it will need some time in the sun before safety is assured.
All in all, I find Permit3 a promising iteration on Permit2 and very elegantly built. We use Merkle trees extensively for Aera and it’s exciting to see how they are used here to make signature validation more efficient.