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

  1. One-time Approval: User approves Permit2 to spend their tokens

  2. 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

  1. Validate Signatures: Always verify signature validity

  2. Check Expiration: Ensure permits haven't expired

  3. Nonce Tracking: Prevent replay attacks

  4. Amount Limits: Set reasonable amount limits

  5. 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

Feature
Permit2
EIP-2612
Traditional Approve

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

Issue
Solution

"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

Further Reading