Skip to content
/ permit3 Public

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

License

Notifications You must be signed in to change notification settings

eco/permit3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

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.

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

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 7