@kittycorn-labs/universal-router-sdk 1.4.43 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/README.md +312 -0
  2. package/dist/cjs/src/abis/UniversalRouter.json +740 -0
  3. package/dist/{entities → cjs/src/entities}/Command.d.ts +12 -12
  4. package/dist/cjs/src/entities/Command.js +9 -0
  5. package/dist/cjs/src/entities/Command.js.map +1 -0
  6. package/dist/cjs/src/entities/actions/across.d.ts +21 -0
  7. package/dist/cjs/src/entities/actions/across.js +7 -0
  8. package/dist/cjs/src/entities/actions/across.js.map +1 -0
  9. package/dist/{entities → cjs/src/entities}/actions/index.d.ts +3 -2
  10. package/dist/cjs/src/entities/actions/index.js +7 -0
  11. package/dist/cjs/src/entities/actions/index.js.map +1 -0
  12. package/dist/cjs/src/entities/actions/uniswap.d.ts +94 -0
  13. package/dist/cjs/src/entities/actions/uniswap.js +740 -0
  14. package/dist/cjs/src/entities/actions/uniswap.js.map +1 -0
  15. package/dist/{entities → cjs/src/entities}/actions/unwrapWETH.d.ts +12 -12
  16. package/dist/cjs/src/entities/actions/unwrapWETH.js +33 -0
  17. package/dist/cjs/src/entities/actions/unwrapWETH.js.map +1 -0
  18. package/dist/{entities → cjs/src/entities}/index.d.ts +2 -2
  19. package/dist/cjs/src/entities/index.js +6 -0
  20. package/dist/cjs/src/entities/index.js.map +1 -0
  21. package/dist/cjs/src/index.d.ts +19 -0
  22. package/dist/cjs/src/index.js +43 -0
  23. package/dist/cjs/src/index.js.map +1 -0
  24. package/dist/cjs/src/kittycorn.d.ts +9 -0
  25. package/dist/cjs/src/kittycorn.js +26 -0
  26. package/dist/cjs/src/kittycorn.js.map +1 -0
  27. package/dist/cjs/src/swapRouter.d.ts +123 -0
  28. package/dist/cjs/src/swapRouter.js +445 -0
  29. package/dist/cjs/src/swapRouter.js.map +1 -0
  30. package/dist/cjs/src/types/encodeSwaps.d.ts +197 -0
  31. package/dist/cjs/src/types/encodeSwaps.js +3 -0
  32. package/dist/cjs/src/types/encodeSwaps.js.map +1 -0
  33. package/dist/{utils → cjs/src/utils}/commandParser.d.ts +36 -34
  34. package/dist/cjs/src/utils/commandParser.js +154 -0
  35. package/dist/cjs/src/utils/commandParser.js.map +1 -0
  36. package/dist/cjs/src/utils/computeEncodeSwapsAmounts.d.ts +8 -0
  37. package/dist/cjs/src/utils/computeEncodeSwapsAmounts.js +46 -0
  38. package/dist/cjs/src/utils/computeEncodeSwapsAmounts.js.map +1 -0
  39. package/dist/{utils → cjs/src/utils}/constants.d.ts +46 -30
  40. package/dist/cjs/src/utils/constants.js +777 -0
  41. package/dist/cjs/src/utils/constants.js.map +1 -0
  42. package/dist/cjs/src/utils/directTransfers.d.ts +15 -0
  43. package/dist/cjs/src/utils/directTransfers.js +381 -0
  44. package/dist/cjs/src/utils/directTransfers.js.map +1 -0
  45. package/dist/cjs/src/utils/eip712.d.ts +17 -0
  46. package/dist/cjs/src/utils/eip712.js +44 -0
  47. package/dist/cjs/src/utils/eip712.js.map +1 -0
  48. package/dist/cjs/src/utils/encodeSwapStep.d.ts +4 -0
  49. package/dist/cjs/src/utils/encodeSwapStep.js +62 -0
  50. package/dist/cjs/src/utils/encodeSwapStep.js.map +1 -0
  51. package/dist/cjs/src/utils/encodeV4Action.d.ts +7 -0
  52. package/dist/cjs/src/utils/encodeV4Action.js +84 -0
  53. package/dist/cjs/src/utils/encodeV4Action.js.map +1 -0
  54. package/dist/{utils → cjs/src/utils}/getCurrencyAddress.d.ts +2 -2
  55. package/dist/cjs/src/utils/getCurrencyAddress.js +9 -0
  56. package/dist/cjs/src/utils/getCurrencyAddress.js.map +1 -0
  57. package/dist/{utils → cjs/src/utils}/inputTokens.d.ts +23 -23
  58. package/dist/cjs/src/utils/inputTokens.js +58 -0
  59. package/dist/cjs/src/utils/inputTokens.js.map +1 -0
  60. package/dist/cjs/src/utils/normalizeEncodeSwapsSpec.d.ts +6 -0
  61. package/dist/cjs/src/utils/normalizeEncodeSwapsSpec.js +34 -0
  62. package/dist/cjs/src/utils/normalizeEncodeSwapsSpec.js.map +1 -0
  63. package/dist/{utils → cjs/src/utils}/numbers.d.ts +7 -6
  64. package/dist/cjs/src/utils/numbers.js +27 -0
  65. package/dist/cjs/src/utils/numbers.js.map +1 -0
  66. package/dist/{utils → cjs/src/utils}/pathCurrency.d.ts +3 -3
  67. package/dist/cjs/src/utils/pathCurrency.js +27 -0
  68. package/dist/cjs/src/utils/pathCurrency.js.map +1 -0
  69. package/dist/cjs/src/utils/portionFees.d.ts +14 -0
  70. package/dist/cjs/src/utils/portionFees.js +40 -0
  71. package/dist/cjs/src/utils/portionFees.js.map +1 -0
  72. package/dist/cjs/src/utils/routerBalanceSteps.d.ts +31 -0
  73. package/dist/cjs/src/utils/routerBalanceSteps.js +293 -0
  74. package/dist/cjs/src/utils/routerBalanceSteps.js.map +1 -0
  75. package/dist/{utils → cjs/src/utils}/routerCommands.d.ts +77 -64
  76. package/dist/cjs/src/utils/routerCommands.js +331 -0
  77. package/dist/cjs/src/utils/routerCommands.js.map +1 -0
  78. package/dist/{utils → cjs/src/utils}/routerTradeAdapter.d.ts +73 -73
  79. package/dist/cjs/src/utils/routerTradeAdapter.js +139 -0
  80. package/dist/cjs/src/utils/routerTradeAdapter.js.map +1 -0
  81. package/dist/cjs/src/utils/toV4URVersion.d.ts +3 -0
  82. package/dist/cjs/src/utils/toV4URVersion.js +17 -0
  83. package/dist/cjs/src/utils/toV4URVersion.js.map +1 -0
  84. package/dist/cjs/src/utils/validateEncodeSwaps.d.ts +2 -0
  85. package/dist/cjs/src/utils/validateEncodeSwaps.js +344 -0
  86. package/dist/cjs/src/utils/validateEncodeSwaps.js.map +1 -0
  87. package/dist/esm/package.json +1 -0
  88. package/dist/esm/src/abis/UniversalRouter.json +740 -0
  89. package/dist/esm/src/entities/Command.d.ts +12 -0
  90. package/dist/esm/src/entities/Command.js +6 -0
  91. package/dist/esm/src/entities/Command.js.map +1 -0
  92. package/dist/esm/src/entities/actions/across.d.ts +21 -0
  93. package/dist/esm/src/entities/actions/across.js +3 -0
  94. package/dist/esm/src/entities/actions/across.js.map +1 -0
  95. package/dist/esm/src/entities/actions/index.d.ts +3 -0
  96. package/dist/esm/src/entities/actions/index.js +4 -0
  97. package/dist/esm/src/entities/actions/index.js.map +1 -0
  98. package/dist/esm/src/entities/actions/uniswap.d.ts +94 -0
  99. package/dist/esm/src/entities/actions/uniswap.js +735 -0
  100. package/dist/esm/src/entities/actions/uniswap.js.map +1 -0
  101. package/dist/esm/src/entities/actions/unwrapWETH.d.ts +12 -0
  102. package/dist/esm/src/entities/actions/unwrapWETH.js +28 -0
  103. package/dist/esm/src/entities/actions/unwrapWETH.js.map +1 -0
  104. package/dist/esm/src/entities/index.d.ts +2 -0
  105. package/dist/esm/src/entities/index.js +3 -0
  106. package/dist/esm/src/entities/index.js.map +1 -0
  107. package/dist/esm/src/index.d.ts +19 -0
  108. package/dist/esm/src/index.js +15 -0
  109. package/dist/esm/src/index.js.map +1 -0
  110. package/dist/esm/src/kittycorn.d.ts +9 -0
  111. package/dist/esm/src/kittycorn.js +22 -0
  112. package/dist/esm/src/kittycorn.js.map +1 -0
  113. package/dist/esm/src/swapRouter.d.ts +123 -0
  114. package/dist/esm/src/swapRouter.js +440 -0
  115. package/dist/esm/src/swapRouter.js.map +1 -0
  116. package/dist/esm/src/types/encodeSwaps.d.ts +197 -0
  117. package/dist/esm/src/types/encodeSwaps.js +2 -0
  118. package/dist/esm/src/types/encodeSwaps.js.map +1 -0
  119. package/dist/esm/src/utils/commandParser.d.ts +36 -0
  120. package/dist/esm/src/utils/commandParser.js +146 -0
  121. package/dist/esm/src/utils/commandParser.js.map +1 -0
  122. package/dist/esm/src/utils/computeEncodeSwapsAmounts.d.ts +8 -0
  123. package/dist/esm/src/utils/computeEncodeSwapsAmounts.js +41 -0
  124. package/dist/esm/src/utils/computeEncodeSwapsAmounts.js.map +1 -0
  125. package/dist/esm/src/utils/constants.d.ts +46 -0
  126. package/dist/esm/src/utils/constants.js +768 -0
  127. package/dist/esm/src/utils/constants.js.map +1 -0
  128. package/dist/esm/src/utils/directTransfers.d.ts +15 -0
  129. package/dist/esm/src/utils/directTransfers.js +369 -0
  130. package/dist/esm/src/utils/directTransfers.js.map +1 -0
  131. package/dist/esm/src/utils/eip712.d.ts +17 -0
  132. package/dist/esm/src/utils/eip712.js +39 -0
  133. package/dist/esm/src/utils/eip712.js.map +1 -0
  134. package/dist/esm/src/utils/encodeSwapStep.d.ts +4 -0
  135. package/dist/esm/src/utils/encodeSwapStep.js +58 -0
  136. package/dist/esm/src/utils/encodeSwapStep.js.map +1 -0
  137. package/dist/esm/src/utils/encodeV4Action.d.ts +7 -0
  138. package/dist/esm/src/utils/encodeV4Action.js +80 -0
  139. package/dist/esm/src/utils/encodeV4Action.js.map +1 -0
  140. package/dist/esm/src/utils/getCurrencyAddress.d.ts +2 -0
  141. package/dist/esm/src/utils/getCurrencyAddress.js +5 -0
  142. package/dist/esm/src/utils/getCurrencyAddress.js.map +1 -0
  143. package/dist/esm/src/utils/inputTokens.d.ts +23 -0
  144. package/dist/esm/src/utils/inputTokens.js +51 -0
  145. package/dist/esm/src/utils/inputTokens.js.map +1 -0
  146. package/dist/esm/src/utils/normalizeEncodeSwapsSpec.d.ts +6 -0
  147. package/dist/esm/src/utils/normalizeEncodeSwapsSpec.js +27 -0
  148. package/dist/esm/src/utils/normalizeEncodeSwapsSpec.js.map +1 -0
  149. package/dist/esm/src/utils/numbers.d.ts +7 -0
  150. package/dist/esm/src/utils/numbers.js +19 -0
  151. package/dist/esm/src/utils/numbers.js.map +1 -0
  152. package/dist/esm/src/utils/pathCurrency.d.ts +3 -0
  153. package/dist/esm/src/utils/pathCurrency.js +23 -0
  154. package/dist/esm/src/utils/pathCurrency.js.map +1 -0
  155. package/dist/esm/src/utils/portionFees.d.ts +14 -0
  156. package/dist/esm/src/utils/portionFees.js +35 -0
  157. package/dist/esm/src/utils/portionFees.js.map +1 -0
  158. package/dist/esm/src/utils/routerBalanceSteps.d.ts +31 -0
  159. package/dist/esm/src/utils/routerBalanceSteps.js +282 -0
  160. package/dist/esm/src/utils/routerBalanceSteps.js.map +1 -0
  161. package/dist/esm/src/utils/routerCommands.d.ts +77 -0
  162. package/dist/esm/src/utils/routerCommands.js +326 -0
  163. package/dist/esm/src/utils/routerCommands.js.map +1 -0
  164. package/dist/esm/src/utils/routerTradeAdapter.d.ts +73 -0
  165. package/dist/esm/src/utils/routerTradeAdapter.js +134 -0
  166. package/dist/esm/src/utils/routerTradeAdapter.js.map +1 -0
  167. package/dist/esm/src/utils/toV4URVersion.d.ts +3 -0
  168. package/dist/esm/src/utils/toV4URVersion.js +13 -0
  169. package/dist/esm/src/utils/toV4URVersion.js.map +1 -0
  170. package/dist/esm/src/utils/validateEncodeSwaps.d.ts +2 -0
  171. package/dist/esm/src/utils/validateEncodeSwaps.js +339 -0
  172. package/dist/esm/src/utils/validateEncodeSwaps.js.map +1 -0
  173. package/dist/types/src/entities/Command.d.ts +13 -0
  174. package/dist/types/src/entities/Command.d.ts.map +1 -0
  175. package/dist/types/src/entities/actions/across.d.ts +22 -0
  176. package/dist/types/src/entities/actions/across.d.ts.map +1 -0
  177. package/dist/types/src/entities/actions/index.d.ts +4 -0
  178. package/dist/types/src/entities/actions/index.d.ts.map +1 -0
  179. package/dist/types/src/entities/actions/uniswap.d.ts +95 -0
  180. package/dist/types/src/entities/actions/uniswap.d.ts.map +1 -0
  181. package/dist/types/src/entities/actions/unwrapWETH.d.ts +13 -0
  182. package/dist/types/src/entities/actions/unwrapWETH.d.ts.map +1 -0
  183. package/dist/types/src/entities/index.d.ts +3 -0
  184. package/dist/types/src/entities/index.d.ts.map +1 -0
  185. package/dist/types/src/index.d.ts +20 -0
  186. package/dist/types/src/index.d.ts.map +1 -0
  187. package/dist/types/src/kittycorn.d.ts +10 -0
  188. package/dist/types/src/kittycorn.d.ts.map +1 -0
  189. package/dist/types/src/swapRouter.d.ts +124 -0
  190. package/dist/types/src/swapRouter.d.ts.map +1 -0
  191. package/dist/types/src/types/encodeSwaps.d.ts +198 -0
  192. package/dist/types/src/types/encodeSwaps.d.ts.map +1 -0
  193. package/dist/types/src/utils/commandParser.d.ts +37 -0
  194. package/dist/types/src/utils/commandParser.d.ts.map +1 -0
  195. package/dist/types/src/utils/computeEncodeSwapsAmounts.d.ts +9 -0
  196. package/dist/types/src/utils/computeEncodeSwapsAmounts.d.ts.map +1 -0
  197. package/dist/types/src/utils/constants.d.ts +47 -0
  198. package/dist/types/src/utils/constants.d.ts.map +1 -0
  199. package/dist/types/src/utils/directTransfers.d.ts +16 -0
  200. package/dist/types/src/utils/directTransfers.d.ts.map +1 -0
  201. package/dist/types/src/utils/eip712.d.ts +18 -0
  202. package/dist/types/src/utils/eip712.d.ts.map +1 -0
  203. package/dist/types/src/utils/encodeSwapStep.d.ts +5 -0
  204. package/dist/types/src/utils/encodeSwapStep.d.ts.map +1 -0
  205. package/dist/types/src/utils/encodeV4Action.d.ts +8 -0
  206. package/dist/types/src/utils/encodeV4Action.d.ts.map +1 -0
  207. package/dist/types/src/utils/getCurrencyAddress.d.ts +3 -0
  208. package/dist/types/src/utils/getCurrencyAddress.d.ts.map +1 -0
  209. package/dist/types/src/utils/inputTokens.d.ts +24 -0
  210. package/dist/types/src/utils/inputTokens.d.ts.map +1 -0
  211. package/dist/types/src/utils/normalizeEncodeSwapsSpec.d.ts +7 -0
  212. package/dist/types/src/utils/normalizeEncodeSwapsSpec.d.ts.map +1 -0
  213. package/dist/types/src/utils/numbers.d.ts +8 -0
  214. package/dist/types/src/utils/numbers.d.ts.map +1 -0
  215. package/dist/types/src/utils/pathCurrency.d.ts +4 -0
  216. package/dist/types/src/utils/pathCurrency.d.ts.map +1 -0
  217. package/dist/types/src/utils/portionFees.d.ts +15 -0
  218. package/dist/types/src/utils/portionFees.d.ts.map +1 -0
  219. package/dist/types/src/utils/routerBalanceSteps.d.ts +32 -0
  220. package/dist/types/src/utils/routerBalanceSteps.d.ts.map +1 -0
  221. package/dist/types/src/utils/routerCommands.d.ts +78 -0
  222. package/dist/types/src/utils/routerCommands.d.ts.map +1 -0
  223. package/dist/types/src/utils/routerTradeAdapter.d.ts +74 -0
  224. package/dist/types/src/utils/routerTradeAdapter.d.ts.map +1 -0
  225. package/dist/types/src/utils/toV4URVersion.d.ts +4 -0
  226. package/dist/types/src/utils/toV4URVersion.d.ts.map +1 -0
  227. package/dist/types/src/utils/validateEncodeSwaps.d.ts +3 -0
  228. package/dist/types/src/utils/validateEncodeSwaps.d.ts.map +1 -0
  229. package/package.json +33 -52
  230. package/dist/entities/actions/uniswap.d.ts +0 -30
  231. package/dist/index.d.ts +0 -10
  232. package/dist/index.js +0 -8
  233. package/dist/swapRouter.d.ts +0 -37
  234. package/dist/test/forge/writeInterop.d.ts +0 -2
  235. package/dist/test/utils/addresses.d.ts +0 -5
  236. package/dist/test/utils/hexToDecimalString.d.ts +0 -2
  237. package/dist/test/utils/permit2.d.ts +0 -7
  238. package/dist/test/utils/uniswapData.d.ts +0 -25
  239. package/dist/universal-router-sdk.cjs.development.js +0 -1500
  240. package/dist/universal-router-sdk.cjs.development.js.map +0 -1
  241. package/dist/universal-router-sdk.cjs.production.min.js +0 -2
  242. package/dist/universal-router-sdk.cjs.production.min.js.map +0 -1
  243. package/dist/universal-router-sdk.esm.js +0 -1493
  244. package/dist/universal-router-sdk.esm.js.map +0 -1
package/README.md CHANGED
@@ -1,3 +1,12 @@
1
+ > **Kittycorn / Ethers v5 dependency security**
2
+ > Applications combining these SDKs with Ethers v5 must put the following override in their root `package.json`, then run `npm install` and `npm audit`. npm does not inherit dependency-package overrides.
3
+ >
4
+ > ```json
5
+ > { "overrides": { "@ethersproject/providers": { "ws": "8.21.0" } } }
6
+ > ```
7
+ >
8
+ > Ethers v5 also retains an unpatched Low [elliptic advisory](https://github.com/advisories/GHSA-848j-6mx2-7j84). The Kittycorn integration builds quotes/calldata and uses external signers; it does not generate signatures from user private keys. This is a scope assessment, not a fix for elliptic.
9
+
1
10
  # universal-router-sdk
2
11
 
3
12
  This SDK facilitates interactions with the contracts in [Universal Router](https://github.com/Uniswap/universal-router)
@@ -22,6 +31,11 @@ const routerTrade = new RouterTrade({ v2Routes, v3Routes, mixedRoutes, tradeType
22
31
  const { calldata, value } = SwapRouter.swapCallParameters(routerTrade, options)
23
32
  ```
24
33
 
34
+ This SDK has two entry points for encoding swap calldata:
35
+
36
+ - **`SwapRouter.swapCallParameters(trade, options)`** — builds calldata from a high-level `RouterTrade` (shown above). Best when your swap fits as one or more independent linear routes through pools.
37
+ - **`SwapRouter.encodeSwaps(spec, swapSteps)`** — takes Universal Router commands directly, with the SDK adding ingress, fee, and settlement calldata around them. Best for topologies that don't fit a Trade, routing-service integrations, or advanced V4 compositions. See [Encoding Router-Provided Swap Steps](#encoding-router-provided-swap-steps-encodeswaps).
38
+
25
39
  ## Running this package
26
40
 
27
41
  Make sure you are running `node v18`
@@ -38,3 +52,301 @@ Run forge integration tests
38
52
  forge install
39
53
  yarn test:forge
40
54
  ```
55
+
56
+ ## Encoding Router-Provided Swap Steps (`encodeSwaps`)
57
+
58
+ `SwapRouter.encodeSwaps(spec, swapSteps)` is an alternative entry point for callers that already produce explicit `SwapStep[]` plans (e.g. routing services) and want the SDK to wrap them in a safety envelope. It decouples route topology from SDK trade construction.
59
+
60
+ The router owns `swapSteps` (V2/V3/V4 swaps + any `WRAP_ETH` / `UNWRAP_WETH`). The SDK owns ingress, fees, final settlement, exact-output refund, and optional `safeMode`.
61
+
62
+ ### Swap Step Types
63
+
64
+ Each `SwapStep` is a 1:1 representation of a Universal Router command:
65
+
66
+ - `V2_SWAP_EXACT_IN` / `V2_SWAP_EXACT_OUT` — V2 swap (multi-hop via `path: address[]`)
67
+ - `V3_SWAP_EXACT_IN` / `V3_SWAP_EXACT_OUT` — V3 swap (multi-hop via packed `path: bytes`)
68
+ - `V4_SWAP` — wraps a sequence of V4 actions (`SWAP_EXACT_IN`, `SETTLE`, `TAKE`, etc.) for the V4 router module
69
+ - `WRAP_ETH` / `UNWRAP_WETH` — required when the route bridges native ETH and WETH
70
+
71
+ Routers compose these to express any supported route topology. The SDK does not infer wrap/unwrap commands — routers must include them when their route depends on it.
72
+
73
+ ### Basic Usage
74
+
75
+ ```typescript
76
+ import { SwapRouter, ROUTER_AS_RECIPIENT } from '@uniswap/universal-router-sdk'
77
+ import { CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
78
+
79
+ const { calldata, value } = SwapRouter.encodeSwaps(
80
+ {
81
+ tradeType: TradeType.EXACT_INPUT,
82
+ routing: {
83
+ inputToken: USDC,
84
+ outputToken: WETH,
85
+ amount: CurrencyAmount.fromRawAmount(USDC, '1000000000'),
86
+ quote: CurrencyAmount.fromRawAmount(WETH, '500000000000000000'),
87
+ },
88
+ slippageTolerance: new Percent(50, 10000), // 0.5%
89
+ recipient: '0x...',
90
+ },
91
+ [
92
+ {
93
+ type: 'V3_SWAP_EXACT_IN',
94
+ recipient: ROUTER_AS_RECIPIENT,
95
+ amountIn: '1000000000',
96
+ amountOutMin: '0', // SDK enforces final slippage via the trailing SWEEP
97
+ path: '0x...', // packed V3 path
98
+ },
99
+ ]
100
+ )
101
+ ```
102
+
103
+ ### What the SDK adds around `swapSteps`
104
+
105
+ 1. **Ingress**: `PERMIT2_TRANSFER_FROM` for ERC20 input, or `proxy.execute()` wrapping for `ApproveProxy`. Native input flows through `msg.value`.
106
+ 2. **Fee deduction** before settlement: portion (`PAY_PORTION` / `PAY_PORTION_FULL_PRECISION`) on exact-input, flat (`TRANSFER`) on exact-output.
107
+ 3. **Final SWEEP** of `outputToken` to recipient with the slippage-bounded floor.
108
+ 4. **Exact-output refund**: SWEEPs unused input back to recipient.
109
+ 5. **safeMode** (optional): trailing zero-min ETH SWEEP to recover dust or unintended `msg.value`.
110
+
111
+ ### Constraints
112
+
113
+ - By default, all swap step recipients must be `ROUTER_AS_RECIPIENT` and `payerIsUser` is `false` (ingress runs once up-front via `PERMIT2_TRANSFER_FROM`) — the SDK's settlement sweeps need router custody to see the funds. The optional `allowDirectTransfers` regime relaxes both (see [Direct Transfers](#direct-transfers-allowdirecttransfers)).
114
+ - Routers must end with output in `routing.outputToken`. For exact-output, unused input must end in `routing.inputToken`.
115
+ - The final top-level `SWEEP` is appended by the SDK — don't include it in `swapSteps`.
116
+
117
+ ### Direct Transfers (`allowDirectTransfers`)
118
+
119
+ By default every transfer routes through router custody. Setting `allowDirectTransfers: true` on the spec lets routing-supplied steps move funds directly between the user and the pools — pulling input straight from the user (`payerIsUser` on V2/V3 swaps and v4 `SETTLE`) and paying output straight to `recipient` — which removes the Permit2 ingress and the final sweep transfer for a simple swap.
120
+
121
+ The safety contract is unchanged (the user pays at most `exactOrMaxAmountIn`; the recipient receives at least the slippage-bounded minimum), but it's enforced by counting instead of custody:
122
+
123
+ - **Inbound budget** — contract-enforced direct pulls must sum within `exactOrMaxAmountIn`; the SDK ingress pulls only the remainder.
124
+ - **Outbound coverage** — contract-enforced direct-output minimums reduce the final `SWEEP` floor. Since independently-floored per-leg minimums can sum a few wei below the trade minimum, the floor forgives a bounded, sub-economic rounding shortfall (`max(min(0.5bps of the minimum, 1% of slippage), a small per-leg allowance)`, zero at zero slippage); a larger, real gap still reverts.
125
+
126
+ Step amounts are never trusted — only counted or capped.
127
+
128
+ **Omitting the settlement sweep.** When direct legs cover the minimum, the final `SWEEP` has a zero floor and usually moves nothing. Set `omitRedundantSettlementSweep: true` to drop it. The SDK drops it only when all of these hold: the trade is exact-input with no fee, the floor is zero, no V4 pool in the plan has a hook, every step that produces the output token pays it to the recipient, input and output are different assets, and the chain's router configuration marks it as having no native/ERC20 balance alias. Otherwise the sweep stays. The `safeMode` ETH sweep is not affected. The flag assumes that the router holds no balance of the output token before the swap, and that no token transfer sends tokens to the router as a side effect. Any such balance stays on the router when the sweep is dropped, except that the `safeMode` ETH sweep still forwards native balance.
129
+
130
+ ### Per-Hop Slippage
131
+
132
+ Per-hop bounds require Universal Router v2.1.1+ — set `urVersion: UniversalRouterVersion.V2_1_1` on `spec` to enable.
133
+
134
+ `encodeSwaps` accepts per-hop bounds as `minHopPriceX36` on each swap step, matching the contract parameter name. The value is a 1e36-scaled price floor.
135
+
136
+ ```typescript
137
+ {
138
+ type: 'V3_SWAP_EXACT_IN',
139
+ // ...
140
+ minHopPriceX36: ['995000000000000000000000000000000000', ...], // one per hop
141
+ }
142
+ ```
143
+
144
+ ## Signed Routes (Universal Router v2.1)
145
+
146
+ Universal Router v2.1 supports EIP712-signed route execution, enabling gasless transactions and intent-based trading.
147
+
148
+ **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.).
149
+
150
+ ### Basic Flow
151
+
152
+ ```typescript
153
+ import { SwapRouter, NONCE_SKIP_CHECK } from '@uniswap/universal-router-sdk'
154
+ import { Wallet } from '@ethersproject/wallet'
155
+
156
+ const wallet = new Wallet('0x...')
157
+ const chainId = 1
158
+ const routerAddress = '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD'
159
+ const deadline = Math.floor(Date.now() / 1000) + 60 * 20
160
+
161
+ // 1. Generate regular swap calldata
162
+ const { calldata, value } = SwapRouter.swapCallParameters(trade, {
163
+ slippageTolerance: new Percent(50, 10000),
164
+ recipient: wallet.address,
165
+ deadline,
166
+ })
167
+
168
+ // 2. Get EIP712 payload to sign
169
+ const payload = SwapRouter.getExecuteSignedPayload(
170
+ calldata,
171
+ {
172
+ intent: '0x' + '0'.repeat(64), // Application-specific intent
173
+ data: '0x' + '0'.repeat(64), // Application-specific data
174
+ sender: wallet.address, // Or address(0) to skip sender verification
175
+ },
176
+ deadline,
177
+ chainId,
178
+ routerAddress
179
+ )
180
+
181
+ // 3. Sign externally (wallet/KMS/hardware)
182
+ const signature = await wallet._signTypedData(payload.domain, payload.types, payload.value)
183
+
184
+ // 4. Encode for executeSigned()
185
+ const { calldata: signedCalldata, value: signedValue } = SwapRouter.encodeExecuteSigned(
186
+ calldata,
187
+ signature,
188
+ {
189
+ intent: payload.value.intent,
190
+ data: payload.value.data,
191
+ sender: payload.value.sender,
192
+ nonce: payload.value.nonce, // Must match what was signed
193
+ },
194
+ deadline,
195
+ BigNumber.from(value)
196
+ )
197
+
198
+ // 5. Submit transaction
199
+ await wallet.sendTransaction({
200
+ to: routerAddress,
201
+ data: signedCalldata,
202
+ value: signedValue,
203
+ })
204
+ ```
205
+
206
+ ### Nonce Management
207
+
208
+ - **Random nonce (default)**: Omit `nonce` parameter - SDK generates random nonce
209
+ - **Skip nonce check**: Use `NONCE_SKIP_CHECK` sentinel to allow signature reuse
210
+ - **Custom nonce**: Provide your own nonce for ordering
211
+
212
+ ```typescript
213
+ import { NONCE_SKIP_CHECK } from '@uniswap/universal-router-sdk'
214
+
215
+ // Reusable signature (no nonce check)
216
+ const payload = SwapRouter.getExecuteSignedPayload(
217
+ calldata,
218
+ {
219
+ intent: '0x...',
220
+ data: '0x...',
221
+ sender: '0x0000000000000000000000000000000000000000', // Skip sender verification too
222
+ nonce: NONCE_SKIP_CHECK, // Allow signature reuse
223
+ },
224
+ deadline,
225
+ chainId,
226
+ routerAddress
227
+ )
228
+ ```
229
+
230
+ ### Sender Verification
231
+
232
+ - **Verify sender**: Pass the actual sender address (e.g., `wallet.address`)
233
+ - **Skip verification**: Pass `'0x0000000000000000000000000000000000000000'`
234
+
235
+ The SDK automatically sets `verifySender` based on whether sender is address(0).
236
+
237
+ ## Cross-Chain Bridging with Across (Universal Router v2.1)
238
+
239
+ Universal 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.
240
+
241
+ ### Basic Usage
242
+
243
+ ```typescript
244
+ import { SwapRouter } from '@uniswap/universal-router-sdk'
245
+ import { BigNumber } from 'ethers'
246
+
247
+ // 1. Prepare your swap (e.g., USDC → WETH on mainnet)
248
+ const { calldata, value } = SwapRouter.swapCallParameters(trade, swapOptions, [
249
+ {
250
+ // Bridge configuration
251
+ depositor: userAddress,
252
+ recipient: userAddress, // Recipient on destination chain
253
+ inputToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH mainnet
254
+ outputToken: '0x4200000000000000000000000000000000000006', // WETH optimism
255
+ inputAmount: BigNumber.from('1000000000000000000'), // 1 WETH
256
+ outputAmount: BigNumber.from('990000000000000000'), // 0.99 WETH (with fees)
257
+ destinationChainId: 10, // Optimism
258
+ exclusiveRelayer: '0x0000000000000000000000000000000000000000',
259
+ quoteTimestamp: Math.floor(Date.now() / 1000),
260
+ fillDeadline: Math.floor(Date.now() / 1000) + 3600,
261
+ exclusivityDeadline: 0,
262
+ message: '0x',
263
+ useNative: false,
264
+ },
265
+ ])
266
+ ```
267
+
268
+ ### Swap + Bridge Example
269
+
270
+ ```typescript
271
+ // Swap USDC to WETH, then bridge WETH to Optimism
272
+ const bridgeParams = {
273
+ depositor: userAddress,
274
+ recipient: userAddress, // Can be different address on destination
275
+ inputToken: WETH_MAINNET,
276
+ outputToken: WETH_OPTIMISM,
277
+ inputAmount: CONTRACT_BALANCE, // Use entire swap output
278
+ outputAmount: expectedOutputAmount,
279
+ destinationChainId: 10,
280
+ exclusiveRelayer: '0x0000000000000000000000000000000000000000',
281
+ quoteTimestamp: Math.floor(Date.now() / 1000),
282
+ fillDeadline: Math.floor(Date.now() / 1000) + 3600,
283
+ exclusivityDeadline: 0,
284
+ message: '0x', // Optional message to execute on destination
285
+ useNative: false, // Set to true to bridge native ETH
286
+ }
287
+
288
+ const { calldata, value } = SwapRouter.swapCallParameters(
289
+ trade,
290
+ swapOptions,
291
+ [bridgeParams] // Array of bridge operations
292
+ )
293
+ ```
294
+
295
+ ### Using CONTRACT_BALANCE
296
+
297
+ When bridging after a swap, you often don't know the exact output amount. Use `CONTRACT_BALANCE` to bridge the entire contract balance:
298
+
299
+ ```typescript
300
+ import { CONTRACT_BALANCE } from '@uniswap/universal-router-sdk'
301
+
302
+ const bridgeParams = {
303
+ // ... other params
304
+ inputAmount: CONTRACT_BALANCE, // Bridge entire balance after swap
305
+ // ... other params
306
+ }
307
+ ```
308
+
309
+ ### Multiple Bridge Operations
310
+
311
+ You can perform multiple bridge operations after a swap:
312
+
313
+ ```typescript
314
+ const { calldata, value } = SwapRouter.swapCallParameters(trade, swapOptions, [
315
+ {
316
+ // Bridge 50% to Optimism
317
+ inputToken: WETH_MAINNET,
318
+ outputToken: WETH_OPTIMISM,
319
+ inputAmount: BigNumber.from('500000000000000000'),
320
+ destinationChainId: 10,
321
+ // ... other params
322
+ },
323
+ {
324
+ // Bridge remaining USDC to Arbitrum
325
+ inputToken: USDC_MAINNET,
326
+ outputToken: USDC_ARBITRUM,
327
+ inputAmount: CONTRACT_BALANCE,
328
+ destinationChainId: 42161,
329
+ // ... other params
330
+ },
331
+ ])
332
+ ```
333
+
334
+ ### Native ETH Bridging
335
+
336
+ To bridge native ETH instead of WETH:
337
+
338
+ ```typescript
339
+ const bridgeParams = {
340
+ inputToken: WETH_ADDRESS, // Must be WETH address
341
+ outputToken: WETH_ON_DESTINATION,
342
+ useNative: true, // Bridge as native ETH
343
+ // ... other params
344
+ }
345
+ ```
346
+
347
+ ### Important Notes
348
+
349
+ 1. **Across Quote**: Bridge parameters (especially `outputAmount`, `quoteTimestamp`, `fillDeadline`) should come from the Across API quote
350
+ 2. **Recipient Address**: Can be different from the sender, allowing cross-chain transfers to other addresses
351
+ 3. **Message Passing**: The `message` field allows executing arbitrary calls on the destination chain
352
+ 4. **Slippage**: The `outputAmount` already accounts for bridge fees and slippage