LLMs.txt: agent-readable Markdown index of this site at /llms.txt

Universal Router Overview

Learn how Uniswap Universal Router composes v2, v3, and v4 swaps with Permit2-based approvals in one transaction.

The UniversalRouter is an ETH and ERC20 swap router that aggregates trades across Uniswap v2, v3, and v4. It is unowned and non-upgradeable.

Its command-based architecture supports:

  • Splitting and interleaving of Uniswap v2/v3/v4 swaps
  • Partial fills of trades
  • Wrapping and unwrapping of ETH (via WETH)
  • Time-bound, signature-controlled token approvals using Permit2
  • v3 and v4 position manager interactions (e.g., permit, liquidity modification, pool initialization)
  • Sub-plan execution and balance checks

Transactions are encoded as a sequence of byte-sized commands, each with structured inputs. These commands can be chained in one transaction to express custom workflows, including multi-hop swaps and liquidity migration from v3 to v4.

How It Works

You call execute(...) with a commands byte string and a parallel inputs array. The router processes each command in order and routes execution to the corresponding module. This lets you combine swap, payment, approval, and position-manager actions without splitting logic across multiple transactions.

Permit2 Integration

UniversalRouter integrates with Permit2, so token transfer permissions can be provided by signature. This reduces repeated approval flows and enables more composable routing plans.

See Permit2 documentation for allowance and signature-transfer patterns.

FAQ

How does Universal Router command encoding work?

You call execute(commands, inputs), optionally with a deadline. The commands argument is a byte string where each byte is one operation, and inputs is a parallel array holding the ABI-encoded parameters for each command. The router walks the command stream in order and dispatches each byte to its module, so a single transaction can chain swaps across v2, v3, and v4, Permit2 permits, ETH wrapping, payments, and position-manager calls. The low 7 bits of each byte select the command, and the high bit is an allow-revert flag.

See Universal Router Commands for the full command table.

How is Universal Router different from SwapRouter?

SwapRouter (SwapRouter02) exposed fixed functions tightly coupled to v2 and v3, so each call ran a scripted sequence. Universal Router is command-based: the caller composes an arbitrary ordered list of operations, so it aggregates v2, v3, and v4 swaps, Permit2 approvals, ETH wrapping, and position-manager actions in one transaction, and it supports splitting, interleaving, and partial fills. It is unowned and non-upgradeable. New integrations should target Universal Router rather than the legacy SwapRouter.

Which Universal Router address should I use for each chain?

Universal Router is deployed at a different address on each chain and per router version, so do not hardcode a single address. The current per-chain addresses are published in Supported Chains & Tokens, and the canonical source of truth is maintained in the universal-router-sdk constants on GitHub. Whitelist the address for the specific chain and version you integrate.

How do I enable partial fills with Universal Router?

Set the high bit (0x80) on a command byte to mark it allow-revert. If that command fails, the rest of the transaction still executes, which is how partial fills work:

command = 0x80 | 0x00; // V3_SWAP_EXACT_IN with allow-revert

When you use allow-revert, include a cleanup command such as SWEEP so no funds are stranded in the router.

Do I need Permit2 to use Universal Router?

Universal Router pulls a user's ERC-20 tokens through Permit2, so the user first approves the Permit2 contract once per token and then authorizes the router by signature. Native ETH does not require Permit2. See the Permit2 documentation for allowance and signature-transfer patterns.

Where to Go Next