{"_id":"@dyadex-finance/universal-router-sdk","name":"@dyadex-finance/universal-router-sdk","dist-tags":{"latest":"5.1.0"},"versions":{"5.1.0":{"name":"@dyadex-finance/universal-router-sdk","version":"5.1.0","description":"sdk for integrating with the Universal Router contracts","repository":{"type":"git","url":"git+https://github.com/dyadex-finance/uniswap-sdks.git"},"keywords":["uniswap","ethereum"],"license":"MIT","main":"./dist/cjs/src/index.js","typings":"./dist/types/src/index.d.ts","module":"./dist/esm/src/index.js","exports":{".":{"types":"./dist/types/src/index.d.ts","import":"./dist/esm/src/index.js","require":"./dist/cjs/src/index.js"}},"sideEffects":false,"engines":{"node":">=18"},"scripts":{"build":"bun run clean && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && tsc -p tsconfig.types.json","clean":"rm -rf dist","docs":"typedoc","forge:fix":"forge fmt","lint":"bun run prettier","lint:fix":"bun run prettier:fix && bun run forge:fix","prettier":"prettier --check '**/*.ts' && prettier --check '**/*.json'","prettier:fix":"prettier --write '**/*.ts' && prettier --write '**/*.json'","release":"changeset publish","test":"bun run test:hardhat && bun run test:forge","test:forge":"forge test","test:hardhat":"env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' hardhat test"},"dependencies":{"@ethersproject/abi":"^5.5.0","@ethersproject/abstract-signer":"^5.7.0","@openzeppelin/contracts":"4.7.0","@dyadex-finance/permit2-sdk":"^1.4.0","@dyadex-finance/router-sdk":"^2.9.0","@dyadex-finance/sdk-core":"^7.13.0","@uniswap/universal-router":"2.1.0","@uniswap/v2-core":"^1.0.1","@dyadex-finance/v2-sdk":"^4.20.0","@uniswap/v3-core":"1.0.0","@dyadex-finance/v3-sdk":"^3.30.0","@dyadex-finance/v4-sdk":"^2.0.0","bignumber.js":"^9.0.2","ethers":"^5.7.0","jsbi":"^3.1.4","tiny-invariant":"^1.1.0","tslib":"^2.3.0"},"devDependencies":{"@types/chai":"^4.3.3","@types/mocha":"^9.1.1","@types/node":"^18.7.16","@types/node-fetch":"^2.6.2","chai":"^4.3.6","dotenv":"^16.0.3","eslint-plugin-prettier":"^3.4.1","hardhat":"^2.25.0","prettier":"^2.4.1","ts-node":"^10.9.1","typedoc":"^0.21.2","typescript":"^4.3.3"},"prettier":{"printWidth":120,"semi":false,"singleQuote":true,"trailingComma":"es5"},"publishConfig":{"access":"public","provenance":true},"gitHead":"06ab4ee985528ad0159a9bfb6d4356a5693d59a1","_id":"@dyadex-finance/universal-router-sdk@5.1.0","bugs":{"url":"https://github.com/dyadex-finance/uniswap-sdks/issues"},"homepage":"https://github.com/dyadex-finance/uniswap-sdks#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-P8a760QhzVQFnRWQLGnE1cCnMvSYk4O2KxW3k5PHPcSQnKWgh969oTKjZMBKkJGXf/odtzXbE4d2DpjtiWrloQ==","shasum":"800b69437998dc873a563d1785e3954afcd3f0db","tarball":"https://registry.npmjs.org/@dyadex-finance/universal-router-sdk/-/universal-router-sdk-5.1.0.tgz","fileCount":121,"unpackedSize":417326,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dyadex-finance%2funiversal-router-sdk@5.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC6K7uGGWtlwafV0hq1e47INUFeGMmt+H7gyptpwcR4gQIgAodF+WnN8FaMyIs38yRPqNiNDXyGTE8laA2kaWcLTu8="}]},"_npmUser":{"name":"neddy34","email":"edwardlee9534@gmail.com"},"directories":{},"maintainers":[{"name":"neddy34","email":"edwardlee9534@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/universal-router-sdk_5.1.0_1777304624066_0.5396197038475972"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-27T15:43:43.973Z","5.1.0":"2026-04-27T15:43:44.268Z","modified":"2026-04-27T15:43:44.689Z"},"maintainers":[{"name":"neddy34","email":"edwardlee9534@gmail.com"}],"description":"sdk for integrating with the Universal Router contracts","homepage":"https://github.com/dyadex-finance/uniswap-sdks#readme","keywords":["uniswap","ethereum"],"repository":{"type":"git","url":"git+https://github.com/dyadex-finance/uniswap-sdks.git"},"bugs":{"url":"https://github.com/dyadex-finance/uniswap-sdks/issues"},"license":"MIT","readme":"# universal-router-sdk\n\nThis SDK facilitates interactions with the contracts in [Universal Router](https://github.com/Uniswap/universal-router)\n\n## Usage\n\nInstall latest version of universal-router-sdk. Then import the corresponding Trade class and Data object for each protocol you'd like to interact with.\n\n### Trading on Uniswap\n\nwarning: `swapERC20CallParameters()` to be deprecated in favor of `swapCallParameters()`\n\n```typescript\nimport { TradeType } from '@dyadex-finance/sdk-core'\nimport { Trade as V2TradeSDK } from '@dyadex-finance/v2-sdk'\nimport { Trade as V3TradeSDK } from '@dyadex-finance/v3-sdk'\nimport { MixedRouteTrade, MixedRouteSDK, Trade as RouterTrade } from '@dyadex-finance/router-sdk'\n\nconst options = { slippageTolerance, recipient }\nconst routerTrade = new RouterTrade({ v2Routes, v3Routes, mixedRoutes, tradeType: TradeType.EXACT_INPUT })\n// Use the raw calldata and value returned to call into Universal Swap Router contracts\nconst { calldata, value } = SwapRouter.swapCallParameters(routerTrade, options)\n```\n\n## Running this package\n\nMake sure you are running `node v18`\nInstall dependencies and run typescript unit tests\n\n```bash\nyarn install\nyarn test:hardhat\n```\n\nRun forge integration tests\n\n```bash\nforge install\nyarn test:forge\n```\n\n## Per-Hop Slippage Protection\n\nUniversal Router v2.1.1 adds granular slippage protection for multi-hop swaps across all protocol versions (V2, V3, V4, and mixed routes). In addition to the overall trade-level slippage check, the contract can verify that each individual pool hop doesn't exceed a maximum price limit.\n\n### How It Works\n\nPer-hop slippage bounds live on each swap's route data (via `RouterTrade`). The `maxHopSlippage` array on each route maps 1:1 to the route's pools: `maxHopSlippage[i]` constrains `route.pools[i]`.\n\nTo enable the V2.1.1 ABI encoding (which includes the `maxHopSlippage` parameter), set `urVersion: URVersion.V2_1_1` on your swap options.\n\n```typescript\nimport { SwapRouter } from '@uniswap/universal-router-sdk'\nimport { Trade as RouterTrade } from '@dyadex-finance/router-sdk'\nimport { URVersion } from '@dyadex-finance/v4-sdk'\nimport { Percent, TradeType } from '@dyadex-finance/sdk-core'\n\n// 1. Build a trade with per-hop slippage on each route\nconst trade = new RouterTrade({\n  v3Routes: [\n    {\n      routev3: myV3Route, // e.g. USDC → DAI → WETH\n      inputAmount,\n      outputAmount,\n      maxHopSlippage: [\n        // one entry per pool in the route\n        BigInt('1010000000000000000'), // Hop 0: USDC→DAI, max price 1.01\n        BigInt('2500000000000000000000'), // Hop 1: DAI→WETH, max price 2500\n      ],\n    },\n  ],\n  tradeType: TradeType.EXACT_INPUT,\n})\n\n// 2. Encode with V2.1.1 ABI\nconst { calldata, value } = SwapRouter.swapCallParameters(trade, {\n  slippageTolerance: new Percent(50, 10000), // 0.5% overall slippage\n  recipient: '0x...',\n  urVersion: URVersion.V2_1_1, // required for per-hop encoding\n})\n```\n\n### Price Calculation\n\nSlippage is expressed as a **price** with 18 decimals of precision:\n\n- `price = amountIn * 1e18 / amountOut`\n\nIf the calculated price for hop `i` exceeds `maxHopSlippage[i]`, the transaction reverts.\n\n### Mixed Routes\n\nFor mixed routes that span multiple protocol versions (e.g. V3 pool → V4 pool → V2 pool), the SDK automatically slices the flat `maxHopSlippage` array by section. Each protocol section receives the corresponding slice of hop bounds:\n\n```typescript\nconst trade = new RouterTrade({\n  mixedRoutes: [\n    {\n      mixedRoute: myMixedRoute, // V3 pool, V3 pool, V2 pool\n      inputAmount,\n      outputAmount,\n      maxHopSlippage: [\n        BigInt('1010000000000000000'), // Hop 0 (V3 section)\n        BigInt('2500000000000000000000'), // Hop 1 (V3 section)\n        BigInt('1005000000000000000'), // Hop 2 (V2 section)\n      ],\n    },\n  ],\n  tradeType: TradeType.EXACT_INPUT,\n})\n```\n\n### Benefits\n\n1. **MEV Protection**: Prevents sandwich attacks on individual pool hops\n2. **Route Quality**: Ensures each segment of a multi-hop route meets price expectations\n3. **Granular Control**: Different slippage tolerances for different pairs (e.g. tighter bounds on stablecoin hops)\n\n### Backward Compatibility\n\n- If `maxHopSlippage` is omitted or is an empty array, only the overall trade-level slippage is checked\n- If `urVersion` is not set (defaults to V2.0), commands use the standard ABI without `maxHopSlippage`\n\n## Signed Routes (Universal Router v2.1)\n\nUniversal Router v2.1 supports EIP712-signed route execution, enabling gasless transactions and intent-based trading.\n\n**Important**: The SDK does not perform signing. It provides utilities to prepare EIP712 payloads and encode signed calldata. You sign with your own mechanism (wallet, KMS, hardware, etc.).\n\n### Basic Flow\n\n```typescript\nimport { SwapRouter, NONCE_SKIP_CHECK } from '@uniswap/universal-router-sdk'\nimport { Wallet } from '@ethersproject/wallet'\n\nconst wallet = new Wallet('0x...')\nconst chainId = 1\nconst routerAddress = '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD'\nconst deadline = Math.floor(Date.now() / 1000) + 60 * 20\n\n// 1. Generate regular swap calldata\nconst { calldata, value } = SwapRouter.swapCallParameters(trade, {\n  slippageTolerance: new Percent(50, 10000),\n  recipient: wallet.address,\n  deadline,\n})\n\n// 2. Get EIP712 payload to sign\nconst payload = SwapRouter.getExecuteSignedPayload(\n  calldata,\n  {\n    intent: '0x' + '0'.repeat(64), // Application-specific intent\n    data: '0x' + '0'.repeat(64), // Application-specific data\n    sender: wallet.address, // Or address(0) to skip sender verification\n  },\n  deadline,\n  chainId,\n  routerAddress\n)\n\n// 3. Sign externally (wallet/KMS/hardware)\nconst signature = await wallet._signTypedData(payload.domain, payload.types, payload.value)\n\n// 4. Encode for executeSigned()\nconst { calldata: signedCalldata, value: signedValue } = SwapRouter.encodeExecuteSigned(\n  calldata,\n  signature,\n  {\n    intent: payload.value.intent,\n    data: payload.value.data,\n    sender: payload.value.sender,\n    nonce: payload.value.nonce, // Must match what was signed\n  },\n  deadline,\n  BigNumber.from(value)\n)\n\n// 5. Submit transaction\nawait wallet.sendTransaction({\n  to: routerAddress,\n  data: signedCalldata,\n  value: signedValue,\n})\n```\n\n### Nonce Management\n\n- **Random nonce (default)**: Omit `nonce` parameter - SDK generates random nonce\n- **Skip nonce check**: Use `NONCE_SKIP_CHECK` sentinel to allow signature reuse\n- **Custom nonce**: Provide your own nonce for ordering\n\n```typescript\nimport { NONCE_SKIP_CHECK } from '@uniswap/universal-router-sdk'\n\n// Reusable signature (no nonce check)\nconst payload = SwapRouter.getExecuteSignedPayload(\n  calldata,\n  {\n    intent: '0x...',\n    data: '0x...',\n    sender: '0x0000000000000000000000000000000000000000', // Skip sender verification too\n    nonce: NONCE_SKIP_CHECK, // Allow signature reuse\n  },\n  deadline,\n  chainId,\n  routerAddress\n)\n```\n\n### Sender Verification\n\n- **Verify sender**: Pass the actual sender address (e.g., `wallet.address`)\n- **Skip verification**: Pass `'0x0000000000000000000000000000000000000000'`\n\nThe SDK automatically sets `verifySender` based on whether sender is address(0).\n\n## Cross-Chain Bridging with Across (Universal Router v2.1)\n\nUniversal Router v2.1 integrates with Across Protocol V3 to enable seamless cross-chain bridging after swaps. This allows you to swap tokens on one chain and automatically bridge them to another chain in a single transaction.\n\n### Basic Usage\n\n```typescript\nimport { SwapRouter } from '@uniswap/universal-router-sdk'\nimport { BigNumber } from 'ethers'\n\n// 1. Prepare your swap (e.g., USDC → WETH on mainnet)\nconst { calldata, value } = SwapRouter.swapCallParameters(trade, swapOptions, [\n  {\n    // Bridge configuration\n    depositor: userAddress,\n    recipient: userAddress, // Recipient on destination chain\n    inputToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH mainnet\n    outputToken: '0x4200000000000000000000000000000000000006', // WETH optimism\n    inputAmount: BigNumber.from('1000000000000000000'), // 1 WETH\n    outputAmount: BigNumber.from('990000000000000000'), // 0.99 WETH (with fees)\n    destinationChainId: 10, // Optimism\n    exclusiveRelayer: '0x0000000000000000000000000000000000000000',\n    quoteTimestamp: Math.floor(Date.now() / 1000),\n    fillDeadline: Math.floor(Date.now() / 1000) + 3600,\n    exclusivityDeadline: 0,\n    message: '0x',\n    useNative: false,\n  },\n])\n```\n\n### Swap + Bridge Example\n\n```typescript\n// Swap USDC to WETH, then bridge WETH to Optimism\nconst bridgeParams = {\n  depositor: userAddress,\n  recipient: userAddress, // Can be different address on destination\n  inputToken: WETH_MAINNET,\n  outputToken: WETH_OPTIMISM,\n  inputAmount: CONTRACT_BALANCE, // Use entire swap output\n  outputAmount: expectedOutputAmount,\n  destinationChainId: 10,\n  exclusiveRelayer: '0x0000000000000000000000000000000000000000',\n  quoteTimestamp: Math.floor(Date.now() / 1000),\n  fillDeadline: Math.floor(Date.now() / 1000) + 3600,\n  exclusivityDeadline: 0,\n  message: '0x', // Optional message to execute on destination\n  useNative: false, // Set to true to bridge native ETH\n}\n\nconst { calldata, value } = SwapRouter.swapCallParameters(\n  trade,\n  swapOptions,\n  [bridgeParams] // Array of bridge operations\n)\n```\n\n### Using CONTRACT_BALANCE\n\nWhen bridging after a swap, you often don't know the exact output amount. Use `CONTRACT_BALANCE` to bridge the entire contract balance:\n\n```typescript\nimport { CONTRACT_BALANCE } from '@uniswap/universal-router-sdk'\n\nconst bridgeParams = {\n  // ... other params\n  inputAmount: CONTRACT_BALANCE, // Bridge entire balance after swap\n  // ... other params\n}\n```\n\n### Multiple Bridge Operations\n\nYou can perform multiple bridge operations after a swap:\n\n```typescript\nconst { calldata, value } = SwapRouter.swapCallParameters(trade, swapOptions, [\n  {\n    // Bridge 50% to Optimism\n    inputToken: WETH_MAINNET,\n    outputToken: WETH_OPTIMISM,\n    inputAmount: BigNumber.from('500000000000000000'),\n    destinationChainId: 10,\n    // ... other params\n  },\n  {\n    // Bridge remaining USDC to Arbitrum\n    inputToken: USDC_MAINNET,\n    outputToken: USDC_ARBITRUM,\n    inputAmount: CONTRACT_BALANCE,\n    destinationChainId: 42161,\n    // ... other params\n  },\n])\n```\n\n### Native ETH Bridging\n\nTo bridge native ETH instead of WETH:\n\n```typescript\nconst bridgeParams = {\n  inputToken: WETH_ADDRESS, // Must be WETH address\n  outputToken: WETH_ON_DESTINATION,\n  useNative: true, // Bridge as native ETH\n  // ... other params\n}\n```\n\n### Important Notes\n\n1. **Across Quote**: Bridge parameters (especially `outputAmount`, `quoteTimestamp`, `fillDeadline`) should come from the Across API quote\n2. **Recipient Address**: Can be different from the sender, allowing cross-chain transfers to other addresses\n3. **Message Passing**: The `message` field allows executing arbitrary calls on the destination chain\n4. **Slippage**: The `outputAmount` already accounts for bridge fees and slippage\n","readmeFilename":"README.md","_rev":"1-5137897f820523a2b8c2f30cbc0fb2f8"}