If you have used Uniswap, CoW, 1inch, or any modern DEX aggregator in the last two years, you have probably granted a Permit2 approval. You may not remember doing it — the prompt often reads as one of several signatures during a swap flow and the wallet modal usually just says "Sign typed data" without a loud "YOU ARE GRANTING A NEW PERMISSION" banner.
Revoking a Permit2 approval is different from revoking a classic ERC-20 approval. The mental model is different; the on-chain artefact is different; and sometimes the "revocation" does not require a chain transaction at all. This post is a short walk-through of what Permit2 revocation actually looks like, when it matters, and what the wallets and scanners can and cannot show you.
The two layers of a Permit2 approval
Permit2 is a contract at 0x000000000022D473030F116dDEE9F6B43aC78BA3 (same address on every major EVM chain). To use Permit2 on a given token, you:
- Grant a one-time, usually unlimited, classic ERC-20 approval to the Permit2 contract itself. This is a regular on-chain
approvetransaction, and it is what Permit2 consumes when protocols actually move your tokens. After this step, the Permit2 contract has the ability to calltransferFromon the token for your address. - Sign off-chain typed-data grants for specific downstream spenders. Each signed grant names a spender (e.g. the Uniswap Universal Router), an amount, and an expiry. These signatures sit off-chain until a downstream contract submits them to Permit2 to actually move tokens.
Two layers means two things to potentially revoke. They behave completely differently.
Layer 1 — revoking the token→Permit2 allowance
The ERC-20 allowance you granted to the Permit2 contract in step (1) is on-chain and behaves like any other approval. You revoke it by calling approve(permit2, 0) on the token. This is the same mechanism as any classic revocation.
In our scanner at allowanceguard.com, these rows appear with Permit2 as the spender name. Tapping "Revoke" on such a row generates an on-chain approve(permit2, 0) transaction for your wallet to sign and pay gas for. Confirmation is immediate.
When to do this: if you are done using Permit2-integrated protocols for a token entirely, or if you want a fresh allowance ceiling, this is the right layer to revoke. It is the broad revocation — removing the entire Permit2 pathway for that token.
Layer 2 — revoking individual off-chain grants
The typed-data signatures in step (2) live in the Permit2 contract's storage as a pair of (owner, token, spender) → (amount, expiration, nonce). Revoking a specific grant means calling Permit2.lockdown([{ token, spender }]) or setting the allowance to zero for that particular spender, which is what lockdown does under the hood.
The UX reality: most wallet UIs do not surface Permit2 sub-allowances directly. Rabby does, and it has a dedicated revoke pane for them. MetaMask does not (as of 2026-04). The Uniswap frontend exposes revocation of your Permit2 grant to its own Universal Router in the wallet settings page but not grants to other downstream routers.
In the AllowanceGuard scanner, Permit2 sub-allowances appear as separate rows with the downstream spender (e.g. Uniswap Universal Router, CoW Settlement) as the row's spender, and via Permit2 as a label. Tapping "Revoke" on these rows generates a Permit2 lockdown call, which is still an on-chain transaction and still costs gas — but the gas is usually lower than a full approval revoke because it's a storage-slot clear.
When to do this: if you used a specific integration once (aggregator X, then switched to aggregator Y) and want to tidy the specific grant without touching the broader token→Permit2 allowance, lockdown is the right tool.
The trapdoor case — expired signatures you did not submit
Here is where Permit2 gets unusual. Some Permit2 grants exist only as off-chain signatures you signed but never submitted — because the downstream protocol's router submits the signature when it executes a swap. If you signed a Permit2 grant for a large amount and a long expiry but then closed the tab before the swap executed, there is a signed message out there that a downstream spender could, in principle, submit to Permit2 up until the deadline passes.
You cannot directly revoke this, because there is nothing on-chain to change. But you can invalidate every unsubmitted signature for a given (owner, token, spender) triple by using Permit2's nonce-invalidation mechanism: Permit2.invalidateNonces(token, spender, newNonce). Calling this with a nonce value higher than any you have signed invalidates all prior signed messages for that triple. It is a belt-and-braces call for anyone who has been signing Permit2 grants with long expiries.
When to do this: if you regularly sign Permit2 grants via aggregators, a periodic nonce-invalidation per (token, spender) on anything you care about is reasonable hygiene. It is overkill for most users; it is essential for treasury wallets.
Can a scanner see un-submitted signatures?
No. Un-submitted Permit2 signatures are pure off-chain data. No on-chain scanner — ours or anyone else's — can see them. The scanner sees the on-chain consequence (an approved-but-not-yet-consumed allowance, or a nonce that has been advanced) but not the signed message itself. This is why wallet-level typed-data decoding matters: Rabby showing you what you are signing at the moment of signature is the only defence for the off-chain layer. Our layer is the on-chain hygiene that follows.
A clean sequence to clear Permit2 exposure for a token
If you want to fully clear Permit2 exposure for a given token — for example, you are about to move that token to a cold wallet and never use it with a Permit2-integrated protocol again — the clean sequence is:
- Invalidate nonces for each downstream spender you remember granting signatures to. One
invalidateNoncescall per (token, spender) triple, any reasonable future nonce value. - Lockdown per spender for any Permit2 sub-allowances our scanner shows on that token. One
lockdowncall can batch multiple spenders. - Revoke the token→Permit2 allowance on-chain with
approve(permit2, 0).
In practice, steps 1 and 2 are the thorough version. Step 3 alone is enough for the vast majority of cases, because any downstream protocol trying to use an old signed grant would have to go through Permit2, and without the token→Permit2 allowance Permit2 cannot transfer anything. Steps 1 and 2 are belt-and-braces.
Gas cost
At current mainnet gas prices, each of these calls is roughly:
approve(permit2, 0)— ~46,000 gas. Same cost as any ERC-20 revoke.Permit2.lockdown— ~32,000 gas per (token, spender) pair.Permit2.invalidateNonces— ~28,000 gas per (token, spender) pair.
On L2s (Arbitrum, Base, Optimism) these are sub-cent operations. On mainnet at moderate gas, the full three-step sequence for a token is under $3 total. The sequence is cheap relative to the risk coverage it delivers.
Where our scanner helps
The scanner identifies Permit2 sub-allowances as separate rows with the downstream spender named, so you can revoke specific grants without touching the broader token→Permit2 allowance. Batch revoke (Pro tier) bundles multiple lockdown calls into a single EIP-5792 transaction where the chain supports it, so clearing ten Permit2 sub-allowances costs one signature and one gas payment instead of ten.
If you are done using Permit2-integrated protocols entirely for a token — and that is not always the right call — the top-level revoke of token→Permit2 is the single most effective action. The rest is hygiene.

