Someone setting up a hardware wallet for the first time, packaging on desk, laptop with wallet interface, afternoon home office light, casual unboxing moment.
Protocols

Permit2 Signature Verification and Witness Types

A technical reference for the EIP-712 typed data structures used by Uniswap's Permit2 contract, covering PermitSingle, PermitBatch, and Witness types. Essential for wallet developers, aggregator frontends, and any dapp implementing gasless approvals without relying on a single SDK.
introduction
EIP-712 SIGNATURE STRUCTURES

Introduction

How Permit2 encodes approvals and witness data for off-chain signatures, and why every wallet and frontend must handle these types correctly.

Permit2 extends Uniswap's token approval architecture by introducing a set of EIP-712 typed data structures that allow users to sign gasless approvals and transfers off-chain. The core structures—PermitSingle, PermitBatch, and the composable Witness types—define exactly what a user authorizes: which token, how much, to which spender, and for how long. Any wallet, aggregator, or dapp that constructs or displays a Permit2 signature must implement these types precisely. A mismatch in the typed data, even in a single field name, produces a signature that the on-chain SignatureTransfer or AllowanceTransfer contracts will reject.

The PermitSingle type authorizes a one-off transfer of a specific token to a single spender, while PermitBatch packs multiple token allowances into one signature for batched operations. The Witness types add a critical composability layer: they allow an integrator to embed arbitrary application-specific data into the signed message, cryptographically binding a Permit2 authorization to a higher-level action such as a swap path or a deposit instruction. This prevents signature replay across different application contexts. For wallets, the challenge is parsing and displaying these nested types clearly so users understand what they are signing. For frontends, the challenge is constructing the exact TypedData DOMAIN, types, and message payloads without relying on a single SDK.

Operationally, incorrect witness handling is a leading source of integration failures and potential phishing vectors. If a frontend constructs a witness with an ambiguous type hash, a malicious relayer could replay the signature in an unintended context. If a wallet fails to decode the witness fields, the user signs blind. Chainscore Labs reviews Permit2 integration code, signature construction, and wallet display logic to ensure that typed data structures are correctly implemented, witness types are non-ambiguous, and the full authorization scope is visible to the end user before signing.

PERMIT2 SIGNATURE VERIFICATION AND WITNESS TYPES

Quick Facts

Key structural facts about Permit2's EIP-712 typed data structures, their operational constraints, and the integration risks they introduce for wallets and protocols.

FieldValueWhy it matters

Core EIP-712 Types

PermitSingle, PermitBatch, AllowanceTransferDetails, PermitTransferFrom, Witness

Wallets must correctly construct and display these exact types to users; a mismatch causes signature failure or blind signing of malicious data.

Witness Type Purpose

Allows a protocol to embed its own typed data into the Permit2 signature, proving user intent for a specific application action atomically with the permit.

Prevents signature replay across different protocols; a witness typed by a lending protocol cannot be reused on a swap aggregator.

Domain Separator

Computed from the Permit2 contract's name, version, chain ID, and verifying contract address.

Wallets must derive this dynamically; hardcoding the domain separator will break signatures across chains or after Permit2 contract upgrades.

Signature Deadline

A uint256 timestamp embedded in PermitSingle and PermitBatch.

Wallets must display this clearly; an indefinite or far-future deadline exposes users to long-term signature replay risk if the permit is not revoked on-chain.

Nonce Scheme

Permit2 uses a bitmap-based nonce system, not a sequential counter.

Wallets cannot simply increment a nonce; they must track used nonce slots to prevent front-end confusion and ensure a new signature invalidates the old one.

Allowance Mapping

Permit2 maps (owner, token, spender) to an allowance amount and expiration, separate from the legacy ERC-20 allowance.

Integrators must not query the ERC-20 allowance to check Permit2 state; doing so will report zero and cause incorrect UI or transaction failures.

Verification Contract

The canonical Permit2 contract address deployed by Uniswap Labs.

Verifying against an incorrect or unofficial Permit2 address can allow an attacker to phish a valid signature and replay it on the real contract.

Chain Availability

Deployed on Ethereum mainnet and major L2s at deterministic addresses.

Integrators must confirm the canonical deployment address for each target chain; a missing deployment means Permit2-dependent flows will fail.

technical-context
SIGNATURE STRUCTURE FOR PERMIT2

EIP-712 Domain and Core Types

The canonical EIP-712 typed data structures that define how Permit2 signatures are constructed, hashed, and verified.

Permit2 relies on EIP-712 structured data signing to enable gasless token approvals and transfers. The core types—PermitSingle, PermitBatch, and AllowanceTransferDetails—define the exact parameters a user signs, including the token, amount, expiration, and nonce. These structures are wrapped in a domain separator that binds the signature to the Permit2 contract address and chain ID, preventing cross-chain replay attacks. For Uniswap's Universal Router and other integrators, the PermitBatchTransferFrom type is the primary workhorse, encoding a batch of token transfers alongside a single permit signature that authorizes them all atomically.

The TokenPermissions struct is the fundamental unit of authorization, specifying the ERC-20 token address and the maximum amount the spender is allowed to transfer. PermitSingle pairs a single TokenPermissions with a nonce and a deadline, while PermitBatch encodes an array of these permissions under a single nonce and deadline. The PermitBatchTransferFrom type extends this by combining a PermitBatch with an array of AllowanceTransferDetails, which specify the actual amounts to transfer to specific recipients. This separation between the permitted maximum and the transferred amount is critical: a user signs a broad allowance, but the spender can only execute transfers up to that limit within a single transaction.

Witness types introduce an additional layer of security by allowing an integrator to commit to arbitrary application-specific data within the signed message. A witness is an extra struct whose type string and data are hashed into the final EIP-712 digest. This prevents signature replay across different protocol contexts—a signature authorizing a swap on UniswapX cannot be replayed to authorize a different action on another contract, even if both use Permit2. The PermitWitnessTransferFrom type combines a PermitSingle with a witness, while PermitBatchWitnessTransferFrom combines a PermitBatch with a witness. Integrators define their own witness type and pass its type string and hash to the Permit2 contract.

For wallet developers, correctly displaying these types to users is a hard security problem. A PermitBatch with an effectively unlimited amount and a 30-year deadline is functionally a full token approval, but the EIP-712 UI may not make this clear. Wallets must parse the PermitBatch structure, identify high-risk parameters, and present them in a human-readable format. For protocol integrators, the primary risk is nonce mismanagement and incorrect witness construction. A miscomputed witness hash or a reused nonce can break the signature verification or open a replay vector. Chainscore Labs can audit Permit2 integration code to verify correct EIP-712 type hashing, witness construction, and nonce management before deployment.

PERMIT2 SIGNATURE VERIFICATION

Affected Actors

Wallet Developers

Wallet teams must implement EIP-712 typed data rendering for Permit2's PermitSingle, PermitBatch, and Witness types. The primary risk is blind-signing, where users approve arbitrary token transfers without understanding the scope.

Required Actions:

  • Display the details.token, details.amount, and details.expiration fields clearly in the signing UI.
  • For PermitBatch, render each token-amount pair individually to prevent hidden approvals.
  • Implement nonce tracking to warn users if a permit with a lower nonce is still active.
  • Flag permits with expiration set to type(uint256).max as indefinite and high-risk.
  • For Witness types, decode and display the witness data if the schema is known, or warn that the signature authorizes an opaque witness payload.

Chainscore can audit wallet Permit2 signature display logic and nonce management to prevent phishing and replay vulnerabilities.

implementation-impact
PERMIT2 INTEGRATION SURFACE

Implementation Impact by Type

The introduction of Witness types and the EIP-712 typed data structures in Permit2 creates distinct implementation burdens and security considerations across wallets, dapps, and smart contracts.

PERMIT2 SIGNATURE VERIFICATION AND WITNESS TYPES

Integration Risk Matrix

Operational risks and compatibility concerns for wallets, frontends, and protocols that construct, sign, or verify Permit2 EIP-712 typed data without relying on the canonical SDK.

AreaWhat changesWho is affectedAction

EIP-712 Domain Construction

Incorrect domain separator (name, version, chainId, verifyingContract) causes signature rejection by Permit2 contract

Wallet developers, frontend teams, aggregators

Verify domain fields against canonical Permit2 deployment address and chain; do not hardcode without chain-awareness

PermitSingle Type Hash

Mismatch between signed type hash and contract's expected hash leads to Permit2 reverting with 'InvalidSignature'

SDK-avoidant integrators, custom signer implementations

Generate type hash from exact PermitSingle struct definition; audit against Uniswap/Permit2 source

PermitBatch Type Hash

Batch permit struct includes array of TokenPermissions; incorrect encoding of nested structs breaks signature validity

Protocols batching approvals, aggregator frontends

Validate ABI-encoding of TokenPermissions[] matches EIP-712 encodeType rules; test with real Permit2 contract

Witness Type String

Witness type string must be appended to primary type; incorrect string breaks type hash derivation for witness-based permits

Protocols using witness functionality for gasless integration

Construct witness type string exactly as 'TokenPermissions permissions)WitnessTypeName(string witnessType)' or equivalent; verify against Permit2 contract's hash computation

Witness Data Encoding

Witness data is hashed and included in the final digest; encoding mismatch causes signature failure without clear error

DeFi protocols embedding custom data in permits

Ensure witness struct matches the type string exactly; use keccak256(abi.encode(...)) consistent with Permit2's internal hashing

Nonce Scheme

Permit2 uses a nonce bitmap, not sequential nonces; incorrect nonce tracking can cause replay or rejection

Wallet developers managing user permits

Implement bitmap-based nonce tracking per owner-token-spender tuple; do not assume sequential nonce model

Expiration Timestamp

Signatures with expiration set too far in the future create long-lived phishing targets; too short causes UX failures

Wallet UX designers, frontend teams

Set reasonable default expirations; display expiration clearly to users; support revocation UI for active permits

Signature Format

Permit2 expects EIP-712 signature in split (r,s,v) format; compact or other encodings cause verification failure

Wallet SDKs, hardware wallet integrators

Ensure signature output is split into r, s, v components before submitting to Permit2 functions; test with Ledger/Trezor signing paths

PERMIT2 SIGNATURE AND WITNESS HANDLING

Integration Verification Checklist

A systematic checklist for wallet developers, frontend engineers, and smart contract integrators to verify that their Permit2 signature construction, witness typing, and on-chain verification logic is correct and secure before deployment.

Verify that the EIP-712 domain separator is constructed exactly as defined in the canonical Permit2 contract. The domain includes the name ("Permit2"), version (stringified version number), chainId, and verifyingContract (the Permit2 deployment address for the target chain).

Why it matters: An incorrect domain separator will produce signatures that the Permit2 contract rejects, causing all gasless approval flows to fail. This is the most common integration mistake.

Confirmation signal: Generate a signature off-chain and simulate permitTransferFrom against a local fork. The call must not revert with InvalidSigner().

Chains We Build On

Looking to build on a specific blockchain?

We build smart contracts, DeFi applications, wallets, tokenization platforms, and blockchain infrastructure across the major ecosystems teams choose today. That includes Ethereum, Arbitrum, Optimism, Polygon, Avalanche, Solana, Sui, Aptos, Hedera, Stellar, and NEAR, with support for additional EVM and non-EVM networks based on your product requirements.

EVM ecosystems

  • Ethereum logo
    Ethereum
  • Arbitrum logo
    Arbitrum
  • Optimism logo
    Optimism
  • Polygon logo
    Polygon
  • Avalanche logo
    Avalanche
  • Cronos logo
    Cronos

Non-EVM ecosystems

  • Solana logo
    Solana
  • Sui logo
    Sui
  • Aptos logo
    Aptos
  • Hedera logo
    Hedera
  • Stellar logo
    Stellar
  • NEAR logo
    NEAR

Additional ecosystems

  • Polkadot logo
    Polkadot
  • Cosmos logo
    Cosmos
  • TON logo
    TON
  • Cardano logo
    Cardano
  • Algorand logo
    Algorand
  • Tempo logo
    Tempo

Also available for Base, appchains, custom EVM networks, and cross-chain product architecture.

PERMIT2 SIGNATURE VERIFICATION AND WITNESS TYPES

Frequently Asked Questions

Common questions from wallet developers, frontend engineers, and protocol integrators about constructing, signing, and verifying Permit2 EIP-712 typed data structures.

These are the three primary EIP-712 typed data structures defined by the Permit2 contract:

  • PermitSingle: Authorizes a single token and a single spender with a specific amount, nonce, and expiration. This is the most common pattern for one-off approvals.
  • PermitBatch: Authorizes multiple tokens for a single spender in one signature. It contains an array of TokenPermissions objects, each specifying a token, amount, and expiration. This is used by aggregators and routers that need to move several assets atomically.
  • Witness: A wrapper type that allows an integrator to attach arbitrary additional data to a permit. The Witness struct includes a witness field of any user-defined type and one of the permit types (PermitSingle or PermitBatch). This is critical for protocols that need to verify extra conditions (e.g., a swap deadline, a minimum output amount, or a hook payload) within the same signature that authorizes the token transfer.

Why it matters: Choosing the wrong type will cause signature verification failures. The Witness type is essential for preventing signature replay across different protocol contexts, as the witnessTypeHash is included in the domain separator.

Trusted by Industry Leaders

Delivering blockchain solutions for 5+ years.

We have partnered with 50+ leading DeFi protocols, NFT ecosystems, and fintech innovators to build secure, scalable, and capital-efficient blockchain products.

Selected Partners & Clients

ChainVote logo
Reax logo
Sokail logo
Swapsicle logo
SyntheX logo
Tekika logo
Telos logo
Zexe logo
ChainVote logo
Reax logo
Sokail logo
Swapsicle logo
SyntheX logo
Tekika logo
Telos logo
Zexe logo
ChainVote logo
Reax logo
Sokail logo
Swapsicle logo
SyntheX logo
Tekika logo
Telos logo
Zexe logo
ChainVote logo
Reax logo
Sokail logo
Swapsicle logo
SyntheX logo
Tekika logo
Telos logo
Zexe logo
“I've been working with Chainscore Labs for last 3+ years, they've consistently delivered with strong ownership across multiple projects. The team is reliable and detail-oriented.”
L
Lee Erswell
CEO, Telos Foundation
how to get started

How to get started?

If you're looking for blockchain integration, ChainScore Labs has 5+ years of experience helping teams build and integrate exchanges, wallets, smart contracts, tokenization solutions, and protocol-connected products, we can help you choose the right path, integrate securely, and get to production faster. Our team consists of experienced blockchain developers and architects who can help you with your blockchain integration needs.

01

Exploration & Strategy

Define your product goals and choose the right blockchain architecture for your use case.

02

Architecture & Design

Design the smart contracts, tokenomics, and security parameters of your system.

03

Development & Integration

Build and integrate with wallets, oracles, and front-end dApps for a seamless experience.

04

Security & Launch

Comprehensive audits followed by a risk-managed mainnet deployment to protect your users.

Start a build

Need a blockchain engineering team?

Send the project context and we will respond with next steps, scope questions, and a practical path to delivery.