Files
237-combo/examples/ts/uniswap-universal-router.ts
2026-02-09 21:51:30 -08:00

137 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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 };