/** * Uniswap: Universal Router with Permit2 integration * * This example demonstrates how to use Universal Router for complex multi-step transactions * with Permit2 signature-based approvals. * * Universal Router supports: * - Token swaps (Uniswap v2/v3) * - NFT operations * - Permit2 approvals * - WETH wrapping/unwrapping * - Multiple commands in one transaction */ import { createWalletRpcClient } from '../../src/utils/chain-config.js'; import { getUniswapUniversalRouter, getPermit2Address } from '../../src/utils/addresses.js'; import { getTokenMetadata, parseTokenAmount } from '../../src/utils/tokens.js'; import { waitForTransaction } from '../../src/utils/rpc.js'; import type { Address, Hex } from 'viem'; const CHAIN_ID = 1; // Mainnet (change to 8453 for Base, etc.) const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`; // Universal Router ABI const UNIVERSAL_ROUTER_ABI = [ { name: 'execute', type: 'function', stateMutability: 'payable', inputs: [ { name: 'commands', type: 'bytes' }, { name: 'inputs', type: 'bytes[]' }, ], outputs: [], }, { name: 'execute', type: 'function', stateMutability: 'payable', inputs: [ { name: 'commands', type: 'bytes' }, { name: 'inputs', type: 'bytes[]' }, { name: 'deadline', type: 'uint256' }, ], outputs: [], }, ] as const; /** * Universal Router command types * See: https://github.com/Uniswap/universal-router/blob/main/contracts/Commands.sol */ const COMMANDS = { V3_SWAP_EXACT_IN: 0x00, V3_SWAP_EXACT_OUT: 0x01, PERMIT2_TRANSFER_FROM: 0x02, PERMIT2_PERMIT_BATCH: 0x03, SWEEP: 0x04, TRANSFER: 0x05, PAY_PORTION: 0x06, V2_SWAP_EXACT_IN: 0x08, V2_SWAP_EXACT_OUT: 0x09, PERMIT2_PERMIT: 0x0a, WRAP_ETH: 0x0b, UNWRAP_WETH: 0x0c, PERMIT2_TRANSFER_FROM_BATCH: 0x0d, } as const; /** * Encode V3 swap exact input command * * This is a simplified example. In production, use the Universal Router SDK * or carefully encode commands according to the Universal Router spec. */ function encodeV3SwapExactInput(params: { recipient: Address; amountIn: bigint; amountOutMin: bigint; path: Hex; payerIsUser: boolean; }): { command: number; input: Hex } { // This is a conceptual example. Actual encoding is more complex. // See: https://docs.uniswap.org/contracts/universal-router/technical-reference throw new Error('Use Universal Router SDK for proper command encoding'); } async function universalRouterSwap() { const walletClient = createWalletRpcClient(CHAIN_ID, PRIVATE_KEY); const publicClient = walletClient as any; const account = walletClient.account?.address; if (!account) { throw new Error('No account available'); } const routerAddress = getUniswapUniversalRouter(CHAIN_ID); const tokenIn = getTokenMetadata(CHAIN_ID, 'USDC'); const tokenOut = getTokenMetadata(CHAIN_ID, 'WETH'); const amountIn = parseTokenAmount('1000', tokenIn.decimals); const deadline = BigInt(Math.floor(Date.now() / 1000) + 600); console.log(`Universal Router swap: ${amountIn} ${tokenIn.symbol} -> ${tokenOut.symbol}`); console.log(`Router: ${routerAddress}`); console.log(`Account: ${account}`); // Note: Universal Router command encoding is complex. // In production, use: // 1. Universal Router SDK (when available) // 2. Or carefully encode commands according to the spec // 3. Or use Protocolink which handles Universal Router integration console.log('\n⚠️ This is a conceptual example.'); console.log('In production, use:'); console.log(' 1. Universal Router SDK for command encoding'); console.log(' 2. Or use Protocolink which integrates Universal Router'); console.log(' 3. Or carefully follow the Universal Router spec:'); console.log(' https://docs.uniswap.org/contracts/universal-router/technical-reference'); // Example flow: // 1. Create Permit2 signature (see uniswap-permit2.ts) // 2. Encode Universal Router commands // 3. Execute via Universal Router.execute() // 4. Universal Router will: // - Use Permit2 to transfer tokens // - Execute swap // - Send output to recipient // - All in one transaction } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { universalRouterSwap().catch(console.error); } export { universalRouterSwap, COMMANDS };