Permit2
Universal token approval and transfer management system with signature-based permissions
Permit2 is a universal token approval contract that enables signature-based approvals and transfers. Developed by Uniswap Labs, it improves upon EIP-2612 by providing a single contract for managing token permissions across all ERC20 tokens, even those that don't natively support permits.
Contract Address: 0x000000000022D473030F116dDEE9F6B43aC78BA3 Deployment Status: Default preinstall
Key Benefits
Universal Compatibility: Works with any ERC20 token
Gas Savings: One-time approval to Permit2, then signature-based transfers
Enhanced Security: Granular permissions with expiration times
Better UX: Gasless approvals via signatures
Batching Support: Multiple token operations in one transaction
Core Concepts
Two-Step Process
One-time Approval: User approves Permit2 to spend their tokens
Signature Permits: User signs messages for specific transfers
Permission Types
AllowanceTransfer: Traditional allowance model with signatures
SignatureTransfer: Direct transfers using only signatures
Core Methods
Allowance Transfer
Signature Transfer
Usage Examples
Basic Permit2 Integration
```javascript "Ethers.js Complete Permit2 Integration" expandable import { ethers } from "ethers"; import { AllowanceProvider, AllowanceTransfer } from "@uniswap/permit2-sdk";
const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
// Step 1: User approves Permit2 for token (one-time) async function approvePermit2(tokenContract, signer) { const tx = await tokenContract.approve( PERMIT2_ADDRESS, ethers.MaxUint256 ); await tx.wait(); console.log("Permit2 approved for token"); }
// Step 2: Create and sign permit async function createPermit(token, spender, amount, deadline, signer) { const permit = { details: { token: token, amount: amount, expiration: deadline, nonce: 0, // Get current nonce from contract }, spender: spender, sigDeadline: deadline, }; // Create permit data const { domain, types, values } = AllowanceTransfer.getPermitData( permit, PERMIT2_ADDRESS, await signer.provider.getNetwork().then(n => n.chainId) ); // Sign permit const signature = await signer._signTypedData(domain, types, values); return { permit, signature };
}
// Step 3: Execute transfer with permit async function transferWithPermit(permit, signature, transferDetails) { const permit2 = new ethers.Contract( PERMIT2_ADDRESS, ["function transferFrom(address,address,uint160,address)"], signer ); // First, submit the permit await permit2.permit( signer.address, permit, signature ); // Then transfer await permit2.transferFrom( transferDetails.from, transferDetails.to, transferDetails.amount, transferDetails.token );
}
Batch Operations
Handle multiple tokens in one transaction:
Gasless Approvals
Enable gasless token approvals using meta-transactions:
Advanced Features
Witness Data
Include additional data in permits for complex protocols:
Nonce Management
Permit2 uses unordered nonces for flexibility:
Expiration Handling
Set appropriate expiration times:
Security Considerations
Best Practices
Validate Signatures: Always verify signature validity
Check Expiration: Ensure permits haven't expired
Nonce Tracking: Prevent replay attacks
Amount Limits: Set reasonable amount limits
Deadline Checks: Validate signature deadlines
Common Attack Vectors
Signature Replay: Mitigated by nonces
Front-running: Use commit-reveal or deadlines
Phishing: Educate users about signing
Unlimited Approvals: Set specific amounts
Integration Patterns
DEX Integration
Payment Processor
Comparison with Alternatives
Universal Support
Yes
No (per-token)
Yes
Gas for Approval
Once per token
None (signature)
Every time
Granular Control
Excellent
Limited
Basic
Batch Operations
Yes
No
No
Signature Required
Yes
Yes
No
Common Issues
"PERMIT_EXPIRED"
Increase deadline or request new signature
"INVALID_SIGNATURE"
Verify signer address and signature data
"INSUFFICIENT_ALLOWANCE"
Ensure Permit2 is approved for token
"NONCE_ALREADY_USED"
Use a new nonce for the permit
Libraries and SDKs
Permit2 SDK - Official TypeScript SDK
Permit2 Universal Router - Integration example
Permit2 Periphery - Helper contracts
