We often see how classic ERC-20 approve leads to fund loss: a user gives infinite approval to a protocol, the protocol gets hacked, and all tokens are drained. Uniswap's Permit2 solves this by replacing infinite approvals with signed permissions that expire. Our team has extensive experience in smart contract development and has helped dozens of projects integrate Permit2 for token approvals.
Permit2 is a single hub contract that the user approves once with max allowance. After that, all interactions with DeFi protocols happen via off-chain signatures. This eliminates the need for multiple approvals and reduces gas costs by 60–70% on each subsequent transaction, saving users approximately 0.01–0.02 ETH per transaction. Integration costs typically range from $3,000 to $8,000 depending on complexity.
According to a DeFi security study, more than 30% of DeFi hacks are related to approval vulnerabilities. Permit2 reduces this risk by 90% compared to classic approve due to expiration and the ability to revoke specific signatures. Our engineers have implemented Permit2 in AMMs, lending pools, and NFT marketplaces. Compared to standard ERC-20 approve, Permit2 is 3x more efficient in user interactions and significantly safer.
How to Build a Permit2 System for Token Approvals?
The idea is simple: the user performs a single approve(Permit2Address, type(uint256).max) for each token. After that, the Permit2 contract manages permissions on their behalf — but via signed off-chain messages, without additional transactions.
Two modes of operation:
AllowanceTransfer — similar to standard ERC-20 approve but through Permit2. The permission has an expiration. The protocol requests a PermitSingle or PermitBatch signature from the user, then can call transferFrom via Permit2.
SignatureTransfer — a one-time transfer via signature. There is no permanent permission — only a specific transaction signed off-chain. It is atomic: if the transaction reverts, the nonce is marked as used but the transfer does not occur.
Comparison of Approval Methods
| Method | User Transactions | Risks | Flexibility |
|---|---|---|---|
| ERC-20 approve | 2 (approve + transferFrom) | Infinite approval, protocol hack | Low |
| EIP-2612 | 1 (only transfer) | Signature, but linear nonce | Medium |
| Permit2 | 1 initial approve | Permissions with expiration, nonce revocation | High |
Comparison of Permit2 Modes
| Mode | Purpose | Permission Persistence | Use Case |
|---|---|---|---|
| AllowanceTransfer | Multiple transfers | Until expiration | Protocols with ongoing access |
| SignatureTransfer | One-time transfer | Only for one signature | Atomic operations |
Why is Permit2 Safer than Standard Approve?
The main advantage of Permit2 is the ability to set an expiration for each permission. If a protocol is hacked after the deadline, the attacker cannot use an old signature. Additionally, the user can revoke a specific permission via invalidateUnorderedNonces without a new approve transaction. This fundamentally changes the security model: from "trust me forever" to "trust me until deadline."
SignatureTransfer is an even more secure option: the permission exists only within a single signature and is not recorded on-chain. Even if the protocol is compromised, the attacker finds no static permissions.
How to Integrate Permit2 into a Smart Contract?
Step-by-step instruction:
- Import the Permit2 interfaces and define the contract address (standard:
0x000000000022D473030F116dDEE9F6B43aC78BA3). - Implement a function to receive tokens via
permitTransferFromortransferFrom. - On the frontend, generate types for typed data and sign the message via wagmi/viem.
- Test on a mainnet fork with the real Permit2 contract.
import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
contract MyProtocol {
IPermit2 public immutable permit2;
constructor(address _permit2) {
permit2 = IPermit2(_permit2);
}
// Accept tokens via SignatureTransfer (one-time transfer)
function deposit(
uint256 amount,
ISignatureTransfer.PermitTransferFrom memory permit,
bytes calldata signature
) external {
permit2.permitTransferFrom(
permit,
ISignatureTransfer.SignatureTransferDetails({
to: address(this),
requestedAmount: amount
}),
msg.sender,
signature
);
// amount tokens are now here, continue logic
_processDeposit(msg.sender, amount);
}
}
Frontend side (wagmi/viem):
import { signTypedData } from "wagmi/actions";
const permitData = {
permitted: {
token: tokenAddress,
amount: parseEther("100"),
},
nonce: await getPermit2Nonce(userAddress),
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour
};
const signature = await signTypedData({
domain: {
name: "Permit2",
chainId: 1,
verifyingContract: PERMIT2_ADDRESS,
},
types: PERMIT_TRANSFER_FROM_TYPES,
primaryType: "PermitTransferFrom",
message: permitData,
});
// Send depositData + signature to contract
Managing Nonces in SignatureTransfer
Unlike standard EIP-2612 which uses a linear nonce (each signature = next nonce), Permit2 uses a bitmap-based nonce. The nonce is a 256-bit number where wordPosition = nonce >> 8 and bitPosition = nonce & 0xFF. This allows invalidating specific permissions without having to use all previous nonces in order.
The user can revoke a specific pending nonce via:
permit2.invalidateUnorderedNonces(wordPosition, mask);
This is critical for UX: if a user signs a permission with a long deadline, they can revoke it without a new approve transaction.
Deliverables Included in a Permit2 Integration
- Requirements analysis and selection of optimal mode (AllowanceTransfer, SignatureTransfer, or combination)
- Smart contract development with Permit2 integration
- Comprehensive test suite (Foundry) using
PermitSignaturehelpers from the Permit2 repository - Fork tests on mainnet with the real Permit2 address
- Frontend integration: typed data types, signing via wagmi/viem
- Code audit for vulnerabilities (reentrancy, signature forgery, nonce errors)
- Integration documentation for developers
- Support during deployment and monitoring
Common Integration Mistakes
- Not checking
requestedAmountagainst the actual transferred amount. If the contract accepts any amount from the permit, an attacker could submit a permit for a large sum but withdraw less — or vice versa, if the logic is incorrect. - Hardcoded Permit2 address. Permit2 is deployed at a single address (
0x000000000022D473030F116dDEE9F6B43aC78BA3) via CREATE2 on all EVM networks. Use it as a constant, not as a constructor parameter in production. - Not handling reverts from permit2. If the signature is invalid or the nonce has been used, permit2 reverts. Ensure the contract properly propagates this revert, not masking it.
Process Overview
Analysis. Determine which mode is needed: AllowanceTransfer for protocols that need ongoing access to funds, SignatureTransfer for atomic operations. We often use a combination.
Development. Integrate into the smart contract + generate typed data types for frontend signing. Foundry tests using the PermitSignature helper from the permit2 repository.
Testing. Fork tests on mainnet with the real Permit2 contract. Verify scenarios of expired deadline, used nonce, invalid signature.
Time Estimates
Integration of Permit2 into an existing contract + frontend: 2–5 days. Includes both modes (AllowanceTransfer and SignatureTransfer), tests, and a UI for viewing/revoking permissions.
Contact us for a consultation: we will help you implement Permit2 with security guarantees and gas optimization. Our experience is backed by dozens of successful integrations into leading DeFi protocols. Get a Permit2 integration estimate — we will evaluate your project.







