Skip to content

eco/permit3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

222 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Permit3: One-Click Cross-Chain Token Permissions

License: MIT

Permit3 is an approval system that enables cross-chain token approvals and transfers with a single signature. It unlocks a one-signature cross-chain future through Unbalanced Merkle Trees and non-sequential nonces, while maintaining Permit2 compatibility.

Security

The contracts in this repository are deployed on-chain and custody user funds. A vulnerability that becomes public before it is fixed can be exploited immediately and irreversibly β€” public disclosure of an unpatched bug is itself the attack.

If you find a security vulnerability, report it privately. Do not open a public pull request, push a branch, or open a public issue. Report it through the Security tab β†’ "Report a vulnerability", which opens a private advisory visible only to you and the maintainers. Permit3 is deployed at a deterministic address on all supported chains β€” treat all contracts as live unless a maintainer explicitly confirms otherwise.

See SECURITY.md for the full policy, including specific instructions for AI coding agents. This applies to humans and automated tools alike.

Overview

Permit3 Architecture

Deployment Information

Permit3 is deployed using ERC-2470 Singleton Factory for deterministic addresses across all chains:

This ensures the same contract address on all supported networks, enabling seamless cross-chain operations.

Key Features

  • Cross-Chain Operations: Authorize token operations across multiple blockchains with one signature
  • Multi-Token Support: Unified interface for ERC20, ERC721 NFTs, and ERC1155 semi-fungible tokens
  • Direct Permit Execution: Execute permit operations without signatures when caller has authority
  • ERC-7702 Integration: Account Abstraction support for enhanced user experience
  • Witness Functionality: Attach arbitrary data to permits for enhanced verification and complex permission patterns
  • NFT & Semi-Fungible Token Features:
    • Dual-allowance system (per-token and collection-wide)
    • TokenId encoding for signed permits
    • Batch operations for multiple token types
    • ERC1155 gaming asset support
  • Flexible Allowance Management:
    • Increase/decrease allowances asynchronously
    • Time-bound permissions with automatic expiration
    • Account locking for enhanced security
  • Gas-Optimized Design:
    • Non-sequential nonces for concurrent operations
    • Bitmap-based nonce tracking for efficient gas usage
    • Standard merkle proofs using OpenZeppelin's MerkleProof library
  • Emergency Security Controls:
    • Cross-chain revocation system
    • Account locking mechanism
    • Time-bound permissions
  • Full Permit2 Compatibility:
    • Implements basic transfer Permit2 interfaces
    • Drop-in replacement for existing integrations
  • Unbalanced Merkle Trees: Hybrid two-part structure for cross-chain proofs:
                   [H1] β†’ [H2] β†’ [H3] β†’ ROOT  ← Unbalanced upper structure
                /      \      \      \
              [BR]    [D5]   [D6]   [D7]      ← Additional chain data
             /     \
         [BH1]     [BH2]                      ← Balanced tree (bottom part)
        /    \     /    \
      [D1]  [D2] [D3]  [D4]                   ← Leaf data
    
    • Unbalanced Design: Combines balanced subtrees with unbalanced upper structure for efficiency
    • Bottom Part: Efficient membership proofs with O(log n) complexity
    • Top Part: Unbalanced structure minimizes proof size for expensive chains
    • Gas Optimization: Chain ordering (cheapest chains first, expensive last)
    • "Unbalanced": Deliberate deviation from balanced trees at top level
    • Security: Uses merkle tree verification for compatibility

Documentation

Comprehensive documentation is available in the docs directory:

Section Description Quick Links
Overview Getting started with Permit3 Introduction
Core Concepts Understanding the fundamentals Architecture Β· Multi-Token Β· Witnesses Β· Cross-Chain Β· Merkle Trees Β· Nonces Β· Allowances Β· Permit2 Compatibility
Guides Step-by-step tutorials Quick Start Β· Multi-Token Β· NFT Permits Β· ERC-7702 Β· Witness Β· Cross-Chain Β· Signatures Β· Security
API Reference Technical specifications Full API Β· Data Structures Β· Interfaces Β· Events Β· Error Codes
Examples Code samples Multi-Token Β· ERC-7702 Β· Witness Β· Cross-Chain Β· Allowance Β· Security Β· Integration

Core Concepts

Allowance Operations

The protocol centers around the AllowanceOrTransfer structure:

struct AllowanceOrTransfer {
    uint48 modeOrExpiration;    // Operation mode/expiration
    address token;              // Token address
    address account;            // Approved spender/recipient
    uint160 amountDelta;        // Amount change/transfer amount
}

Timestamp Management

struct Allowance {
    uint160 amount;
    uint48 expiration;
    uint48 timestamp;
}
  • Timestamps order operations across chains
  • Most recent timestamp takes precedence in expiration updates
  • Prevents cross-chain race conditions
  • Critical for async allowance updates

Account Locking

Locked accounts have special restrictions:

  • Cannot increase/decrease allowances
  • Cannot execute transfers
  • Must submit unlock command with timestamp validation to disable
  • Provides emergency security control

Integration

Basic Setup

// Access Permit2 compatibility
IPermit permit = IPermit(PERMIT3_ADDRESS);
permit.transferFrom(msg.sender, recipient, 1000e6, USDC);

// Access Permit3 features
IPermit3 permit3 = IPermit3(PERMIT3_ADDRESS);

Direct Multi-Token Functions

For direct transfers without signatures, use specialized functions:

// NFT transfer
permit3.transferFromERC721(from, to, nftContract, tokenId);

// ERC1155 transfer  
permit3.transferFromERC1155(from, to, erc1155Contract, tokenId, amount);

// Batch mixed tokens
TokenTypeTransfer[] memory transfers = [...];
permit3.batchTransferMultiToken(transfers);

Example Operations

// 1. Create permits array directly
AllowanceOrTransfer[] memory permits = new AllowanceOrTransfer[](3);

// 2. Increase Allowance
permits[0] = AllowanceOrTransfer({
    modeOrExpiration: uint48(block.timestamp + 1 days),
    token: USDC,
    account: DEX,
    amountDelta: 1000e6
});

// 3. Lock Account
permits[1] = AllowanceOrTransfer({
    modeOrExpiration: 2,
    token: USDC,
    account: address(0),
    amountDelta: 0
});

// 4. Execute Transfer
permits[2] = AllowanceOrTransfer({
    modeOrExpiration: 0,
    token: USDC,
    account: recipient,
    amountDelta: 500e6
});

// Execute the permits
permit3.permit(owner, salt, deadline, timestamp, permits, signature);

Cross-Chain Usage with Merkle Proofs

// Create permits for each chain
const ethPermits = {
    chainId: 1,
    permits: [{
        modeOrExpiration: futureTimestamp,
        token: USDC_ETH,
        account: DEX_ETH,
        amountDelta: 1000e6
    }]
};

const arbPermits = {
    chainId: 42161,
    permits: [{
        modeOrExpiration: 1, // Decrease mode
        token: USDC_ARB,
        account: DEX_ARB,
        amountDelta: 500e6
    }]
};

// Hash each chain's permits to create leaf nodes
const ethLeaf = permit3.hashChainPermits(ethPermits);
const arbLeaf = permit3.hashChainPermits(arbPermits);

// Build merkle tree and get root (typically done off-chain)
const leaves = [ethLeaf, arbLeaf];
const merkleRoot = buildMerkleRoot(leaves);

// Generate merkle proof for specific chain
const arbProof = generateMerkleProof(leaves, 1); // Index 1 for Arbitrum
const proof = { nodes: arbProof };

// Create and sign with the unbalanced root
const signature = signPermit3(owner, salt, deadline, timestamp, merkleRoot);

Security Guidelines

  1. Allowance Management

    • Set reasonable expiration times
    • Use lock mode for sensitive accounts
    • Monitor allowance changes across chains
  2. Timestamp Validation

    • Validate operation ordering
    • Check for expired timestamps
    • Handle locked state properly
  3. Cross-Chain Security

    • Verify chain IDs match
    • Use unique nonces
    • Monitor pending operations

Development

# Install
forge install

# Test
forge test

# Deploy
forge script script/DeployPermit3.s.sol:DeployPermit3 \
    --rpc-url <RPC_URL> \
    --private-key <KEY> \
    --broadcast

Audits

See Audits

πŸ“„ License

MIT License - see LICENSE

About

πŸ” Permit3: One-Click Cross-Chain Token Permissions

Resources

License

Security policy

Stars

17 stars

Watchers

6 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors