Initial commit: add .gitignore and README
This commit is contained in:
136
examples/ts/uniswap-universal-router.ts
Normal file
136
examples/ts/uniswap-universal-router.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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 };
|
||||
|
||||
Reference in New Issue
Block a user