# Uniswap SDK > Documentation for Uniswap SDK Core, V2, V3, and V4 ## Constants The V4 SDK exports various constants for use with V4 pools, positions, and router operations. ### Import ```typescript import { ADDRESS_ZERO, EMPTY_BYTES, MSG_SENDER, DYNAMIC_FEE_FLAG, FeeAmount, TICK_SPACINGS, Actions } from '@uniswap/v4-sdk-next' ``` ### Action Constants #### MSG\_SENDER ```typescript const MSG_SENDER = '0x0000000000000000000000000000000000000001' ``` A sentinel value indicating that `msg.sender` should be used as the recipient/payer for operations. ```typescript import { V4PositionPlanner, MSG_SENDER } from '@uniswap/v4-sdk-next' const planner = new V4PositionPlanner() planner.addTakePair(currency0, currency1, MSG_SENDER) // Takes to msg.sender planner.addSweep(currency0, MSG_SENDER) // Sweeps to msg.sender ``` #### Actions Enum The `Actions` enum defines all available V4 Router actions: ```typescript enum Actions { // Liquidity actions INCREASE_LIQUIDITY = 0x00, DECREASE_LIQUIDITY = 0x01, MINT_POSITION = 0x02, BURN_POSITION = 0x03, // Swapping SWAP_EXACT_IN_SINGLE = 0x06, SWAP_EXACT_IN = 0x07, SWAP_EXACT_OUT_SINGLE = 0x08, SWAP_EXACT_OUT = 0x09, // Settling (closing deltas on the pool manager) SETTLE = 0x0b, SETTLE_ALL = 0x0c, SETTLE_PAIR = 0x0d, // Taking TAKE = 0x0e, TAKE_ALL = 0x0f, TAKE_PORTION = 0x10, TAKE_PAIR = 0x11, CLOSE_CURRENCY = 0x12, SWEEP = 0x14, // Wrapping/unwrapping native UNWRAP = 0x16, } ``` ### Address Constants #### ADDRESS\_ZERO ```typescript const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000' ``` The zero address. Used for: * Representing native ETH in pool keys * Indicating no hook (hookless pool) ```typescript import { Pool, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' // Pool with native ETH (not WETH) const pool = new Pool( ETH, // Native ether USDC, 3000, 60, ADDRESS_ZERO, // No hooks sqrtPriceX96, liquidity, tick ) ``` #### EMPTY\_BYTES ```typescript const EMPTY_BYTES = '0x' ``` Empty bytes. Used as default value for hook data. ```typescript import { V4PositionPlanner, EMPTY_BYTES } from '@uniswap/v4-sdk-next' const planner = new V4PositionPlanner() planner.addMint(pool, tickLower, tickUpper, liquidity, amount0Max, amount1Max, owner, EMPTY_BYTES) ``` #### EMPTY\_HOOK ```typescript const EMPTY_HOOK = '0x0000000000000000000000000000000000000000' ``` Alias for `ADDRESS_ZERO`, explicitly for hook addresses. ### Fee Constants #### DYNAMIC\_FEE\_FLAG ```typescript const DYNAMIC_FEE_FLAG = 0x800000 ``` The flag indicating a pool uses dynamic fees controlled by a hook. When this value is set as the fee, the pool's fee is determined by the hook at swap time. ```typescript import { Pool, DYNAMIC_FEE_FLAG } from '@uniswap/v4-sdk-next' // Pool with dynamic fees (requires a hook) const dynamicFeePool = new Pool( currency0, currency1, DYNAMIC_FEE_FLAG, // 0x800000 - dynamic fees 60, hookAddress, // Hook must be set for dynamic fees sqrtPriceX96, liquidity, tick ) ``` #### FeeAmount Enum ```typescript enum FeeAmount { LOWEST = 100, // 0.01% LOW = 500, // 0.05% MEDIUM = 3000, // 0.30% HIGH = 10000, // 1.00% } ``` Standard fee tiers in hundredths of a basis point. ```typescript import { Pool, FeeAmount, TICK_SPACINGS, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' const pool = new Pool( ETH, USDC, FeeAmount.MEDIUM, // 3000 (0.3%) TICK_SPACINGS[FeeAmount.MEDIUM], // 60 ADDRESS_ZERO, sqrtPriceX96, liquidity, tick ) ``` #### TICK\_SPACINGS ```typescript const TICK_SPACINGS: { [amount in FeeAmount]: number } = { [FeeAmount.LOWEST]: 1, [FeeAmount.LOW]: 10, [FeeAmount.MEDIUM]: 60, [FeeAmount.HIGH]: 200, } ``` The default tick spacings for each fee tier. | Fee Amount | Fee (%) | Tick Spacing | | ------------- | ------- | ------------ | | LOWEST (100) | 0.01% | 1 | | LOW (500) | 0.05% | 10 | | MEDIUM (3000) | 0.30% | 60 | | HIGH (10000) | 1.00% | 200 | ### Numeric Constants #### Q96 and Q192 ```typescript const Q96 = 2n ** 96n const Q192 = 2n ** 192n ``` Fixed-point math constants: * **Q96**: Used for sqrt price representation (Q64.96 format) * **Q192**: Used for price ratios (Q96 squared) #### ONE\_ETHER ```typescript const ONE_ETHER = 10n ** 18n ``` One ether in wei (10^18). #### OPEN\_DELTA ```typescript const OPEN_DELTA = 0n ``` Used when specifying "full delta" amounts in settle/take operations. A value of 0 means "use the full delta". #### Default Price ```typescript const SQRT_PRICE_1_1 = 79228162514264337593543950336n ``` The sqrt price representing a 1:1 ratio between tokens (`encodeSqrtRatioX96(1, 1)`). ```typescript import { Pool, SQRT_PRICE_1_1, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' // Pool with 1:1 price const pool = new Pool( currency0, currency1, 3000, 60, ADDRESS_ZERO, SQRT_PRICE_1_1, // 1:1 price liquidity, 0 // Tick 0 for 1:1 price ) ``` ### Position Manager Constants #### PositionFunctions Enum ```typescript enum PositionFunctions { INITIALIZE_POOL = 'initializePool', MODIFY_LIQUIDITIES = 'modifyLiquidities', PERMIT_BATCH = '0x002a3e3a', ERC721PERMIT_PERMIT = '0x0f5730f1', } ``` Function identifiers for the V4 PositionManager contract. ### Error Constants ```typescript const NATIVE_NOT_SET = 'NATIVE_NOT_SET' const ZERO_LIQUIDITY = 'ZERO_LIQUIDITY' const NO_SQRT_PRICE = 'NO_SQRT_PRICE' const CANNOT_BURN = 'CANNOT_BURN' ``` Error message constants used by the SDK. ### Common Fee/Tick Spacing Constants ```typescript const FEE_AMOUNT_LOW = 100 const FEE_AMOUNT_MEDIUM = 3000 const FEE_AMOUNT_HIGHEST = 10_000 const TICK_SPACING_TEN = 10 const TICK_SPACING_SIXTY = 60 ``` Additional convenience constants for common configurations. ### Usage Examples #### Creating a Standard Pool ```typescript import { Pool, FeeAmount, TICK_SPACINGS, ADDRESS_ZERO, SQRT_PRICE_1_1 } from '@uniswap/v4-sdk-next' const pool = new Pool( currency0, currency1, FeeAmount.MEDIUM, TICK_SPACINGS[FeeAmount.MEDIUM], ADDRESS_ZERO, SQRT_PRICE_1_1, 0n, 0 ) ``` #### Building a Swap with Actions ```typescript import { V4Planner, Actions, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' const planner = new V4Planner() planner.addAction(Actions.SWAP_EXACT_IN, [swapParams]) planner.addAction(Actions.SETTLE, [ADDRESS_ZERO, 0n, true]) planner.addAction(Actions.TAKE, [outputCurrency, recipient, 0n]) ``` #### Handling Native ETH ```typescript import { MSG_SENDER, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' // Check if currency is native const isNative = currency.isNative const currencyAddress = isNative ? ADDRESS_ZERO : currency.address // Sweep remaining ETH to sender planner.addSweep(nativeCurrency, MSG_SENDER) ``` ## encodeRouteToPath The `encodeRouteToPath` function encodes a V4 route into an array of `PathKey` structs for use in router calls. ### Import ```typescript import { encodeRouteToPath, type PathKey } from '@uniswap/v4-sdk-next' ``` ### Function Signature ```typescript function encodeRouteToPath( route: Route, exactOutput?: boolean ): PathKey[] ``` #### Parameters | Name | Type | Description | | ------------- | --------------------------- | -------------------------------------------------------- | | `route` | `Route` | The route to encode | | `exactOutput` | `boolean?` | Whether this is an exact output swap (reverses the path) | #### Returns An array of `PathKey` structs representing each hop in the swap path. ### PathKey Type ```typescript type PathKey = { /** The currency address for this path segment (0x0 for native) */ intermediateCurrency: string /** The fee tier of the pool (in hundredths of a bip) */ fee: number /** The tick spacing of the pool */ tickSpacing: number /** The hook address for this pool */ hooks: string /** Optional hook data for this hop (default: 0x) */ hookData: string } ``` ### Example ```typescript import { Pool, Route, encodeRouteToPath, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Ether, Token } from '@uniswap/sdk-core-next' // Define currencies const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const DAI = new Token(1, '0x6B175474E89094C44Da98b954EescdeCB5BE3830', 18, 'DAI') // Create pools const ethUsdcPool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96_1, liquidity1, tick1) const usdcDaiPool = new Pool(USDC, DAI, 500, 10, ADDRESS_ZERO, sqrtPriceX96_2, liquidity2, tick2) // Create route: ETH -> USDC -> DAI const route = new Route([ethUsdcPool, usdcDaiPool], ETH, DAI) // Encode for exact input swap const pathExactIn = encodeRouteToPath(route, false) console.log(pathExactIn) // [ // { // intermediateCurrency: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC // fee: 3000, // tickSpacing: 60, // hooks: '0x0000000000000000000000000000000000000000', // hookData: '0x' // }, // { // intermediateCurrency: '0x6B175474E89094C44Da98b954EedecsB5BE3830', // DAI // fee: 500, // tickSpacing: 10, // hooks: '0x0000000000000000000000000000000000000000', // hookData: '0x' // } // ] // Encode for exact output swap (path is reversed) const pathExactOut = encodeRouteToPath(route, true) // Path keys are in reverse order for exact output ``` ### Exact Input vs Exact Output The path encoding differs based on the swap direction: #### Exact Input For exact input swaps, the path follows the natural order: * Start currency -> Intermediate currency 1 -> ... -> End currency * Each PathKey contains the **next** currency in the path ```typescript // ETH -> USDC -> DAI (exact input) const path = encodeRouteToPath(route, false) // path[0].intermediateCurrency = USDC (next after ETH) // path[1].intermediateCurrency = DAI (next after USDC) ``` #### Exact Output For exact output swaps, the path is reversed: * End currency -> ... -> Intermediate currency 1 -> Start currency * The router processes the path backwards ```typescript // ETH -> USDC -> DAI (exact output) const path = encodeRouteToPath(route, true) // Path is reversed internally for the router ``` ### Native Currency Handling Native ETH is represented with the zero address: ```typescript const ethUsdcPool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, ...) const route = new Route([ethUsdcPool], ETH, USDC) const path = encodeRouteToPath(route, false) // If ETH is the intermediate, intermediateCurrency will be: // '0x0000000000000000000000000000000000000000' ``` ### With Hooks Pools with hooks include the hook address in the path: ```typescript const hookAddress = '0x000000000000000000000000000000000000C0C0' const poolWithHook = new Pool(ETH, USDC, 3000, 60, hookAddress, ...) const route = new Route([poolWithHook], ETH, USDC) const path = encodeRouteToPath(route, false) console.log(path[0].hooks) // '0x000000000000000000000000000000000000C0C0' ``` ### Usage with V4Planner The encoded path is used internally by `V4Planner.addTrade()`: ```typescript import { V4Planner } from '@uniswap/v4-sdk-next' const planner = new V4Planner() // addTrade internally calls encodeRouteToPath planner.addTrade(trade, slippageTolerance) ``` You can also use it directly when building custom swap calls: ```typescript import { V4Planner, Actions, encodeRouteToPath } from '@uniswap/v4-sdk-next' const planner = new V4Planner() const path = encodeRouteToPath(route, false) planner.addAction(Actions.SWAP_EXACT_IN, [{ currencyIn: ADDRESS_ZERO, // ETH path: path, amountIn: inputAmount.toString(), amountOutMinimum: minOutput.toString() }]) ``` ### Multi-Hop Routing For multi-hop routes, each pool contributes one PathKey: ```typescript // Three-hop route: ETH -> USDC -> WBTC -> DAI const route = new Route( [ethUsdcPool, usdcWbtcPool, wbtcDaiPool], ETH, DAI ) const path = encodeRouteToPath(route, false) // path.length === 3 // path[0]: ETH -> USDC hop // path[1]: USDC -> WBTC hop // path[2]: WBTC -> DAI hop ``` ### Notes * The function creates a deep copy of the pools array, so it does not modify the original route * Hook data is currently set to `'0x'` for all hops (custom hook data per hop is not yet supported) * The `intermediateCurrency` in each PathKey is the **output** currency of that hop ## Hook Permissions Uniswap V4 hooks encode their permissions in the contract address. This page documents the `HookOptions` enum and all 14 hook permission types. ### Import ```typescript import { HookOptions, hookFlagIndex, type HookPermissions } from '@uniswap/v4-sdk-next' ``` ### HookOptions Enum The `HookOptions` enum defines all available hook permissions: ```typescript enum HookOptions { AfterRemoveLiquidityReturnsDelta = 'afterRemoveLiquidityReturnsDelta', AfterAddLiquidityReturnsDelta = 'afterAddLiquidityReturnsDelta', AfterSwapReturnsDelta = 'afterSwapReturnsDelta', BeforeSwapReturnsDelta = 'beforeSwapReturnsDelta', AfterDonate = 'afterDonate', BeforeDonate = 'beforeDonate', AfterSwap = 'afterSwap', BeforeSwap = 'beforeSwap', AfterRemoveLiquidity = 'afterRemoveLiquidity', BeforeRemoveLiquidity = 'beforeRemoveLiquidity', AfterAddLiquidity = 'afterAddLiquidity', BeforeAddLiquidity = 'beforeAddLiquidity', AfterInitialize = 'afterInitialize', BeforeInitialize = 'beforeInitialize', } ``` ### HookPermissions Type The `HookPermissions` type represents all permissions as a boolean object: ```typescript type HookPermissions = { [key in HookOptions]: boolean } ``` ### Hook Flag Index The `hookFlagIndex` constant maps each permission to its bit position in the hook address: ```typescript const hookFlagIndex: { [key in HookOptions]: number } = { afterRemoveLiquidityReturnsDelta: 0, afterAddLiquidityReturnsDelta: 1, afterSwapReturnsDelta: 2, beforeSwapReturnsDelta: 3, afterDonate: 4, beforeDonate: 5, afterSwap: 6, beforeSwap: 7, afterRemoveLiquidity: 8, beforeRemoveLiquidity: 9, afterAddLiquidity: 10, beforeAddLiquidity: 11, afterInitialize: 12, beforeInitialize: 13, } ``` ### Permission Categories #### Initialize Permissions Called when a pool is initialized. | Permission | Bit | Description | | ------------------ | --- | --------------------------------- | | `BeforeInitialize` | 13 | Called before pool initialization | | `AfterInitialize` | 12 | Called after pool initialization | ```typescript import { Hook, HookOptions } from '@uniswap/v4-sdk-next' // Check initialize permissions Hook.hasPermission(hookAddress, HookOptions.BeforeInitialize) Hook.hasPermission(hookAddress, HookOptions.AfterInitialize) // Or use convenience method Hook.hasInitializePermissions(hookAddress) ``` #### Liquidity Permissions Called during liquidity operations (mint, burn, modify). | Permission | Bit | Description | | ----------------------- | --- | -------------------------------- | | `BeforeAddLiquidity` | 11 | Called before adding liquidity | | `AfterAddLiquidity` | 10 | Called after adding liquidity | | `BeforeRemoveLiquidity` | 9 | Called before removing liquidity | | `AfterRemoveLiquidity` | 8 | Called after removing liquidity | ```typescript // Check liquidity permissions Hook.hasPermission(hookAddress, HookOptions.BeforeAddLiquidity) Hook.hasPermission(hookAddress, HookOptions.AfterAddLiquidity) Hook.hasPermission(hookAddress, HookOptions.BeforeRemoveLiquidity) Hook.hasPermission(hookAddress, HookOptions.AfterRemoveLiquidity) // Or use convenience method Hook.hasLiquidityPermissions(hookAddress) ``` #### Swap Permissions Called during swap operations. | Permission | Bit | Description | | ------------ | --- | -------------------- | | `BeforeSwap` | 7 | Called before a swap | | `AfterSwap` | 6 | Called after a swap | ```typescript // Check swap permissions Hook.hasPermission(hookAddress, HookOptions.BeforeSwap) Hook.hasPermission(hookAddress, HookOptions.AfterSwap) // Or use convenience method Hook.hasSwapPermissions(hookAddress) ``` #### Donate Permissions Called during donate operations (adding to pool fees without receiving LP tokens). | Permission | Bit | Description | | -------------- | --- | ---------------------- | | `BeforeDonate` | 5 | Called before a donate | | `AfterDonate` | 4 | Called after a donate | ```typescript // Check donate permissions Hook.hasPermission(hookAddress, HookOptions.BeforeDonate) Hook.hasPermission(hookAddress, HookOptions.AfterDonate) // Or use convenience method Hook.hasDonatePermissions(hookAddress) ``` #### Delta Permissions These special permissions allow hooks to modify the token amounts in operations. | Permission | Bit | Description | | ---------------------------------- | --- | --------------------------------------------- | | `BeforeSwapReturnsDelta` | 3 | beforeSwap can modify swap amounts | | `AfterSwapReturnsDelta` | 2 | afterSwap can modify swap amounts | | `AfterAddLiquidityReturnsDelta` | 1 | afterAddLiquidity can modify token amounts | | `AfterRemoveLiquidityReturnsDelta` | 0 | afterRemoveLiquidity can modify token amounts | ```typescript // Check delta permissions Hook.hasPermission(hookAddress, HookOptions.BeforeSwapReturnsDelta) Hook.hasPermission(hookAddress, HookOptions.AfterSwapReturnsDelta) Hook.hasPermission(hookAddress, HookOptions.AfterAddLiquidityReturnsDelta) Hook.hasPermission(hookAddress, HookOptions.AfterRemoveLiquidityReturnsDelta) ``` ### Computing Hook Addresses Hook addresses must have specific bits set to enable permissions. Here's how to compute them: ```typescript import { hookFlagIndex, HookOptions } from '@uniswap/v4-sdk-next' function computeHookFlags(permissions: HookOptions[]): number { let flags = 0 for (const permission of permissions) { flags |= (1 << hookFlagIndex[permission]) } return flags } // Example: Hook with beforeSwap and afterSwap const swapHookFlags = computeHookFlags([ HookOptions.BeforeSwap, HookOptions.AfterSwap ]) // Result: 0xC0 (bits 6 and 7 set) // The hook address must end with these flags // e.g., 0x000000000000000000000000000000000000C0C0 ``` ### Example: Creating Permission-Aware Code ```typescript import { Pool, Hook, HookOptions, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' async function getSwapQuote(pool: Pool, inputAmount: CurrencyAmount) { // Check if the hook affects swap calculations if (pool.hooks !== ADDRESS_ZERO) { const hasSwapHooks = Hook.hasSwapPermissions(pool.hooks) const hasDeltaHooks = Hook.hasPermission(pool.hooks, HookOptions.BeforeSwapReturnsDelta) || Hook.hasPermission(pool.hooks, HookOptions.AfterSwapReturnsDelta) if (hasSwapHooks || hasDeltaHooks) { throw new Error( 'Cannot compute quote for pools with swap hooks. ' + 'Use an on-chain quoter instead.' ) } } // Safe to compute quote off-chain return pool.getOutputAmount(inputAmount) } ``` ### Permission Bit Layout The last 14 bits of a hook address determine its permissions: ``` Address: 0x...............XXXX ^^^^ |||\- bits 0-3: Delta permissions ||\-- bits 4-5: Donate permissions |\--- bits 6-7: Swap permissions \---- bits 8-13: Liquidity & Initialize permissions ``` Visual representation of bits: ``` Bit 13: beforeInitialize Bit 12: afterInitialize Bit 11: beforeAddLiquidity Bit 10: afterAddLiquidity Bit 9: beforeRemoveLiquidity Bit 8: afterRemoveLiquidity Bit 7: beforeSwap Bit 6: afterSwap Bit 5: beforeDonate Bit 4: afterDonate Bit 3: beforeSwapReturnsDelta Bit 2: afterSwapReturnsDelta Bit 1: afterAddLiquidityReturnsDelta Bit 0: afterRemoveLiquidityReturnsDelta ``` ### Common Permission Combinations | Use Case | Hex Suffix | Permissions | | -------------------- | ---------- | -------------------------------------------- | | No hooks | `0x0000` | None | | Swap monitoring | `0x00C0` | beforeSwap, afterSwap | | Fee taking | `0x00C4` | beforeSwap, afterSwap, afterSwapReturnsDelta | | Liquidity management | `0x0F00` | All liquidity hooks | | Full control | `0x3FFF` | All permissions | ## Hook The `Hook` class provides utilities for working with V4 hook permissions. V4 hooks encode their permissions in the last 14 bits of the hook contract address. ### Import ```typescript import { Hook, HookOptions } from '@uniswap/v4-sdk-next' ``` ### Overview In Uniswap V4, hooks are smart contracts that can execute custom logic at various points during pool operations. The permissions a hook has are encoded directly in its contract address, making it impossible to change permissions after deployment. The last 14 bits of a hook address indicate which hook functions are enabled: | Bit | Permission | | --- | -------------------------------- | | 0 | afterRemoveLiquidityReturnsDelta | | 1 | afterAddLiquidityReturnsDelta | | 2 | afterSwapReturnsDelta | | 3 | beforeSwapReturnsDelta | | 4 | afterDonate | | 5 | beforeDonate | | 6 | afterSwap | | 7 | beforeSwap | | 8 | afterRemoveLiquidity | | 9 | beforeRemoveLiquidity | | 10 | afterAddLiquidity | | 11 | beforeAddLiquidity | | 12 | afterInitialize | | 13 | beforeInitialize | ### Static Methods #### `permissions(address)` ```typescript static permissions(address: string): HookPermissions ``` Returns all permissions for a given hook address. ```typescript const hookAddress = '0x000000000000000000000000000000000000C0C0' const perms = Hook.permissions(hookAddress) console.log(perms) // { // beforeInitialize: false, // afterInitialize: false, // beforeAddLiquidity: false, // afterAddLiquidity: false, // beforeRemoveLiquidity: false, // afterRemoveLiquidity: false, // beforeSwap: true, // afterSwap: true, // beforeDonate: false, // afterDonate: false, // beforeSwapReturnsDelta: false, // afterSwapReturnsDelta: false, // afterAddLiquidityReturnsDelta: false, // afterRemoveLiquidityReturnsDelta: false // } ``` #### `hasPermission(address, hookOption)` ```typescript static hasPermission(address: string, hookOption: HookOptions): boolean ``` Check if a hook has a specific permission. ```typescript import { HookOptions } from '@uniswap/v4-sdk-next' const hookAddress = '0x000000000000000000000000000000000000C0C0' Hook.hasPermission(hookAddress, HookOptions.BeforeSwap) // true Hook.hasPermission(hookAddress, HookOptions.AfterSwap) // true Hook.hasPermission(hookAddress, HookOptions.BeforeDonate) // false ``` #### `hasInitializePermissions(address)` ```typescript static hasInitializePermissions(address: string): boolean ``` Check if a hook has any initialize permissions (beforeInitialize or afterInitialize). ```typescript const hookAddress = '0x000000000000000000000000000000000000C0C0' Hook.hasInitializePermissions(hookAddress) // false ``` #### `hasLiquidityPermissions(address)` ```typescript static hasLiquidityPermissions(address: string): boolean ``` Check if a hook has any liquidity-related permissions. This includes: * beforeAddLiquidity * afterAddLiquidity * beforeRemoveLiquidity * afterRemoveLiquidity Note: This implicitly covers the delta permissions since they require the base permissions. ```typescript const hookAddress = '0x0000000000000000000000000000000000000C00' Hook.hasLiquidityPermissions(hookAddress) // true (has beforeAddLiquidity) ``` #### `hasSwapPermissions(address)` ```typescript static hasSwapPermissions(address: string): boolean ``` Check if a hook has any swap-related permissions (beforeSwap or afterSwap). ```typescript const hookAddress = '0x000000000000000000000000000000000000C0C0' Hook.hasSwapPermissions(hookAddress) // true ``` #### `hasDonatePermissions(address)` ```typescript static hasDonatePermissions(address: string): boolean ``` Check if a hook has any donate-related permissions (beforeDonate or afterDonate). ```typescript const hookAddress = '0x000000000000000000000000000000000000C0C0' Hook.hasDonatePermissions(hookAddress) // false ``` ### Example: Analyzing a Hook Address ```typescript import { Hook, HookOptions } from '@uniswap/v4-sdk-next' function analyzeHook(hookAddress: string) { console.log('Hook Analysis:', hookAddress) console.log('---') const perms = Hook.permissions(hookAddress) // Group permissions by category console.log('Initialize:', perms.beforeInitialize ? 'before' : '', perms.afterInitialize ? 'after' : '' ) console.log('Add Liquidity:', perms.beforeAddLiquidity ? 'before' : '', perms.afterAddLiquidity ? 'after' : '', perms.afterAddLiquidityReturnsDelta ? '(returns delta)' : '' ) console.log('Remove Liquidity:', perms.beforeRemoveLiquidity ? 'before' : '', perms.afterRemoveLiquidity ? 'after' : '', perms.afterRemoveLiquidityReturnsDelta ? '(returns delta)' : '' ) console.log('Swap:', perms.beforeSwap ? 'before' : '', perms.afterSwap ? 'after' : '', perms.beforeSwapReturnsDelta ? '(before returns delta)' : '', perms.afterSwapReturnsDelta ? '(after returns delta)' : '' ) console.log('Donate:', perms.beforeDonate ? 'before' : '', perms.afterDonate ? 'after' : '' ) } // Analyze a swap-only hook analyzeHook('0x000000000000000000000000000000000000C0C0') ``` ### Example: Pool with Hook Validation ```typescript import { Pool, Hook, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' function createPool(currencyA, currencyB, fee, tickSpacing, hookAddress, ...poolParams) { // Validate hook if provided if (hookAddress !== ADDRESS_ZERO) { const perms = Hook.permissions(hookAddress) // Log which hooks are active console.log('Creating pool with hook permissions:', perms) // Warn if hook affects swap calculations if (Hook.hasSwapPermissions(hookAddress)) { console.warn('Warning: Hook may affect swap calculations') } } return new Pool(currencyA, currencyB, fee, tickSpacing, hookAddress, ...poolParams) } ``` ### Address Validation All Hook methods validate that the provided address is a valid Ethereum address: ```typescript // Valid addresses work Hook.permissions('0x000000000000000000000000000000000000C0C0') // OK // Invalid addresses throw Hook.permissions('invalid') // throws 'invalid address' Hook.permissions('0x123') // throws 'invalid address' ``` ### Common Hook Address Patterns ```typescript // No hooks (zero address) const NO_HOOK = '0x0000000000000000000000000000000000000000' // Swap hooks only (bits 6-7) const SWAP_HOOK = '0x000000000000000000000000000000000000C0' // 0b11000000 // Liquidity hooks only (bits 8-11) const LIQUIDITY_HOOK = '0x000000000000000000000000000000000000F00' // 0b111100000000 // All hooks const ALL_HOOKS = '0x0000000000000000000000000000000000003FFF' // 0b11111111111111 ``` ## V4 SDK The V4 SDK (`@uniswap/v4-sdk-next`) provides tools for building on Uniswap V4, the most powerful and flexible version of the protocol. V4 introduces hooks for custom pool logic and native ETH support. ### Features * **Hooks**: Customize pool behavior with 14 different hook permissions * **Native ETH**: Trade ETH directly without WETH wrapping * **Singleton Design**: All pools in a single contract for gas efficiency * **Dynamic Fees**: Hooks can implement custom fee logic ### Installation ```bash npm install @uniswap/v4-sdk-next ``` ```bash pnpm add @uniswap/v4-sdk-next ``` ```bash yarn add @uniswap/v4-sdk-next ``` ### Quick Start ```typescript import { Pool, Position, Hook, HookOptions } from '@uniswap/v4-sdk-next' import { Token, Ether, CurrencyAmount } from '@uniswap/sdk-core-next' // V4 supports native ETH directly const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Hook address (address encodes permissions in last 14 bits) const hookAddress = '0x0000000000000000000000000000000000000000' // Create a V4 pool with hook const pool = new Pool( ETH, USDC, 3000, // fee (0.3%) 60, // tickSpacing hookAddress, // hooks address '1234567890123456789', // sqrtPriceX96 '1000000000000000000', // liquidity -58000 // tickCurrent ) // Get pool identifiers console.log(pool.poolId) // keccak256 hash of pool key console.log(pool.poolKey) // { currency0, currency1, fee, tickSpacing, hooks } // Check hook permissions const permissions = Hook.permissions(hookAddress) console.log(permissions.beforeSwap) // true/false console.log(permissions.afterSwap) // true/false ``` ### What's New in V4 #### Hooks Hooks allow custom code to run at key points in a pool's lifecycle: * **Initialize**: `beforeInitialize`, `afterInitialize` * **Liquidity**: `beforeAddLiquidity`, `afterAddLiquidity`, `beforeRemoveLiquidity`, `afterRemoveLiquidity` * **Swap**: `beforeSwap`, `afterSwap` * **Donate**: `beforeDonate`, `afterDonate` * **Delta Returns**: Hooks can return deltas to modify amounts Hook permissions are encoded in the last 14 bits of the hook contract address. #### Native ETH V4 pools can use native ETH directly: ```typescript // V4: Native ETH const pool = new Pool(Ether.onChain(1), USDC, ...) // V2/V3: Required WETH const pool = new Pool(WETH, USDC, ...) ``` #### Pool Keys and IDs Pools are identified by a `PoolKey` struct: ```typescript type PoolKey = { currency0: string // Lower address currency1: string // Higher address fee: number // Fee in bips tickSpacing: number // Tick spacing hooks: string // Hook address } ``` The `poolId` is the keccak256 hash of the encoded pool key. ### Modules #### Entities * [Pool](/v4-sdk/pool) - V4 pool with hook support and native ETH * [Position](/v4-sdk/position) - LP position in a V4 pool * [Route](/v4-sdk/route) - Trade path through V4 pools * [Trade](/v4-sdk/trade) - Swap execution #### Hooks * [Hook](/v4-sdk/hook) - Hook permission utilities * [Hook Permissions](/v4-sdk/hook-permissions) - All 14 permission types #### Contracts * [PositionManager](/v4-sdk/position-manager) - V4 position management * [Multicall](/v4-sdk/multicall) - Batch multiple calls #### Utilities * [V4Planner](/v4-sdk/v4-planner) - Plan V4 actions for execution * [V4PositionPlanner](/v4-sdk/v4-position-planner) - Position-specific planning * [encodeRouteToPath](/v4-sdk/encode-route-to-path) - Encode routes for contracts #### Reference * [Constants](/v4-sdk/constants) - Action constants and sentinels ## Installation ### Package Manager :::code-group ```bash [npm] npm install @uniswap/v4-sdk-next ``` ```bash [pnpm] pnpm add @uniswap/v4-sdk-next ``` ```bash [yarn] yarn add @uniswap/v4-sdk-next ``` ::: ### Requirements * **Node.js**: 18.x or later * **TypeScript**: 5.0 or later (recommended) ### Peer Dependencies The V4 SDK depends on SDK Core and V3 SDK: ```bash npm install @uniswap/sdk-core-next @uniswap/v3-sdk-next ``` ### Usage ```typescript import { Pool, Position, Route, Trade, Hook, HookOptions, PositionManager, V4Planner, } from '@uniswap/v4-sdk-next' import { Token, Ether, CurrencyAmount } from '@uniswap/sdk-core-next' ``` ### TypeScript Configuration ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true } } ``` ## Multicall The `Multicall` class provides utilities for batching multiple contract calls into a single transaction. ### Import ```typescript import { Multicall } from '@uniswap/v4-sdk-next' ``` ### Overview Multicall allows you to combine multiple contract calls into a single transaction, reducing gas costs and ensuring atomic execution. This is commonly used with the V4 PositionManager to batch operations like permits and liquidity modifications. ### Static Methods #### `encodeMulticall(calldataList)` ```typescript static encodeMulticall(calldataList: string | string[]): string ``` Encodes a list of calldatas into a single multicall calldata. ##### Parameters | Name | Type | Description | | -------------- | -------------------- | ------------------------- | | `calldataList` | `string \| string[]` | The calldata(s) to encode | ##### Returns If a single calldata is provided, returns it unchanged. If multiple calldatas are provided, returns the encoded multicall. ```typescript import { Multicall, V4PositionManager } from '@uniswap/v4-sdk-next' // Single call - returns unchanged const singleCalldata = Multicall.encodeMulticall(someCalldata) // Multiple calls - encodes as multicall const permitCalldata = V4PositionManager.encodePermitBatch(owner, permitBatch, signature) const mintCalldata = V4PositionManager.encodeModifyLiquidities(plannerData, deadline) const multicallData = Multicall.encodeMulticall([ permitCalldata, mintCalldata ]) ``` #### `decodeMulticall(encodedCalldata)` ```typescript static decodeMulticall(encodedCalldata: string): string[] ``` Decodes a multicall calldata into its component calldatas. ##### Parameters | Name | Type | Description | | ----------------- | -------- | ------------------------------ | | `encodedCalldata` | `string` | The encoded multicall calldata | ##### Returns An array of the individual calldatas. ```typescript const calldatas = Multicall.decodeMulticall(multicallData) // Returns: ['0x...', '0x...'] ``` ### Example: Batch Position Operations ```typescript import { Multicall, V4PositionManager, V4PositionPlanner } from '@uniswap/v4-sdk-next' import { Percent } from '@uniswap/sdk-core-next' // Build the calldata list const calldataList: string[] = [] // 1. Add permit (if using Permit2) if (batchPermit) { calldataList.push( V4PositionManager.encodePermitBatch( owner, batchPermit.permitBatch, batchPermit.signature ) ) } // 2. Add the position modification const planner = new V4PositionPlanner() planner.addMint(pool, tickLower, tickUpper, liquidity, amount0Max, amount1Max, recipient) planner.addSettlePair(pool.currency0, pool.currency1) calldataList.push( V4PositionManager.encodeModifyLiquidities(planner.finalize(), deadline) ) // 3. Encode as multicall const multicallData = Multicall.encodeMulticall(calldataList) // 4. Send transaction await positionManager.multicall(multicallData, { value: ethValue }) ``` ### Example: Initialize Pool and Mint Position ```typescript import { Multicall, V4PositionManager, Pool } from '@uniswap/v4-sdk-next' const calldataList: string[] = [] // 1. Initialize the pool const poolKey = Pool.getPoolKey(currency0, currency1, fee, tickSpacing, hooks) const initializeCalldata = V4PositionManager.createCallParameters(poolKey, sqrtPriceX96) calldataList.push(initializeCalldata.calldata) // 2. Add the mint calldata const { calldata: mintCalldata } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline, recipient, useNative: ETH }) calldataList.push(mintCalldata) // 3. Encode and send const multicallData = Multicall.encodeMulticall(calldataList) ``` ### ABI The Multicall function uses the following ABI: ```typescript const MULTICALL_ABI = { name: 'multicall', type: 'function', inputs: [{ name: 'data', type: 'bytes[]' }], outputs: [{ name: 'results', type: 'bytes[]' }], stateMutability: 'payable', } ``` ### Optimization The `encodeMulticall` function automatically optimizes by returning the single calldata unchanged when only one call is provided: ```typescript // These produce identical results const direct = someCalldata const wrapped = Multicall.encodeMulticall(someCalldata) // direct === wrapped (single call not wrapped) // This wraps in multicall const batched = Multicall.encodeMulticall([call1, call2]) // batched !== call1 (multiple calls are wrapped) ``` This optimization saves gas when only a single operation is needed. ## Pool The `Pool` class represents a Uniswap V4 liquidity pool. V4 pools support hooks for custom logic and native currency (ETH without WETH wrapping). ### Import ```typescript import { Pool } from '@uniswap/v4-sdk-next' ``` ### Types #### PoolKey The `PoolKey` type uniquely identifies a V4 pool. ```typescript type PoolKey = { currency0: string // Address of first currency (0x0 for native ETH) currency1: string // Address of second currency fee: number // Fee in hundredths of bips tickSpacing: number // Tick spacing of the pool hooks: string // Hook contract address } ``` #### PoolId The Pool ID is a `bytes32` hash (keccak256) of the encoded PoolKey. It serves as the unique identifier for a pool in the V4 PoolManager contract. ### Constructor ```typescript new Pool( currencyA: Currency, currencyB: Currency, fee: number, tickSpacing: number, hooks: string, sqrtRatioX96: BigintIsh, liquidity: BigintIsh, tickCurrent: number, ticks?: TickDataProvider | (Tick | TickConstructorArgs)[] ) ``` #### Parameters | Name | Type | Description | | -------------- | ---------------------------- | ------------------------------------------------------------------ | | `currencyA` | `Currency` | One of the currencies in the pool | | `currencyB` | `Currency` | The other currency in the pool | | `fee` | `number` | Fee in hundredths of bips (or `DYNAMIC_FEE_FLAG` for dynamic fees) | | `tickSpacing` | `number` | The tick spacing of the pool | | `hooks` | `string` | The hook contract address (use `ADDRESS_ZERO` for no hooks) | | `sqrtRatioX96` | `BigintIsh` | The sqrt of the current ratio of amounts (Q64.96 format) | | `liquidity` | `BigintIsh` | The current value of in-range liquidity | | `tickCurrent` | `number` | The current tick of the pool | | `ticks` | `TickDataProvider \| Tick[]` | Optional tick data provider or array of ticks | ### Example ```typescript import { Pool, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Token, Ether, CurrencyAmount } from '@uniswap/sdk-core-next' // Define currencies const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create a V4 pool with native ETH (no hooks) const pool = new Pool( ETH, USDC, 3000, // 0.3% fee 60, // tick spacing ADDRESS_ZERO, // no hooks '79228162514264337593543950336', // sqrtPriceX96 (1:1 price) '1000000000000000000', // liquidity 0 // current tick ) // Access pool properties console.log(pool.chainId) // 1 console.log(pool.fee) // 3000 console.log(pool.tickSpacing) // 60 console.log(pool.poolId) // bytes32 pool identifier ``` ### Static Methods #### `getPoolKey(currencyA, currencyB, fee, tickSpacing, hooks)` ```typescript static getPoolKey( currencyA: Currency, currencyB: Currency, fee: number, tickSpacing: number, hooks: string ): PoolKey ``` Constructs the pool key for a V4 pool. Currencies are automatically sorted. ```typescript const poolKey = Pool.getPoolKey(ETH, USDC, 3000, 60, ADDRESS_ZERO) // { // currency0: '0x0000000000000000000000000000000000000000', // currency1: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // fee: 3000, // tickSpacing: 60, // hooks: '0x0000000000000000000000000000000000000000' // } ``` #### `getPoolId(currencyA, currencyB, fee, tickSpacing, hooks)` ```typescript static getPoolId( currencyA: Currency, currencyB: Currency, fee: number, tickSpacing: number, hooks: string ): string ``` Computes the pool ID (keccak256 hash of the encoded pool key). ```typescript const poolId = Pool.getPoolId(ETH, USDC, 3000, 60, ADDRESS_ZERO) // Returns: '0x...' (32-byte hex string) ``` ### Properties #### `currency0` / `currency1` ```typescript readonly currency0: Currency readonly currency1: Currency ``` The currencies in the pool, sorted by address. Native ETH is represented with address `0x0`. #### `token0` / `token1` ```typescript get token0(): Currency get token1(): Currency ``` Aliases for `currency0` and `currency1` for backwards compatibility with V2/V3 SDKs. #### `fee` ```typescript readonly fee: number ``` The pool fee in hundredths of a basis point (e.g., 3000 = 0.3%). #### `tickSpacing` ```typescript readonly tickSpacing: number ``` The spacing between usable ticks in the pool. #### `hooks` ```typescript readonly hooks: string ``` The hook contract address. Use `ADDRESS_ZERO` for pools without hooks. #### `sqrtRatioX96` ```typescript readonly sqrtRatioX96: bigint ``` The current sqrt price in Q64.96 format. #### `liquidity` ```typescript readonly liquidity: bigint ``` The current in-range liquidity. #### `tickCurrent` ```typescript readonly tickCurrent: number ``` The current tick of the pool. #### `poolKey` ```typescript readonly poolKey: PoolKey ``` The pool key that uniquely identifies this pool. #### `poolId` ```typescript readonly poolId: string ``` The pool ID (keccak256 hash of the pool key). #### `chainId` ```typescript get chainId(): number ``` The chain ID of the currencies in the pool. #### `currency0Price` / `currency1Price` ```typescript get currency0Price(): Price get currency1Price(): Price ``` The current mid price of the pool in terms of currency0 or currency1. ### Methods #### `involvesCurrency(currency)` ```typescript involvesCurrency(currency: Currency): boolean ``` Returns `true` if the currency is either currency0 or currency1. #### `v4InvolvesToken(currency)` ```typescript v4InvolvesToken(currency: Currency): boolean ``` V4-specific method that checks if the currency or its wrapped version is in the pool. Useful for ETH/WETH connection in mixed routes. #### `priceOf(currency)` ```typescript priceOf(currency: Currency): Price ``` Returns the price of the given currency in terms of the other currency in the pool. #### `getOutputAmount(inputAmount, sqrtPriceLimitX96?)` ```typescript async getOutputAmount( inputAmount: CurrencyAmount, sqrtPriceLimitX96?: bigint ): Promise<[CurrencyAmount, Pool]> ``` Given an input amount, returns the computed output amount and a pool with updated state. Only works for vanilla hookless pools. ```typescript const inputAmount = CurrencyAmount.fromRawAmount(ETH, '1000000000000000000') const [outputAmount, newPool] = await pool.getOutputAmount(inputAmount) ``` #### `getInputAmount(outputAmount, sqrtPriceLimitX96?)` ```typescript async getInputAmount( outputAmount: CurrencyAmount, sqrtPriceLimitX96?: bigint ): Promise<[CurrencyAmount, Pool]> ``` Given a desired output amount, returns the computed input amount and a pool with updated state. Only works for vanilla hookless pools. ### V4-Specific Features #### Native Currency Support V4 pools can include native ETH directly without wrapping to WETH: ```typescript import { Ether } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96, liquidity, tick) // currency0 will be native ETH (address 0x0) console.log(pool.currency0.isNative) // true ``` #### Dynamic Fees V4 supports dynamic fees controlled by hooks: ```typescript import { DYNAMIC_FEE_FLAG } from '@uniswap/v4-sdk-next' // Pool with dynamic fees (requires a hook) const dynamicFeePool = new Pool( currencyA, currencyB, DYNAMIC_FEE_FLAG, // 0x800000 60, hookAddress, // Must have a valid hook for dynamic fees sqrtPriceX96, liquidity, tick ) ``` #### Hook Integration Pools can have hooks that execute custom logic at various points: ```typescript // Pool with a custom hook const poolWithHook = new Pool( ETH, USDC, 3000, 60, '0x1234...', // Hook contract address sqrtPriceX96, liquidity, tick ) // Note: Pools with swap-affecting hooks cannot use getOutputAmount/getInputAmount // as the hook may modify swap behavior in ways the SDK cannot predict ``` ## PositionManager The `V4PositionManager` class provides methods to encode calldata for the V4 PositionManager contract. It handles position minting, liquidity management, and fee collection. ### Import ```typescript import { V4PositionManager } from '@uniswap/v4-sdk-next' ``` ### Overview The V4PositionManager is an abstract class with static methods for encoding transactions. It does not require instantiation. ### Types #### CommonOptions Options shared by all position operations. ```typescript interface CommonOptions { /** How much the pool price is allowed to move */ slippageTolerance: Percent /** Optional data to pass to hooks */ hookData?: string /** When the transaction expires, in epoch seconds */ deadline: BigintIsh } ``` #### MintOptions Options for minting a new position. ```typescript interface MintOptions extends CommonOptions, CommonAddLiquidityOptions { /** The account that should receive the minted NFT */ recipient: string /** Creates pool if not initialized before mint */ createPool?: boolean /** Initial price to set on the pool if creating */ sqrtPriceX96?: BigintIsh /** Whether the mint is part of a migration from V3 to V4 */ migrate?: boolean } ``` #### IncreaseLiquidityOptions Options for increasing liquidity on an existing position. ```typescript interface IncreaseLiquidityOptions extends CommonOptions, CommonAddLiquidityOptions { /** The ID of the position to modify */ tokenId: BigintIsh } ``` #### RemoveLiquidityOptions Options for removing liquidity from a position. ```typescript interface RemoveLiquidityOptions extends CommonOptions { /** The ID of the position to modify */ tokenId: BigintIsh /** The percentage of position liquidity to exit */ liquidityPercentage: Percent /** Whether the NFT should be burned if exiting entirely */ burnToken?: boolean /** Optional permit for the token ID being exited */ permit?: NFTPermitOptions } ``` #### CollectOptions Options for collecting fees from a position. ```typescript interface CollectOptions extends CommonOptions { /** The ID of the position to collect for */ tokenId: BigintIsh /** The account that should receive the tokens */ recipient: string } ``` #### CommonAddLiquidityOptions Options for operations that add liquidity. ```typescript interface CommonAddLiquidityOptions { /** Whether to spend ether. If true, one currency must be native */ useNative?: NativeCurrency /** Optional permit2 batch permit for spending tokens */ batchPermit?: BatchPermitOptions } ``` #### BatchPermitOptions Options for Permit2 batch permits. ```typescript interface BatchPermitOptions { owner: string permitBatch: AllowanceTransferPermitBatch signature: string } ``` #### NFTPermitOptions Options for ERC721 position NFT permits. ```typescript interface NFTPermitOptions { spender: string tokenId: BigintIsh deadline: BigintIsh nonce: BigintIsh signature: string } ``` ### Static Methods #### `createCallParameters(poolKey, sqrtPriceX96)` ```typescript static createCallParameters(poolKey: PoolKey, sqrtPriceX96: BigintIsh): MethodParameters ``` Produces calldata to initialize a new pool. ```typescript import { V4PositionManager, Pool, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' const poolKey = Pool.getPoolKey(ETH, USDC, 3000, 60, ADDRESS_ZERO) const sqrtPriceX96 = '79228162514264337593543950336' // 1:1 price const { calldata, value } = V4PositionManager.createCallParameters(poolKey, sqrtPriceX96) ``` #### `addCallParameters(position, options)` ```typescript static addCallParameters(position: Position, options: AddLiquidityOptions): MethodParameters ``` Produces calldata for minting a new position or increasing liquidity on an existing position. ##### Minting a New Position ```typescript import { V4PositionManager, Pool, Position, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Percent, Ether, Token } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96, liquidity, tick) const position = new Position({ pool, liquidity: '1000000000000000000', tickLower: -887220, tickUpper: 887220 }) const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), // 0.5% deadline: Math.floor(Date.now() / 1000) + 3600, recipient: '0xYourAddress', useNative: ETH // Use native ETH instead of WETH }) ``` ##### Minting with Pool Creation ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, recipient: '0xYourAddress', createPool: true, sqrtPriceX96: '79228162514264337593543950336' }) ``` ##### Increasing Liquidity ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, tokenId: 12345n // Existing position token ID }) ``` ##### With Permit2 ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, recipient: '0xYourAddress', batchPermit: { owner: '0xYourAddress', permitBatch: { details: [ { token: USDC.address, amount: amount0, expiration: deadline, nonce: 0n }, { token: WETH.address, amount: amount1, expiration: deadline, nonce: 1n } ], spender: POSITION_MANAGER_ADDRESS, sigDeadline: deadline }, signature: '0x...' // Signed permit } }) ``` #### `removeCallParameters(position, options)` ```typescript static removeCallParameters(position: Position, options: RemoveLiquidityOptions): MethodParameters ``` Produces calldata for removing liquidity from a position. ##### Partial Removal ```typescript const { calldata, value } = V4PositionManager.removeCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, tokenId: 12345n, liquidityPercentage: new Percent(50, 100) // Remove 50% }) ``` ##### Full Removal with Burn ```typescript const { calldata, value } = V4PositionManager.removeCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, tokenId: 12345n, liquidityPercentage: new Percent(100, 100), // Remove 100% burnToken: true // Burn the NFT }) ``` ##### With NFT Permit ```typescript const { calldata, value } = V4PositionManager.removeCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, tokenId: 12345n, liquidityPercentage: new Percent(100, 100), burnToken: true, permit: { spender: POSITION_MANAGER_ADDRESS, tokenId: 12345n, deadline: Math.floor(Date.now() / 1000) + 3600, nonce: 0n, signature: '0x...' } }) ``` #### `collectCallParameters(position, options)` ```typescript static collectCallParameters(position: Position, options: CollectOptions): MethodParameters ``` Produces calldata for collecting fees from a position. ```typescript const { calldata, value } = V4PositionManager.collectCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 3600, tokenId: 12345n, recipient: '0xYourAddress' }) ``` #### `encodeModifyLiquidities(unlockData, deadline)` ```typescript static encodeModifyLiquidities(unlockData: string, deadline: BigintIsh): string ``` Encodes a modifyLiquidities call with the given unlock data and deadline. ```typescript const calldata = V4PositionManager.encodeModifyLiquidities( plannerData, Math.floor(Date.now() / 1000) + 3600 ) ``` #### `encodePermitBatch(owner, permitBatch, signature)` ```typescript static encodePermitBatch( owner: string, permitBatch: AllowanceTransferPermitBatch, signature: string ): string ``` Encodes a Permit2 batch permit call. #### `encodeERC721Permit(spender, tokenId, deadline, nonce, signature)` ```typescript static encodeERC721Permit( spender: string, tokenId: BigintIsh, deadline: BigintIsh, nonce: BigintIsh, signature: string ): string ``` Encodes an ERC721 permit call for position NFTs. #### `getPermitData(permit, positionManagerAddress, chainId)` ```typescript static getPermitData( permit: NFTPermitValues, positionManagerAddress: string, chainId: number ): NFTPermitData ``` Prepares the data for signing an EIP-712 NFT permit. ```typescript const permitData = V4PositionManager.getPermitData( { spender: '0xSpenderAddress', tokenId: 12345n, deadline: Math.floor(Date.now() / 1000) + 3600, nonce: 0n }, POSITION_MANAGER_ADDRESS, 1 // Ethereum mainnet ) // Sign with EIP-712 // const signature = await wallet._signTypedData( // permitData.domain, // permitData.types, // permitData.values // ) ``` ### V4-Specific Features #### Native ETH Support V4 PositionManager supports native ETH directly: ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: deadline, recipient: '0xYourAddress', useNative: Ether.onChain(1) // Send ETH with the transaction }) // `value` will contain the hex amount of ETH to send ``` #### Hook Data Pass custom data to hooks during position operations: ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: deadline, recipient: '0xYourAddress', hookData: '0x1234...' // Custom hook data }) ``` #### Migration Support Support for migrating positions from V3 to V4: ```typescript const { calldata, value } = V4PositionManager.addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: deadline, recipient: '0xYourAddress', migrate: true // Special handling for migration }) ``` ## Position The `Position` class represents a liquidity position on a Uniswap V4 pool. It provides methods to calculate token amounts, handle slippage, and generate permit data. ### Import ```typescript import { Position } from '@uniswap/v4-sdk-next' ``` ### Constructor ```typescript new Position({ pool: Pool, liquidity: BigintIsh, tickLower: number, tickUpper: number }) ``` #### Parameters | Name | Type | Description | | ----------- | ----------- | --------------------------------------- | | `pool` | `Pool` | The pool on which the position exists | | `liquidity` | `BigintIsh` | The amount of liquidity in the position | | `tickLower` | `number` | The lower tick boundary of the position | | `tickUpper` | `number` | The upper tick boundary of the position | ### Example ```typescript import { Pool, Position, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Token, Ether, Percent } from '@uniswap/sdk-core-next' // Create pool const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const pool = new Pool( ETH, USDC, 3000, 60, ADDRESS_ZERO, '79228162514264337593543950336', '1000000000000000000', 0 ) // Create a position const position = new Position({ pool, liquidity: '1000000000000000000', tickLower: -887220, tickUpper: 887220 }) // Get token amounts console.log(position.amount0.toSignificant(6)) console.log(position.amount1.toSignificant(6)) // Calculate amounts with slippage const slippage = new Percent(50, 10000) // 0.5% const { amount0, amount1 } = position.mintAmountsWithSlippage(slippage) ``` ### Properties #### `pool` ```typescript readonly pool: Pool ``` The pool on which this position exists. #### `tickLower` ```typescript readonly tickLower: number ``` The lower tick boundary of the position. #### `tickUpper` ```typescript readonly tickUpper: number ``` The upper tick boundary of the position. #### `liquidity` ```typescript readonly liquidity: bigint ``` The amount of liquidity in this position. #### `token0PriceLower` ```typescript get token0PriceLower(): Price ``` The price of token0 at the lower tick boundary. #### `token0PriceUpper` ```typescript get token0PriceUpper(): Price ``` The price of token0 at the upper tick boundary. #### `amount0` ```typescript get amount0(): CurrencyAmount ``` The amount of currency0 that this position's liquidity could be burned for at the current pool price. #### `amount1` ```typescript get amount1(): CurrencyAmount ``` The amount of currency1 that this position's liquidity could be burned for at the current pool price. #### `mintAmounts` ```typescript get mintAmounts(): Readonly<{ amount0: bigint; amount1: bigint }> ``` The minimum amounts that must be sent to mint the amount of liquidity held by the position at the current price. ### Static Methods #### `fromAmounts(params)` ```typescript static fromAmounts({ pool: Pool, tickLower: number, tickUpper: number, amount0: BigintIsh, amount1: BigintIsh, useFullPrecision: boolean }): Position ``` Computes the maximum amount of liquidity received for given amounts of token0 and token1. ```typescript const position = Position.fromAmounts({ pool, tickLower: -887220, tickUpper: 887220, amount0: '1000000000000000000', // 1 ETH amount1: '1000000000', // 1000 USDC useFullPrecision: true }) ``` #### `fromAmount0(params)` ```typescript static fromAmount0({ pool: Pool, tickLower: number, tickUpper: number, amount0: BigintIsh, useFullPrecision: boolean }): Position ``` Computes a position with maximum liquidity for a given amount of token0, assuming unlimited token1. ```typescript const position = Position.fromAmount0({ pool, tickLower: -887220, tickUpper: 887220, amount0: '1000000000000000000', // 1 ETH useFullPrecision: true }) ``` #### `fromAmount1(params)` ```typescript static fromAmount1({ pool: Pool, tickLower: number, tickUpper: number, amount1: BigintIsh }): Position ``` Computes a position with maximum liquidity for a given amount of token1, assuming unlimited token0. Always uses full precision. ```typescript const position = Position.fromAmount1({ pool, tickLower: -887220, tickUpper: 887220, amount1: '1000000000' // 1000 USDC }) ``` ### Methods #### `mintAmountsWithSlippage(slippageTolerance)` ```typescript mintAmountsWithSlippage(slippageTolerance: Percent): Readonly<{ amount0: bigint; amount1: bigint }> ``` Returns the maximum amounts of token0 and token1 that must be sent to safely mint the position with the given slippage tolerance. In V4, minting is protected by maximum amounts (unlike V3 which uses minimum amounts). ```typescript const slippage = new Percent(50, 10000) // 0.5% const { amount0, amount1 } = position.mintAmountsWithSlippage(slippage) ``` #### `burnAmountsWithSlippage(slippageTolerance)` ```typescript burnAmountsWithSlippage(slippageTolerance: Percent): Readonly<{ amount0: bigint; amount1: bigint }> ``` Returns the minimum amounts that should be requested when burning the position's liquidity with the given slippage tolerance. ```typescript const slippage = new Percent(50, 10000) // 0.5% const { amount0, amount1 } = position.burnAmountsWithSlippage(slippage) ``` #### `permitBatchData(slippageTolerance, spender, nonce, deadline)` ```typescript permitBatchData( slippageTolerance: Percent, spender: string, nonce: BigintIsh, deadline: BigintIsh ): AllowanceTransferPermitBatch ``` Returns the `AllowanceTransferPermitBatch` data for adding liquidity using Permit2. ```typescript const permitData = position.permitBatchData( new Percent(50, 10000), // 0.5% slippage '0x...PositionManagerAddress', // Spender (Position Manager) 1n, // Permit2 nonce Math.floor(Date.now() / 1000) + 3600 // Deadline (1 hour from now) ) // permitData can be signed and submitted with the transaction // { // details: [ // { token: '0x...', amount: ..., expiration: ..., nonce: ... }, // { token: '0x...', amount: ..., expiration: ..., nonce: ... } // ], // spender: '0x...', // sigDeadline: ... // } ``` ### Tick Validation The constructor validates that: * `tickLower` is less than `tickUpper` * Both ticks are within the valid range (MIN\_TICK to MAX\_TICK) * Both ticks are divisible by the pool's tick spacing ```typescript // Valid position const position = new Position({ pool, liquidity: '1000000000000000000', tickLower: -60, // Must be divisible by tickSpacing (60) tickUpper: 60 }) // Invalid - will throw const invalid = new Position({ pool, liquidity: '1000000000000000000', tickLower: -50, // Not divisible by 60 tickUpper: 50 }) ``` ### V4-Specific Features #### Native Currency Positions V4 positions can include native ETH directly: ```typescript import { Ether } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, ...) const position = new Position({ pool, liquidity: '1000000000000000000', tickLower: -887220, tickUpper: 887220 }) // amount0 is native ETH (not WETH) console.log(position.pool.currency0.isNative) // true ``` #### Hook-Enabled Pools Positions can exist in pools with hooks: ```typescript const poolWithHook = new Pool( ETH, USDC, 3000, 60, '0x1234...', // Hook address sqrtPriceX96, liquidity, tick ) const position = new Position({ pool: poolWithHook, liquidity: '1000000000000000000', tickLower: -887220, tickUpper: 887220 }) ``` ## Route The `Route` class represents a list of V4 pools through which a swap can occur. It handles the path calculation including native ETH and wrapped token conversions. ### Import ```typescript import { Route } from '@uniswap/v4-sdk-next' ``` ### Constructor ```typescript new Route( pools: Pool[], input: TInput, output: TOutput ) ``` #### Parameters | Name | Type | Description | | -------- | --------- | ----------------------------------------------------------------- | | `pools` | `Pool[]` | An array of Pool objects, ordered by the route the swap will take | | `input` | `TInput` | The input currency | | `output` | `TOutput` | The output currency | ### Example ```typescript import { Pool, Route, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Token, Ether, CurrencyAmount } from '@uniswap/sdk-core-next' // Define currencies const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const DAI = new Token(1, '0x6B175474E89094C44Da98b954EescdeCB5BE3830', 18, 'DAI') // Create pools const ethUsdcPool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96_1, liquidity1, tick1) const usdcDaiPool = new Pool(USDC, DAI, 500, 10, ADDRESS_ZERO, sqrtPriceX96_2, liquidity2, tick2) // Single pool route: ETH -> USDC const directRoute = new Route([ethUsdcPool], ETH, USDC) // Multi-hop route: ETH -> USDC -> DAI const multiHopRoute = new Route([ethUsdcPool, usdcDaiPool], ETH, DAI) // Access route properties console.log(directRoute.midPrice.toSignificant(6)) console.log(multiHopRoute.currencyPath.map(c => c.symbol)) ``` ### Properties #### `pools` ```typescript readonly pools: Pool[] ``` The ordered array of pools through which the swap occurs. #### `input` ```typescript readonly input: TInput ``` The input currency of the route. #### `output` ```typescript readonly output: TOutput ``` The output currency of the route. #### `pathInput` ```typescript readonly pathInput: Currency ``` The equivalent or wrapped/unwrapped input currency that matches the first pool. This handles cases where the input is native ETH but the pool uses a wrapped representation. #### `pathOutput` ```typescript readonly pathOutput: Currency ``` The equivalent or wrapped/unwrapped output currency that matches the last pool. #### `currencyPath` ```typescript readonly currencyPath: Currency[] ``` An array of all currencies in the route, starting with the input and ending with the output. ```typescript const route = new Route([ethUsdcPool, usdcDaiPool], ETH, DAI) console.log(route.currencyPath.map(c => c.symbol)) // ['ETH', 'USDC', 'DAI'] ``` #### `chainId` ```typescript get chainId(): number ``` The chain ID of the route (derived from the first pool). #### `midPrice` ```typescript get midPrice(): Price ``` The mid price of the route, calculated by multiplying the prices of each pool along the path. The price is cached after first calculation. ```typescript const route = new Route([ethUsdcPool], ETH, USDC) console.log(route.midPrice.toSignificant(6)) // e.g., "1800.00" console.log(route.midPrice.invert().toSignificant(6)) // e.g., "0.000556" ``` ### Validation The constructor validates: 1. **Non-empty pools**: At least one pool must be provided 2. **Same chain**: All pools must be on the same chain 3. **Path connectivity**: Each pool must involve the output currency of the previous pool 4. **Input/Output validation**: The input must be in the first pool and output must be in the last pool ```typescript // Valid - pools connect properly const validRoute = new Route([ethUsdcPool, usdcDaiPool], ETH, DAI) // Invalid - pools don't connect (will throw 'PATH' error) const invalidRoute = new Route([ethUsdcPool, wbtcDaiPool], ETH, DAI) // Invalid - different chains (will throw 'CHAIN_IDS' error) const wrongChainRoute = new Route([mainnetPool, arbitrumPool], ETH, USDC) ``` ### V4-Specific Features #### Native ETH Routes V4 routes can include native ETH directly without wrapping: ```typescript import { Ether } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, ...) // Route with native ETH input const route = new Route([pool], ETH, USDC) console.log(route.pathInput.isNative) // true ``` #### ETH-WETH Pool Handling The Route class automatically handles ETH-WETH pools for wrapping/unwrapping: ```typescript const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Pool for ETH <-> WETH (wrap/unwrap) const ethWethPool = new Pool(ETH, WETH, 500, 10, ADDRESS_ZERO, ...) // Route that wraps ETH first, then swaps const route = new Route([ethWethPool, wethUsdcPool], ETH, USDC) ``` #### Hook-Enabled Pools Routes can include pools with hooks: ```typescript const hookPool = new Pool( ETH, USDC, 3000, 60, '0x1234...', // Hook address sqrtPriceX96, liquidity, tick ) const route = new Route([hookPool], ETH, USDC) // Note: The midPrice calculation works, but actual swap amounts // may differ if the hook modifies swap behavior ``` ### Multi-Hop Routing Routes can traverse multiple pools to find indirect swap paths: ```typescript // ETH -> USDC -> WBTC (2 hops) const route = new Route( [ethUsdcPool, usdcWbtcPool], ETH, WBTC ) // Access intermediate currencies route.currencyPath.forEach((currency, i) => { console.log(`Step ${i}: ${currency.symbol}`) }) // Step 0: ETH // Step 1: USDC // Step 2: WBTC ``` ## Trade The `Trade` class represents a trade executed against one or more V4 routes. It calculates execution price, price impact, and slippage-adjusted amounts. ### Import ```typescript import { Trade } from '@uniswap/v4-sdk-next' ``` ### Types #### BestTradeOptions ```typescript interface BestTradeOptions { /** Maximum number of results to return (default: 3) */ maxNumResults?: number /** Maximum number of hops a trade should contain (default: 3) */ maxHops?: number } ``` ### Constructor The constructor is private. Use the static factory methods to create trades. ### Example ```typescript import { Pool, Route, Trade, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Token, Ether, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core-next' // Setup currencies and pool const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96, liquidity, tick, ticks) // Create route const route = new Route([pool], ETH, USDC) // Create exact input trade const inputAmount = CurrencyAmount.fromRawAmount(ETH, '1000000000000000000') // 1 ETH const trade = await Trade.exactIn(route, inputAmount) // Access trade properties console.log(trade.inputAmount.toSignificant(6)) // "1.0" console.log(trade.outputAmount.toSignificant(6)) // e.g., "1800.00" console.log(trade.executionPrice.toSignificant(6)) console.log(trade.priceImpact.toSignificant(2)) // e.g., "0.05%" // Calculate slippage-adjusted amounts const slippage = new Percent(50, 10000) // 0.5% const minOutput = trade.minimumAmountOut(slippage) console.log(minOutput.toSignificant(6)) ``` ### Static Methods #### `exactIn(route, amountIn)` ```typescript static async exactIn( route: Route, amountIn: CurrencyAmount ): Promise> ``` Constructs an exact input trade. ```typescript const inputAmount = CurrencyAmount.fromRawAmount(ETH, '1000000000000000000') const trade = await Trade.exactIn(route, inputAmount) ``` #### `exactOut(route, amountOut)` ```typescript static async exactOut( route: Route, amountOut: CurrencyAmount ): Promise> ``` Constructs an exact output trade. ```typescript const outputAmount = CurrencyAmount.fromRawAmount(USDC, '1000000000') // 1000 USDC const trade = await Trade.exactOut(route, outputAmount) ``` #### `fromRoute(route, amount, tradeType)` ```typescript static async fromRoute( route: Route, amount: CurrencyAmount, tradeType: TTradeType ): Promise> ``` Constructs a trade by simulating swaps through the given route. ```typescript const trade = await Trade.fromRoute(route, amount, TradeType.EXACT_INPUT) ``` #### `fromRoutes(routes, tradeType)` ```typescript static async fromRoutes( routes: { amount: CurrencyAmount; route: Route }[], tradeType: TTradeType ): Promise> ``` Constructs a trade with split routes (multiple paths for the same swap). ```typescript // Split trade across two routes const trade = await Trade.fromRoutes( [ { amount: CurrencyAmount.fromRawAmount(ETH, '500000000000000000'), route: route1 }, { amount: CurrencyAmount.fromRawAmount(ETH, '500000000000000000'), route: route2 } ], TradeType.EXACT_INPUT ) ``` #### `createUncheckedTrade(params)` ```typescript static createUncheckedTrade( params: { route: Route inputAmount: CurrencyAmount outputAmount: CurrencyAmount tradeType: TTradeType } ): Trade ``` Creates a trade without simulating the swap. Useful when you have pre-computed amounts (e.g., from a quoter). ```typescript const trade = Trade.createUncheckedTrade({ route, inputAmount: CurrencyAmount.fromRawAmount(ETH, '1000000000000000000'), outputAmount: CurrencyAmount.fromRawAmount(USDC, '1800000000'), tradeType: TradeType.EXACT_INPUT }) ``` #### `createUncheckedTradeWithMultipleRoutes(params)` ```typescript static createUncheckedTradeWithMultipleRoutes( params: { routes: { route: Route inputAmount: CurrencyAmount outputAmount: CurrencyAmount }[] tradeType: TTradeType } ): Trade ``` Creates a multi-route trade without simulating swaps. #### `bestTradeExactIn(pools, currencyAmountIn, currencyOut, options?)` ```typescript static async bestTradeExactIn( pools: Pool[], currencyAmountIn: CurrencyAmount, currencyOut: TOutput, options?: BestTradeOptions ): Promise[]> ``` Finds the best trades for a given exact input amount. ```typescript const trades = await Trade.bestTradeExactIn( [pool1, pool2, pool3], CurrencyAmount.fromRawAmount(ETH, '1000000000000000000'), USDC, { maxNumResults: 3, maxHops: 3 } ) // trades are sorted by output amount (best first) const bestTrade = trades[0] ``` #### `bestTradeExactOut(pools, currencyIn, currencyAmountOut, options?)` ```typescript static async bestTradeExactOut( pools: Pool[], currencyIn: TInput, currencyAmountOut: CurrencyAmount, options?: BestTradeOptions ): Promise[]> ``` Finds the best trades for a given exact output amount. ```typescript const trades = await Trade.bestTradeExactOut( [pool1, pool2, pool3], ETH, CurrencyAmount.fromRawAmount(USDC, '1000000000'), { maxNumResults: 3, maxHops: 3 } ) ``` ### Properties #### `swaps` ```typescript readonly swaps: { route: Route inputAmount: CurrencyAmount outputAmount: CurrencyAmount }[] ``` The individual swaps that make up this trade. A trade can consist of multiple routes. #### `route` ```typescript get route(): Route ``` Returns the route if the trade has only one swap. Throws if the trade has multiple routes. #### `tradeType` ```typescript readonly tradeType: TTradeType ``` The type of trade (`TradeType.EXACT_INPUT` or `TradeType.EXACT_OUTPUT`). #### `inputAmount` ```typescript get inputAmount(): CurrencyAmount ``` The total input amount for the trade (sum of all swap input amounts). #### `outputAmount` ```typescript get outputAmount(): CurrencyAmount ``` The total output amount for the trade (sum of all swap output amounts). #### `executionPrice` ```typescript get executionPrice(): Price ``` The execution price (output amount / input amount). #### `priceImpact` ```typescript get priceImpact(): Percent ``` The percent difference between the route's mid price and the execution price. ### Methods #### `minimumAmountOut(slippageTolerance, amountOut?)` ```typescript minimumAmountOut( slippageTolerance: Percent, amountOut?: CurrencyAmount ): CurrencyAmount ``` Returns the minimum amount to receive for the given slippage tolerance. For exact output trades, returns the output amount unchanged. ```typescript const slippage = new Percent(50, 10000) // 0.5% const minOutput = trade.minimumAmountOut(slippage) ``` #### `maximumAmountIn(slippageTolerance, amountIn?)` ```typescript maximumAmountIn( slippageTolerance: Percent, amountIn?: CurrencyAmount ): CurrencyAmount ``` Returns the maximum amount to spend for the given slippage tolerance. For exact input trades, returns the input amount unchanged. ```typescript const slippage = new Percent(50, 10000) // 0.5% const maxInput = trade.maximumAmountIn(slippage) ``` #### `worstExecutionPrice(slippageTolerance)` ```typescript worstExecutionPrice(slippageTolerance: Percent): Price ``` Returns the worst execution price after accounting for slippage tolerance. ```typescript const slippage = new Percent(50, 10000) // 0.5% const worstPrice = trade.worstExecutionPrice(slippage) ``` ### Trade Comparator ```typescript function tradeComparator( a: Trade, b: Trade ): number ``` A comparator function for sorting trades. Compares by: 1. Output amount (higher is better) 2. Input amount (lower is better) 3. Number of hops (fewer is better) ### Validation Trades validate that: * All routes have the same input currency * All routes have the same output currency * No pool is used in multiple routes (pools cannot be duplicated) ```typescript // Invalid - same pool used twice (will throw 'POOLS_DUPLICATED') const invalidTrade = await Trade.fromRoutes([ { amount: amount1, route: new Route([pool], ETH, USDC) }, { amount: amount2, route: new Route([pool], ETH, USDC) } // Same pool ], TradeType.EXACT_INPUT) ``` ## V4Planner The `V4Planner` class builds encoded calldata for V4 Router operations. It maintains a list of actions and their encoded parameters for swap execution. ### Import ```typescript import { V4Planner, Actions } from '@uniswap/v4-sdk-next' ``` ### Constructor ```typescript new V4Planner() ``` Creates a new planner instance with an empty action list. ### Actions Enum The `Actions` enum defines all available V4 Router actions: ```typescript enum Actions { // Liquidity actions INCREASE_LIQUIDITY = 0x00, DECREASE_LIQUIDITY = 0x01, MINT_POSITION = 0x02, BURN_POSITION = 0x03, // Swapping SWAP_EXACT_IN_SINGLE = 0x06, SWAP_EXACT_IN = 0x07, SWAP_EXACT_OUT_SINGLE = 0x08, SWAP_EXACT_OUT = 0x09, // Settling (closing deltas on the pool manager) SETTLE = 0x0b, SETTLE_ALL = 0x0c, SETTLE_PAIR = 0x0d, // Taking TAKE = 0x0e, TAKE_ALL = 0x0f, TAKE_PORTION = 0x10, TAKE_PAIR = 0x11, CLOSE_CURRENCY = 0x12, SWEEP = 0x14, // Wrapping/unwrapping native UNWRAP = 0x16, } ``` ### Example ```typescript import { V4Planner, Actions, Trade, Pool, Route, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { CurrencyAmount, Percent, TradeType, Ether, Token } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create a planner const planner = new V4Planner() // Build a trade const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96, liquidity, tick, ticks) const route = new Route([pool], ETH, USDC) const trade = await Trade.exactIn(route, CurrencyAmount.fromRawAmount(ETH, '1000000000000000000')) // Add trade to planner const slippage = new Percent(50, 10000) // 0.5% planner.addTrade(trade, slippage) // Add settlement actions planner.addSettle(ETH, true) // User pays ETH planner.addTake(USDC, '0xRecipient') // Take USDC to recipient // Finalize and get encoded calldata const encodedData = planner.finalize() ``` ### Properties #### `actions` ```typescript actions: string ``` The encoded action bytes. Each action is a single byte. #### `params` ```typescript params: string[] ``` The encoded parameters for each action. ### Methods #### `addAction(type, parameters)` ```typescript addAction(type: Actions, parameters: unknown[]): V4Planner ``` Add a raw action to the planner. | Parameter | Type | Description | | ------------ | ----------- | ----------------------------- | | `type` | `Actions` | The action type | | `parameters` | `unknown[]` | The parameters for the action | Returns the planner for chaining. ```typescript planner.addAction(Actions.SETTLE, [ '0x0000000000000000000000000000000000000000', // currency address 0n, // amount (0 = full delta) true // payerIsUser ]) ``` #### `addTrade(trade, slippageTolerance?)` ```typescript addTrade(trade: Trade, slippageTolerance?: Percent): V4Planner ``` Add a trade to the planner. Automatically encodes the appropriate swap action. | Parameter | Type | Description | | ------------------- | ---------- | -------------------------------- | | `trade` | `Trade` | The trade to add | | `slippageTolerance` | `Percent?` | Required for exact output trades | **Note**: Only accepts trades with a single swap. Split trades must be added individually. ```typescript // Exact input trade planner.addTrade(exactInTrade, slippage) // Exact output trade (slippage required) planner.addTrade(exactOutTrade, slippage) ``` #### `addSettle(currency, payerIsUser, amount?)` ```typescript addSettle(currency: Currency, payerIsUser: boolean, amount?: bigint): V4Planner ``` Add a settle action to close a delta. | Parameter | Type | Description | | ------------- | ---------- | ------------------------------------- | | `currency` | `Currency` | The currency to settle | | `payerIsUser` | `boolean` | Whether the user is the payer | | `amount` | `bigint?` | Specific amount (default: full delta) | ```typescript // User settles the full delta planner.addSettle(ETH, true) // Contract settles a specific amount planner.addSettle(USDC, false, 1000000n) ``` #### `addTake(currency, recipient, amount?)` ```typescript addTake(currency: Currency, recipient: string, amount?: bigint): V4Planner ``` Add a take action to receive tokens. | Parameter | Type | Description | | ----------- | ---------- | ------------------------------------- | | `currency` | `Currency` | The currency to take | | `recipient` | `string` | The recipient address | | `amount` | `bigint?` | Specific amount (default: full delta) | ```typescript // Take full output to recipient planner.addTake(USDC, '0xRecipient') // Take specific amount planner.addTake(USDC, '0xRecipient', 1000000000n) ``` #### `addUnwrap(amount)` ```typescript addUnwrap(amount: bigint): V4Planner ``` Add an unwrap action to convert WETH to ETH. | Parameter | Type | Description | | --------- | -------- | -------------------- | | `amount` | `bigint` | The amount to unwrap | ```typescript planner.addUnwrap(1000000000000000000n) // Unwrap 1 WETH to ETH ``` #### `finalize()` ```typescript finalize(): string ``` Finalize the planner and return the encoded calldata for the router. ```typescript const encodedData = planner.finalize() // Use with router.execute(encodedData, deadline) ``` ### Action Parameters #### Swap Actions ##### SWAP\_EXACT\_IN ```typescript { currencyIn: string, // Input currency address path: PathKey[], // Array of path keys amountIn: string, // Input amount amountOutMinimum: string // Minimum output (slippage protection) } ``` ##### SWAP\_EXACT\_OUT ```typescript { currencyOut: string, // Output currency address path: PathKey[], // Array of path keys amountOut: string, // Desired output amount amountInMaximum: string // Maximum input (slippage protection) } ``` #### Settlement Actions ##### SETTLE ```typescript [ currency: string, // Currency address (0x0 for native) amount: bigint, // Amount (0 for full delta) payerIsUser: boolean // Whether user pays ] ``` ##### SETTLE\_PAIR ```typescript [ currency0: string, // First currency address currency1: string // Second currency address ] ``` #### Take Actions ##### TAKE ```typescript [ currency: string, // Currency address recipient: string, // Recipient address amount: bigint // Amount (0 for full delta) ] ``` ##### TAKE\_PAIR ```typescript [ currency0: string, // First currency address currency1: string, // Second currency address recipient: string // Recipient address ] ``` ### Complete Swap Example ```typescript import { V4Planner, Trade, Route, Pool } from '@uniswap/v4-sdk-next' import { CurrencyAmount, Percent } from '@uniswap/sdk-core-next' async function buildSwapCalldata( pool: Pool, inputAmount: CurrencyAmount, recipient: string, slippage: Percent ) { // Create route and trade const route = new Route([pool], inputAmount.currency, pool.currency1) const trade = await Trade.exactIn(route, inputAmount) // Build planner const planner = new V4Planner() // Add swap planner.addTrade(trade, slippage) // Settle input (user pays) planner.addSettle(inputAmount.currency, true) // Take output to recipient planner.addTake(pool.currency1, recipient) return planner.finalize() } ``` ## V4PositionPlanner The `V4PositionPlanner` class extends `V4Planner` with convenience methods for position management actions. It simplifies creating mint, increase, decrease, burn, settle, and take operations. ### Import ```typescript import { V4PositionPlanner } from '@uniswap/v4-sdk-next' ``` ### Constructor ```typescript new V4PositionPlanner() ``` Creates a new position planner instance. ### Inheritance `V4PositionPlanner` extends `V4Planner`, so all base methods like `addAction`, `addSettle`, `addTake`, `addUnwrap`, and `finalize` are available. ### Example ```typescript import { V4PositionPlanner, Pool, ADDRESS_ZERO } from '@uniswap/v4-sdk-next' import { Ether, Token } from '@uniswap/sdk-core-next' const ETH = Ether.onChain(1) const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const pool = new Pool(ETH, USDC, 3000, 60, ADDRESS_ZERO, sqrtPriceX96, liquidity, tick) // Create position planner const planner = new V4PositionPlanner() // Add mint action planner.addMint( pool, -887220, // tickLower 887220, // tickUpper '1000000000000000000', // liquidity '1000000000000000000', // amount0Max (1 ETH) '2000000000', // amount1Max (2000 USDC) '0xRecipient' // owner ) // Add settlement planner.addSettlePair(pool.currency0, pool.currency1) // Finalize const encodedData = planner.finalize() ``` ### Methods #### `addMint(pool, tickLower, tickUpper, liquidity, amount0Max, amount1Max, owner, hookData?)` ```typescript addMint( pool: Pool, tickLower: number, tickUpper: number, liquidity: BigintIsh, amount0Max: BigintIsh, amount1Max: BigintIsh, owner: string, hookData?: string ): void ``` Add a `MINT_POSITION` action to create a new position. | Parameter | Type | Description | | ------------ | ----------- | ---------------------------------------------- | | `pool` | `Pool` | The pool to mint in | | `tickLower` | `number` | The lower tick boundary | | `tickUpper` | `number` | The upper tick boundary | | `liquidity` | `BigintIsh` | The amount of liquidity to mint | | `amount0Max` | `BigintIsh` | Maximum amount of currency0 to spend | | `amount1Max` | `BigintIsh` | Maximum amount of currency1 to spend | | `owner` | `string` | The owner of the minted position NFT | | `hookData` | `string?` | Optional data to pass to hooks (default: `0x`) | ```typescript planner.addMint( pool, -60, // tickLower 60, // tickUpper liquidity, amount0Max, amount1Max, recipient, '0x1234...' // Optional hook data ) ``` #### `addIncrease(tokenId, liquidity, amount0Max, amount1Max, hookData?)` ```typescript addIncrease( tokenId: BigintIsh, liquidity: BigintIsh, amount0Max: BigintIsh, amount1Max: BigintIsh, hookData?: string ): void ``` Add an `INCREASE_LIQUIDITY` action to add liquidity to an existing position. | Parameter | Type | Description | | ------------ | ----------- | ---------------------------------------------- | | `tokenId` | `BigintIsh` | The position NFT token ID | | `liquidity` | `BigintIsh` | The amount of liquidity to add | | `amount0Max` | `BigintIsh` | Maximum amount of currency0 to spend | | `amount1Max` | `BigintIsh` | Maximum amount of currency1 to spend | | `hookData` | `string?` | Optional data to pass to hooks (default: `0x`) | ```typescript planner.addIncrease( 12345n, // tokenId liquidity, amount0Max, amount1Max ) ``` #### `addDecrease(tokenId, liquidity, amount0Min, amount1Min, hookData?)` ```typescript addDecrease( tokenId: BigintIsh, liquidity: BigintIsh, amount0Min: BigintIsh, amount1Min: BigintIsh, hookData?: string ): void ``` Add a `DECREASE_LIQUIDITY` action to remove liquidity from an existing position. | Parameter | Type | Description | | ------------ | ----------- | ---------------------------------------------- | | `tokenId` | `BigintIsh` | The position NFT token ID | | `liquidity` | `BigintIsh` | The amount of liquidity to remove | | `amount0Min` | `BigintIsh` | Minimum amount of currency0 to receive | | `amount1Min` | `BigintIsh` | Minimum amount of currency1 to receive | | `hookData` | `string?` | Optional data to pass to hooks (default: `0x`) | ```typescript planner.addDecrease( 12345n, // tokenId liquidity, amount0Min, amount1Min ) ``` #### `addBurn(tokenId, amount0Min, amount1Min, hookData?)` ```typescript addBurn( tokenId: BigintIsh, amount0Min: BigintIsh, amount1Min: BigintIsh, hookData?: string ): void ``` Add a `BURN_POSITION` action to burn a position NFT and collect all remaining tokens. | Parameter | Type | Description | | ------------ | ----------- | ---------------------------------------------- | | `tokenId` | `BigintIsh` | The position NFT token ID to burn | | `amount0Min` | `BigintIsh` | Minimum amount of currency0 to receive | | `amount1Min` | `BigintIsh` | Minimum amount of currency1 to receive | | `hookData` | `string?` | Optional data to pass to hooks (default: `0x`) | ```typescript planner.addBurn( 12345n, // tokenId amount0Min, amount1Min ) ``` #### `addSettlePair(currency0, currency1)` ```typescript addSettlePair(currency0: Currency, currency1: Currency): void ``` Add a `SETTLE_PAIR` action to settle both currencies of a pool. | Parameter | Type | Description | | ----------- | ---------- | ------------------- | | `currency0` | `Currency` | The first currency | | `currency1` | `Currency` | The second currency | ```typescript planner.addSettlePair(pool.currency0, pool.currency1) ``` #### `addTakePair(currency0, currency1, recipient)` ```typescript addTakePair(currency0: Currency, currency1: Currency, recipient: string): void ``` Add a `TAKE_PAIR` action to take both currencies to a recipient. | Parameter | Type | Description | | ----------- | ---------- | --------------------- | | `currency0` | `Currency` | The first currency | | `currency1` | `Currency` | The second currency | | `recipient` | `string` | The recipient address | ```typescript planner.addTakePair(pool.currency0, pool.currency1, '0xRecipient') ``` #### `addSweep(currency, to)` ```typescript addSweep(currency: Currency, to: string): void ``` Add a `SWEEP` action to sweep any remaining balance of a currency. | Parameter | Type | Description | | ---------- | ---------- | --------------------- | | `currency` | `Currency` | The currency to sweep | | `to` | `string` | The recipient address | ```typescript planner.addSweep(ETH, '0xRecipient') ``` ### Complete Examples #### Mint Position with Native ETH ```typescript import { V4PositionPlanner, Pool, Position, ADDRESS_ZERO, MSG_SENDER } from '@uniswap/v4-sdk-next' const planner = new V4PositionPlanner() // Add mint planner.addMint( pool, position.tickLower, position.tickUpper, position.liquidity, amount0Max, amount1Max, recipient ) // Settle both currencies (user is payer) planner.addSettlePair(pool.currency0, pool.currency1) // Sweep any leftover ETH back to sender planner.addSweep(pool.currency0, MSG_SENDER) const encodedData = planner.finalize() ``` #### Decrease Liquidity and Collect ```typescript const planner = new V4PositionPlanner() // Decrease liquidity planner.addDecrease( tokenId, liquidityToRemove, amount0Min, amount1Min ) // Take both currencies to recipient planner.addTakePair(pool.currency0, pool.currency1, recipient) const encodedData = planner.finalize() ``` #### Collect Fees Only ```typescript const planner = new V4PositionPlanner() // Decrease by 0 liquidity (just collect fees) planner.addDecrease( tokenId, 0n, // 0 liquidity = just collect fees 0n, // No minimum required 0n ) // Take fees to recipient planner.addTakePair(pool.currency0, pool.currency1, recipient) const encodedData = planner.finalize() ``` #### Full Exit with Burn ```typescript const planner = new V4PositionPlanner() // Burn the position (removes all liquidity and burns NFT) planner.addBurn( tokenId, amount0Min, amount1Min ) // Take all tokens to recipient planner.addTakePair(pool.currency0, pool.currency1, recipient) const encodedData = planner.finalize() ``` #### Migration from V3 ```typescript const planner = new V4PositionPlanner() // Mint new V4 position planner.addMint( pool, tickLower, tickUpper, liquidity, amount0Max, amount1Max, recipient ) // For migration, the V4 position manager is the payer (not the user) planner.addSettle(pool.currency0, false) // false = payer is not user planner.addSettle(pool.currency1, false) // Sweep any remaining tokens back planner.addSweep(pool.currency0, recipient) planner.addSweep(pool.currency1, recipient) const encodedData = planner.finalize() ``` ## computePoolAddress The `computePoolAddress` utility computes the address of a Uniswap V3 pool given the factory, tokens, and fee tier. It uses CREATE2 address derivation. ### Import ```typescript import { computePoolAddress } from '@uniswap/v3-sdk' ``` ### Function Signature ```typescript function computePoolAddress({ factoryAddress?: Address.Address, tokenA: Token, tokenB: Token, fee: FeeAmount, initCodeHashManualOverride?: `0x${string}` }): Address.Address ``` #### Parameters | Parameter | Type | Description | | ---------------------------- | ------------------- | ---------------------------------------------------- | | `factoryAddress` | `Address.Address` | The V3 factory address (defaults to mainnet factory) | | `tokenA` | `Token` | The first token of the pair (order doesn't matter) | | `tokenB` | `Token` | The second token of the pair (order doesn't matter) | | `fee` | `FeeAmount` | The fee tier of the pool | | `initCodeHashManualOverride` | `` `0x${string}` `` | Optional override for the init code hash | #### Returns Returns the computed pool address as `Address.Address`. ### Example ```typescript import { computePoolAddress, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const poolAddress = computePoolAddress({ tokenA: USDC, tokenB: WETH, fee: FeeAmount.MEDIUM }) console.log(poolAddress) // '0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8' ``` ### Token Order Independence The function automatically sorts tokens, so the order of `tokenA` and `tokenB` doesn't matter: ```typescript // These produce the same address const address1 = computePoolAddress({ tokenA: USDC, tokenB: WETH, fee: FeeAmount.MEDIUM }) const address2 = computePoolAddress({ tokenA: WETH, tokenB: USDC, fee: FeeAmount.MEDIUM }) console.log(address1 === address2) // true ``` ### Custom Factory Address For non-mainnet deployments or custom factories: ```typescript const poolAddress = computePoolAddress({ factoryAddress: '0x1F98431c8aD98523631AE4a59f267346ea31F984', tokenA: USDC, tokenB: WETH, fee: FeeAmount.MEDIUM }) ``` ### Chain-Specific Init Code Hash Different chains may have different bytecode for the pool contract. The SDK automatically handles this for known chains like ZKSync: ```typescript import { Token, ChainId } from '@uniswap/sdk-core' // ZKSync tokens const zkSyncToken0 = new Token(ChainId.ZKSYNC, '0x...', 18, 'TOKEN0') const zkSyncToken1 = new Token(ChainId.ZKSYNC, '0x...', 18, 'TOKEN1') // SDK automatically uses the correct init code hash for ZKSync const poolAddress = computePoolAddress({ tokenA: zkSyncToken0, tokenB: zkSyncToken1, fee: FeeAmount.MEDIUM }) ``` For chains not built into the SDK, you can override the init code hash: ```typescript const poolAddress = computePoolAddress({ tokenA: customToken0, tokenB: customToken1, fee: FeeAmount.MEDIUM, initCodeHashManualOverride: '0x...' // Custom init code hash }) ``` ### Using with Pool.getAddress The `Pool` class also provides a static method that calls `computePoolAddress`: ```typescript import { Pool, FeeAmount } from '@uniswap/v3-sdk' const poolAddress = Pool.getAddress(USDC, WETH, FeeAmount.MEDIUM) ``` ### How CREATE2 Works The pool address is deterministically computed using CREATE2: 1. **Salt**: Computed from `keccak256(abi.encodePacked(token0, token1, fee))` 2. **Init Code Hash**: The keccak256 hash of the pool contract bytecode 3. **Factory Address**: The V3 factory that deploys pools ``` address = keccak256(0xff ++ factory ++ salt ++ initCodeHash)[12:] ``` ### Constants #### Default Factory Address ```typescript const FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984' ``` #### Default Init Code Hash ```typescript const POOL_INIT_CODE_HASH = '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54' ``` #### ZKSync Init Code Hash ```typescript const ZKSYNC_POOL_INIT_CODE_HASH = '0x010013f177ea1fcbc4520f9a3ca7cd2d1d77959e05aa66484027cb38e712aeed' ``` ### Use Cases #### Verifying Pool Existence ```typescript import { computePoolAddress, FeeAmount } from '@uniswap/v3-sdk' import { ethers } from 'ethers' const poolAddress = computePoolAddress({ tokenA: USDC, tokenB: WETH, fee: FeeAmount.MEDIUM }) // Check if pool exists by checking code at address const code = await provider.getCode(poolAddress) const poolExists = code !== '0x' ``` #### Finding All Fee Tier Pools ```typescript import { computePoolAddress, FeeAmount } from '@uniswap/v3-sdk' const feeTiers = [ FeeAmount.LOWEST, // 0.01% FeeAmount.LOW, // 0.05% FeeAmount.MEDIUM, // 0.3% FeeAmount.HIGH // 1% ] const poolAddresses = feeTiers.map(fee => computePoolAddress({ tokenA: USDC, tokenB: WETH, fee }) ) ``` ## Constants The V3 SDK exports several constants used throughout the Uniswap V3 protocol. ### Import ```typescript import { FACTORY_ADDRESS, ADDRESS_ZERO, POOL_INIT_CODE_HASH, poolInitCodeHash, FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk' ``` ### Contract Addresses #### FACTORY\_ADDRESS The default V3 factory address (mainnet and most chains). ```typescript const FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984' ``` #### ADDRESS\_ZERO The zero address constant. ```typescript const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000' ``` ### Init Code Hashes #### POOL\_INIT\_CODE\_HASH The default pool init code hash used for CREATE2 address computation. ```typescript const POOL_INIT_CODE_HASH = '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54' ``` #### poolInitCodeHash Function that returns the pool init code hash for a given chain. Most chains use the default hash, but some (like ZKSync) have different bytecode. ```typescript function poolInitCodeHash(chainId?: ChainId): `0x${string}` ``` ##### Example ```typescript import { poolInitCodeHash } from '@uniswap/v3-sdk' import { ChainId } from '@uniswap/sdk-core' // Default init code hash const defaultHash = poolInitCodeHash() console.log(defaultHash) // '0xe34f199b19b2b4f...' // ZKSync-specific init code hash const zkSyncHash = poolInitCodeHash(ChainId.ZKSYNC) console.log(zkSyncHash) // '0x010013f177ea1fc...' ``` ### Fee Amounts #### FeeAmount Enum of the default factory-enabled fee amounts, denominated in hundredths of bips (0.01%). ```typescript enum FeeAmount { LOWEST = 100, // 0.01% LOW_200 = 200, // 0.02% LOW_300 = 300, // 0.03% LOW_400 = 400, // 0.04% LOW = 500, // 0.05% MEDIUM = 3000, // 0.3% HIGH = 10000 // 1% } ``` ##### Fee Tier Details | Fee Tier | Value | Percentage | Typical Use Case | | --------- | ----- | ---------- | ------------------------------- | | `LOWEST` | 100 | 0.01% | Stable-stable pairs (USDC/USDT) | | `LOW_200` | 200 | 0.02% | Low volatility pairs | | `LOW_300` | 300 | 0.03% | Low volatility pairs | | `LOW_400` | 400 | 0.04% | Low volatility pairs | | `LOW` | 500 | 0.05% | Stable pairs, correlated assets | | `MEDIUM` | 3000 | 0.3% | Most pairs (ETH/USDC, etc.) | | `HIGH` | 10000 | 1% | Exotic pairs, high volatility | ##### Example ```typescript import { FeeAmount } from '@uniswap/v3-sdk' // Creating a pool with 0.3% fee const pool = new Pool( token0, token1, FeeAmount.MEDIUM, // 3000 = 0.3% sqrtPriceX96, liquidity, tick ) ``` ### Tick Spacings #### TICK\_SPACINGS Maps fee amounts to their corresponding tick spacings. Lower fee tiers have tighter tick spacing for more granular pricing. ```typescript const TICK_SPACINGS: { [amount in FeeAmount]: number } = { [FeeAmount.LOWEST]: 1, [FeeAmount.LOW_200]: 4, [FeeAmount.LOW_300]: 6, [FeeAmount.LOW_400]: 8, [FeeAmount.LOW]: 10, [FeeAmount.MEDIUM]: 60, [FeeAmount.HIGH]: 200 } ``` ##### Tick Spacing Details | Fee Tier | Tick Spacing | Price Granularity | | -------- | ------------ | ---------------------------------- | | 0.01% | 1 | Every tick (\~0.01% increments) | | 0.02% | 4 | Every 4 ticks (\~0.04% increments) | | 0.03% | 6 | Every 6 ticks (\~0.06% increments) | | 0.04% | 8 | Every 8 ticks (\~0.08% increments) | | 0.05% | 10 | Every 10 ticks (\~0.1% increments) | | 0.3% | 60 | Every 60 ticks (\~0.6% increments) | | 1% | 200 | Every 200 ticks (\~2% increments) | ##### Example ```typescript import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk' const tickSpacing = TICK_SPACINGS[FeeAmount.MEDIUM] console.log(tickSpacing) // 60 // Ensure tick is valid for fee tier function isValidTick(tick: number, feeAmount: FeeAmount): boolean { const spacing = TICK_SPACINGS[feeAmount] return tick % spacing === 0 } // Round tick to nearest valid tick function roundToValidTick(tick: number, feeAmount: FeeAmount): number { const spacing = TICK_SPACINGS[feeAmount] return Math.round(tick / spacing) * spacing } ``` ### Usage Examples #### Computing Pool Address ```typescript import { FACTORY_ADDRESS, POOL_INIT_CODE_HASH, FeeAmount } from '@uniswap/v3-sdk' import { computePoolAddress } from '@uniswap/v3-sdk' const poolAddress = computePoolAddress({ factoryAddress: FACTORY_ADDRESS, tokenA: USDC, tokenB: WETH, fee: FeeAmount.MEDIUM }) ``` #### Finding All Fee Tier Pools ```typescript import { FeeAmount, computePoolAddress } from '@uniswap/v3-sdk' const feeAmounts = Object.values(FeeAmount).filter(v => typeof v === 'number') as FeeAmount[] const poolAddresses = feeAmounts.map(fee => ({ fee, address: computePoolAddress({ tokenA: token0, tokenB: token1, fee }) })) ``` #### Creating Valid Position Ticks ```typescript import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk' function createPositionTicks( currentTick: number, rangePercent: number, feeAmount: FeeAmount ): { tickLower: number; tickUpper: number } { const spacing = TICK_SPACINGS[feeAmount] // Approximate tick range for desired price range const tickRange = Math.floor(Math.log(1 + rangePercent / 100) / Math.log(1.0001)) // Round to valid tick spacing const tickLower = Math.floor((currentTick - tickRange) / spacing) * spacing const tickUpper = Math.ceil((currentTick + tickRange) / spacing) * spacing return { tickLower, tickUpper } } ``` ### Chain-Specific Deployments While `FACTORY_ADDRESS` is the same on most EVM chains, some chains have different deployment addresses. Always verify the correct addresses for your target chain: | Chain | Factory Address | | ---------------- | -------------------------------------------- | | Ethereum Mainnet | `0x1F98431c8aD98523631AE4a59f267346ea31F984` | | Polygon | `0x1F98431c8aD98523631AE4a59f267346ea31F984` | | Arbitrum | `0x1F98431c8aD98523631AE4a59f267346ea31F984` | | Optimism | `0x1F98431c8aD98523631AE4a59f267346ea31F984` | | Base | `0x33128a8fC17869897dcE68Ed026d694621f6FDfD` | | BNB Chain | `0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7` | ## encodeRouteToPath The `encodeRouteToPath` utility converts a swap route into the hex-encoded path format used by the Uniswap V3 router contracts. ### Import ```typescript import { encodeRouteToPath } from '@uniswap/v3-sdk' ``` ### Function Signature ```typescript function encodeRouteToPath( route: Route, exactOutput: boolean ): Hex.Hex ``` #### Parameters | Parameter | Type | Description | | ------------- | ------------------------ | ----------------------------------------------------- | | `route` | `Route` | The swap route to encode | | `exactOutput` | `boolean` | Whether the trade is exact output (reverses the path) | #### Returns Returns the hex-encoded path as `Hex.Hex`. ### Path Format The path is encoded as a packed sequence of tokens and fees: ``` (token, fee, token, fee, ..., token) ``` Each element is: * `token`: 20 bytes (address) * `fee`: 3 bytes (uint24) ### Example ```typescript import { encodeRouteToPath, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const DAI = new Token(1, '0x6B175474E89094C44Da98b954EescdeCB5', 18, 'DAI') // Single-hop route: USDC -> WETH const singleHopRoute = new Route([usdcWethPool], USDC, WETH) const singleHopPath = encodeRouteToPath(singleHopRoute, false) // Multi-hop route: USDC -> WETH -> DAI const multiHopRoute = new Route([usdcWethPool, wethDaiPool], USDC, DAI) const multiHopPath = encodeRouteToPath(multiHopRoute, false) ``` ### Exact Input vs Exact Output #### Exact Input (Forward Path) For exact input swaps, the path is encoded in forward order (input to output): ```typescript // USDC -> WETH -> DAI (exact input) const path = encodeRouteToPath(route, false) // Encodes: USDC -> fee -> WETH -> fee -> DAI ``` #### Exact Output (Reverse Path) For exact output swaps, the path is encoded in reverse order (output to input): ```typescript // USDC -> WETH -> DAI (exact output, path reversed) const path = encodeRouteToPath(route, true) // Encodes: DAI -> fee -> WETH -> fee -> USDC ``` ### Usage with SwapRouter The `encodeRouteToPath` function is used internally by `swapCallParameters`: ```typescript import { swapCallParameters, Trade, Route, FeeAmount } from '@uniswap/v3-sdk' import { TradeType } from '@uniswap/sdk-core' const trade = await Trade.fromRoute( route, inputAmount, TradeType.EXACT_INPUT ) // swapCallParameters internally calls encodeRouteToPath const { calldata, value } = swapCallParameters(trade, { slippageTolerance, recipient, deadline }) ``` ### Usage with Quoter The function is also used when generating quoter call parameters: ```typescript import { quoteCallParameters, Route, FeeAmount } from '@uniswap/v3-sdk' import { TradeType } from '@uniswap/sdk-core' // Multi-hop quote const route = new Route([pool1, pool2], tokenIn, tokenOut) const { calldata } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT ) // Internally uses encodeRouteToPath for multi-hop paths ``` ### Manual Path Construction You can also construct paths manually for advanced use cases: ```typescript import { encodeRouteToPath, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' // Create route with specific pools const route = new Route( [ new Pool(tokenA, tokenB, FeeAmount.LOW, sqrtPrice1, liquidity1, tick1), new Pool(tokenB, tokenC, FeeAmount.MEDIUM, sqrtPrice2, liquidity2, tick2), new Pool(tokenC, tokenD, FeeAmount.HIGH, sqrtPrice3, liquidity3, tick3) ], tokenA, tokenD ) // Encode the path const path = encodeRouteToPath(route, false) // Result: tokenA (20 bytes) + fee500 (3 bytes) + tokenB (20 bytes) + fee3000 (3 bytes) + tokenC (20 bytes) + fee10000 (3 bytes) + tokenD (20 bytes) ``` ### Path Length The encoded path length depends on the number of hops: | Hops | Tokens | Fees | Path Length (bytes) | | ---- | ------ | ---- | ---------------------------------- | | 1 | 2 | 1 | 43 (20 + 3 + 20) | | 2 | 3 | 2 | 66 (20 + 3 + 20 + 3 + 20) | | 3 | 4 | 3 | 89 (20 + 3 + 20 + 3 + 20 + 3 + 20) | Formula: `20 + n * 23` bytes where `n` is the number of hops. ### Decoding Paths To decode a path back to tokens and fees: ```typescript function decodePath(path: string): { tokens: string[]; fees: number[] } { const tokens: string[] = [] const fees: number[] = [] // Remove 0x prefix const pathData = path.slice(2) let offset = 0 while (offset < pathData.length) { // Extract token address (20 bytes = 40 hex chars) tokens.push('0x' + pathData.slice(offset, offset + 40)) offset += 40 if (offset < pathData.length) { // Extract fee (3 bytes = 6 hex chars) fees.push(parseInt(pathData.slice(offset, offset + 6), 16)) offset += 6 } } return { tokens, fees } } ``` ### Error Handling The function will throw if: * The route has no pools * The route's token path is inconsistent with the pools ```typescript try { const path = encodeRouteToPath(route, false) } catch (error) { console.error('Invalid route:', error) } ``` ## encodeSqrtRatioX96 The `encodeSqrtRatioX96` utility converts a price ratio into the Q64.96 sqrt price format used by Uniswap V3 pools. ### Import ```typescript import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk' ``` ### Function Signature ```typescript function encodeSqrtRatioX96(amount1: BigintIsh, amount0: BigintIsh): bigint ``` #### Parameters | Parameter | Type | Description | | --------- | ----------- | ----------------------------------------- | | `amount1` | `BigintIsh` | The numerator amount (amount of token1) | | `amount0` | `BigintIsh` | The denominator amount (amount of token0) | #### Returns Returns the sqrt ratio as a Q64.96 value (`bigint`). ### Formula The function computes: ``` sqrtRatioX96 = sqrt(amount1 / amount0) * 2^96 ``` Or equivalently: ``` sqrtRatioX96 = sqrt(amount1 * 2^192 / amount0) ``` ### Example ```typescript import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk' // For a 1:1 price ratio const sqrtPriceX96 = encodeSqrtRatioX96(1n, 1n) console.log(sqrtPriceX96) // 79228162514264337593543950336n (2^96) // For a 2:1 price ratio (token1/token0 = 2) const sqrtPrice2to1 = encodeSqrtRatioX96(2n, 1n) console.log(sqrtPrice2to1) // ~112045541949572279837463876454n // For a 1:2 price ratio (token1/token0 = 0.5) const sqrtPrice1to2 = encodeSqrtRatioX96(1n, 2n) console.log(sqrtPrice1to2) // ~56022770974786139918731938227n ``` ### Use Cases #### Initializing a Pool When creating a new pool, you need to provide the initial sqrt price: ```typescript import { encodeSqrtRatioX96, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Price: 1 ETH = 2000 USDC // Since USDC is token0 (sorted), we need WETH/USDC ratio // But amounts need to account for decimals: // 1 WETH (18 decimals) = 1e18 // 2000 USDC (6 decimals) = 2000e6 const sqrtPriceX96 = encodeSqrtRatioX96( 1n * 10n ** 18n, // 1 WETH in smallest units 2000n * 10n ** 6n // 2000 USDC in smallest units ) const pool = new Pool( USDC, WETH, FeeAmount.MEDIUM, sqrtPriceX96, 0n, // liquidity 0 // tick (needs to match sqrtPriceX96) ) ``` #### Computing Price from Token Amounts ```typescript import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk' // If you have 1000 USDC and 0.5 ETH in a position const usdcAmount = 1000n * 10n ** 6n // 1000 USDC const wethAmount = 5n * 10n ** 17n // 0.5 WETH // The implied price ratio const sqrtPriceX96 = encodeSqrtRatioX96(wethAmount, usdcAmount) ``` ### Understanding Q64.96 Format Uniswap V3 uses a Q64.96 fixed-point number format for sqrt prices: * 64 bits for the integer part * 96 bits for the fractional part This allows precise representation of prices across a very wide range while maintaining numerical precision. #### Conversion Examples ```typescript import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk' // The value 2^96 represents sqrt(1) = 1 const Q96 = 2n ** 96n console.log(encodeSqrtRatioX96(1n, 1n)) // Approximately Q96 // sqrt(2) * 2^96 console.log(encodeSqrtRatioX96(2n, 1n)) // Approximately 1.414 * Q96 // sqrt(0.5) * 2^96 console.log(encodeSqrtRatioX96(1n, 2n)) // Approximately 0.707 * Q96 ``` ### Related Functions #### Inverse Operation To get the tick from a sqrt price, use `getTickAtSqrtRatio`: ```typescript import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk' import { getTickAtSqrtRatio } from '@uniswap/v3-sdk' const sqrtPriceX96 = encodeSqrtRatioX96(2000n * 10n ** 6n, 1n * 10n ** 18n) const tick = getTickAtSqrtRatio(sqrtPriceX96) ``` #### Price Conversion To convert between ticks and prices, see the [Price Tick Conversions](/v3-sdk/price-tick-conversions) utilities. ### Precision Considerations The function uses the `sqrt` function from `@uniswap/sdk-core`, which computes the integer square root. This means there may be small rounding errors for very precise calculations: ```typescript // The result is an integer, so there's implicit rounding const sqrtPrice = encodeSqrtRatioX96(3n, 2n) // For maximum precision, use larger numbers const sqrtPricePrecise = encodeSqrtRatioX96( 3n * 10n ** 18n, 2n * 10n ** 18n ) ``` ## V3 SDK The V3 SDK (`@uniswap/v3-sdk-next`) provides tools for building on Uniswap V3's concentrated liquidity protocol. It includes entities for pools, positions, and trades, along with comprehensive contract interfaces. ### Features * **Concentrated Liquidity**: Position liquidity in specific price ranges * **Multiple Fee Tiers**: Choose from 0.01%, 0.05%, 0.3%, or 1% fee tiers * **NFT Positions**: Manage positions as unique NFTs * **Full Math Library**: Tick math, sqrt price math, and liquidity calculations ### Installation ```bash npm install @uniswap/v3-sdk-next ``` ```bash pnpm add @uniswap/v3-sdk-next ``` ```bash yarn add @uniswap/v3-sdk-next ``` ### Quick Start ```typescript import { Pool, Position, nearestUsableTick, FeeAmount } from '@uniswap/v3-sdk-next' import { Token, CurrencyAmount } from '@uniswap/sdk-core-next' // Define tokens const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create a pool (data typically fetched from chain) const pool = new Pool( WETH, USDC, FeeAmount.MEDIUM, // 0.3% fee '1234567890123456789', // sqrtPriceX96 '1000000000000000000', // liquidity -58000 // tickCurrent ) // Get the pool price console.log(pool.token0Price.toSignificant(6)) // Create a position in a price range const position = new Position({ pool, liquidity: 1000000n, tickLower: nearestUsableTick(-60000, pool.tickSpacing), tickUpper: nearestUsableTick(-56000, pool.tickSpacing), }) // Get position amounts console.log(position.amount0.toSignificant(6)) console.log(position.amount1.toSignificant(6)) ``` ### How V3 Works Uniswap V3 introduces concentrated liquidity: * **Price Ranges**: LPs provide liquidity within specific price ranges * **Capital Efficiency**: Up to 4000x more capital efficient than V2 * **Tick-based Pricing**: Prices are tracked in discrete "ticks" * **NFT Positions**: Each position is a unique NFT with its own range #### Fee Tiers | Fee | Tick Spacing | Best For | | ----- | ------------ | --------------------- | | 0.01% | 1 | Stable pairs | | 0.05% | 10 | Stable/similar assets | | 0.3% | 60 | Most pairs | | 1% | 200 | Exotic pairs | ### Modules #### Entities * [Pool](/v3-sdk/pool) - V3 pool representation with tick-based pricing * [Position](/v3-sdk/position) - LP position in a specific price range * [Route](/v3-sdk/route) - Sequence of pools for a trade path * [Trade](/v3-sdk/trade) - Represents a swap with slippage handling * [Tick](/v3-sdk/tick) - Tick data structure * [TickDataProvider](/v3-sdk/tick-data-provider) - Interface for tick data access #### Contracts * [SwapRouter](/v3-sdk/swap-router) - Swap execution interface * [NFTPositionManager](/v3-sdk/nft-position-manager) - Position management * [Quoter](/v3-sdk/quoter) - Quote swap amounts * [Staker](/v3-sdk/staker) - Liquidity mining interface * [Multicall](/v3-sdk/multicall) - Batch multiple calls * [Payments](/v3-sdk/payments) - ETH and token payment helpers * [SelfPermit](/v3-sdk/self-permit) - Permit2 integration #### Utilities * [computePoolAddress](/v3-sdk/compute-pool-address) - Calculate pool addresses * [encodeSqrtRatioX96](/v3-sdk/encode-sqrt-ratio-x96) - Encode prices * [tickMath](/v3-sdk/tick-math) - Tick to price conversions * [sqrtPriceMath](/v3-sdk/sqrt-price-math) - Sqrt price calculations * [maxLiquidityForAmounts](/v3-sdk/max-liquidity-for-amounts) - Liquidity calculations * [priceTickConversions](/v3-sdk/price-tick-conversions) - Price/tick helpers * [encodeRouteToPath](/v3-sdk/encode-route-to-path) - Encode routes for contracts #### Reference * [Constants](/v3-sdk/constants) - Fee amounts, factory addresses, and more ## Installation ### Package Manager :::code-group ```bash [npm] npm install @uniswap/v3-sdk-next ``` ```bash [pnpm] pnpm add @uniswap/v3-sdk-next ``` ```bash [yarn] yarn add @uniswap/v3-sdk-next ``` ::: ### Requirements * **Node.js**: 18.x or later * **TypeScript**: 5.0 or later (recommended) ### Peer Dependencies The V3 SDK depends on SDK Core and V2 SDK: ```bash npm install @uniswap/sdk-core-next @uniswap/v2-sdk-next ``` ### Usage ```typescript import { Pool, Position, Route, Trade, SwapRouter, NonfungiblePositionManager, FeeAmount, } from '@uniswap/v3-sdk-next' import { Token, CurrencyAmount, Percent } from '@uniswap/sdk-core-next' ``` ### TypeScript Configuration ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true } } ``` ## maxLiquidityForAmounts The `maxLiquidityForAmounts` utility computes the maximum amount of liquidity that can be minted given token amounts and price bounds. ### Import ```typescript import { maxLiquidityForAmounts } from '@uniswap/v3-sdk' ``` ### Function Signature ```typescript function maxLiquidityForAmounts( sqrtRatioCurrentX96: bigint, sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, amount0: BigintIsh, amount1: BigintIsh, useFullPrecision: boolean ): bigint ``` #### Parameters | Parameter | Type | Description | | --------------------- | ----------- | ----------------------------------------- | | `sqrtRatioCurrentX96` | `bigint` | The current pool sqrt price | | `sqrtRatioAX96` | `bigint` | The sqrt price at the lower tick boundary | | `sqrtRatioBX96` | `bigint` | The sqrt price at the upper tick boundary | | `amount0` | `BigintIsh` | The amount of token0 available | | `amount1` | `BigintIsh` | The amount of token1 available | | `useFullPrecision` | `boolean` | Whether to use full precision calculation | #### Returns Returns the maximum liquidity that can be minted (`bigint`). ### Example ```typescript import { maxLiquidityForAmounts, getSqrtRatioAtTick } from '@uniswap/v3-sdk' const currentSqrtPrice = 79228162514264337593543950336n // price = 1.0 const sqrtPriceLower = getSqrtRatioAtTick(-60) const sqrtPriceUpper = getSqrtRatioAtTick(60) const amount0 = 1000000n // 1 USDC (6 decimals) const amount1 = 1000000000000000000n // 1 WETH (18 decimals) const maxLiquidity = maxLiquidityForAmounts( currentSqrtPrice, sqrtPriceLower, sqrtPriceUpper, amount0, amount1, true // use full precision ) console.log('Max liquidity:', maxLiquidity) ``` ### Precision Modes #### Full Precision (`useFullPrecision: true`) Uses full 256-bit precision for the calculation. This gives the most accurate result but may differ from what the router contract calculates. ```typescript const liquidityPrecise = maxLiquidityForAmounts( currentSqrtPrice, sqrtPriceLower, sqrtPriceUpper, amount0, amount1, true // Full precision ) ``` #### Imprecise Mode (`useFullPrecision: false`) Matches the precision used by the V3 periphery's `LiquidityAmounts` library. Use this when you need to match the router's calculation exactly. ```typescript const liquidityImprecise = maxLiquidityForAmounts( currentSqrtPrice, sqrtPriceLower, sqrtPriceUpper, amount0, amount1, false // Match router precision ) ``` ### Behavior Based on Current Price The function behaves differently depending on where the current price is relative to the position range: #### Price Below Range When `sqrtRatioCurrentX96 <= sqrtRatioAX96`: * All liquidity is in token0 * `amount1` is not used * Returns liquidity based solely on `amount0` ```typescript // Price below range - only token0 matters const liquidity = maxLiquidityForAmounts( getSqrtRatioAtTick(-200), // current price below range getSqrtRatioAtTick(-60), getSqrtRatioAtTick(60), 1000000n, 1000000000000000000n, true ) // Liquidity limited by amount0 only ``` #### Price Within Range When `sqrtRatioAX96 < sqrtRatioCurrentX96 < sqrtRatioBX96`: * Both tokens are needed * Returns the minimum of liquidity from token0 and token1 * This ensures both amounts are sufficient ```typescript // Price in range - both tokens matter const liquidity = maxLiquidityForAmounts( getSqrtRatioAtTick(0), // current price in range getSqrtRatioAtTick(-60), getSqrtRatioAtTick(60), 1000000n, 1000000000000000000n, true ) // Liquidity limited by the smaller contribution ``` #### Price Above Range When `sqrtRatioCurrentX96 >= sqrtRatioBX96`: * All liquidity is in token1 * `amount0` is not used * Returns liquidity based solely on `amount1` ```typescript // Price above range - only token1 matters const liquidity = maxLiquidityForAmounts( getSqrtRatioAtTick(200), // current price above range getSqrtRatioAtTick(-60), getSqrtRatioAtTick(60), 1000000n, 1000000000000000000n, true ) // Liquidity limited by amount1 only ``` ### Usage with Position The `Position.fromAmounts` static method uses this function internally: ```typescript import { Position, Pool, FeeAmount } from '@uniswap/v3-sdk' const position = Position.fromAmounts({ pool, tickLower: -60, tickUpper: 60, amount0: '1000000', amount1: '1000000000000000000', useFullPrecision: true }) // position.liquidity is computed using maxLiquidityForAmounts ``` ### Computing Required Amounts To do the inverse (compute amounts from liquidity), use `getAmount0Delta` and `getAmount1Delta`: ```typescript import { maxLiquidityForAmounts, getAmount0Delta, getAmount1Delta, getSqrtRatioAtTick } from '@uniswap/v3-sdk' // First compute max liquidity const liquidity = maxLiquidityForAmounts( currentSqrtPrice, sqrtPriceLower, sqrtPriceUpper, amount0, amount1, true ) // Then compute the actual amounts needed for that liquidity const actualAmount0 = getAmount0Delta(currentSqrtPrice, sqrtPriceUpper, liquidity, true) const actualAmount1 = getAmount1Delta(sqrtPriceLower, currentSqrtPrice, liquidity, true) ``` ### Important Considerations 1. **Token Sort Order**: The function assumes `sqrtRatioA` and `sqrtRatioB` can be in any order - it sorts them internally. 2. **Rounding**: This function returns the maximum liquidity that can be minted. The actual amounts used may be slightly less than provided due to rounding. 3. **Precision Trade-offs**: Use `useFullPrecision: true` for off-chain calculations, and `useFullPrecision: false` when you need to match on-chain router behavior exactly. ## Multicall The `Multicall` module provides a utility for encoding multiple function calls into a single multicall transaction. This is useful for batching operations like minting positions with permits or combining swaps with other actions. ### Import ```typescript import { encodeMulticall } from '@uniswap/v3-sdk' ``` ### encodeMulticall Encodes multiple function calls into a single multicall calldata. ```typescript function encodeMulticall(calldatasInput: Hex.Hex | Hex.Hex[]): Hex.Hex ``` #### Parameters | Parameter | Type | Description | | ---------------- | ---------------------- | ----------------------------------------------- | | `calldatasInput` | `Hex.Hex \| Hex.Hex[]` | Single calldata or array of calldatas to encode | #### Returns Returns the encoded multicall calldata as `Hex.Hex`. #### Behavior * If a single calldata is passed (not an array), it returns the calldata unchanged * If multiple calldatas are passed, they are encoded into a multicall ### Example: Single Call When you pass a single calldata, it's returned as-is: ```typescript import { encodeMulticall } from '@uniswap/v3-sdk' const singleCalldata = '0x1234...' const result = encodeMulticall(singleCalldata) // result === singleCalldata ``` ### Example: Multiple Calls When you pass multiple calldatas, they're encoded into a multicall: ```typescript import { encodeMulticall } from '@uniswap/v3-sdk' const calldata1 = '0xabc...' const calldata2 = '0xdef...' const calldata3 = '0x123...' const multicallData = encodeMulticall([calldata1, calldata2, calldata3]) // Execute all three calls in one transaction const tx = await contract.multicall(multicallData) ``` ### Usage with Position Manager The multicall is commonly used internally by the SDK when generating position manager calldata: ```typescript import { addCallParameters, Position } from '@uniswap/v3-sdk' import { Percent, Ether } from '@uniswap/sdk-core' // When minting with native ETH, the SDK internally uses multicall to combine: // 1. The mint call // 2. The refundETH call (to return excess ETH) const { calldata, value } = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: BigInt(deadline), recipient: userAddress, useNative: Ether.onChain(1) }) // The calldata is already a multicall combining mint + refundETH ``` ### Usage with SwapRouter The SwapRouter also uses multicall internally: ```typescript import { swapCallParameters, Trade } from '@uniswap/v3-sdk' import { Percent, TradeType } from '@uniswap/sdk-core' // When swapping with permits, fees, or native currency handling, // the SDK combines multiple calls: // 1. selfPermit (if permit provided) // 2. swap call // 3. unwrapWETH9 or sweepToken (if needed) // 4. refundETH (for exact output ETH swaps) const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: userAddress, deadline: BigInt(deadline), inputTokenPermit: permitData, fee: { fee: new Percent(3, 1000), recipient: feeRecipient } }) ``` ### Manual Multicall Usage You can manually construct multicalls for custom operations: ```typescript import { encodeMulticall, encodeSelfPermit, encodeUnwrapWETH9 } from '@uniswap/v3-sdk' import { AbiFunction } from 'ox' // Encode individual calls const permitCalldata = encodeSelfPermit(token, owner, permitOptions) const swapCalldata = AbiFunction.encodeData(swapAbi, swapParams) const unwrapCalldata = encodeUnwrapWETH9({ amountMinimum, recipient }) // Combine into multicall const multicallData = encodeMulticall([ permitCalldata, swapCalldata, unwrapCalldata ]) // Execute const tx = await swapRouter.multicall(multicallData) ``` ### Error Handling When using multicall, if any individual call fails, the entire transaction reverts. The revert reason will typically indicate which call failed: ```typescript try { const tx = await contract.multicall(multicallData) await tx.wait() } catch (error) { // The error message will contain the revert reason // from the specific call that failed console.error('Multicall failed:', error) } ``` ### Gas Considerations * Multicall saves gas on transaction overhead by batching multiple calls * Each individual call within the multicall still consumes its own gas * For read-only calls, consider using `callStatic` to simulate the multicall without sending a transaction ```typescript // Simulate multicall without sending transaction const results = await contract.callStatic.multicall(multicallData) ``` ## NonfungiblePositionManager The `NonfungiblePositionManager` module provides utilities for interacting with the Uniswap V3 NonfungiblePositionManager contract, which manages liquidity positions as NFTs. ### Import ```typescript import { createCallParameters, addCallParameters, collectCallParameters, removeCallParameters, safeTransferFromParameters } from '@uniswap/v3-sdk' ``` ### Functions #### createCallParameters Produces the calldata for creating and initializing a new pool. ```typescript function createCallParameters(pool: Pool): MethodParameters ``` ##### Example ```typescript import { createCallParameters, Pool, FeeAmount } from '@uniswap/v3-sdk' const pool = new Pool( token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, 0n, // No liquidity yet tick ) const { calldata, value } = createCallParameters(pool) ``` #### addCallParameters Produces the calldata for adding liquidity to a position. ```typescript function addCallParameters( position: Position, options: AddLiquidityOptions ): MethodParameters ``` ##### MintOptions (for new positions) | Option | Type | Description | | ------------------- | --------------- | --------------------------------------------------- | | `slippageTolerance` | `Percent` | How much the pool price is allowed to move | | `deadline` | `bigint` | When the transaction expires | | `recipient` | `string` | Account that receives the minted NFT | | `createPool` | `boolean` | Whether to create the pool if not initialized | | `useNative` | `Currency` | Whether to use native ETH (must match a pool token) | | `token0Permit` | `PermitOptions` | Optional permit for token0 | | `token1Permit` | `PermitOptions` | Optional permit for token1 | ##### IncreaseOptions (for existing positions) | Option | Type | Description | | ------------------- | --------------- | ------------------------------------------ | | `slippageTolerance` | `Percent` | How much the pool price is allowed to move | | `deadline` | `bigint` | When the transaction expires | | `tokenId` | `BigintIsh` | The ID of the position to increase | | `useNative` | `Currency` | Whether to use native ETH | | `token0Permit` | `PermitOptions` | Optional permit for token0 | | `token1Permit` | `PermitOptions` | Optional permit for token1 | ##### Example: Minting a New Position ```typescript import { addCallParameters, Position, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Percent } from '@uniswap/sdk-core' const position = Position.fromAmounts({ pool, tickLower: -60, tickUpper: 60, amount0: '1000000', amount1: '1000000000000000000', useFullPrecision: true }) const { calldata, value } = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), // 0.5% deadline: BigInt(Math.floor(Date.now() / 1000) + 1800), recipient: '0x1234567890123456789012345678901234567890' }) ``` ##### Example: Increasing Liquidity ```typescript const { calldata, value } = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: BigInt(Math.floor(Date.now() / 1000) + 1800), tokenId: 12345 // Existing position NFT ID }) ``` ##### Example: Using Native ETH ```typescript import { Ether } from '@uniswap/sdk-core' const { calldata, value } = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: BigInt(deadline), recipient: recipientAddress, useNative: Ether.onChain(1) // Use ETH instead of WETH }) // value will contain the ETH amount to send ``` #### collectCallParameters Produces the calldata for collecting fees from a position. ```typescript function collectCallParameters(options: CollectOptions): MethodParameters ``` ##### CollectOptions | Option | Type | Description | | ----------------------- | -------------------------- | ---------------------------------------- | | `tokenId` | `BigintIsh` | The ID of the token to collect fees from | | `expectedCurrencyOwed0` | `CurrencyAmount` | Expected token0 fees | | `expectedCurrencyOwed1` | `CurrencyAmount` | Expected token1 fees | | `recipient` | `string` | Account that receives the fees | ##### Example ```typescript import { collectCallParameters } from '@uniswap/v3-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' const { calldata, value } = collectCallParameters({ tokenId: 12345, expectedCurrencyOwed0: CurrencyAmount.fromRawAmount(token0, '1000000'), expectedCurrencyOwed1: CurrencyAmount.fromRawAmount(token1, '1000000000000000000'), recipient: '0x1234567890123456789012345678901234567890' }) ``` #### removeCallParameters Produces the calldata for removing liquidity from a position. ```typescript function removeCallParameters( position: Position, options: RemoveLiquidityOptions ): MethodParameters ``` ##### RemoveLiquidityOptions | Option | Type | Description | | --------------------- | ---------------- | ---------------------------------------- | | `tokenId` | `BigintIsh` | The ID of the token to exit | | `liquidityPercentage` | `Percent` | Percentage of position liquidity to exit | | `slippageTolerance` | `Percent` | How much the pool price can move | | `deadline` | `bigint` | When the transaction expires | | `burnToken` | `boolean` | Whether to burn the NFT if fully exiting | | `permit` | `object` | Optional permit for the NFT | | `collectOptions` | `CollectOptions` | Parameters for collecting tokens | ##### Example ```typescript import { removeCallParameters, Position } from '@uniswap/v3-sdk' import { Percent, CurrencyAmount } from '@uniswap/sdk-core' const { calldata, value } = removeCallParameters(position, { tokenId: 12345, liquidityPercentage: new Percent(100, 100), // 100% = full exit slippageTolerance: new Percent(50, 10000), deadline: BigInt(Math.floor(Date.now() / 1000) + 1800), burnToken: true, // Burn NFT after full exit collectOptions: { tokenId: 12345, expectedCurrencyOwed0: CurrencyAmount.fromRawAmount(token0, '1000000'), expectedCurrencyOwed1: CurrencyAmount.fromRawAmount(token1, '1000000000000000000'), recipient: recipientAddress } }) ``` #### safeTransferFromParameters Produces the calldata for transferring a position NFT. ```typescript function safeTransferFromParameters(options: SafeTransferOptions): MethodParameters ``` ##### SafeTransferOptions | Option | Type | Description | | ----------- | ----------- | ------------------------------------ | | `sender` | `string` | The account sending the NFT | | `recipient` | `string` | The account receiving the NFT | | `tokenId` | `BigintIsh` | The ID of the token being sent | | `data` | `Hex.Hex` | Optional data for `onERC721Received` | ##### Example ```typescript import { safeTransferFromParameters } from '@uniswap/v3-sdk' const { calldata, value } = safeTransferFromParameters({ sender: '0xSenderAddress...', recipient: '0xRecipientAddress...', tokenId: 12345 }) ``` ### Complete Workflow Example ```typescript import { Pool, Position, FeeAmount, addCallParameters, collectCallParameters, removeCallParameters } from '@uniswap/v3-sdk' import { Percent, CurrencyAmount } from '@uniswap/sdk-core' // 1. Create a position const pool = new Pool(token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, tick) const position = Position.fromAmounts({ pool, tickLower: -60, tickUpper: 60, amount0: '1000000', amount1: '1000000000000000000', useFullPrecision: true }) // 2. Mint the position const mintParams = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: BigInt(Math.floor(Date.now() / 1000) + 1800), recipient: userAddress }) // 3. Later, collect fees const collectParams = collectCallParameters({ tokenId: positionNftId, expectedCurrencyOwed0: CurrencyAmount.fromRawAmount(token0, fees0), expectedCurrencyOwed1: CurrencyAmount.fromRawAmount(token1, fees1), recipient: userAddress }) // 4. Finally, remove liquidity and burn const removeParams = removeCallParameters(position, { tokenId: positionNftId, liquidityPercentage: new Percent(100, 100), slippageTolerance: new Percent(50, 10000), deadline: BigInt(Math.floor(Date.now() / 1000) + 1800), burnToken: true, collectOptions: { tokenId: positionNftId, expectedCurrencyOwed0: CurrencyAmount.fromRawAmount(token0, 0), expectedCurrencyOwed1: CurrencyAmount.fromRawAmount(token1, 0), recipient: userAddress } }) ``` ## Payments The `Payments` module provides utilities for encoding calldata related to ETH/WETH handling and token sweeping in Uniswap V3 periphery contracts. ### Import ```typescript import { encodeUnwrapWETH9, encodeSweepToken, encodeRefundETH } from '@uniswap/v3-sdk' ``` ### Functions #### encodeUnwrapWETH9 Encodes the calldata to unwrap WETH9 to native ETH. ```typescript function encodeUnwrapWETH9(options: UnwrapWETH9Options): Hex.Hex ``` ##### UnwrapWETH9Options | Option | Type | Description | | --------------- | ------------------------------------- | ------------------------------------- | | `amountMinimum` | `BigintIsh` | The minimum amount of WETH9 to unwrap | | `recipient` | `string` | The recipient of the native ETH | | `feeOptions` | `{ fee: Percent; recipient: string }` | Optional fee to take | ##### Example ```typescript import { encodeUnwrapWETH9 } from '@uniswap/v3-sdk' // Basic unwrap const calldata = encodeUnwrapWETH9({ amountMinimum: '1000000000000000000', // 1 WETH minimum recipient: '0x1234567890123456789012345678901234567890' }) ``` ##### Example with Fee ```typescript import { encodeUnwrapWETH9 } from '@uniswap/v3-sdk' import { Percent } from '@uniswap/sdk-core' const calldata = encodeUnwrapWETH9({ amountMinimum: '1000000000000000000', recipient: userAddress, feeOptions: { fee: new Percent(3, 1000), // 0.3% fee recipient: feeRecipientAddress } }) ``` #### encodeSweepToken Encodes the calldata to sweep ERC20 tokens from the contract to a recipient. ```typescript function encodeSweepToken(options: SweepTokenOptions): Hex.Hex ``` ##### SweepTokenOptions | Option | Type | Description | | --------------- | ------------------------------------- | ------------------------------------ | | `token` | `Token` | The token to sweep | | `amountMinimum` | `BigintIsh` | The minimum amount of token to sweep | | `recipient` | `string` | The recipient of the tokens | | `feeOptions` | `{ fee: Percent; recipient: string }` | Optional fee to take | ##### Example ```typescript import { encodeSweepToken } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const calldata = encodeSweepToken({ token: USDC, amountMinimum: '1000000', // 1 USDC minimum recipient: '0x1234567890123456789012345678901234567890' }) ``` ##### Example with Fee ```typescript import { encodeSweepToken } from '@uniswap/v3-sdk' import { Percent } from '@uniswap/sdk-core' const calldata = encodeSweepToken({ token: USDC, amountMinimum: '1000000', recipient: userAddress, feeOptions: { fee: new Percent(3, 1000), // 0.3% fee recipient: feeRecipientAddress } }) ``` #### encodeRefundETH Encodes the calldata to refund any excess ETH sent to the contract back to the sender. ```typescript function encodeRefundETH(): Hex.Hex ``` ##### Example ```typescript import { encodeRefundETH } from '@uniswap/v3-sdk' const calldata = encodeRefundETH() ``` ### Usage Scenarios #### Swap Output to Native ETH When a swap outputs WETH but the user wants native ETH: ```typescript import { encodeMulticall, encodeUnwrapWETH9 } from '@uniswap/v3-sdk' // After the swap calldata, add unwrap const calldatas = [ swapCalldata, encodeUnwrapWETH9({ amountMinimum: minimumOutputAmount, recipient: userAddress }) ] const multicallData = encodeMulticall(calldatas) ``` #### Refund Excess ETH on Exact Output Swaps When doing an exact output swap with native ETH input, excess ETH should be refunded: ```typescript import { encodeMulticall, encodeRefundETH } from '@uniswap/v3-sdk' // For exact output swaps with ETH input const calldatas = [ exactOutputSwapCalldata, encodeRefundETH() ] const multicallData = encodeMulticall(calldatas) ``` #### Sweep Tokens with Fee When collecting tokens and taking a fee: ```typescript import { encodeSweepToken, encodeMulticall } from '@uniswap/v3-sdk' import { Percent } from '@uniswap/sdk-core' const sweepCalldata = encodeSweepToken({ token: outputToken, amountMinimum: minOutputAmount, recipient: userAddress, feeOptions: { fee: new Percent(30, 10000), // 0.3% recipient: protocolFeeRecipient } }) ``` ### Internal SDK Usage These functions are used internally by the SDK in various places: #### SwapRouter The `swapCallParameters` function uses these utilities when: * Output is native ETH (uses `encodeUnwrapWETH9`) * A fee is being taken on the output (uses `encodeSweepToken`) * Input is native ETH with exact output (uses `encodeRefundETH`) #### NonfungiblePositionManager The `addCallParameters` and `removeCallParameters` functions use these utilities when: * Using native ETH instead of WETH (uses `encodeRefundETH`) * Collecting fees that include ETH (uses `encodeUnwrapWETH9`) * Collecting ERC20 tokens (uses `encodeSweepToken`) ### Contract Functions These functions encode calls to the `IPeripheryPaymentsWithFee` interface: | Function | Contract Method | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------- | | `encodeUnwrapWETH9` | `unwrapWETH9(uint256 amountMinimum, address recipient)` | | `encodeUnwrapWETH9` (with fee) | `unwrapWETH9WithFee(uint256 amountMinimum, address recipient, uint256 feeBips, address feeRecipient)` | | `encodeSweepToken` | `sweepToken(address token, uint256 amountMinimum, address recipient)` | | `encodeSweepToken` (with fee) | `sweepTokenWithFee(address token, uint256 amountMinimum, address recipient, uint256 feeBips, address feeRecipient)` | | `encodeRefundETH` | `refundETH()` | ## Pool The `Pool` class represents a Uniswap V3 pool with its current state, including the tokens, fee tier, current price, and liquidity. ### Import ```typescript import { Pool } from '@uniswap/v3-sdk' ``` ### Constructor Creates a new Pool instance. ```typescript new Pool( tokenA: Token, tokenB: Token, fee: FeeAmount, sqrtRatioX96: BigintIsh, liquidity: BigintIsh, tickCurrent: number, ticks?: TickDataProvider | (Tick | TickConstructorArgs)[] ) ``` #### Parameters | Parameter | Type | Description | | -------------- | ----------------------------------------------------- | ----------------------------------------------------------------- | | `tokenA` | `Token` | One of the tokens in the pool | | `tokenB` | `Token` | The other token in the pool | | `fee` | `FeeAmount` | The fee in hundredths of a bips of the input amount of every swap | | `sqrtRatioX96` | `BigintIsh` | The sqrt of the current ratio of amounts of token1 to token0 | | `liquidity` | `BigintIsh` | The current value of in range liquidity | | `tickCurrent` | `number` | The current tick of the pool | | `ticks` | `TickDataProvider \| (Tick \| TickConstructorArgs)[]` | Optional tick data provider or array of ticks | ### Example ```typescript import { Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const pool = new Pool( USDC, WETH, FeeAmount.MEDIUM, '1234567890123456789012345678', // sqrtRatioX96 '1000000000000000000', // liquidity 100 // tickCurrent ) ``` ### Properties | Property | Type | Description | | ------------------ | ------------------ | ----------------------------------------------- | | `token0` | `Token` | The first token of the pool, sorted by address | | `token1` | `Token` | The second token of the pool, sorted by address | | `fee` | `FeeAmount` | The fee tier of the pool | | `sqrtRatioX96` | `bigint` | The current sqrt price as a Q64.96 value | | `liquidity` | `bigint` | The current in-range liquidity | | `tickCurrent` | `number` | The current tick | | `tickDataProvider` | `TickDataProvider` | The tick data provider for this pool | ### Getters #### token0Price Returns the current mid price of the pool in terms of token0 (the ratio of token1 over token0). ```typescript get token0Price(): Price ``` #### token1Price Returns the current mid price of the pool in terms of token1 (the ratio of token0 over token1). ```typescript get token1Price(): Price ``` #### chainId Returns the chain ID of the tokens in the pool. ```typescript get chainId(): number ``` #### tickSpacing Returns the tick spacing for this pool's fee tier. ```typescript get tickSpacing(): number ``` ### Static Methods #### getAddress Computes the pool address for the given tokens and fee. ```typescript static getAddress( tokenA: Token, tokenB: Token, fee: FeeAmount, initCodeHashManualOverride?: `0x${string}`, factoryAddressOverride?: Address.Address ): Address.Address ``` ##### Parameters | Parameter | Type | Description | | ---------------------------- | ------------------- | ------------------------------------- | | `tokenA` | `Token` | The first token | | `tokenB` | `Token` | The second token | | `fee` | `FeeAmount` | The fee tier | | `initCodeHashManualOverride` | `` `0x${string}` `` | Optional override for init code hash | | `factoryAddressOverride` | `Address.Address` | Optional override for factory address | ##### Example ```typescript const poolAddress = Pool.getAddress(USDC, WETH, FeeAmount.MEDIUM) ``` ### Methods #### involvesToken Returns true if the token is either token0 or token1. ```typescript involvesToken(token: Token): boolean ``` #### priceOf Returns the price of the given token in terms of the other token in the pool. ```typescript priceOf(token: Token): Price ``` #### getOutputAmount Given an input amount of a token, returns the computed output amount and a pool with updated state. ```typescript async getOutputAmount( inputAmount: CurrencyAmount, sqrtPriceLimitX96?: bigint ): Promise<[CurrencyAmount, Pool]> ``` ##### Parameters | Parameter | Type | Description | | ------------------- | ----------------------- | ----------------------------------------------------- | | `inputAmount` | `CurrencyAmount` | The input amount for which to quote the output amount | | `sqrtPriceLimitX96` | `bigint` | Optional Q64.96 sqrt price limit | ##### Example ```typescript const inputAmount = CurrencyAmount.fromRawAmount(USDC, '1000000') const [outputAmount, updatedPool] = await pool.getOutputAmount(inputAmount) ``` #### getInputAmount Given a desired output amount of a token, returns the computed input amount and a pool with updated state. ```typescript async getInputAmount( outputAmount: CurrencyAmount, sqrtPriceLimitX96?: bigint ): Promise<[CurrencyAmount, Pool]> ``` ##### Parameters | Parameter | Type | Description | | ------------------- | ----------------------- | ----------------------------------------------------- | | `outputAmount` | `CurrencyAmount` | The output amount for which to quote the input amount | | `sqrtPriceLimitX96` | `bigint` | Optional Q64.96 sqrt price limit | ##### Example ```typescript const outputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') const [inputAmount, updatedPool] = await pool.getInputAmount(outputAmount) ``` ## Position The `Position` class represents a liquidity position on a Uniswap V3 pool. It contains information about the pool, the tick range, and the liquidity amount. ### Import ```typescript import { Position } from '@uniswap/v3-sdk' ``` ### Constructor Creates a new Position instance. ```typescript new Position({ pool: Pool, liquidity: BigintIsh, tickLower: number, tickUpper: number }) ``` #### Parameters | Parameter | Type | Description | | ----------- | ----------- | ----------------------------------------- | | `pool` | `Pool` | The pool for which to create the position | | `liquidity` | `BigintIsh` | The liquidity of the position | | `tickLower` | `number` | The lower tick of the position | | `tickUpper` | `number` | The upper tick of the position | ### Example ```typescript import { Position, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const pool = new Pool( USDC, WETH, FeeAmount.MEDIUM, '1234567890123456789012345678', '1000000000000000000', 100 ) const position = new Position({ pool, liquidity: '1000000000000000000', tickLower: -60, tickUpper: 60 }) ``` ### Properties | Property | Type | Description | | ----------- | -------- | -------------------------------------- | | `pool` | `Pool` | The pool that this position is on | | `tickLower` | `number` | The lower tick of the position's range | | `tickUpper` | `number` | The upper tick of the position's range | | `liquidity` | `bigint` | The liquidity of this position | ### Getters #### token0PriceLower Returns the sqrt price of token0 at the lower tick boundary. ```typescript get token0PriceLower(): bigint ``` #### token0PriceUpper Returns the sqrt price of token0 at the upper tick boundary. ```typescript get token0PriceUpper(): bigint ``` #### amount0 Returns the amount of token0 that this position's liquidity could be burned for at the current pool price. ```typescript get amount0(): CurrencyAmount ``` #### amount1 Returns the amount of token1 that this position's liquidity could be burned for at the current pool price. ```typescript get amount1(): CurrencyAmount ``` #### mintAmounts Returns the minimum amounts that must be sent in order to mint the amount of liquidity held by the position. These values are rounded up. ```typescript get mintAmounts(): { amount0: bigint; amount1: bigint } ``` ### Static Methods #### fromAmounts Creates a position from the specified amounts of token0 and token1. ```typescript static fromAmounts({ pool: Pool, tickLower: number, tickUpper: number, amount0: BigintIsh, amount1: BigintIsh, useFullPrecision: boolean }): Position ``` ##### Parameters | Parameter | Type | Description | | ------------------ | ----------- | ------------------------------------------------------- | | `pool` | `Pool` | The pool for which to create the position | | `tickLower` | `number` | The lower tick | | `tickUpper` | `number` | The upper tick | | `amount0` | `BigintIsh` | The amount of token0 | | `amount1` | `BigintIsh` | The amount of token1 | | `useFullPrecision` | `boolean` | Whether to use full precision for liquidity calculation | ##### Example ```typescript const position = Position.fromAmounts({ pool, tickLower: -60, tickUpper: 60, amount0: '1000000', amount1: '1000000000000000000', useFullPrecision: true }) ``` #### fromAmount0 Creates a position from the specified amount of token0. ```typescript static fromAmount0({ pool: Pool, tickLower: number, tickUpper: number, amount0: BigintIsh, useFullPrecision: boolean }): Position ``` #### fromAmount1 Creates a position from the specified amount of token1. ```typescript static fromAmount1({ pool: Pool, tickLower: number, tickUpper: number, amount1: BigintIsh, useFullPrecision: boolean }): Position ``` ### Methods #### mintAmountsWithSlippage Returns the minimum amounts that must be sent in order to safely mint the amount of liquidity held by the position with the given slippage tolerance. ```typescript mintAmountsWithSlippage(slippageTolerance: Percent): { amount0: bigint; amount1: bigint } ``` ##### Parameters | Parameter | Type | Description | | ------------------- | --------- | ---------------------- | | `slippageTolerance` | `Percent` | The slippage tolerance | ##### Example ```typescript import { Percent } from '@uniswap/sdk-core' const slippage = new Percent(5, 1000) // 0.5% const { amount0, amount1 } = position.mintAmountsWithSlippage(slippage) ``` #### burnAmountsWithSlippage Returns the minimum amounts that should be requested in order to safely burn the amount of liquidity held by the position with the given slippage tolerance. ```typescript burnAmountsWithSlippage(slippageTolerance: Percent): { amount0: bigint; amount1: bigint } ``` ##### Parameters | Parameter | Type | Description | | ------------------- | --------- | ---------------------- | | `slippageTolerance` | `Percent` | The slippage tolerance | ##### Example ```typescript import { Percent } from '@uniswap/sdk-core' const slippage = new Percent(5, 1000) // 0.5% const { amount0, amount1 } = position.burnAmountsWithSlippage(slippage) ``` ## Price Tick Conversions The price tick conversion utilities provide functions for converting between `Price` objects and ticks in Uniswap V3. ### Import ```typescript import { tickToPrice, priceToClosestTick } from '@uniswap/v3-sdk' ``` ### Functions #### tickToPrice Returns a `Price` object corresponding to the input tick and the base/quote tokens. ```typescript function tickToPrice(baseToken: Token, quoteToken: Token, tick: number): Price ``` ##### Parameters | Parameter | Type | Description | | ------------ | -------- | -------------------------------------- | | `baseToken` | `Token` | The base token of the price | | `quoteToken` | `Token` | The quote token of the price | | `tick` | `number` | The tick for which to return the price | ##### Returns Returns a `Price` object representing the price at the given tick. ##### Example ```typescript import { tickToPrice } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Get price at tick 0 (approximately 1:1) const priceAtTick0 = tickToPrice(USDC, WETH, 0) console.log(priceAtTick0.toSignificant(6)) // "1" // Get price at tick 100 const priceAtTick100 = tickToPrice(USDC, WETH, 100) console.log(priceAtTick100.toSignificant(6)) // "1.01005" // Get price at tick -100 const priceAtTickMinus100 = tickToPrice(USDC, WETH, -100) console.log(priceAtTickMinus100.toSignificant(6)) // "0.990049" ``` #### priceToClosestTick Returns the first tick for which the given price is greater than or equal to the tick price. ```typescript function priceToClosestTick(price: Price): number ``` ##### Parameters | Parameter | Type | Description | | --------- | --------------------- | ---------------------------------------------- | | `price` | `Price` | The price for which to return the closest tick | ##### Returns Returns the closest tick (`number`) to the given price. ##### Example ```typescript import { priceToClosestTick, tickToPrice } from '@uniswap/v3-sdk' import { Price, Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Create a price (1 USDC = 0.0005 WETH, meaning 1 ETH = 2000 USDC) const price = new Price(USDC, WETH, 2000, 1) // quoteAmount / baseAmount const tick = priceToClosestTick(price) console.log(tick) ``` ### Token Order Matters The order of tokens affects the interpretation of the price and tick: ```typescript import { tickToPrice } from '@uniswap/v3-sdk' // USDC as base, WETH as quote: "How much WETH per USDC?" const priceUsdcBase = tickToPrice(USDC, WETH, 100) console.log(`1 USDC = ${priceUsdcBase.toSignificant(6)} WETH`) // WETH as base, USDC as quote: "How much USDC per WETH?" const priceWethBase = tickToPrice(WETH, USDC, 100) console.log(`1 WETH = ${priceWethBase.toSignificant(6)} USDC`) ``` ### Use Cases #### Setting Position Price Range ```typescript import { tickToPrice, priceToClosestTick } from '@uniswap/v3-sdk' import { Price, Token } from '@uniswap/sdk-core' // Define desired price range const lowerPrice = new Price(WETH, USDC, 1, 1800) // 1 ETH = 1800 USDC const upperPrice = new Price(WETH, USDC, 1, 2200) // 1 ETH = 2200 USDC // Convert to ticks const tickLower = priceToClosestTick(lowerPrice) const tickUpper = priceToClosestTick(upperPrice) // Round to valid tick spacing (e.g., 60 for 0.3% fee tier) const tickSpacing = 60 const tickLowerRounded = Math.floor(tickLower / tickSpacing) * tickSpacing const tickUpperRounded = Math.ceil(tickUpper / tickSpacing) * tickSpacing // Get the actual prices for the rounded ticks const actualLowerPrice = tickToPrice(WETH, USDC, tickLowerRounded) const actualUpperPrice = tickToPrice(WETH, USDC, tickUpperRounded) console.log(`Lower: ${actualLowerPrice.toSignificant(6)} USDC/ETH`) console.log(`Upper: ${actualUpperPrice.toSignificant(6)} USDC/ETH`) ``` #### Displaying Current Pool Price ```typescript import { tickToPrice } from '@uniswap/v3-sdk' // Get the current tick from pool state const currentTick = pool.tickCurrent // Convert to human-readable price const currentPrice = tickToPrice(pool.token1, pool.token0, currentTick) console.log(`Current price: ${currentPrice.toSignificant(6)}`) ``` #### Creating a Price from Amounts ```typescript import { priceToClosestTick } from '@uniswap/v3-sdk' import { Price, Token } from '@uniswap/sdk-core' // If 1000 USDC trades for 0.5 WETH const price = new Price( USDC, WETH, 1000n * 10n ** 6n, // 1000 USDC in smallest units 5n * 10n ** 17n // 0.5 WETH in smallest units ) const tick = priceToClosestTick(price) ``` ### Price Formula The relationship between tick and price is: ``` price = 1.0001^tick ``` For the Q64.96 sqrt price format: ``` sqrtPriceX96 = sqrt(1.0001^tick) * 2^96 ``` ### Handling Token Decimals The `Price` class automatically handles decimal differences between tokens: ```typescript import { tickToPrice } from '@uniswap/v3-sdk' const USDC = new Token(1, '0x...', 6, 'USDC') // 6 decimals const WETH = new Token(1, '0x...', 18, 'WETH') // 18 decimals // The price is automatically adjusted for decimals const price = tickToPrice(USDC, WETH, 0) // Display in human-readable format console.log(price.toSignificant(6)) // Decimal-adjusted console.log(price.toFixed(18)) // Full precision ``` ### Precision Considerations Due to the discrete nature of ticks, there may be small rounding errors: ```typescript import { tickToPrice, priceToClosestTick } from '@uniswap/v3-sdk' const originalTick = 12345 const price = tickToPrice(token0, token1, originalTick) const recoveredTick = priceToClosestTick(price) // recoveredTick should equal originalTick, but verify console.log(originalTick === recoveredTick) // true (in most cases) ``` The `priceToClosestTick` function returns the floor tick, so there may be edge cases where the exact tick differs by 1. ## Quoter The `Quoter` module provides utilities for generating calldata to get swap quotes from the Uniswap V3 Quoter contracts without executing the swap. ### Import ```typescript import { quoteCallParameters } from '@uniswap/v3-sdk' ``` ### quoteCallParameters Produces the on-chain method name and parameters for quoting a swap. ```typescript function quoteCallParameters( route: Route, amount: CurrencyAmount, tradeType: TradeType, options?: QuoteOptions ): MethodParameters ``` #### Parameters | Parameter | Type | Description | | ----------- | ------------------------ | -------------------------------------------------------------------------- | | `route` | `Route` | The swap route to quote | | `amount` | `CurrencyAmount` | The amount of the quote (input for EXACT\_INPUT, output for EXACT\_OUTPUT) | | `tradeType` | `TradeType` | The trade type (EXACT\_INPUT or EXACT\_OUTPUT) | | `options` | `QuoteOptions` | Optional quote parameters | #### QuoteOptions | Option | Type | Description | | ------------------- | ----------- | -------------------------------------------------- | | `sqrtPriceLimitX96` | `BigintIsh` | Optional price limit for single-hop quotes | | `useQuoterV2` | `boolean` | Whether to use QuoterV2 interface (default: false) | #### Returns Returns a `MethodParameters` object: ```typescript interface MethodParameters { calldata: Hex.Hex value: Hex.Hex } ``` ### Example: Single-Hop Quote ```typescript import { quoteCallParameters, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { CurrencyAmount, TradeType } from '@uniswap/sdk-core' const route = new Route([pool], USDC, WETH) const amountIn = CurrencyAmount.fromRawAmount(USDC, '1000000') const { calldata, value } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT ) // Use with ethers or viem to call the Quoter contract const quoterContract = new Contract(QUOTER_ADDRESS, QUOTER_ABI, provider) const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle( // ... decoded params from calldata ) ``` ### Example: Multi-Hop Quote ```typescript // USDC -> WETH -> DAI route const route = new Route([usdcWethPool, wethDaiPool], USDC, DAI) const amountIn = CurrencyAmount.fromRawAmount(USDC, '1000000') const { calldata, value } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT ) ``` ### Example: Exact Output Quote ```typescript const route = new Route([pool], USDC, WETH) const amountOut = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const { calldata, value } = quoteCallParameters( route, amountOut, TradeType.EXACT_OUTPUT ) ``` ### Using QuoterV2 QuoterV2 provides additional information like gas estimates and price after swap: ```typescript const { calldata, value } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT, { useQuoterV2: true } ) ``` #### QuoterV2 Response When using QuoterV2, the response includes: * `amountOut` (or `amountIn` for exact output) * `sqrtPriceX96After` - The pool price after the swap * `initializedTicksCrossed` - Number of initialized ticks crossed * `gasEstimate` - Estimated gas for the swap ### Price Limits For single-hop swaps, you can set a price limit: ```typescript const { calldata, value } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT, { sqrtPriceLimitX96: 1234567890123456789012345678n } ) ``` Note: Price limits are not supported for multi-hop swaps. ### Quoter Contract Addresses #### QuoterV1 * Mainnet: `0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6` #### QuoterV2 * Mainnet: `0x61fFE014bA17989E743c5F6cB21bF9697530B21e` ### Complete Usage Example ```typescript import { quoteCallParameters, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core' import { Contract, providers } from 'ethers' const provider = new providers.JsonRpcProvider(RPC_URL) // Define tokens const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Fetch pool data (you would get this from on-chain) const pool = new Pool( USDC, WETH, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, tick ) // Create route const route = new Route([pool], USDC, WETH) // Get quote parameters const amountIn = CurrencyAmount.fromRawAmount(USDC, '1000000000') // 1000 USDC const { calldata } = quoteCallParameters( route, amountIn, TradeType.EXACT_INPUT, { useQuoterV2: true } ) // Call the quoter (using ethers) const QUOTER_V2_ADDRESS = '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' const result = await provider.call({ to: QUOTER_V2_ADDRESS, data: calldata }) // Decode the result to get quoted output amount console.log('Quoted output:', result) ``` ### Error Handling The quoter may revert if: * The pool doesn't have enough liquidity * The price limit is reached before the full amount is swapped * The route is invalid Always wrap quoter calls in try-catch: ```typescript try { const result = await provider.call({ to: QUOTER_ADDRESS, data: calldata }) // Process result } catch (error) { console.error('Quote failed:', error) // Handle insufficient liquidity or other errors } ``` ## Route The `Route` class represents a route through one or more Uniswap V3 pools for a swap. ### Import ```typescript import { Route } from '@uniswap/v3-sdk' ``` ### Constructor Creates a new Route instance. ```typescript new Route( pools: Pool[], input: TInput, output: TOutput ) ``` #### Parameters | Parameter | Type | Description | | --------- | --------- | --------------------------------------- | | `pools` | `Pool[]` | An array of interconnected Pool objects | | `input` | `TInput` | The input currency | | `output` | `TOutput` | The output currency | ### Example ```typescript import { Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token, Ether } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const DAI = new Token(1, '0x6B175474E89094C44Da98b954EescdeCB5', 18, 'DAI') // Single pool route const pool1 = new Pool(USDC, WETH, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, tick) const singleRoute = new Route([pool1], USDC, WETH) // Multi-pool route (USDC -> WETH -> DAI) const pool2 = new Pool(WETH, DAI, FeeAmount.MEDIUM, sqrtRatioX96_2, liquidity_2, tick_2) const multiRoute = new Route([pool1, pool2], USDC, DAI) ``` ### Properties | Property | Type | Description | | ----------- | --------- | ---------------------------------------------- | | `pools` | `Pool[]` | The pools that make up this route | | `tokenPath` | `Token[]` | The tokens in the route path (input to output) | | `input` | `TInput` | The input currency for this route | | `output` | `TOutput` | The output currency for this route | ### Getters #### chainId Returns the chain ID of the route. ```typescript get chainId(): number ``` #### midPrice Returns the mid price of the route. This is calculated by multiplying the prices of each pool in the route. ```typescript get midPrice(): Price ``` ##### Example ```typescript const route = new Route([pool1, pool2], USDC, DAI) const price = route.midPrice console.log(`1 USDC = ${price.toSignificant(6)} DAI`) ``` ### Usage Notes #### Route Validation When constructing a route, the SDK validates: 1. The pools array is not empty 2. All pools are on the same chain 3. The input currency is involved in the first pool 4. The output currency is involved in the last pool 5. Each pool in the sequence is connected (output of one pool is input of the next) #### Multi-hop Routes Routes can contain multiple pools to enable swaps between tokens that don't have a direct pool: ```typescript // USDC -> WETH -> DAI route const route = new Route( [usdcWethPool, wethDaiPool], USDC, DAI ) ``` #### Native Currency Support Routes can start or end with native currency (ETH). The SDK will automatically handle wrapping/unwrapping: ```typescript import { Ether } from '@uniswap/sdk-core' const ETHER = Ether.onChain(1) // ETH -> USDC route const route = new Route([wethUsdcPool], ETHER, USDC) ``` ## SelfPermit The `SelfPermit` module provides utilities for encoding EIP-2612 permit calls, allowing users to approve token spending in the same transaction as the action that requires the approval. ### Import ```typescript import { encodeSelfPermit, encodeSelfPermitIfNecessary } from '@uniswap/v3-sdk' ``` ### Types #### StandardPermitArguments Standard EIP-2612 permit arguments. ```typescript interface StandardPermitArguments { v: 0 | 1 | 27 | 28 // Signature recovery id r: `0x${string}` // Signature r value s: `0x${string}` // Signature s value amount: BigintIsh // Amount to approve deadline: BigintIsh // Permit deadline } ``` #### AllowedPermitArguments DAI-style permit arguments (uses nonce and expiry instead of amount and deadline). ```typescript interface AllowedPermitArguments { v: 0 | 1 | 27 | 28 // Signature recovery id r: `0x${string}` // Signature r value s: `0x${string}` // Signature s value nonce: BigintIsh // Permit nonce expiry: BigintIsh // Permit expiry } ``` #### PermitOptions Union type of both permit styles. ```typescript type PermitOptions = StandardPermitArguments | AllowedPermitArguments ``` ### Functions #### encodeSelfPermit Encodes the calldata to self-permit a token. ```typescript function encodeSelfPermit( token: Token, _owner: string, permitOptions: PermitOptions ): Hex.Hex ``` ##### Parameters | Parameter | Type | Description | | --------------- | --------------- | ------------------------------------------ | | `token` | `Token` | The token to permit | | `_owner` | `string` | Owner address (kept for API compatibility) | | `permitOptions` | `PermitOptions` | The permit signature and parameters | ##### Example with Standard Permit ```typescript import { encodeSelfPermit } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Standard EIP-2612 permit const permitOptions = { v: 28, r: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', s: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890', amount: '1000000', // 1 USDC deadline: BigInt(Math.floor(Date.now() / 1000) + 3600) } const calldata = encodeSelfPermit(USDC, ownerAddress, permitOptions) ``` ##### Example with DAI-style Permit ```typescript import { encodeSelfPermit } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const DAI = new Token(1, '0x6B175474E89094C44Da98b954EescdeCB5', 18, 'DAI') // DAI-style permit (allowed) const permitOptions = { v: 28, r: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', s: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890', nonce: 0n, expiry: BigInt(Math.floor(Date.now() / 1000) + 3600) } const calldata = encodeSelfPermit(DAI, ownerAddress, permitOptions) ``` #### encodeSelfPermitIfNecessary Encodes the calldata to self-permit a token only if the current allowance is insufficient. ```typescript function encodeSelfPermitIfNecessary( token: Token, _owner: string, permitOptions: PermitOptions ): Hex.Hex ``` This variant will only execute the permit if the current allowance is less than the required amount. ##### Example ```typescript import { encodeSelfPermitIfNecessary } from '@uniswap/v3-sdk' const calldata = encodeSelfPermitIfNecessary(token, ownerAddress, permitOptions) ``` ### Usage with SwapRouter The most common use case is combining permits with swaps: ```typescript import { swapCallParameters, Trade, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { CurrencyAmount, Percent, TradeType, Token } from '@uniswap/sdk-core' // Create a trade const trade = await Trade.fromRoute( route, CurrencyAmount.fromRawAmount(inputToken, '1000000'), TradeType.EXACT_INPUT ) // Generate permit signature (using ethers or viem) const permitData = await signPermit(inputToken, spenderAddress, amount, deadline) // Generate swap calldata with permit const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: userAddress, deadline: BigInt(deadline), inputTokenPermit: { v: permitData.v, r: permitData.r, s: permitData.s, amount: amount, deadline: BigInt(deadline) } }) ``` ### Usage with NonfungiblePositionManager Permits can also be used when adding liquidity: ```typescript import { addCallParameters, Position } from '@uniswap/v3-sdk' import { Percent } from '@uniswap/sdk-core' const { calldata, value } = addCallParameters(position, { slippageTolerance: new Percent(50, 10000), deadline: BigInt(deadline), recipient: userAddress, token0Permit: { v: permitData0.v, r: permitData0.r, s: permitData0.s, amount: amount0, deadline: BigInt(deadline) }, token1Permit: { v: permitData1.v, r: permitData1.r, s: permitData1.s, amount: amount1, deadline: BigInt(deadline) } }) ``` ### Generating Permit Signatures #### Using ethers.js ```typescript import { ethers } from 'ethers' async function signPermit( token: Token, spender: string, value: bigint, deadline: bigint, signer: ethers.Signer ) { const ownerAddress = await signer.getAddress() const nonce = await tokenContract.nonces(ownerAddress) const domain = { name: await tokenContract.name(), version: '1', chainId: token.chainId, verifyingContract: token.address } const types = { Permit: [ { name: 'owner', type: 'address' }, { name: 'spender', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'nonce', type: 'uint256' }, { name: 'deadline', type: 'uint256' } ] } const message = { owner: ownerAddress, spender, value, nonce, deadline } const signature = await signer._signTypedData(domain, types, message) const { v, r, s } = ethers.utils.splitSignature(signature) return { v, r, s, amount: value, deadline } } ``` ### Contract Functions These functions encode calls to the `ISelfPermit` interface: | Function | Contract Method | | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `encodeSelfPermit` (standard) | `selfPermit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)` | | `encodeSelfPermit` (allowed) | `selfPermitAllowed(address token, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)` | | `encodeSelfPermitIfNecessary` (standard) | `selfPermitIfNecessary(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)` | | `encodeSelfPermitIfNecessary` (allowed) | `selfPermitAllowedIfNecessary(address token, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)` | ### Token Support Not all tokens support EIP-2612 permits. Notable tokens that do: * USDC (standard permit) * DAI (allowed permit style) * UNI (standard permit) Check if a token supports permit by calling `nonces(address)` on the token contract. If it reverts, the token doesn't support permits. ## Sqrt Price Math The sqrt price math utilities provide functions for computing token amounts and price changes in Uniswap V3 pools. ### Import ```typescript import { getNextSqrtPriceFromInput, getNextSqrtPriceFromOutput, getAmount0Delta, getAmount1Delta } from '@uniswap/v3-sdk' ``` ### Functions #### getNextSqrtPriceFromInput Gets the next sqrt price given an input amount of token0 or token1. ```typescript function getNextSqrtPriceFromInput( sqrtPX96: bigint, liquidity: bigint, amountIn: bigint, zeroForOne: boolean ): bigint ``` ##### Parameters | Parameter | Type | Description | | ------------ | --------- | -------------------------------------------------------- | | `sqrtPX96` | `bigint` | The starting sqrt price | | `liquidity` | `bigint` | The amount of usable liquidity | | `amountIn` | `bigint` | How much of token0 or token1 is being swapped in | | `zeroForOne` | `boolean` | Whether the amount in is token0 (true) or token1 (false) | ##### Returns The next sqrt price after swapping the given amount in. ##### Example ```typescript import { getNextSqrtPriceFromInput } from '@uniswap/v3-sdk' const currentSqrtPrice = 79228162514264337593543950336n // ~1.0 const liquidity = 1000000000000000000n const amountIn = 1000000n // Swapping token0 for token1 (price decreases) const nextPrice0For1 = getNextSqrtPriceFromInput( currentSqrtPrice, liquidity, amountIn, true // zeroForOne ) // Swapping token1 for token0 (price increases) const nextPrice1For0 = getNextSqrtPriceFromInput( currentSqrtPrice, liquidity, amountIn, false // oneForZero ) ``` #### getNextSqrtPriceFromOutput Gets the next sqrt price given an output amount of token0 or token1. ```typescript function getNextSqrtPriceFromOutput( sqrtPX96: bigint, liquidity: bigint, amountOut: bigint, zeroForOne: boolean ): bigint ``` ##### Parameters | Parameter | Type | Description | | ------------ | --------- | ----------------------------------------------------- | | `sqrtPX96` | `bigint` | The starting sqrt price | | `liquidity` | `bigint` | The amount of usable liquidity | | `amountOut` | `bigint` | How much of token0 or token1 is being swapped out | | `zeroForOne` | `boolean` | Whether the output is token1 (true) or token0 (false) | ##### Example ```typescript import { getNextSqrtPriceFromOutput } from '@uniswap/v3-sdk' const currentSqrtPrice = 79228162514264337593543950336n const liquidity = 1000000000000000000n const amountOut = 1000000n // Getting token1 out (zeroForOne swap) const nextPrice = getNextSqrtPriceFromOutput( currentSqrtPrice, liquidity, amountOut, true ) ``` #### getAmount0Delta Gets the amount of token0 delta between two sqrt prices. ```typescript function getAmount0Delta( sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, liquidity: bigint, roundUp: boolean ): bigint ``` ##### Parameters | Parameter | Type | Description | | --------------- | --------- | ------------------------------ | | `sqrtRatioAX96` | `bigint` | A sqrt ratio | | `sqrtRatioBX96` | `bigint` | Another sqrt ratio | | `liquidity` | `bigint` | The liquidity amount | | `roundUp` | `boolean` | Whether to round the result up | ##### Formula ``` amount0 = liquidity * (sqrtRatioB - sqrtRatioA) / (sqrtRatioA * sqrtRatioB) ``` ##### Example ```typescript import { getAmount0Delta, getSqrtRatioAtTick } from '@uniswap/v3-sdk' const sqrtPriceLower = getSqrtRatioAtTick(-60) const sqrtPriceUpper = getSqrtRatioAtTick(60) const liquidity = 1000000000000000000n // Amount of token0 in the position (rounded down for burns) const amount0 = getAmount0Delta(sqrtPriceLower, sqrtPriceUpper, liquidity, false) // Amount of token0 needed to mint (rounded up) const amount0Mint = getAmount0Delta(sqrtPriceLower, sqrtPriceUpper, liquidity, true) ``` #### getAmount1Delta Gets the amount of token1 delta between two sqrt prices. ```typescript function getAmount1Delta( sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, liquidity: bigint, roundUp: boolean ): bigint ``` ##### Parameters | Parameter | Type | Description | | --------------- | --------- | ------------------------------ | | `sqrtRatioAX96` | `bigint` | A sqrt ratio | | `sqrtRatioBX96` | `bigint` | Another sqrt ratio | | `liquidity` | `bigint` | The liquidity amount | | `roundUp` | `boolean` | Whether to round the result up | ##### Formula ``` amount1 = liquidity * (sqrtRatioB - sqrtRatioA) ``` ##### Example ```typescript import { getAmount1Delta, getSqrtRatioAtTick } from '@uniswap/v3-sdk' const sqrtPriceLower = getSqrtRatioAtTick(-60) const sqrtPriceUpper = getSqrtRatioAtTick(60) const liquidity = 1000000000000000000n // Amount of token1 in the position const amount1 = getAmount1Delta(sqrtPriceLower, sqrtPriceUpper, liquidity, false) ``` ### Use Cases #### Computing Position Token Amounts ```typescript import { getAmount0Delta, getAmount1Delta, getSqrtRatioAtTick } from '@uniswap/v3-sdk' function getPositionAmounts( tickLower: number, tickUpper: number, tickCurrent: number, sqrtPriceX96: bigint, liquidity: bigint ) { const sqrtPriceLower = getSqrtRatioAtTick(tickLower) const sqrtPriceUpper = getSqrtRatioAtTick(tickUpper) let amount0: bigint let amount1: bigint if (tickCurrent < tickLower) { // All in token0 amount0 = getAmount0Delta(sqrtPriceLower, sqrtPriceUpper, liquidity, false) amount1 = 0n } else if (tickCurrent < tickUpper) { // Split between tokens amount0 = getAmount0Delta(sqrtPriceX96, sqrtPriceUpper, liquidity, false) amount1 = getAmount1Delta(sqrtPriceLower, sqrtPriceX96, liquidity, false) } else { // All in token1 amount0 = 0n amount1 = getAmount1Delta(sqrtPriceLower, sqrtPriceUpper, liquidity, false) } return { amount0, amount1 } } ``` #### Simulating a Swap ```typescript import { getNextSqrtPriceFromInput, getAmount0Delta, getAmount1Delta } from '@uniswap/v3-sdk' function simulateSwap( sqrtPriceX96: bigint, liquidity: bigint, amountIn: bigint, zeroForOne: boolean ) { const sqrtPriceAfter = getNextSqrtPriceFromInput( sqrtPriceX96, liquidity, amountIn, zeroForOne ) // Calculate output amount const amountOut = zeroForOne ? getAmount1Delta(sqrtPriceAfter, sqrtPriceX96, liquidity, false) : getAmount0Delta(sqrtPriceX96, sqrtPriceAfter, liquidity, false) return { sqrtPriceAfter, amountOut } } ``` ### Rounding Behavior The `roundUp` parameter is critical for maintaining solvency: * **For minting**: Round amounts UP so the user provides at least enough tokens * **For burning**: Round amounts DOWN so the protocol doesn't give more than it has * **For swaps**: Input amounts round up, output amounts round down ```typescript // Minting - round up to ensure enough tokens provided const mintAmount0 = getAmount0Delta(sqrtA, sqrtB, liquidity, true) const mintAmount1 = getAmount1Delta(sqrtA, sqrtB, liquidity, true) // Burning - round down to not give more than available const burnAmount0 = getAmount0Delta(sqrtA, sqrtB, liquidity, false) const burnAmount1 = getAmount1Delta(sqrtA, sqrtB, liquidity, false) ``` ### Precision Notes These functions use 256-bit arithmetic internally to maintain precision during intermediate calculations. The final results are returned as `bigint` values with the appropriate rounding applied. ## Staker The `Staker` module provides utilities for interacting with the Uniswap V3 Staker contract, which allows liquidity providers to earn additional rewards by staking their position NFTs. ### Import ```typescript import { collectRewards, withdrawToken, encodeDeposit } from '@uniswap/v3-sdk' ``` ### Types #### IncentiveKey Represents a unique staking program. ```typescript interface IncentiveKey { rewardToken: Token // The token rewarded for participating pool: Pool // The pool that staked positions must provide in startTime: BigintIsh // When the incentive program begins endTime: BigintIsh // When the incentive program ends refundee: string // Address that receives remaining rewards at endTime } ``` #### ClaimOptions Options for claiming rewards. ```typescript interface ClaimOptions { tokenId: BigintIsh // The NFT position ID recipient: string // Address to send rewards to amount?: BigintIsh // Amount to claim (0 = all) } ``` #### WithdrawOptions Options for withdrawing a position. ```typescript interface WithdrawOptions { owner: string // Position owner address data?: Hex.Hex // Optional data for safeTransferFrom } ``` #### FullWithdrawOptions Combined options for withdrawing with claim. ```typescript type FullWithdrawOptions = ClaimOptions & WithdrawOptions ``` ### Functions #### collectRewards Produces the calldata for collecting rewards and re-staking a position. ```typescript function collectRewards( incentiveKeysInput: IncentiveKey | IncentiveKey[], options: ClaimOptions ): MethodParameters ``` ##### Parameters | Parameter | Type | Description | | -------------------- | -------------------------------- | ------------------------------------------- | | `incentiveKeysInput` | `IncentiveKey \| IncentiveKey[]` | Incentive(s) that the position is staked in | | `options` | `ClaimOptions` | Options for claiming rewards | ##### Example ```typescript import { collectRewards, Pool, FeeAmount } from '@uniswap/v3-sdk' import { Token } from '@uniswap/sdk-core' const rewardToken = new Token(1, '0x...', 18, 'UNI') const pool = new Pool(token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, tick) const incentiveKey = { rewardToken, pool, startTime: 1625097600n, endTime: 1627776000n, refundee: '0xRefundeeAddress...' } const { calldata, value } = collectRewards(incentiveKey, { tokenId: 12345, recipient: '0xRecipientAddress...', amount: 0n // Claim all available rewards }) ``` #### withdrawToken Produces the calldata for withdrawing a staked position and claiming rewards. ```typescript function withdrawToken( incentiveKeysInput: IncentiveKey | IncentiveKey[], withdrawOptions: FullWithdrawOptions ): MethodParameters ``` ##### Parameters | Parameter | Type | Description | | -------------------- | -------------------------------- | ------------------------------------ | | `incentiveKeysInput` | `IncentiveKey \| IncentiveKey[]` | Incentive(s) to unstake from | | `withdrawOptions` | `FullWithdrawOptions` | Options for withdrawing and claiming | ##### Example ```typescript import { withdrawToken } from '@uniswap/v3-sdk' const { calldata, value } = withdrawToken(incentiveKey, { tokenId: 12345, recipient: '0xRecipientAddress...', // Reward recipient owner: '0xOwnerAddress...', // NFT recipient amount: 0n // Claim all rewards }) ``` #### encodeDeposit Encodes the data for depositing and staking a position. This is passed to `safeTransferFrom` when transferring the NFT to the staker contract. ```typescript function encodeDeposit( incentiveKeysInput: IncentiveKey | IncentiveKey[] ): Hex.Hex ``` ##### Example ```typescript import { encodeDeposit, safeTransferFromParameters } from '@uniswap/v3-sdk' // Encode deposit data for staking in an incentive const depositData = encodeDeposit(incentiveKey) // Use with safeTransferFrom to deposit and stake in one transaction const { calldata } = safeTransferFromParameters({ sender: ownerAddress, recipient: STAKER_CONTRACT_ADDRESS, tokenId: 12345, data: depositData }) ``` ### Complete Staking Workflow #### 1. Deposit and Stake Transfer your position NFT to the staker contract with encoded incentive data: ```typescript import { encodeDeposit, safeTransferFromParameters } from '@uniswap/v3-sdk' const incentiveKey = { rewardToken, pool, startTime: 1625097600n, endTime: 1627776000n, refundee: refundeeAddress } // Encode the deposit data const depositData = encodeDeposit(incentiveKey) // Create the transfer calldata const { calldata } = safeTransferFromParameters({ sender: userAddress, recipient: STAKER_ADDRESS, tokenId: positionNftId, data: depositData }) // Execute the transaction to deposit and stake await nftManagerContract.safeTransferFrom( userAddress, STAKER_ADDRESS, positionNftId, depositData ) ``` #### 2. Collect Rewards (Stay Staked) Claim accumulated rewards while keeping the position staked: ```typescript import { collectRewards } from '@uniswap/v3-sdk' const { calldata, value } = collectRewards(incentiveKey, { tokenId: positionNftId, recipient: userAddress, amount: 0n // Claim all }) // Execute on staker contract await stakerContract.multicall([calldata]) ``` #### 3. Withdraw and Claim Unstake the position, claim rewards, and get the NFT back: ```typescript import { withdrawToken } from '@uniswap/v3-sdk' const { calldata, value } = withdrawToken(incentiveKey, { tokenId: positionNftId, recipient: userAddress, // Reward recipient owner: userAddress, // NFT recipient amount: 0n }) // Execute withdrawal await stakerContract.multicall([calldata]) ``` ### Staking in Multiple Incentives You can stake a position in multiple incentive programs: ```typescript // Deposit with multiple incentives const depositData = encodeDeposit([incentiveKey1, incentiveKey2]) // Collect from multiple incentives const { calldata } = collectRewards([incentiveKey1, incentiveKey2], { tokenId: positionNftId, recipient: userAddress, amount: 0n }) // Withdraw from multiple incentives const { calldata } = withdrawToken([incentiveKey1, incentiveKey2], { tokenId: positionNftId, recipient: userAddress, owner: userAddress, amount: 0n }) ``` ### Contract Address The Uniswap V3 Staker contract is deployed at: * Mainnet: `0xe34139463bA50bD61336E0c446Bd8C0867c6fE65` ## SwapRouter The `SwapRouter` module provides utilities for generating calldata to execute swaps on the Uniswap V3 SwapRouter contract. ### Import ```typescript import { swapCallParameters } from '@uniswap/v3-sdk' ``` ### swapCallParameters Produces the calldata for executing a trade on the router. ```typescript function swapCallParameters( trades: Trade | Trade[], options: SwapOptions ): MethodParameters ``` #### Parameters | Parameter | Type | Description | | --------- | ------------------ | ------------------------------- | | `trades` | `Trade \| Trade[]` | The trade(s) to execute | | `options` | `SwapOptions` | Options for the call parameters | #### SwapOptions | Option | Type | Description | | ------------------- | ------------------------------------- | ----------------------------------------------------------- | | `slippageTolerance` | `Percent` | How much the execution price is allowed to move unfavorably | | `recipient` | `string` | The account that should receive the output | | `deadline` | `bigint` | When the transaction expires, in epoch seconds | | `inputTokenPermit` | `PermitOptions` | Optional permit for the input token (EIP-2612) | | `sqrtPriceLimitX96` | `bigint` | Optional price limit for the trade | | `fee` | `{ fee: Percent; recipient: string }` | Optional fee to take on the output | #### Returns Returns a `MethodParameters` object: ```typescript interface MethodParameters { calldata: Hex.Hex value: Hex.Hex } ``` ### Example ```typescript import { swapCallParameters, Trade, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' // Create a trade const route = new Route([pool], USDC, WETH) const inputAmount = CurrencyAmount.fromRawAmount(USDC, '1000000') const trade = await Trade.fromRoute(route, inputAmount, TradeType.EXACT_INPUT) // Generate swap calldata const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), // 0.5% recipient: '0x1234567890123456789012345678901234567890', deadline: BigInt(Math.floor(Date.now() / 1000) + 1800) // 30 minutes }) // Use with ethers or viem to send transaction const tx = { to: SWAP_ROUTER_ADDRESS, data: calldata, value: value } ``` ### Swap Types #### Exact Input Single Hop Swap an exact amount of input tokens for as many output tokens as possible through a single pool. ```typescript const trade = await Trade.fromRoute( new Route([pool], tokenIn, tokenOut), CurrencyAmount.fromRawAmount(tokenIn, '1000000'), TradeType.EXACT_INPUT ) const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline) }) ``` #### Exact Output Single Hop Swap as few input tokens as possible for an exact amount of output tokens. ```typescript const trade = await Trade.fromRoute( new Route([pool], tokenIn, tokenOut), CurrencyAmount.fromRawAmount(tokenOut, '1000000000000000000'), TradeType.EXACT_OUTPUT ) const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline) }) ``` #### Multi-Hop Swaps Swaps can route through multiple pools: ```typescript // USDC -> WETH -> DAI (two hops) const route = new Route([usdcWethPool, wethDaiPool], USDC, DAI) const trade = await Trade.fromRoute( route, CurrencyAmount.fromRawAmount(USDC, '1000000'), TradeType.EXACT_INPUT ) ``` #### Native Currency Swaps When swapping with native ETH, the SDK automatically handles wrapping/unwrapping: ```typescript import { Ether } from '@uniswap/sdk-core' const ETHER = Ether.onChain(1) // ETH -> USDC swap const trade = await Trade.fromRoute( new Route([wethUsdcPool], ETHER, USDC), CurrencyAmount.fromRawAmount(ETHER, '1000000000000000000'), TradeType.EXACT_INPUT ) const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline) }) // Note: value will be non-zero for ETH input swaps ``` ### Using Permits You can use EIP-2612 permits to avoid a separate approval transaction: ```typescript const permitOptions = { v: 28, r: '0x...', s: '0x...', amount: '1000000', deadline: BigInt(deadline) } const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline), inputTokenPermit: permitOptions }) ``` ### Taking Fees You can take a fee on the output: ```typescript const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline), fee: { fee: new Percent(3, 1000), // 0.3% fee recipient: feeRecipientAddress } }) ``` ### Price Limits For single-hop swaps, you can set a price limit: ```typescript const { calldata, value } = swapCallParameters(trade, { slippageTolerance: new Percent(50, 10000), recipient: recipientAddress, deadline: BigInt(deadline), sqrtPriceLimitX96: 1234567890123456789012345678n // Price limit }) ``` Note: `sqrtPriceLimitX96` cannot be used with multi-hop swaps. ## TickDataProvider The `TickDataProvider` interface defines the contract for providing tick data to V3 pools. It allows pools to fetch tick information dynamically during swap calculations. ### Import ```typescript import { TickDataProvider, NoTickDataProvider } from '@uniswap/v3-sdk' ``` ### TickDataProvider Interface The interface that tick data providers must implement. ```typescript interface TickDataProvider { getTick(tick: number): Promise<{ liquidityNet: BigintIsh; liquidityGross?: BigintIsh }> nextInitializedTickWithinOneWord( tick: number, lte: boolean, tickSpacing: number ): Promise<[number, boolean]> } ``` #### Methods ##### getTick Returns information corresponding to a specific tick. ```typescript getTick(tick: number): Promise<{ liquidityNet: BigintIsh; liquidityGross?: BigintIsh }> ``` | Parameter | Type | Description | | --------- | -------- | ---------------------- | | `tick` | `number` | The tick index to load | **Returns:** A promise resolving to an object containing: * `liquidityNet`: The net liquidity change at this tick * `liquidityGross` (optional): The gross liquidity at this tick ##### nextInitializedTickWithinOneWord Returns the next initialized tick within a single word. ```typescript nextInitializedTickWithinOneWord( tick: number, lte: boolean, tickSpacing: number ): Promise<[number, boolean]> ``` | Parameter | Type | Description | | ------------- | --------- | ---------------------------------------------------------------------- | | `tick` | `number` | The current tick | | `lte` | `boolean` | Whether the next tick should be less than or equal to the current tick | | `tickSpacing` | `number` | The tick spacing of the pool | **Returns:** A promise resolving to a tuple: * `[0]`: The next initialized tick index * `[1]`: Whether the tick is initialized ### NoTickDataProvider A placeholder tick data provider that throws errors when accessed. Useful when tick data is not needed. ```typescript class NoTickDataProvider implements TickDataProvider { async getTick(_tick: number): Promise<{ liquidityNet: BigintIsh }> async nextInitializedTickWithinOneWord( _tick: number, _lte: boolean, _tickSpacing: number ): Promise<[number, boolean]> } ``` Both methods throw an error with the message: "No tick data provider was given" ### Example: Custom Tick Data Provider ```typescript import { TickDataProvider } from '@uniswap/v3-sdk' class OnChainTickDataProvider implements TickDataProvider { private poolAddress: string private provider: any // ethers provider constructor(poolAddress: string, provider: any) { this.poolAddress = poolAddress this.provider = provider } async getTick(tick: number): Promise<{ liquidityNet: bigint; liquidityGross: bigint }> { // Fetch tick data from the blockchain const poolContract = new Contract(this.poolAddress, POOL_ABI, this.provider) const tickData = await poolContract.ticks(tick) return { liquidityGross: tickData.liquidityGross, liquidityNet: tickData.liquidityNet } } async nextInitializedTickWithinOneWord( tick: number, lte: boolean, tickSpacing: number ): Promise<[number, boolean]> { // Fetch from bitmap const poolContract = new Contract(this.poolAddress, POOL_ABI, this.provider) const wordPos = Math.floor(tick / tickSpacing / 256) const bitPos = (tick / tickSpacing) % 256 const bitmap = await poolContract.tickBitmap(wordPos) // Find next initialized tick in bitmap // ... implementation details return [nextTick, initialized] } } ``` ### Usage with Pool ```typescript import { Pool, FeeAmount } from '@uniswap/v3-sdk' // Using a custom tick data provider const tickDataProvider = new OnChainTickDataProvider(poolAddress, provider) const pool = new Pool( token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, currentTick, tickDataProvider ) // Now pool.getOutputAmount() and pool.getInputAmount() will use // the tick data provider to fetch tick information during swaps ``` ### TickListDataProvider The SDK also includes a `TickListDataProvider` that wraps an array of ticks: ```typescript import { Pool, Tick, FeeAmount } from '@uniswap/v3-sdk' const ticks = [ new Tick({ index: -60, liquidityGross: '1000000', liquidityNet: '1000000' }), new Tick({ index: 0, liquidityGross: '2000000', liquidityNet: '1000000' }), new Tick({ index: 60, liquidityGross: '1000000', liquidityNet: '-1000000' }), ] // When you pass an array of ticks, it's automatically wrapped in TickListDataProvider const pool = new Pool( token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, currentTick, ticks // Automatically converted to TickListDataProvider ) ``` ## Tick Math The tick math utilities provide functions for converting between ticks and sqrt prices in Uniswap V3. ### Import ```typescript import { MIN_TICK, MAX_TICK, MIN_SQRT_RATIO, MAX_SQRT_RATIO, getSqrtRatioAtTick, getTickAtSqrtRatio } from '@uniswap/v3-sdk' ``` ### Constants #### MIN\_TICK The minimum tick that can be used on any pool. ```typescript const MIN_TICK = -887272 ``` #### MAX\_TICK The maximum tick that can be used on any pool. ```typescript const MAX_TICK = 887272 ``` #### MIN\_SQRT\_RATIO The sqrt ratio corresponding to the minimum tick. ```typescript const MIN_SQRT_RATIO = 4295128739n ``` #### MAX\_SQRT\_RATIO The sqrt ratio corresponding to the maximum tick. ```typescript const MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342n ``` ### Functions #### getSqrtRatioAtTick Returns the sqrt ratio as a Q64.96 value for a given tick. ```typescript function getSqrtRatioAtTick(tick: number): bigint ``` ##### Parameters | Parameter | Type | Description | | --------- | -------- | -------------------------------------------- | | `tick` | `number` | The tick for which to compute the sqrt ratio | ##### Returns Returns the sqrt ratio as a Q64.96 value (`bigint`). ##### Formula The sqrt ratio at a tick is computed as: ``` sqrtRatio = sqrt(1.0001^tick) * 2^96 ``` ##### Example ```typescript import { getSqrtRatioAtTick } from '@uniswap/v3-sdk' // Tick 0 corresponds to price 1.0 const sqrtRatioAtTick0 = getSqrtRatioAtTick(0) console.log(sqrtRatioAtTick0) // 79228162514264337593543950336n (2^96) // Tick 100 corresponds to price ~1.01 const sqrtRatioAtTick100 = getSqrtRatioAtTick(100) console.log(sqrtRatioAtTick100) // ~79623317895830914510639640423n // Negative tick corresponds to price < 1 const sqrtRatioAtTickMinus100 = getSqrtRatioAtTick(-100) console.log(sqrtRatioAtTickMinus100) // ~78833030112140176575862854579n ``` #### getTickAtSqrtRatio Returns the tick corresponding to a given sqrt ratio. ```typescript function getTickAtSqrtRatio(sqrtRatioX96: bigint): number ``` ##### Parameters | Parameter | Type | Description | | -------------- | -------- | -------------------------------- | | `sqrtRatioX96` | `bigint` | The sqrt ratio as a Q64.96 value | ##### Returns Returns the greatest tick for which the sqrt ratio is greater than or equal to the input. ##### Example ```typescript import { getTickAtSqrtRatio } from '@uniswap/v3-sdk' // 2^96 corresponds to tick 0 const Q96 = 2n ** 96n const tick0 = getTickAtSqrtRatio(Q96) console.log(tick0) // 0 // Higher sqrt ratio = higher tick const tick100 = getTickAtSqrtRatio(79623317895830914510639640423n) console.log(tick100) // 100 ``` ### Understanding Ticks #### Price to Tick Relationship Each tick represents a 0.01% (1 basis point) change in price: ``` price = 1.0001^tick ``` | Tick | Price (approximate) | | ----- | ------------------- | | 0 | 1.0 | | 100 | 1.01 | | 1000 | 1.105 | | 10000 | 2.718 | | -100 | 0.99 | | -1000 | 0.905 | #### Tick Spacing Pools only allow positions at certain ticks based on the fee tier: | Fee Tier | Tick Spacing | | ----------- | ------------ | | 0.01% (100) | 1 | | 0.05% (500) | 10 | | 0.3% (3000) | 60 | | 1% (10000) | 200 | ### Usage Examples #### Computing Pool Price Range ```typescript import { getSqrtRatioAtTick } from '@uniswap/v3-sdk' const tickLower = -60 const tickUpper = 60 const sqrtPriceLower = getSqrtRatioAtTick(tickLower) const sqrtPriceUpper = getSqrtRatioAtTick(tickUpper) // Price range for the position const priceLower = (sqrtPriceLower * sqrtPriceLower) / (2n ** 192n) const priceUpper = (sqrtPriceUpper * sqrtPriceUpper) / (2n ** 192n) ``` #### Finding Current Tick from Pool State ```typescript import { getTickAtSqrtRatio } from '@uniswap/v3-sdk' // Given a pool's current sqrtPriceX96 const currentSqrtPrice = 79228162514264337593543950336n const currentTick = getTickAtSqrtRatio(currentSqrtPrice) ``` #### Validating Tick Bounds ```typescript import { MIN_TICK, MAX_TICK } from '@uniswap/v3-sdk' function isValidTick(tick: number): boolean { return tick >= MIN_TICK && tick <= MAX_TICK && Number.isInteger(tick) } // Also check tick spacing for specific fee tier function isValidPositionTick(tick: number, tickSpacing: number): boolean { return isValidTick(tick) && tick % tickSpacing === 0 } ``` #### Converting Between Price and Tick ```typescript import { getSqrtRatioAtTick, getTickAtSqrtRatio, encodeSqrtRatioX96 } from '@uniswap/v3-sdk' // Price to tick (approximate) function priceToTick(price: number): number { // tick = log(price) / log(1.0001) return Math.floor(Math.log(price) / Math.log(1.0001)) } // More precise: use encodeSqrtRatioX96 then getTickAtSqrtRatio function precisepriceToTick(priceNumerator: bigint, priceDenominator: bigint): number { const sqrtPrice = encodeSqrtRatioX96(priceNumerator, priceDenominator) return getTickAtSqrtRatio(sqrtPrice) } ``` ### Implementation Details #### getSqrtRatioAtTick Implementation The function uses a Taylor series expansion with pre-computed constants to efficiently compute `1.0001^(tick/2) * 2^96`. This is more gas-efficient than computing the actual exponential. Key implementation details: 1. Takes absolute value of tick 2. Multiplies pre-computed factors for each bit of the tick 3. Inverts the ratio for positive ticks 4. Shifts to Q64.96 format #### getTickAtSqrtRatio Implementation The inverse function uses: 1. Binary search on the log2 of the sqrt ratio 2. Conversion from log base 2 to log base sqrt(1.0001) 3. Verification that the result is correct ## Tick The `Tick` class represents a tick in a Uniswap V3 pool. Ticks are discrete price points at which liquidity can be added or removed. ### Import ```typescript import { Tick } from '@uniswap/v3-sdk' ``` ### Constructor Creates a new Tick instance. ```typescript new Tick({ index: number, liquidityGross: BigintIsh, liquidityNet: BigintIsh }) ``` #### Parameters | Parameter | Type | Description | | ---------------- | ----------- | ------------------------------------------------------- | | `index` | `number` | The tick index, must be between MIN\_TICK and MAX\_TICK | | `liquidityGross` | `BigintIsh` | The total liquidity referencing this tick | | `liquidityNet` | `BigintIsh` | The net liquidity change when crossing this tick | ### Example ```typescript import { Tick } from '@uniswap/v3-sdk' const tick = new Tick({ index: 100, liquidityGross: '1000000000000000000', liquidityNet: '500000000000000000' }) console.log(tick.index) // 100 console.log(tick.liquidityGross) // 1000000000000000000n console.log(tick.liquidityNet) // 500000000000000000n ``` ### Properties | Property | Type | Description | | ---------------- | -------- | -------------------------------------------- | | `index` | `number` | The tick index | | `liquidityGross` | `bigint` | Total liquidity referencing this tick | | `liquidityNet` | `bigint` | Net liquidity change when crossing this tick | ### TickConstructorArgs Interface The constructor accepts an object with the following shape: ```typescript interface TickConstructorArgs { index: number liquidityGross: BigintIsh liquidityNet: BigintIsh } ``` ### Understanding Ticks #### Tick Index The tick index represents a specific price point. The price at a given tick is calculated as: ``` price = 1.0001^tick ``` For example: * Tick 0 corresponds to price 1.0 * Tick 100 corresponds to price \~1.01 (1.0001^100) * Tick -100 corresponds to price \~0.99 (1.0001^-100) #### Tick Bounds Ticks have minimum and maximum values: ```typescript import { MIN_TICK, MAX_TICK } from '@uniswap/v3-sdk' console.log(MIN_TICK) // -887272 console.log(MAX_TICK) // 887272 ``` #### Liquidity Values * **liquidityGross**: The total amount of liquidity that references this tick as either its lower or upper bound. Used to determine if the tick needs to be crossed during a swap. * **liquidityNet**: The amount of liquidity added (positive) or removed (negative) when the tick is crossed from left to right. When crossing from right to left, the sign is flipped. ### Usage with Pool Ticks are typically used when constructing a Pool: ```typescript import { Pool, Tick, FeeAmount } from '@uniswap/v3-sdk' const ticks = [ new Tick({ index: -60, liquidityGross: '1000000', liquidityNet: '1000000' }), new Tick({ index: 0, liquidityGross: '2000000', liquidityNet: '1000000' }), new Tick({ index: 60, liquidityGross: '1000000', liquidityNet: '-1000000' }), ] const pool = new Pool( token0, token1, FeeAmount.MEDIUM, sqrtRatioX96, liquidity, currentTick, ticks ) ``` ## Trade The `Trade` class represents a trade executed against a set of routes where some percentage of the input may be split across each route. ### Import ```typescript import { Trade } from '@uniswap/v3-sdk' ``` ### Creating Trades Trades are created using static factory methods rather than the constructor directly. #### fromRoute Constructs a trade from a single route. ```typescript static async fromRoute( route: Route, amount: TTradeType extends TradeType.EXACT_INPUT ? CurrencyAmount : CurrencyAmount, tradeType: TTradeType ): Promise> ``` ##### Parameters | Parameter | Type | Description | | ----------- | ------------------------ | ------------------------------------------------- | | `route` | `Route` | The route of the trade | | `amount` | `CurrencyAmount` | The amount being passed in or expected out | | `tradeType` | `TTradeType` | The type of trade (EXACT\_INPUT or EXACT\_OUTPUT) | ##### Example ```typescript import { Trade, Route, Pool, FeeAmount } from '@uniswap/v3-sdk' import { CurrencyAmount, TradeType } from '@uniswap/sdk-core' const route = new Route([pool], USDC, WETH) const inputAmount = CurrencyAmount.fromRawAmount(USDC, '1000000') // 1 USDC const trade = await Trade.fromRoute( route, inputAmount, TradeType.EXACT_INPUT ) ``` #### fromRoutes Constructs a trade from multiple routes with split amounts. ```typescript static async fromRoutes( routes: { amount: TTradeType extends TradeType.EXACT_INPUT ? CurrencyAmount : CurrencyAmount route: Route }[], tradeType: TTradeType ): Promise> ``` ##### Example ```typescript const trade = await Trade.fromRoutes( [ { route: route1, amount: amount1 }, { route: route2, amount: amount2 } ], TradeType.EXACT_INPUT ) ``` #### createUncheckedTrade Creates a trade without computing the amounts. Useful when amounts are already known. ```typescript static createUncheckedTrade(args: { route: Route inputAmount: CurrencyAmount outputAmount: CurrencyAmount tradeType: TTradeType }): Trade ``` #### createUncheckedTradeWithMultipleRoutes Creates a trade with multiple routes without computing amounts. ```typescript static createUncheckedTradeWithMultipleRoutes(args: { routes: { route: Route inputAmount: CurrencyAmount outputAmount: CurrencyAmount }[] tradeType: TTradeType }): Trade ``` ### Properties | Property | Type | Description | | ----------- | ------------ | ------------------------------------------------------------------ | | `swaps` | `Array` | The swaps for this trade with route, inputAmount, and outputAmount | | `tradeType` | `TTradeType` | The type of trade (EXACT\_INPUT or EXACT\_OUTPUT) | ### Getters #### route Returns the route for a single-route trade. Throws if the trade has multiple routes. ```typescript get route(): Route ``` #### inputAmount Returns the total input amount for the trade. ```typescript get inputAmount(): CurrencyAmount ``` #### outputAmount Returns the total output amount for the trade. ```typescript get outputAmount(): CurrencyAmount ``` #### executionPrice Returns the price expressed in terms of output amount / input amount. ```typescript get executionPrice(): Price ``` #### priceImpact Returns the percent difference between the route's mid price and the execution price. ```typescript get priceImpact(): Percent ``` #### inputTax Returns the sell tax for the input currency (if any). ```typescript get inputTax(): Percent ``` #### outputTax Returns the buy tax for the output currency (if any). ```typescript get outputTax(): Percent ``` ### Methods #### minimumAmountOut Get the minimum amount that must be received for this trade, given a slippage tolerance. ```typescript minimumAmountOut(slippageTolerance: Percent): CurrencyAmount ``` ##### Example ```typescript import { Percent } from '@uniswap/sdk-core' const slippage = new Percent(50, 10000) // 0.5% const minOut = trade.minimumAmountOut(slippage) ``` #### maximumAmountIn Get the maximum amount that should be spent for this trade, given a slippage tolerance. ```typescript maximumAmountIn(slippageTolerance: Percent): CurrencyAmount ``` #### worstExecutionPrice Return the execution price after accounting for slippage tolerance. ```typescript worstExecutionPrice(slippageTolerance: Percent): Price ``` ### Static Methods #### bestTradeExactIn Given a list of pools, returns the top trades that go from an input token amount to an output token. ```typescript static async bestTradeExactIn( pools: Pool[], currencyAmountIn: CurrencyAmount, currencyOut: TOutput, options?: BestTradeOptions, currentPools?: Pool[], nextAmountIn?: CurrencyAmount, bestTrades?: Trade[] ): Promise[]> ``` ##### BestTradeOptions | Option | Type | Default | Description | | --------------- | -------- | ------- | --------------------------------------- | | `maxNumResults` | `number` | 3 | Maximum number of results to return | | `maxHops` | `number` | 3 | Maximum number of hops a trade can make | ##### Example ```typescript import { Trade, Pool } from '@uniswap/v3-sdk' import { CurrencyAmount } from '@uniswap/sdk-core' const pools = [pool1, pool2, pool3] const amountIn = CurrencyAmount.fromRawAmount(USDC, '1000000') const trades = await Trade.bestTradeExactIn( pools, amountIn, WETH, { maxNumResults: 3, maxHops: 3 } ) // Get the best trade const bestTrade = trades[0] ``` #### bestTradeExactOut Given a list of pools, returns the top trades that go from an input token to an output token amount. ```typescript static async bestTradeExactOut( pools: Pool[], currencyIn: TInput, currencyAmountOut: CurrencyAmount, options?: BestTradeOptions, currentPools?: Pool[], nextAmountOut?: CurrencyAmount, bestTrades?: Trade[] ): Promise[]> ``` ##### Example ```typescript const amountOut = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') const trades = await Trade.bestTradeExactOut( pools, USDC, amountOut, { maxNumResults: 3, maxHops: 3 } ) ``` ## Constants V2 SDK constants including factory addresses and init code hash. ### Import ```typescript import { FACTORY_ADDRESS, FACTORY_ADDRESS_MAP, INIT_CODE_HASH, MINIMUM_LIQUIDITY, } from '@uniswap/v2-sdk-next' ``` ### Factory Addresses #### `FACTORY_ADDRESS` The default V2 factory address (Ethereum mainnet). ```typescript const FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' ``` > **Deprecated**: Use `FACTORY_ADDRESS_MAP` instead. #### `FACTORY_ADDRESS_MAP` Factory addresses by chain ID. ```typescript import { FACTORY_ADDRESS_MAP } from '@uniswap/v2-sdk-next' import { ChainId } from '@uniswap/sdk-core-next' const mainnetFactory = FACTORY_ADDRESS_MAP[ChainId.MAINNET] // '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' const baseFactory = FACTORY_ADDRESS_MAP[ChainId.BASE] // '0x8909dc15e40173ff4699343b6eb8132c65e18ec6' ``` ### Init Code Hash #### `INIT_CODE_HASH` The keccak256 hash of the pair bytecode, used for computing pair addresses. ```typescript const INIT_CODE_HASH = '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' ``` Used in CREATE2 address computation: ```typescript import { computePairAddress } from '@uniswap/v2-sdk-next' const pairAddress = computePairAddress({ factoryAddress: FACTORY_ADDRESS, tokenA, tokenB, }) // Uses INIT_CODE_HASH internally ``` ### Liquidity Constants #### `MINIMUM_LIQUIDITY` The minimum liquidity locked in every pair (burned on first mint). ```typescript const MINIMUM_LIQUIDITY = 1000n ``` When a pair is first created, 1000 units of liquidity are permanently locked to prevent division by zero attacks. ### Supported Chains V2 is deployed on: | Chain | Factory Address | | --------- | -------------------------------------------- | | Ethereum | `0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f` | | Optimism | `0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf` | | Arbitrum | `0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9` | | Polygon | `0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C` | | Base | `0x8909dc15e40173ff4699343b6eb8132c65e18ec6` | | BNB Chain | `0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6` | | Avalanche | `0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C` | | Blast | `0x5C346464d33F90bABaf70dB6388507CC889C1070` | | Celo | `0x79a530c8e2fA8748B7B40dd3629C0520c2cCf03f` | ## Errors Custom error types for V2 SDK operations. ### Import ```typescript import { InsufficientReservesError, InsufficientInputAmountError, } from '@uniswap/v2-sdk-next' ``` ### Error Types #### `InsufficientReservesError` Thrown when a pair doesn't have enough reserves to complete a trade. ```typescript class InsufficientReservesError extends Error { public readonly isInsufficientReservesError = true } ``` ##### When It's Thrown * Output amount requested is greater than or equal to the reserve * Trying to get input amount for an output that exceeds liquidity ```typescript import { Pair, InsufficientReservesError } from '@uniswap/v2-sdk-next' try { // Trying to get 1000 USDC when reserve is only 500 const [inputAmount] = pair.getInputAmount( CurrencyAmount.fromRawAmount(USDC, 1000_000000n) ) } catch (error) { if (error instanceof InsufficientReservesError) { console.log('Not enough liquidity in this pair') } } ``` #### `InsufficientInputAmountError` Thrown when the input amount is too small to produce any output. ```typescript class InsufficientInputAmountError extends Error { public readonly isInsufficientInputAmountError = true } ``` ##### When It's Thrown * Input amount is too small (output rounds to zero) * After FOT fees, the effective input is zero ```typescript import { Pair, InsufficientInputAmountError } from '@uniswap/v2-sdk-next' try { // Very small input that rounds to zero output const [outputAmount] = pair.getOutputAmount( CurrencyAmount.fromRawAmount(WETH, 1n) ) } catch (error) { if (error instanceof InsufficientInputAmountError) { console.log('Input amount too small') } } ``` ### Error Handling Pattern ```typescript import { Trade, Pair, InsufficientReservesError, InsufficientInputAmountError, } from '@uniswap/v2-sdk-next' function findBestTrade(pairs: Pair[], amountIn: CurrencyAmount, currencyOut: Token) { try { const trades = Trade.bestTradeExactIn(pairs, amountIn, currencyOut) if (trades.length === 0) { return { success: false, error: 'No routes found' } } return { success: true, trade: trades[0] } } catch (error) { if (error instanceof InsufficientReservesError) { return { success: false, error: 'Insufficient liquidity' } } if (error instanceof InsufficientInputAmountError) { return { success: false, error: 'Amount too small' } } throw error // Re-throw unexpected errors } } ``` ### Type Guards Use the boolean flags for type narrowing: ```typescript try { const [output] = pair.getOutputAmount(inputAmount) } catch (error) { if ((error as { isInsufficientReservesError?: boolean }).isInsufficientReservesError) { // Handle insufficient reserves } if ((error as { isInsufficientInputAmountError?: boolean }).isInsufficientInputAmountError) { // Handle insufficient input } } ``` This pattern is used internally by `Trade.bestTradeExactIn` and `Trade.bestTradeExactOut` to skip pairs that can't handle the trade amount. ## V2 SDK The V2 SDK (`@uniswap/v2-sdk-next`) provides tools for building on Uniswap V2's constant-product automated market maker. It includes entities for pairs, routes, and trades, with full support for fee-on-transfer tokens. ### Features * **Pair Management**: Create and query V2 liquidity pairs * **Trade Routing**: Find optimal multi-hop trade paths * **FOT Support**: Full fee-on-transfer token handling * **Liquidity Math**: Calculate minted liquidity and values ### Installation ```bash npm install @uniswap/v2-sdk-next ``` ```bash pnpm add @uniswap/v2-sdk-next ``` ```bash yarn add @uniswap/v2-sdk-next ``` ### Quick Start ```typescript import { Pair, Route, Trade } from '@uniswap/v2-sdk-next' import { Token, CurrencyAmount, TradeType, Percent } from '@uniswap/sdk-core-next' // Define tokens const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create a pair with reserves (typically fetched from chain) const pair = new Pair( CurrencyAmount.fromRawAmount(WETH, '2000000000000000000000'), // 2000 WETH CurrencyAmount.fromRawAmount(USDC, '4000000000000') // 4M USDC ) // Create a route const route = new Route([pair], WETH, USDC) // Get the mid price console.log(route.midPrice.toSignificant(6)) // "2000" // Create a trade const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const trade = Trade.exactIn(route, inputAmount) // Get execution price and price impact console.log(trade.executionPrice.toSignificant(6)) console.log(trade.priceImpact.toSignificant(2) + '%') ``` ### How V2 Works Uniswap V2 uses the constant product formula: ``` x * y = k ``` Where: * `x` is the reserve of token0 * `y` is the reserve of token1 * `k` is a constant that only changes when liquidity is added/removed This formula ensures that trades always have a price, with larger trades having more price impact. ### Modules #### Entities * [Pair](/v2-sdk/pair) - V2 liquidity pair representation * [Route](/v2-sdk/route) - Sequence of pairs for a trade path * [Trade](/v2-sdk/trade) - Represents a swap with amounts and prices #### Interfaces * [Router](/v2-sdk/router) - Trade options for router interactions #### Reference * [Constants](/v2-sdk/constants) - Factory addresses and init code hashes * [Errors](/v2-sdk/errors) - Custom error types ## Installation ### Package Manager :::code-group ```bash [npm] npm install @uniswap/v2-sdk-next ``` ```bash [pnpm] pnpm add @uniswap/v2-sdk-next ``` ```bash [yarn] yarn add @uniswap/v2-sdk-next ``` ::: ### Requirements * **Node.js**: 18.x or later * **TypeScript**: 5.0 or later (recommended) ### Peer Dependencies The V2 SDK depends on SDK Core: ```bash npm install @uniswap/sdk-core-next ``` ### Usage ```typescript import { Pair, Route, Trade } from '@uniswap/v2-sdk-next' import { Token, CurrencyAmount, TradeType } from '@uniswap/sdk-core-next' ``` ### TypeScript Configuration ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true } } ``` ## Pair The `Pair` class represents a Uniswap V2 liquidity pair. ### Import ```typescript import { Pair, computePairAddress } from '@uniswap/v2-sdk-next' ``` ### Constructor ```typescript new Pair( currencyAmountA: CurrencyAmount, currencyAmountB: CurrencyAmount ) ``` Creates a pair with the given reserve amounts. Tokens are automatically sorted. ### Example ```typescript import { Pair } from '@uniswap/v2-sdk-next' import { Token, CurrencyAmount } from '@uniswap/sdk-core-next' const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create pair with reserves (typically fetched from chain) const pair = new Pair( CurrencyAmount.fromRawAmount(WETH, '2000000000000000000000'), // 2000 WETH CurrencyAmount.fromRawAmount(USDC, '4000000000000') // 4M USDC ) // Get pair information console.log(pair.token0.symbol) // Token with lower address console.log(pair.token1.symbol) // Token with higher address console.log(pair.reserve0.toSignificant(6)) console.log(pair.reserve1.toSignificant(6)) ``` ### Static Methods #### `Pair.getAddress(tokenA, tokenB)` Computes the pair address for two tokens. ```typescript static getAddress(tokenA: Token, tokenB: Token): Address.Address ``` ```typescript const pairAddress = Pair.getAddress(WETH, USDC) // Deterministic address based on factory and tokens ``` ### Properties #### `token0` / `token1` ```typescript get token0(): Token get token1(): Token ``` The two tokens in the pair, sorted by address. #### `reserve0` / `reserve1` ```typescript get reserve0(): CurrencyAmount get reserve1(): CurrencyAmount ``` The reserve amounts for each token. #### `liquidityToken` ```typescript readonly liquidityToken: Token ``` The LP token representing liquidity in this pair. #### `token0Price` / `token1Price` ```typescript get token0Price(): Price get token1Price(): Price ``` Current mid prices of the pair. ```typescript // Price of WETH in USDC console.log(pair.token0Price.toSignificant(6)) // Price of USDC in WETH console.log(pair.token1Price.toSignificant(6)) ``` #### `chainId` ```typescript get chainId(): number ``` The chain ID of the pair. ### Methods #### `involvesToken(token)` ```typescript involvesToken(token: Token): boolean ``` Returns true if the token is one of the pair's tokens. #### `priceOf(token)` ```typescript priceOf(token: Token): Price ``` Returns the price of the given token in terms of the other token. #### `reserveOf(token)` ```typescript reserveOf(token: Token): CurrencyAmount ``` Returns the reserve of the given token. #### `getOutputAmount(inputAmount, calculateFotFees?)` ```typescript getOutputAmount( inputAmount: CurrencyAmount, calculateFotFees?: boolean ): [CurrencyAmount, Pair] ``` Given an input amount, returns the output amount and the pair with updated reserves. ```typescript const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const [outputAmount, newPair] = pair.getOutputAmount(inputAmount) console.log(outputAmount.toSignificant(6)) // Amount of USDC received ``` #### `getInputAmount(outputAmount, calculateFotFees?)` ```typescript getInputAmount( outputAmount: CurrencyAmount, calculateFotFees?: boolean ): [CurrencyAmount, Pair] ``` Given a desired output amount, returns the required input amount. ```typescript const outputAmount = CurrencyAmount.fromRawAmount(USDC, 2000_000000n) // 2000 USDC const [inputAmount, newPair] = pair.getInputAmount(outputAmount) console.log(inputAmount.toSignificant(6)) // Amount of WETH needed ``` #### `getLiquidityMinted(totalSupply, tokenAmountA, tokenAmountB)` ```typescript getLiquidityMinted( totalSupply: CurrencyAmount, tokenAmountA: CurrencyAmount, tokenAmountB: CurrencyAmount ): CurrencyAmount ``` Calculates LP tokens minted for depositing the given amounts. #### `getLiquidityValue(token, totalSupply, liquidity, feeOn?, kLast?)` ```typescript getLiquidityValue( token: Token, totalSupply: CurrencyAmount, liquidity: CurrencyAmount, feeOn?: boolean, kLast?: BigintIsh ): CurrencyAmount ``` Calculates the value of LP tokens in terms of a specific token. ### Fee-on-Transfer Tokens The pair handles fee-on-transfer (FOT) tokens automatically when `calculateFotFees` is true: ```typescript // Token with buy/sell fees const FOT_TOKEN = new Token( 1, '0x...', 18, 'FOT', 'Fee Token', false, 100n, // 1% buy fee 200n // 2% sell fee ) const pair = new Pair( CurrencyAmount.fromRawAmount(FOT_TOKEN, '1000000000000000000000'), CurrencyAmount.fromRawAmount(USDC, '1000000000000') ) // FOT fees are calculated automatically const [output] = pair.getOutputAmount(inputAmount, true) ``` ### computePairAddress Utility function to compute pair addresses: ```typescript import { computePairAddress } from '@uniswap/v2-sdk-next' const address = computePairAddress({ factoryAddress: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', tokenA: WETH, tokenB: USDC, }) ``` ## Route The `Route` class represents a path through one or more V2 pairs for a trade. ### Import ```typescript import { Route } from '@uniswap/v2-sdk-next' ``` ### Constructor ```typescript new Route( pairs: Pair[], input: TInput, output: TOutput ) ``` #### Parameters | Name | Type | Description | | -------- | --------- | -------------------------------------- | | `pairs` | `Pair[]` | Ordered list of pairs to route through | | `input` | `TInput` | The input currency | | `output` | `TOutput` | The output currency | ### Example ```typescript import { Pair, Route } from '@uniswap/v2-sdk-next' import { Token, CurrencyAmount, Ether } from '@uniswap/sdk-core-next' const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const DAI = new Token(1, '0x6B175474E89094C44Da98b954EesidC44Da98b954E', 18, 'DAI') // Single hop route: WETH -> USDC const wethUsdcPair = new Pair( CurrencyAmount.fromRawAmount(WETH, '1000000000000000000000'), CurrencyAmount.fromRawAmount(USDC, '2000000000000') ) const directRoute = new Route([wethUsdcPair], WETH, USDC) // Multi-hop route: WETH -> USDC -> DAI const usdcDaiPair = new Pair( CurrencyAmount.fromRawAmount(USDC, '1000000000000'), CurrencyAmount.fromRawAmount(DAI, '1000000000000000000000') ) const multiHopRoute = new Route([wethUsdcPair, usdcDaiPair], WETH, DAI) // Route with native ETH input const ETH = Ether.onChain(1) const ethRoute = new Route([wethUsdcPair], ETH, USDC) ``` ### Properties #### `pairs` ```typescript readonly pairs: Pair[] ``` The ordered list of pairs in the route. #### `path` ```typescript readonly path: Token[] ``` The token path through the route (always uses wrapped versions). ```typescript const route = new Route([wethUsdcPair, usdcDaiPair], WETH, DAI) console.log(route.path.map(t => t.symbol)) // ['WETH', 'USDC', 'DAI'] ``` #### `input` ```typescript readonly input: TInput ``` The input currency (can be native like ETH). #### `output` ```typescript readonly output: TOutput ``` The output currency (can be native like ETH). #### `midPrice` ```typescript get midPrice(): Price ``` The mid price of the route (price without any trade). ```typescript const route = new Route([wethUsdcPair], WETH, USDC) console.log(route.midPrice.toSignificant(6)) // "2000" (USDC per WETH) const multiRoute = new Route([wethUsdcPair, usdcDaiPair], WETH, DAI) console.log(multiRoute.midPrice.toSignificant(6)) // Compound price ``` #### `chainId` ```typescript get chainId(): number ``` The chain ID (all pairs must be on the same chain). ### Validation The Route constructor validates: 1. At least one pair is provided 2. All pairs are on the same chain 3. The input token is in the first pair 4. The output token is in the last pair 5. The path is connected (each pair shares a token with the next) ```typescript // This throws: input not in first pair new Route([usdcDaiPair], WETH, DAI) // This throws: pairs not connected new Route([wethUsdcPair, wethDaiPair], WETH, DAI) // This throws: different chains new Route([mainnetPair, arbitrumPair], tokenA, tokenB) ``` ### Use with Trade Routes are typically used to construct trades: ```typescript import { Route, Trade } from '@uniswap/v2-sdk-next' import { CurrencyAmount, TradeType } from '@uniswap/sdk-core-next' const route = new Route([pair], WETH, USDC) const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') const trade = Trade.exactIn(route, inputAmount) console.log(trade.executionPrice.toSignificant(6)) console.log(trade.priceImpact.toSignificant(2) + '%') ``` ## Router The `Router` class provides static methods to generate calldata for V2 Router contract interactions. ### Import ```typescript import { Router, type TradeOptions, type TradeOptionsDeadline, type SwapParameters } from '@uniswap/v2-sdk-next' ``` ### Static Methods #### `Router.swapCallParameters(trade, options)` Generates the method name and arguments for executing a swap. ```typescript static swapCallParameters( trade: Trade, options: TradeOptions | TradeOptionsDeadline ): SwapParameters ``` ### Example ```typescript import { Router, Trade, Route, Pair } from '@uniswap/v2-sdk-next' import { Percent, CurrencyAmount, Token } from '@uniswap/sdk-core-next' // Create a trade const trade = Trade.exactIn(route, inputAmount) // Generate call parameters const params = Router.swapCallParameters(trade, { allowedSlippage: new Percent(50, 10000), // 0.5% ttl: 60 * 20, // 20 minutes recipient: '0xYourAddress...', }) console.log(params.methodName) // 'swapExactTokensForTokens' console.log(params.args) // [amountIn, amountOutMin, path, to, deadline] console.log(params.value) // '0x0' (or ETH value if swapping ETH) ``` ### Trade Options #### `TradeOptions` ```typescript interface TradeOptions { allowedSlippage: Percent ttl: number // Time to live in seconds recipient: string feeOnTransfer?: boolean } ``` #### `TradeOptionsDeadline` ```typescript interface TradeOptionsDeadline { allowedSlippage: Percent deadline: number // Unix timestamp recipient: string feeOnTransfer?: boolean } ``` ### SwapParameters ```typescript interface SwapParameters { methodName: string args: (string | string[])[] value: string // Wei amount in hex } ``` ### Router Methods by Trade Type #### Exact Input Trades | Input | Output | Method | | ----- | ------ | -------------------------- | | Token | Token | `swapExactTokensForTokens` | | Token | ETH | `swapExactTokensForETH` | | ETH | Token | `swapExactETHForTokens` | #### Exact Output Trades | Input | Output | Method | | ----- | ------ | -------------------------- | | Token | Token | `swapTokensForExactTokens` | | Token | ETH | `swapTokensForExactETH` | | ETH | Token | `swapETHForExactTokens` | #### Fee-on-Transfer Tokens When `feeOnTransfer: true`: | Input | Output | Method | | ----- | ------ | ------------------------------------------------------- | | Token | Token | `swapExactTokensForTokensSupportingFeeOnTransferTokens` | | Token | ETH | `swapExactTokensForETHSupportingFeeOnTransferTokens` | | ETH | Token | `swapExactETHForTokensSupportingFeeOnTransferTokens` | Note: FOT methods only support exact input trades. ### Usage with ethers.js ```typescript import { ethers } from 'ethers' import { Router, Trade } from '@uniswap/v2-sdk-next' import { Percent } from '@uniswap/sdk-core-next' // Create trade const trade = Trade.exactIn(route, inputAmount) // Get call parameters const params = Router.swapCallParameters(trade, { allowedSlippage: new Percent(50, 10000), ttl: 60 * 20, recipient: wallet.address, }) // V2 Router ABI (simplified) const routerAbi = [ 'function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] path, address to, uint deadline) returns (uint[] amounts)', 'function swapExactETHForTokens(uint amountOutMin, address[] path, address to, uint deadline) payable returns (uint[] amounts)', // ... other methods ] const router = new ethers.Contract(ROUTER_ADDRESS, routerAbi, signer) // Execute the swap const tx = await router[params.methodName](...params.args, { value: params.value, }) ``` ### Usage with viem ```typescript import { createWalletClient, http } from 'viem' import { mainnet } from 'viem/chains' import { Router, Trade } from '@uniswap/v2-sdk-next' const params = Router.swapCallParameters(trade, { allowedSlippage: new Percent(50, 10000), deadline: Math.floor(Date.now() / 1000) + 1200, recipient: account.address, }) // Encode the function call const data = encodeFunctionData({ abi: routerAbi, functionName: params.methodName, args: params.args, }) // Send transaction const hash = await walletClient.sendTransaction({ to: ROUTER_ADDRESS, data, value: BigInt(params.value), }) ``` ## Trade The `Trade` class represents a V2 swap, including the route, amounts, and price impact. ### Import ```typescript import { Trade } from '@uniswap/v2-sdk-next' ``` ### Creating Trades #### `Trade.exactIn(route, amountIn)` Create a trade with an exact input amount. ```typescript import { Trade, Route, Pair } from '@uniswap/v2-sdk-next' import { CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core-next' const pair = new Pair(/* ... */) const route = new Route([pair], WETH, USDC) const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const trade = Trade.exactIn(route, inputAmount) console.log(trade.tradeType) // TradeType.EXACT_INPUT console.log(trade.inputAmount.toSignificant(6)) // "1" console.log(trade.outputAmount.toSignificant(6)) // Calculated output ``` #### `Trade.exactOut(route, amountOut)` Create a trade with an exact output amount. ```typescript const outputAmount = CurrencyAmount.fromRawAmount(USDC, 2000_000000n) // 2000 USDC const trade = Trade.exactOut(route, outputAmount) console.log(trade.tradeType) // TradeType.EXACT_OUTPUT console.log(trade.inputAmount.toSignificant(6)) // Calculated input console.log(trade.outputAmount.toSignificant(6)) // "2000" ``` ### Properties #### `route` ```typescript readonly route: Route ``` The route of the trade. #### `tradeType` ```typescript readonly tradeType: TTradeType ``` `TradeType.EXACT_INPUT` or `TradeType.EXACT_OUTPUT`. #### `inputAmount` ```typescript readonly inputAmount: CurrencyAmount ``` The input amount (fixed for exact input trades). #### `outputAmount` ```typescript readonly outputAmount: CurrencyAmount ``` The output amount (fixed for exact output trades). #### `executionPrice` ```typescript readonly executionPrice: Price ``` The price at which the trade executes (output/input). ```typescript console.log(trade.executionPrice.toSignificant(6)) // "1990" USDC/WETH ``` #### `priceImpact` ```typescript readonly priceImpact: Percent ``` The percent difference between mid price and execution price. ```typescript console.log(trade.priceImpact.toSignificant(2)) // "0.5" (0.5% impact) ``` ### Methods #### `minimumAmountOut(slippageTolerance)` ```typescript minimumAmountOut(slippageTolerance: Percent): CurrencyAmount ``` Returns the minimum output amount accounting for slippage. ```typescript import { Percent } from '@uniswap/sdk-core-next' const slippage = new Percent(50, 10000) // 0.5% const minOutput = trade.minimumAmountOut(slippage) console.log(minOutput.toSignificant(6)) // For exact output trades, returns the exact output amount ``` #### `maximumAmountIn(slippageTolerance)` ```typescript maximumAmountIn(slippageTolerance: Percent): CurrencyAmount ``` Returns the maximum input amount accounting for slippage. ```typescript const slippage = new Percent(50, 10000) // 0.5% const maxInput = trade.maximumAmountIn(slippage) console.log(maxInput.toSignificant(6)) // For exact input trades, returns the exact input amount ``` #### `worstExecutionPrice(slippageTolerance)` ```typescript worstExecutionPrice(slippageTolerance: Percent): Price ``` The worst price the trade could execute at given slippage. ```typescript const worstPrice = trade.worstExecutionPrice(slippage) console.log(worstPrice.toSignificant(6)) ``` ### Finding Best Trades #### `Trade.bestTradeExactIn(pairs, amountIn, currencyOut, options?)` Finds the best trades for an exact input amount. ```typescript import { Trade, Pair } from '@uniswap/v2-sdk-next' const pairs: Pair[] = [/* all available pairs */] const amountIn = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') const trades = Trade.bestTradeExactIn( pairs, amountIn, USDC, { maxNumResults: 3, maxHops: 3 } ) // trades is sorted best to worst const bestTrade = trades[0] console.log(bestTrade.outputAmount.toSignificant(6)) console.log(bestTrade.priceImpact.toSignificant(2)) ``` #### `Trade.bestTradeExactOut(pairs, currencyIn, amountOut, options?)` Finds the best trades for an exact output amount. ```typescript const amountOut = CurrencyAmount.fromRawAmount(USDC, 2000_000000n) const trades = Trade.bestTradeExactOut( pairs, WETH, amountOut, { maxNumResults: 3, maxHops: 3 } ) const bestTrade = trades[0] console.log(bestTrade.inputAmount.toSignificant(6)) ``` #### Options ```typescript interface BestTradeOptions { maxNumResults?: number // default: 3 maxHops?: number // default: 3 } ``` ### Trade Comparison Trades are compared by: 1. Output amount (higher is better) 2. Input amount (lower is better for same output) 3. Price impact (lower is better) 4. Number of hops (fewer is better) ```typescript import { tradeComparator, inputOutputComparator } from '@uniswap/v2-sdk-next' // Sort trades by quality trades.sort(tradeComparator) ``` ### Example: Complete Trade Flow ```typescript import { Pair, Route, Trade } from '@uniswap/v2-sdk-next' import { Token, CurrencyAmount, Percent } from '@uniswap/sdk-core-next' // 1. Fetch pair data from chain const pair = new Pair( CurrencyAmount.fromRawAmount(WETH, reserves.weth), CurrencyAmount.fromRawAmount(USDC, reserves.usdc) ) // 2. Create route and trade const route = new Route([pair], WETH, USDC) const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') const trade = Trade.exactIn(route, inputAmount) // 3. Check trade details console.log(`Input: ${trade.inputAmount.toSignificant(6)} WETH`) console.log(`Output: ${trade.outputAmount.toSignificant(6)} USDC`) console.log(`Price: ${trade.executionPrice.toSignificant(6)} USDC/WETH`) console.log(`Price Impact: ${trade.priceImpact.toSignificant(2)}%`) // 4. Calculate with slippage const slippage = new Percent(50, 10000) // 0.5% console.log(`Min Output: ${trade.minimumAmountOut(slippage).toSignificant(6)} USDC`) ``` ## Addresses Contract address mappings for Uniswap deployments across supported chains. ### Import ```typescript import { V2_FACTORY_ADDRESSES, V2_ROUTER_ADDRESSES, V3_CORE_FACTORY_ADDRESSES, QUOTER_ADDRESSES, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, MULTICALL_ADDRESSES, CHAIN_TO_ADDRESSES_MAP, SWAP_ROUTER_02_ADDRESSES, } from '@uniswap/sdk-core-next' ``` ### V2 Addresses #### `V2_FACTORY_ADDRESSES` V2 factory contract addresses by chain. ```typescript import { V2_FACTORY_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const mainnetFactory = V2_FACTORY_ADDRESSES[ChainId.MAINNET] // '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' ``` #### `V2_ROUTER_ADDRESSES` V2 router contract addresses by chain. ```typescript import { V2_ROUTER_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const router = V2_ROUTER_ADDRESSES[ChainId.MAINNET] // '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' ``` ### V3 Addresses #### `V3_CORE_FACTORY_ADDRESSES` V3 factory contract addresses. ```typescript import { V3_CORE_FACTORY_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const v3Factory = V3_CORE_FACTORY_ADDRESSES[ChainId.MAINNET] // '0x1F98431c8aD98523631AE4a59f267346ea31F984' ``` #### `QUOTER_ADDRESSES` V3 Quoter contract addresses. ```typescript import { QUOTER_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const quoter = QUOTER_ADDRESSES[ChainId.MAINNET] // '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6' ``` #### `NONFUNGIBLE_POSITION_MANAGER_ADDRESSES` V3 NFT Position Manager addresses. ```typescript import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const positionManager = NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[ChainId.MAINNET] // '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' ``` #### `SWAP_ROUTER_02_ADDRESSES(chainId)` Function to get SwapRouter02 address. ```typescript import { SWAP_ROUTER_02_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const swapRouter = SWAP_ROUTER_02_ADDRESSES(ChainId.MAINNET) // '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' ``` ### Universal Addresses #### `MULTICALL_ADDRESSES` Multicall contract addresses for batch calls. ```typescript import { MULTICALL_ADDRESSES, ChainId } from '@uniswap/sdk-core-next' const multicall = MULTICALL_ADDRESSES[ChainId.MAINNET] // '0x1F98415757620B543A52E61c46B32eB19261F984' ``` ### Complete Chain Addresses #### `CHAIN_TO_ADDRESSES_MAP` Complete address mapping for each chain. ```typescript import { CHAIN_TO_ADDRESSES_MAP, ChainId } from '@uniswap/sdk-core-next' const mainnetAddresses = CHAIN_TO_ADDRESSES_MAP[ChainId.MAINNET] /* { v3CoreFactoryAddress: '0x1F98431c8aD98523631AE4a59f267346ea31F984', multicallAddress: '0x1F98415757620B543A52E61c46B32eB19261F984', quoterAddress: '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6', v3MigratorAddress: '0xA5644E29708357803b5A882D272c41cC0dF92B34', nonfungiblePositionManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88', mixedRouteQuoterV1Address: '0x84E44095eeBfEC7793Cd7d5b57B7e401D7f1cA2E', v4PoolManagerAddress: '0x000000000004444c5dc75cB358380D2e3dE08A90', v4PositionManagerAddress: '0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e', v4StateView: '0x7ffe42c4a5deea5b0fec41c94c136cf115597227', v4QuoterAddress: '0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203', } */ ``` ### V4 Addresses V4 addresses are included in `CHAIN_TO_ADDRESSES_MAP`: ```typescript import { CHAIN_TO_ADDRESSES_MAP, ChainId } from '@uniswap/sdk-core-next' const addresses = CHAIN_TO_ADDRESSES_MAP[ChainId.MAINNET] const v4PoolManager = addresses.v4PoolManagerAddress // '0x000000000004444c5dc75cB358380D2e3dE08A90' const v4PositionManager = addresses.v4PositionManagerAddress // '0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e' const v4StateView = addresses.v4StateView // '0x7ffe42c4a5deea5b0fec41c94c136cf115597227' const v4Quoter = addresses.v4QuoterAddress // '0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203' ``` ### Governance Addresses ```typescript import { UNI_ADDRESSES, GOVERNANCE_BRAVO_ADDRESSES, TIMELOCK_ADDRESSES, ChainId, } from '@uniswap/sdk-core-next' const uni = UNI_ADDRESSES[ChainId.MAINNET] // '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984' const governor = GOVERNANCE_BRAVO_ADDRESSES[ChainId.MAINNET] // '0x408ED6354d4973f66138C91495F2f2FCbd8724C3' const timelock = TIMELOCK_ADDRESSES[ChainId.MAINNET] // '0x1a9C8182C09F50C8318d769245beA52c32BE35BC' ``` ### Type Definition ```typescript type ChainAddresses = { v3CoreFactoryAddress: Address.Address multicallAddress: Address.Address quoterAddress: Address.Address v3MigratorAddress?: Address.Address nonfungiblePositionManagerAddress?: Address.Address tickLensAddress?: Address.Address swapRouter02Address?: Address.Address mixedRouteQuoterV1Address?: Address.Address mixedRouteQuoterV2Address?: Address.Address v4PoolManagerAddress?: Address.Address v4PositionManagerAddress?: Address.Address v4StateView?: Address.Address v4QuoterAddress?: Address.Address } ``` ## Chains Chain IDs and native currency configurations for supported networks. ### Import ```typescript import { ChainId, SUPPORTED_CHAINS, NativeCurrencyName, type SupportedChainsType, } from '@uniswap/sdk-core-next' ``` ### ChainId Enum ```typescript enum ChainId { // Mainnets MAINNET = 1, OPTIMISM = 10, ARBITRUM_ONE = 42161, POLYGON = 137, BNB = 56, AVALANCHE = 43114, BASE = 8453, ZORA = 7777777, BLAST = 81457, ZKSYNC = 324, WORLDCHAIN = 480, UNICHAIN = 130, CELO = 42220, GNOSIS = 100, MOONBEAM = 1284, ROOTSTOCK = 30, SONEIUM = 1868, MONAD = 143, XLAYER = 196, // Testnets GOERLI = 5, SEPOLIA = 11155111, OPTIMISM_GOERLI = 420, OPTIMISM_SEPOLIA = 11155420, ARBITRUM_GOERLI = 421613, ARBITRUM_SEPOLIA = 421614, POLYGON_MUMBAI = 80001, BASE_GOERLI = 84531, BASE_SEPOLIA = 84532, ZORA_SEPOLIA = 999999999, CELO_ALFAJORES = 44787, UNICHAIN_SEPOLIA = 1301, MONAD_TESTNET = 10143, } ``` ### Usage ```typescript import { ChainId, Ether, Token } from '@uniswap/sdk-core-next' // Create ETH for a specific chain const eth = Ether.onChain(ChainId.MAINNET) // Create a token on Arbitrum const ARB = new Token( ChainId.ARBITRUM_ONE, '0x912CE59144191C1204E64559FE8253a0e49E6548', 18, 'ARB', 'Arbitrum' ) // Check chain support function isSupported(chainId: number): boolean { return SUPPORTED_CHAINS.includes(chainId as SupportedChainsType) } ``` ### SUPPORTED\_CHAINS Array of all supported chain IDs: ```typescript const SUPPORTED_CHAINS = [ ChainId.MAINNET, ChainId.OPTIMISM, ChainId.ARBITRUM_ONE, ChainId.POLYGON, ChainId.BNB, ChainId.AVALANCHE, ChainId.BASE, ChainId.ZORA, ChainId.BLAST, ChainId.ZKSYNC, ChainId.WORLDCHAIN, ChainId.UNICHAIN, ChainId.CELO, ChainId.ROOTSTOCK, ChainId.SONEIUM, ChainId.MONAD, ChainId.XLAYER, // ... testnets ] as const ``` ### NativeCurrencyName Names for native currencies on different chains: ```typescript enum NativeCurrencyName { ETHER = 'ETH', MATIC = 'MATIC', CELO = 'CELO', GNOSIS = 'XDAI', MOONBEAM = 'GLMR', BNB = 'BNB', AVAX = 'AVAX', ROOTSTOCK = 'RBTC', } ``` ### Chain Details | Chain | ID | Native | Type | | ----------- | ------- | ------ | --------- | | Ethereum | 1 | ETH | Mainnet | | Optimism | 10 | ETH | L2 | | Arbitrum | 42161 | ETH | L2 | | Polygon | 137 | MATIC | Sidechain | | BNB Chain | 56 | BNB | L1 | | Avalanche | 43114 | AVAX | L1 | | Base | 8453 | ETH | L2 | | Zora | 7777777 | ETH | L2 | | Blast | 81457 | ETH | L2 | | zkSync Era | 324 | ETH | L2 | | World Chain | 480 | ETH | L2 | | Unichain | 130 | ETH | L2 | | Celo | 42220 | CELO | L1 | ### Type Safety ```typescript import { ChainId, type SupportedChainsType } from '@uniswap/sdk-core-next' // Type-safe chain ID function getChainName(chainId: SupportedChainsType): string { switch (chainId) { case ChainId.MAINNET: return 'Ethereum' case ChainId.OPTIMISM: return 'Optimism' case ChainId.ARBITRUM_ONE: return 'Arbitrum One' // ... TypeScript ensures all chains are handled default: return 'Unknown' } } ``` ## computePriceImpact Computes the percent difference between the mid price and the execution price of a trade. ### Import ```typescript import { computePriceImpact } from '@uniswap/sdk-core-next' ``` ### Function Signature ```typescript function computePriceImpact( midPrice: Price, inputAmount: CurrencyAmount, outputAmount: CurrencyAmount ): Percent ``` ### Parameters | Name | Type | Description | | -------------- | ------------------------ | ------------------------------ | | `midPrice` | `Price` | The mid price before the trade | | `inputAmount` | `CurrencyAmount` | The input amount of the trade | | `outputAmount` | `CurrencyAmount` | The output amount of the trade | ### Returns `Percent` - The price impact as a percentage (positive means worse execution than mid price). ### Formula ``` priceImpact = (quotedOutput - actualOutput) / quotedOutput ``` Where: * `quotedOutput` = midPrice \* inputAmount (expected output at mid price) * `actualOutput` = outputAmount (what you actually receive) ### Example ```typescript import { computePriceImpact, Price, CurrencyAmount, Token, } from '@uniswap/sdk-core-next' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Mid price: 1 WETH = 2000 USDC const midPrice = new Price(WETH, USDC, 1n, 2000n) // Trade: Swap 1 WETH const inputAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // Actual output: 1980 USDC (worse than mid price due to slippage) const outputAmount = CurrencyAmount.fromRawAmount(USDC, 1980_000000n) const priceImpact = computePriceImpact(midPrice, inputAmount, outputAmount) console.log(priceImpact.toSignificant(4)) // "1" (1% price impact) console.log(priceImpact.toFixed(2)) // "1.00" // Expected: 2000 USDC, Got: 1980 USDC // Impact = (2000 - 1980) / 2000 = 0.01 = 1% ``` ### Use Cases #### Trade Warning Thresholds ```typescript import { Percent, computePriceImpact } from '@uniswap/sdk-core-next' const LOW_IMPACT = new Percent(1, 100) // 1% const MEDIUM_IMPACT = new Percent(3, 100) // 3% const HIGH_IMPACT = new Percent(5, 100) // 5% function getImpactWarning( midPrice: Price, inputAmount: CurrencyAmount, outputAmount: CurrencyAmount ): 'none' | 'low' | 'medium' | 'high' { const impact = computePriceImpact(midPrice, inputAmount, outputAmount) if (impact.lessThan(LOW_IMPACT)) return 'none' if (impact.lessThan(MEDIUM_IMPACT)) return 'low' if (impact.lessThan(HIGH_IMPACT)) return 'medium' return 'high' } ``` #### With Pool Data ```typescript import { Pool } from '@uniswap/v3-sdk-next' async function getTradeImpact(pool: Pool, inputAmount: CurrencyAmount) { // Get mid price from pool const midPrice = pool.priceOf(inputAmount.currency) // Simulate the trade const [outputAmount] = await pool.getOutputAmount(inputAmount) // Calculate impact return computePriceImpact(midPrice, inputAmount, outputAmount) } ``` ### Notes * A positive price impact means the execution price is worse than the mid price * Large trades in low liquidity pools will have higher price impact * Price impact is different from slippage tolerance (slippage is the maximum acceptable deviation) ## Constants Global constants and types used throughout the SDK. ### Import ```typescript import { TradeType, Rounding, MaxUint256, toBigInt, type BigintIsh, } from '@uniswap/sdk-core-next' ``` ### Types #### `BigintIsh` A type that can be converted to `bigint`. ```typescript type BigintIsh = bigint | string | number ``` ```typescript import { toBigInt, type BigintIsh } from '@uniswap/sdk-core-next' const a: BigintIsh = 100n const b: BigintIsh = '100' const c: BigintIsh = 100 toBigInt(a) // 100n toBigInt(b) // 100n toBigInt(c) // 100n ``` ### Enums #### `TradeType` Direction of a trade. ```typescript enum TradeType { EXACT_INPUT = 0, EXACT_OUTPUT = 1, } ``` | Value | Description | | -------------- | ---------------------------------------- | | `EXACT_INPUT` | The input amount is fixed, output varies | | `EXACT_OUTPUT` | The output amount is fixed, input varies | ```typescript import { TradeType } from '@uniswap/sdk-core-next' // Exact input: "Swap exactly 1 ETH for USDC" const tradeType = TradeType.EXACT_INPUT // Exact output: "Swap ETH to get exactly 2000 USDC" const tradeType = TradeType.EXACT_OUTPUT ``` #### `Rounding` Rounding mode for decimal operations. ```typescript enum Rounding { ROUND_DOWN = 0, ROUND_HALF_UP = 1, ROUND_UP = 2, } ``` | Value | Description | | --------------- | --------------------------------------------- | | `ROUND_DOWN` | Truncate toward zero | | `ROUND_HALF_UP` | Round half away from zero (standard rounding) | | `ROUND_UP` | Always round away from zero | ```typescript import { Fraction, Rounding } from '@uniswap/sdk-core-next' const f = new Fraction(5, 3) // 1.666... f.toFixed(1, {}, Rounding.ROUND_DOWN) // "1.6" f.toFixed(1, {}, Rounding.ROUND_HALF_UP) // "1.7" f.toFixed(1, {}, Rounding.ROUND_UP) // "1.7" const f2 = new Fraction(3, 2) // 1.5 f2.toFixed(0, {}, Rounding.ROUND_DOWN) // "1" f2.toFixed(0, {}, Rounding.ROUND_HALF_UP) // "2" f2.toFixed(0, {}, Rounding.ROUND_UP) // "2" ``` ### Constants #### `MaxUint256` Maximum value for a uint256. ```typescript const MaxUint256 = 2n ** 256n - 1n ``` ```typescript import { MaxUint256 } from '@uniswap/sdk-core-next' console.log(MaxUint256) // 115792089237316195423570985008687907853269984665640564039457584007913129639935n // Common use: approval amounts const UNLIMITED_APPROVAL = MaxUint256 ``` ### Functions #### `toBigInt(value)` Safely converts a `BigintIsh` value to `bigint`. ```typescript function toBigInt(value: BigintIsh): bigint ``` ```typescript import { toBigInt } from '@uniswap/sdk-core-next' // From bigint toBigInt(100n) // 100n // From string (decimal) toBigInt('100') // 100n // From string (hex) toBigInt('0x64') // 100n // From number toBigInt(100) // 100n // Non-integer number throws toBigInt(1.5) // throws "Cannot convert non-integer 1.5 to bigint" ``` ## CurrencyAmount The `CurrencyAmount` class represents an amount of a specific currency with precise arithmetic. ### Import ```typescript import { CurrencyAmount } from '@uniswap/sdk-core-next' ``` ### Creating Amounts #### `fromRawAmount(currency, rawAmount)` Create from the raw/smallest unit amount (e.g., wei for ETH). ```typescript import { CurrencyAmount, Token, Ether } from '@uniswap/sdk-core-next' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // 1 USDC = 1,000,000 raw units (6 decimals) const amount = CurrencyAmount.fromRawAmount(USDC, 1000000n) console.log(amount.toExact()) // "1" console.log(amount.quotient) // 1000000n // 1 ETH = 10^18 wei const ethAmount = CurrencyAmount.fromRawAmount(Ether.onChain(1), '1000000000000000000') ``` #### `fromFractionalAmount(currency, numerator, denominator)` Create from a fractional amount (useful for precise calculations). ```typescript // 0.5 USDC const halfUsdc = CurrencyAmount.fromFractionalAmount(USDC, 1, 2) // From a calculation result const result = CurrencyAmount.fromFractionalAmount(USDC, 1234567n, 1000000n) ``` ### Properties #### `currency` ```typescript readonly currency: T ``` The currency this amount is denominated in. #### `decimalScale` ```typescript readonly decimalScale: bigint ``` The scale factor based on decimals (10^decimals). ```typescript const usdcAmount = CurrencyAmount.fromRawAmount(USDC, 1000000n) usdcAmount.decimalScale // 1000000n (10^6) ``` #### `quotient` ```typescript get quotient(): bigint ``` The raw integer amount (inherited from Fraction). #### `wrapped` ```typescript get wrapped(): CurrencyAmount ``` Returns the amount as a wrapped token amount. ```typescript const ethAmount = CurrencyAmount.fromRawAmount(Ether.onChain(1), '1000000000000000000') const wethAmount = ethAmount.wrapped wethAmount.currency.symbol // 'WETH' wethAmount.quotient // Same value ``` ### Methods #### `add(other)` ```typescript add(other: CurrencyAmount): CurrencyAmount ``` Add two amounts of the same currency. ```typescript const a = CurrencyAmount.fromRawAmount(USDC, 1000000n) const b = CurrencyAmount.fromRawAmount(USDC, 2000000n) const sum = a.add(b) sum.toExact() // "3" ``` **Throws**: If currencies don't match. #### `subtract(other)` ```typescript subtract(other: CurrencyAmount): CurrencyAmount ``` Subtract an amount. ```typescript const a = CurrencyAmount.fromRawAmount(USDC, 3000000n) const b = CurrencyAmount.fromRawAmount(USDC, 1000000n) const diff = a.subtract(b) diff.toExact() // "2" ``` #### `multiply(other)` ```typescript multiply(other: Fraction | BigintIsh): CurrencyAmount ``` Multiply by a fraction or number. ```typescript const amount = CurrencyAmount.fromRawAmount(USDC, 1000000n) const doubled = amount.multiply(2) doubled.toExact() // "2" // Multiply by percentage (for slippage) const slippage = new Percent(5, 100) // 5% const reduced = amount.multiply(new Percent(95, 100)) ``` #### `divide(other)` ```typescript divide(other: Fraction | BigintIsh): CurrencyAmount ``` Divide by a fraction or number. ```typescript const amount = CurrencyAmount.fromRawAmount(USDC, 2000000n) const half = amount.divide(2) half.toExact() // "1" ``` #### `toSignificant(significantDigits?, format?, rounding?)` ```typescript toSignificant( significantDigits?: number, // default: 6 format?: { groupSeparator?: string }, rounding?: Rounding // default: ROUND_DOWN ): string ``` Format with significant digits, accounting for decimals. ```typescript const amount = CurrencyAmount.fromRawAmount(USDC, 1234567n) // 1.234567 USDC amount.toSignificant(4) // "1.235" amount.toSignificant(2) // "1.2" ``` #### `toFixed(decimalPlaces?, format?, rounding?)` ```typescript toFixed( decimalPlaces?: number, // default: currency.decimals format?: { groupSeparator?: string }, rounding?: Rounding // default: ROUND_DOWN ): string ``` Format with fixed decimal places. ```typescript const amount = CurrencyAmount.fromRawAmount(USDC, 1234567n) // 1.234567 USDC amount.toFixed(2) // "1.23" amount.toFixed(4) // "1.2345" amount.toFixed(6) // "1.234567" ``` **Throws**: If decimalPlaces > currency.decimals. #### `toExact(format?)` ```typescript toExact(format?: { groupSeparator?: string }): string ``` Format with all decimal places (no rounding). ```typescript const amount = CurrencyAmount.fromRawAmount(USDC, 1234567n) amount.toExact() // "1.234567" // With thousands separator const largeAmount = CurrencyAmount.fromRawAmount(USDC, 1234567890n) largeAmount.toExact({ groupSeparator: ',' }) // "1,234.56789" ``` ### Example: Working with Trade Amounts ```typescript import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core-next' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Input amount const inputAmount = CurrencyAmount.fromRawAmount(USDC, 1000_000000n) // 1000 USDC // Slippage tolerance const slippageTolerance = new Percent(50, 10000) // 0.5% // Minimum output (for exact input trade) const outputAmount = CurrencyAmount.fromRawAmount(WETH, 500000000000000000n) // 0.5 WETH const minOutput = outputAmount.multiply( new Percent(10000 - 50, 10000) // 99.5% ) console.log(`Input: ${inputAmount.toSignificant(6)} ${inputAmount.currency.symbol}`) console.log(`Expected output: ${outputAmount.toSignificant(6)} ${outputAmount.currency.symbol}`) console.log(`Minimum output: ${minOutput.toSignificant(6)} ${minOutput.currency.symbol}`) ``` ## Currency The `Currency` type is a union of `Token` and `NativeCurrency`. It represents any fungible asset that can be used in Uniswap. ### Import ```typescript import type { Currency } from '@uniswap/sdk-core-next' ``` ### Type Definition ```typescript type Currency = NativeCurrency | Token ``` ### Usage Currency is used as a generic type throughout the SDK to handle both native currencies (like ETH) and ERC20 tokens uniformly. ```typescript import { Token, Ether, CurrencyAmount, type Currency } from '@uniswap/sdk-core-next' // Both are valid Currency types const eth: Currency = Ether.onChain(1) const usdc: Currency = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Create amounts from any currency const ethAmount = CurrencyAmount.fromRawAmount(eth, '1000000000000000000') const usdcAmount = CurrencyAmount.fromRawAmount(usdc, '1000000') ``` ### Type Guards You can use the `isNative` and `isToken` properties to narrow the type: ```typescript function getAddress(currency: Currency): string { if (currency.isToken) { // TypeScript knows this is a Token return currency.address } // Native currency - return wrapped address return currency.wrapped.address } ``` ### Common Properties All currencies share these properties from `BaseCurrency`: | Property | Type | Description | | ---------- | --------------------- | ---------------------------------------- | | `chainId` | `number` | The chain ID where the currency exists | | `decimals` | `number` | Number of decimal places | | `symbol` | `string \| undefined` | Ticker symbol | | `name` | `string \| undefined` | Full name | | `isNative` | `boolean` | True for native currencies | | `isToken` | `boolean` | True for ERC20 tokens | | `wrapped` | `Token` | The wrapped version (e.g., WETH for ETH) | ### Methods #### `equals(other)` ```typescript equals(other: Currency): boolean ``` Returns true if the currencies are equivalent. ```typescript const eth = Ether.onChain(1) const eth2 = Ether.onChain(1) const usdc = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) eth.equals(eth2) // true eth.equals(usdc) // false ``` ### Working with Currency in Generics ```typescript import { CurrencyAmount, type Currency } from '@uniswap/sdk-core-next' // Generic function that works with any currency function formatAmount(amount: CurrencyAmount): string { return `${amount.toSignificant(6)} ${amount.currency.symbol}` } // Works with both native and token amounts const ethAmount = CurrencyAmount.fromRawAmount(Ether.onChain(1), '1000000000000000000') const usdcAmount = CurrencyAmount.fromRawAmount(usdc, '1000000') formatAmount(ethAmount) // "1 ETH" formatAmount(usdcAmount) // "1 USDC" ``` ## Ether The `Ether` class represents the native ETH currency on Ethereum mainnet and testnets. ### Import ```typescript import { Ether } from '@uniswap/sdk-core-next' ``` ### Creating Ether Use the static `onChain` method to get an Ether instance: ```typescript import { Ether } from '@uniswap/sdk-core-next' // Ethereum mainnet const eth = Ether.onChain(1) // Sepolia testnet const sepoliaEth = Ether.onChain(11155111) // Instances are cached - same chain returns same instance Ether.onChain(1) === Ether.onChain(1) // true ``` ### Properties #### `isNative` ```typescript readonly isNative: true ``` Always `true` for Ether. #### `isToken` ```typescript readonly isToken: false ``` Always `false` for Ether. #### `chainId` ```typescript readonly chainId: number ``` The chain ID (1 for mainnet). #### `decimals` ```typescript readonly decimals: 18 ``` Always 18 for ETH. #### `symbol` ```typescript readonly symbol: 'ETH' ``` Always 'ETH'. #### `name` ```typescript readonly name: 'Ether' ``` Always 'Ether'. #### `wrapped` ```typescript get wrapped(): Token ``` Returns the WETH9 token for the chain. ```typescript const eth = Ether.onChain(1) const weth = eth.wrapped console.log(weth.address) // '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' console.log(weth.symbol) // 'WETH' ``` **Throws**: If WETH9 is not defined for the chain. ### Methods #### `equals(other)` ```typescript equals(other: Currency): boolean ``` Returns `true` if the other currency is also a native currency on the same chain. ```typescript const eth1 = Ether.onChain(1) const eth2 = Ether.onChain(1) const sepoliaEth = Ether.onChain(11155111) eth1.equals(eth2) // true eth1.equals(sepoliaEth) // false (different chain) ``` ### Example Usage ```typescript import { Ether, CurrencyAmount, Token } from '@uniswap/sdk-core-next' const eth = Ether.onChain(1) const weth = eth.wrapped // Create an ETH amount (1 ETH) const ethAmount = CurrencyAmount.fromRawAmount(eth, '1000000000000000000') console.log(ethAmount.toSignificant(6)) // "1" console.log(ethAmount.currency.symbol) // "ETH" // Convert to wrapped amount for contract interactions const wrappedAmount = ethAmount.wrapped console.log(wrappedAmount.currency.symbol) // "WETH" console.log(wrappedAmount.currency.address) // WETH address ``` ### Supported Chains Ether can be created for any chain, but the `wrapped` property requires a WETH9 entry in the [WETH9](/sdk-core/weth9) mapping. ## Fraction The `Fraction` class provides precise fractional arithmetic using BigInt numerator and denominator. ### Import ```typescript import { Fraction } from '@uniswap/sdk-core-next' ``` ### Constructor ```typescript new Fraction(numerator: BigintIsh, denominator?: BigintIsh) ``` #### Parameters | Name | Type | Default | Description | | ------------- | ----------- | ------- | --------------- | | `numerator` | `BigintIsh` | - | The numerator | | `denominator` | `BigintIsh` | `1n` | The denominator | `BigintIsh` can be `bigint`, `string`, or `number`. ### Example ```typescript import { Fraction } from '@uniswap/sdk-core-next' // Create fractions const half = new Fraction(1, 2) const quarter = new Fraction(1n, 4n) const fromString = new Fraction('100', '3') // Arithmetic const sum = half.add(quarter) // 3/4 const diff = half.subtract(quarter) // 1/4 const product = half.multiply(2) // 1 const quotient = half.divide(2) // 1/4 // Formatting half.toSignificant(2) // "0.5" half.toFixed(4) // "0.5000" ``` ### Properties #### `numerator` ```typescript readonly numerator: bigint ``` #### `denominator` ```typescript readonly denominator: bigint ``` #### `quotient` ```typescript get quotient(): bigint ``` Returns the floor division result (numerator / denominator). ```typescript const f = new Fraction(7, 3) f.quotient // 2n ``` #### `remainder` ```typescript get remainder(): Fraction ``` Returns the remainder after floor division. ```typescript const f = new Fraction(7, 3) f.remainder // Fraction(1, 3) ``` #### `asFraction` ```typescript get asFraction(): Fraction ``` Returns a new Fraction with the same numerator/denominator. Useful for converting subclasses back to Fraction. ### Methods #### `invert()` ```typescript invert(): Fraction ``` Returns a new fraction with numerator and denominator swapped. ```typescript new Fraction(3, 4).invert() // Fraction(4, 3) ``` #### `add(other)` ```typescript add(other: Fraction | BigintIsh): Fraction ``` Returns a new fraction that is the sum of this and the other. ```typescript new Fraction(1, 4).add(new Fraction(1, 4)) // Fraction(2, 4) = 1/2 new Fraction(1, 2).add(1) // Fraction(3, 2) ``` #### `subtract(other)` ```typescript subtract(other: Fraction | BigintIsh): Fraction ``` Returns a new fraction that is this minus the other. ```typescript new Fraction(3, 4).subtract(new Fraction(1, 4)) // Fraction(2, 4) = 1/2 ``` #### `multiply(other)` ```typescript multiply(other: Fraction | BigintIsh): Fraction ``` Returns a new fraction that is the product. ```typescript new Fraction(1, 2).multiply(new Fraction(2, 3)) // Fraction(2, 6) = 1/3 new Fraction(1, 2).multiply(4) // Fraction(4, 2) = 2 ``` #### `divide(other)` ```typescript divide(other: Fraction | BigintIsh): Fraction ``` Returns a new fraction that is the quotient. ```typescript new Fraction(1, 2).divide(new Fraction(3, 4)) // Fraction(4, 6) = 2/3 new Fraction(1, 2).divide(2) // Fraction(1, 4) ``` #### `lessThan(other)` ```typescript lessThan(other: Fraction | BigintIsh): boolean ``` ```typescript new Fraction(1, 4).lessThan(new Fraction(1, 2)) // true ``` #### `equalTo(other)` ```typescript equalTo(other: Fraction | BigintIsh): boolean ``` ```typescript new Fraction(1, 2).equalTo(new Fraction(2, 4)) // true ``` #### `greaterThan(other)` ```typescript greaterThan(other: Fraction | BigintIsh): boolean ``` ```typescript new Fraction(3, 4).greaterThan(new Fraction(1, 2)) // true ``` #### `toSignificant(significantDigits, format?, rounding?)` ```typescript toSignificant( significantDigits: number, format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Returns a string with the specified number of significant digits. ```typescript import { Rounding } from '@uniswap/sdk-core-next' const f = new Fraction(1, 3) f.toSignificant(4) // "0.3333" f.toSignificant(2) // "0.33" f.toSignificant(4, { groupSeparator: ',' }) // "0.3333" f.toSignificant(4, {}, Rounding.ROUND_UP) // "0.3334" ``` #### `toFixed(decimalPlaces, format?, rounding?)` ```typescript toFixed( decimalPlaces: number, format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Returns a string with the specified number of decimal places. ```typescript const f = new Fraction(1, 3) f.toFixed(4) // "0.3333" f.toFixed(2) // "0.33" f.toFixed(4, { groupSeparator: ',' }, Rounding.ROUND_UP) // "0.3334" ``` ### Rounding Modes ```typescript import { Rounding } from '@uniswap/sdk-core-next' Rounding.ROUND_DOWN // 0 - Truncate Rounding.ROUND_HALF_UP // 1 - Round half away from zero (default) Rounding.ROUND_UP // 2 - Always round away from zero ``` ## SDK Core The SDK Core (`@uniswap/sdk-core-next`) provides the foundational building blocks for all Uniswap SDKs. It includes core entities for representing tokens and currencies, precise arithmetic with fractions, and essential utilities. ### Features * **Type-safe Currency Handling**: Abstract currency types with Token and NativeCurrency implementations * **Precise Arithmetic**: Fraction-based math for accurate DeFi calculations * **Native BigInt**: All numeric operations use native JavaScript BigInt * **Address Validation**: Zod-based schema validation with checksum verification ### Installation ```bash npm install @uniswap/sdk-core-next ``` ```bash pnpm add @uniswap/sdk-core-next ``` ```bash yarn add @uniswap/sdk-core-next ``` ### Quick Start ```typescript import { Token, CurrencyAmount, Percent, Price } from '@uniswap/sdk-core-next' // Create a token const USDC = new Token( 1, // chainId (Ethereum mainnet) '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, // decimals 'USDC', 'USD Coin' ) // Create a currency amount const amount = CurrencyAmount.fromRawAmount(USDC, 1000000n) // 1 USDC // Format for display console.log(amount.toSignificant(6)) // "1" console.log(amount.toFixed(2)) // "1.00" // Work with percentages const slippage = new Percent(50, 10000) // 0.5% const minAmount = amount.multiply(new Percent(9950, 10000)) ``` ### Modules #### Entities Core data structures for representing currencies and tokens: * [Token](/sdk-core/token) - ERC20 token representation * [Currency](/sdk-core/currency) - Union type of Token and NativeCurrency * [Ether](/sdk-core/ether) - ETH representation for mainnet * [NativeCurrency](/sdk-core/native-currency) - Abstract base for chain-native currencies * [WETH9](/sdk-core/weth9) - Wrapped Ether token addresses #### Fractions Precise fractional arithmetic for DeFi: * [Fraction](/sdk-core/fraction) - Base fraction class with arbitrary precision * [CurrencyAmount](/sdk-core/currency-amount) - Amount of a specific currency * [Price](/sdk-core/price) - Exchange rate between two currencies * [Percent](/sdk-core/percent) - Percentage representation #### Utilities Helper functions for common operations: * [computePriceImpact](/sdk-core/compute-price-impact) - Calculate price impact of trades * [validateAndParseAddress](/sdk-core/validate-and-parse-address) - Address validation with checksum * [sqrt](/sdk-core/sqrt) - BigInt square root * [sortedInsert](/sdk-core/sorted-insert) - Insert into sorted array #### Configuration Chain and address configuration: * [Constants](/sdk-core/constants) - Global constants and rounding modes * [Chains](/sdk-core/chains) - Supported chain configurations * [Addresses](/sdk-core/addresses) - Contract address mappings ## Installation ### Package Manager :::code-group ```bash [npm] npm install @uniswap/sdk-core-next ``` ```bash [pnpm] pnpm add @uniswap/sdk-core-next ``` ```bash [yarn] yarn add @uniswap/sdk-core-next ``` ::: ### Requirements * **Node.js**: 18.x or later (for native BigInt support) * **TypeScript**: 5.0 or later (recommended) ### Dependencies The SDK Core has minimal dependencies: * `ox` - Web3 library for address and encoding utilities * `tiny-invariant` - Runtime assertions * `zod` - Schema validation ### Usage Import what you need from the package: ```typescript import { Token, CurrencyAmount, Price, Percent, Fraction, Ether, WETH9, validateAndParseAddress, } from '@uniswap/sdk-core-next' ``` ### TypeScript Configuration For the best experience, ensure your `tsconfig.json` has: ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true } } ``` ### ESM Only This package is ESM-only. If you're using CommonJS, you'll need to use dynamic imports: ```javascript const sdk = await import('@uniswap/sdk-core-next') ``` Or configure your bundler to handle ESM modules. ## NativeCurrency The `NativeCurrency` abstract class is the base for chain-native currencies like ETH, MATIC, or AVAX. ### Import ```typescript import { NativeCurrency } from '@uniswap/sdk-core-next' ``` ### Class Definition ```typescript abstract class NativeCurrency extends BaseCurrency { public readonly isNative = true public readonly isToken = false } ``` `NativeCurrency` is abstract and cannot be instantiated directly. Use concrete implementations like [Ether](/sdk-core/ether) or create your own for other chains. ### Creating a Custom Native Currency ```typescript import { NativeCurrency, Token, type Currency } from '@uniswap/sdk-core-next' class Matic extends NativeCurrency { private static _cache: { [chainId: number]: Matic } = {} protected constructor(chainId: number) { super(chainId, 18, 'MATIC', 'Polygon') } public get wrapped(): Token { // WMATIC on Polygon return new Token( this.chainId, '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', 18, 'WMATIC', 'Wrapped MATIC' ) } public static onChain(chainId: number): Matic { if (!Matic._cache[chainId]) { Matic._cache[chainId] = new Matic(chainId) } return Matic._cache[chainId] } public equals(other: Currency): boolean { return other.isNative && other.chainId === this.chainId } } // Usage const matic = Matic.onChain(137) console.log(matic.symbol) // 'MATIC' console.log(matic.wrapped.symbol) // 'WMATIC' ``` ### Properties #### `isNative` ```typescript readonly isNative: true ``` Always `true` for native currencies. #### `isToken` ```typescript readonly isToken: false ``` Always `false` for native currencies. ### Inherited from BaseCurrency | Property | Type | Description | | ---------- | --------------------- | --------------------------- | | `chainId` | `number` | The chain ID | | `decimals` | `number` | Decimal places (usually 18) | | `symbol` | `string \| undefined` | Currency symbol | | `name` | `string \| undefined` | Currency name | ### Abstract Methods Implementations must provide: #### `equals(other)` ```typescript abstract equals(other: Currency): boolean ``` Check if two currencies are equivalent. #### `wrapped` ```typescript abstract get wrapped(): Token ``` Return the wrapped version of the native currency (e.g., WETH for ETH). ### Use Cases Native currencies are used when: 1. **V4 Pools**: V4 supports native ETH directly in pools 2. **Gas Payments**: Native currency for transaction fees 3. **Wrapping**: Converting native to wrapped for V2/V3 pools ```typescript import { Ether, CurrencyAmount } from '@uniswap/sdk-core-next' const eth = Ether.onChain(1) // Create an ETH amount const amount = CurrencyAmount.fromRawAmount(eth, '1000000000000000000') // Check if native before contract interactions if (amount.currency.isNative) { // Use wrapped version for V2/V3 const wrappedAmount = amount.wrapped } ``` ## Percent The `Percent` class represents a percentage value as a fraction. ### Import ```typescript import { Percent } from '@uniswap/sdk-core-next' ``` ### Constructor ```typescript new Percent(numerator: BigintIsh, denominator?: BigintIsh) ``` #### Parameters | Name | Type | Default | Description | | ------------- | ----------- | ------- | --------------- | | `numerator` | `BigintIsh` | - | The numerator | | `denominator` | `BigintIsh` | `1n` | The denominator | ### Example ```typescript import { Percent } from '@uniswap/sdk-core-next' // 50% = 50/100 const halfPercent = new Percent(50, 100) // 0.5% = 50/10000 (common for slippage) const slippage = new Percent(50, 10000) // 1% = 1/100 const onePercent = new Percent(1, 100) // 100% = 1/1 or 100/100 const fullPercent = new Percent(1) // Display halfPercent.toSignificant(2) // "50" slippage.toSignificant(2) // "0.5" onePercent.toFixed(2) // "1.00" ``` ### Common Percentages ```typescript import { Percent } from '@uniswap/sdk-core-next' // Slippage tolerances const SLIPPAGE_05 = new Percent(50, 10000) // 0.5% const SLIPPAGE_1 = new Percent(100, 10000) // 1% const SLIPPAGE_5 = new Percent(500, 10000) // 5% // Fee percentages const FEE_001 = new Percent(1, 10000) // 0.01% const FEE_005 = new Percent(5, 10000) // 0.05% const FEE_03 = new Percent(30, 10000) // 0.3% const FEE_1 = new Percent(100, 10000) // 1% ``` ### Properties #### `isPercent` ```typescript readonly isPercent: true ``` Type discriminator to identify Percent instances. ### Methods All arithmetic methods return `Percent` instances: #### `add(other)` ```typescript add(other: Fraction | BigintIsh): Percent ``` #### `subtract(other)` ```typescript subtract(other: Fraction | BigintIsh): Percent ``` #### `multiply(other)` ```typescript multiply(other: Fraction | BigintIsh): Percent ``` #### `divide(other)` ```typescript divide(other: Fraction | BigintIsh): Percent ``` #### `toSignificant(significantDigits?, format?, rounding?)` ```typescript toSignificant( significantDigits?: number, // default: 5 format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Returns the percentage as a string (multiplied by 100). ```typescript const p = new Percent(1, 200) // 0.5% p.toSignificant(2) // "0.5" ``` #### `toFixed(decimalPlaces?, format?, rounding?)` ```typescript toFixed( decimalPlaces?: number, // default: 2 format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Returns the percentage with fixed decimals. ```typescript const p = new Percent(1, 200) p.toFixed(2) // "0.50" p.toFixed(4) // "0.5000" ``` ### Example: Slippage Calculation ```typescript import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core-next' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') // Expected output from a trade const expectedOutput = CurrencyAmount.fromRawAmount(USDC, 1000_000000n) // 1000 USDC // Slippage tolerance const slippageTolerance = new Percent(50, 10000) // 0.5% // Calculate minimum output // minOutput = expectedOutput * (1 - slippage) const slippageAdjustment = new Percent(1).subtract(slippageTolerance) const minOutput = expectedOutput.multiply(slippageAdjustment) console.log(`Expected: ${expectedOutput.toSignificant(6)} USDC`) // "1000" console.log(`Slippage: ${slippageTolerance.toSignificant(2)}%`) // "0.5" console.log(`Minimum: ${minOutput.toSignificant(6)} USDC`) // "995" // Or calculate maximum input for exact output trades const expectedInput = CurrencyAmount.fromRawAmount(USDC, 1000_000000n) const maxInput = expectedInput.multiply(new Percent(1).add(slippageTolerance)) console.log(`Maximum input: ${maxInput.toSignificant(6)} USDC`) // "1005" ``` ### Example: Price Impact ```typescript import { Percent } from '@uniswap/sdk-core-next' // Price impact thresholds const LOW_PRICE_IMPACT = new Percent(1, 100) // 1% const MEDIUM_PRICE_IMPACT = new Percent(3, 100) // 3% const HIGH_PRICE_IMPACT = new Percent(5, 100) // 5% function getPriceImpactSeverity(priceImpact: Percent): string { if (priceImpact.lessThan(LOW_PRICE_IMPACT)) { return 'low' } if (priceImpact.lessThan(MEDIUM_PRICE_IMPACT)) { return 'medium' } if (priceImpact.lessThan(HIGH_PRICE_IMPACT)) { return 'high' } return 'very high' } const impact = new Percent(25, 1000) // 2.5% console.log(getPriceImpactSeverity(impact)) // "medium" ``` ## Price The `Price` class represents an exchange rate between two currencies. ### Import ```typescript import { Price } from '@uniswap/sdk-core-next' ``` ### Constructor ```typescript // Option 1: Direct values new Price(baseCurrency, quoteCurrency, denominator, numerator) // Option 2: From amounts new Price({ baseAmount, quoteAmount }) ``` #### Parameters (Option 1) | Name | Type | Description | | --------------- | ----------- | ---------------------------- | | `baseCurrency` | `TBase` | The base (input) currency | | `quoteCurrency` | `TQuote` | The quote (output) currency | | `denominator` | `BigintIsh` | The denominator of the price | | `numerator` | `BigintIsh` | The numerator of the price | #### Parameters (Option 2) | Name | Type | Description | | ------------- | ------------------------ | ------------------------ | | `baseAmount` | `CurrencyAmount` | Amount of base currency | | `quoteAmount` | `CurrencyAmount` | Amount of quote currency | ### Example ```typescript import { Price, Token, CurrencyAmount } from '@uniswap/sdk-core-next' const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC') const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18, 'WETH') // Create price: 1 ETH = 2000 USDC // Price is quote/base, so 2000 USDC per 1 ETH const ethPrice = new Price( WETH, USDC, 1n, // denominator (1 WETH) 2000n // numerator (2000 USDC) ) console.log(ethPrice.toSignificant(6)) // "2000" // From amounts const wethAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const usdcAmount = CurrencyAmount.fromRawAmount(USDC, 2000_000000n) // 2000 USDC const priceFromAmounts = new Price({ baseAmount: wethAmount, quoteAmount: usdcAmount, }) console.log(priceFromAmounts.toSignificant(6)) // "2000" ``` ### Properties #### `baseCurrency` ```typescript readonly baseCurrency: TBase ``` The input currency (denominator of the rate). #### `quoteCurrency` ```typescript readonly quoteCurrency: TQuote ``` The output currency (numerator of the rate). #### `scalar` ```typescript readonly scalar: Fraction ``` Internal scalar for decimal adjustment. ### Methods #### `invert()` ```typescript invert(): Price ``` Returns the inverse price (swap base and quote). ```typescript const ethUsdcPrice = new Price(WETH, USDC, 1n, 2000n) // 2000 USDC/WETH const usdcEthPrice = ethUsdcPrice.invert() // 0.0005 WETH/USDC console.log(usdcEthPrice.toSignificant(6)) // "0.0005" ``` #### `multiply(other)` ```typescript multiply( other: Price ): Price ``` Multiply prices to get a derived price. The other price's base must match this price's quote. ```typescript const ethUsdc = new Price(WETH, USDC, 1n, 2000n) // ETH/USDC = 2000 const usdcDai = new Price(USDC, DAI, 1n, 1n) // USDC/DAI = 1 const ethDai = ethUsdc.multiply(usdcDai) // ETH/DAI = 2000 ``` #### `quote(currencyAmount)` ```typescript quote(currencyAmount: CurrencyAmount): CurrencyAmount ``` Convert an amount of base currency to quote currency using this price. ```typescript const ethUsdcPrice = new Price(WETH, USDC, 1n, 2000n) const wethAmount = CurrencyAmount.fromRawAmount(WETH, '1000000000000000000') // 1 WETH const usdcAmount = ethUsdcPrice.quote(wethAmount) console.log(usdcAmount.toSignificant(6)) // "2000" ``` #### `toSignificant(significantDigits?, format?, rounding?)` ```typescript toSignificant( significantDigits?: number, // default: 6 format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Format the price with significant digits, adjusted for decimal differences. ```typescript const price = new Price(WETH, USDC, 1n, 2000n) price.toSignificant(4) // "2000" price.toSignificant(2) // "2.0e+3" ``` #### `toFixed(decimalPlaces?, format?, rounding?)` ```typescript toFixed( decimalPlaces?: number, // default: 4 format?: { groupSeparator?: string }, rounding?: Rounding ): string ``` Format the price with fixed decimal places. ```typescript const price = new Price(WETH, USDC, 1n, 2000n) price.toFixed(2) // "2000.00" price.toFixed(0) // "2000" ``` ### Example: Price from Pool ```typescript import { Price, Token, CurrencyAmount } from '@uniswap/sdk-core-next' // Simulated pool reserves const wethReserve = CurrencyAmount.fromRawAmount(WETH, '100000000000000000000') // 100 WETH const usdcReserve = CurrencyAmount.fromRawAmount(USDC, 200000_000000n) // 200,000 USDC // Price of WETH in terms of USDC const wethPrice = new Price({ baseAmount: wethReserve, quoteAmount: usdcReserve, }) console.log(`1 WETH = ${wethPrice.toSignificant(6)} USDC`) // "1 WETH = 2000 USDC" // Price of USDC in terms of WETH const usdcPrice = wethPrice.invert() console.log(`1 USDC = ${usdcPrice.toSignificant(6)} WETH`) // "1 USDC = 0.0005 WETH" ``` ## sortedInsert Inserts an item into a sorted array while maintaining sort order and size constraints. ### Import ```typescript import { sortedInsert } from '@uniswap/sdk-core-next' ``` ### Function Signature ```typescript function sortedInsert( items: T[], add: T, maxSize: number, comparator: (a: T, b: T) => number ): T | null ``` ### Parameters | Name | Type | Description | | ------------ | ------------------------ | --------------------------------------------------- | | `items` | `T[]` | The sorted array to insert into (modified in place) | | `add` | `T` | The item to insert | | `maxSize` | `number` | Maximum array size | | `comparator` | `(a: T, b: T) => number` | Comparison function (negative if a \< b) | ### Returns `T | null` - The removed item if the array was at max capacity, otherwise `null`. ### Example ```typescript import { sortedInsert } from '@uniswap/sdk-core-next' // Numeric comparator (ascending) const compareNumbers = (a: number, b: number) => a - b // Start with empty array const items: number[] = [] // Insert items, max size 3 sortedInsert(items, 5, 3, compareNumbers) // returns null, items = [5] sortedInsert(items, 3, 3, compareNumbers) // returns null, items = [3, 5] sortedInsert(items, 7, 3, compareNumbers) // returns null, items = [3, 5, 7] sortedInsert(items, 4, 3, compareNumbers) // returns 7, items = [3, 4, 5] sortedInsert(items, 1, 3, compareNumbers) // returns 5, items = [1, 3, 4] sortedInsert(items, 10, 3, compareNumbers) // returns 10, items = [1, 3, 4] (10 not inserted) ``` ### Use Cases #### Best Trades Finding the best N trades by output amount: ```typescript import { sortedInsert, CurrencyAmount, type Currency } from '@uniswap/sdk-core-next' interface Trade { outputAmount: CurrencyAmount // ... other fields } // Comparator: better trades first (higher output) const compareTrades = (a: Trade, b: Trade): number => { if (a.outputAmount.greaterThan(b.outputAmount)) return -1 if (a.outputAmount.lessThan(b.outputAmount)) return 1 return 0 } const bestTrades: Trade[] = [] const MAX_RESULTS = 3 for (const trade of allPossibleTrades) { sortedInsert(bestTrades, trade, MAX_RESULTS, compareTrades) } // bestTrades now contains the top 3 trades by output amount ``` #### Price-Sorted Orders ```typescript interface Order { price: bigint amount: bigint } // Ascending price (best buy orders) const compareByPrice = (a: Order, b: Order): number => { if (a.price < b.price) return -1 if (a.price > b.price) return 1 return 0 } const orderBook: Order[] = [] // Add orders, keeping only top 10 for (const order of incomingOrders) { sortedInsert(orderBook, order, 10, compareByPrice) } ``` ### Complexity * Time: O(log n) for binary search + O(n) for insertion = O(n) * Space: O(1) (modifies array in place) ### Invariants The function enforces: * `maxSize` must be greater than 0 * `items.length` must be at most `maxSize` (throws if violated) ```typescript // These will throw: sortedInsert([], 1, 0, compareNumbers) // maxSize must be > 0 sortedInsert([1, 2, 3, 4], 5, 3, compareNumbers) // array exceeds maxSize ``` ## sqrt Computes the floor of the square root of a BigInt value. ### Import ```typescript import { sqrt } from '@uniswap/sdk-core-next' ``` ### Function Signature ```typescript function sqrt(value: bigint): bigint ``` ### Parameters | Name | Type | Description | | ------- | -------- | --------------------------------------- | | `value` | `bigint` | The value to compute the square root of | ### Returns `bigint` - The floor of the square root (largest integer n where n² is at most the input value). ### Throws Error if the value is negative. ### Example ```typescript import { sqrt } from '@uniswap/sdk-core-next' // Small values (uses Math.sqrt) sqrt(4n) // 2n sqrt(9n) // 3n sqrt(10n) // 3n (floor) sqrt(0n) // 0n sqrt(1n) // 1n // Large values (uses Newton's method) sqrt(1000000000000000000n) // 1000000000n // Very large values (common in DeFi) const liquidity = 1000000000000000000000000n sqrt(liquidity) // 1000000000000n // Negative throws try { sqrt(-1n) } catch (e) { console.log(e.message) // "NEGATIVE" } ``` ### Algorithm For small values (\< `Number.MAX_SAFE_INTEGER`), uses JavaScript's `Math.sqrt` for performance. For large values, uses Newton's method: ```typescript let z = value let x = value / 2n + 1n while (x < z) { z = x x = (value / x + x) / 2n } return z ``` ### Use Cases #### V2 Liquidity Calculation In Uniswap V2, initial liquidity is calculated as the geometric mean of the reserves: ```typescript import { sqrt } from '@uniswap/sdk-core-next' function getInitialLiquidity(reserve0: bigint, reserve1: bigint): bigint { return sqrt(reserve0 * reserve1) } const liquidity = getInitialLiquidity( 1000000000000000000n, // 1 token with 18 decimals 2000000000n // 2000 tokens with 6 decimals ) ``` #### Price Calculation Converting between sqrtPriceX96 and regular prices: ```typescript import { sqrt } from '@uniswap/sdk-core-next' // Get sqrtPriceX96 from a price ratio function toSqrtPriceX96(amount1: bigint, amount0: bigint): bigint { const Q96 = 2n ** 96n // sqrtPrice = sqrt(amount1/amount0) * 2^96 // To avoid precision loss: sqrt(amount1 * 2^192 / amount0) return sqrt((amount1 * (Q96 * Q96)) / amount0) } ``` ### Performance * Values \< 2^53: O(1) using native Math.sqrt * Large values: O(log n) using Newton's method The function automatically chooses the appropriate algorithm based on the input size. ## Token The `Token` class represents an ERC20 token with a specific address on a chain. ### Import ```typescript import { Token } from '@uniswap/sdk-core-next' ``` ### Constructor ```typescript new Token( chainId: number, address: string, decimals: number, symbol?: string, name?: string, bypassChecksum?: boolean, buyFeeBps?: bigint, sellFeeBps?: bigint ) ``` #### Parameters | Name | Type | Description | | ---------------- | ---------- | --------------------------------------- | | `chainId` | `number` | The chain ID where this token exists | | `address` | `string` | The contract address of the token | | `decimals` | `number` | The number of decimals (0-254) | | `symbol` | `string?` | Optional ticker symbol (e.g., "USDC") | | `name` | `string?` | Optional full name (e.g., "USD Coin") | | `bypassChecksum` | `boolean?` | If true, skips checksum validation | | `buyFeeBps` | `bigint?` | Buy fee in basis points for FOT tokens | | `sellFeeBps` | `bigint?` | Sell fee in basis points for FOT tokens | ### Example ```typescript import { Token } from '@uniswap/sdk-core-next' // Create a token const USDC = new Token( 1, // Ethereum mainnet '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC address 6, // 6 decimals 'USDC', // Symbol 'USD Coin' // Name ) // Create a fee-on-transfer token const TAX_TOKEN = new Token( 1, '0x1234567890123456789012345678901234567890', 18, 'TAX', 'Tax Token', false, 100n, // 1% buy fee 200n // 2% sell fee ) ``` ### Properties #### `address` ```typescript readonly address: Address.Address ``` The checksummed contract address of the token. #### `isNative` ```typescript readonly isNative: false ``` Always `false` for tokens (they are not native currencies). #### `isToken` ```typescript readonly isToken: true ``` Always `true` for tokens. #### `chainId` ```typescript readonly chainId: number ``` The chain ID where this token exists. #### `decimals` ```typescript readonly decimals: number ``` The number of decimals used to represent token amounts. #### `symbol` ```typescript readonly symbol: string | undefined ``` The token's ticker symbol. #### `name` ```typescript readonly name: string | undefined ``` The token's full name. #### `buyFeeBps` ```typescript readonly buyFeeBps: bigint | undefined ``` For fee-on-transfer tokens, the buy fee in basis points. #### `sellFeeBps` ```typescript readonly sellFeeBps: bigint | undefined ``` For fee-on-transfer tokens, the sell fee in basis points. #### `wrapped` ```typescript get wrapped(): Token ``` Returns the token itself (tokens don't need wrapping). ### Methods #### `equals(other)` ```typescript equals(other: Currency): boolean ``` Returns `true` if the other currency is a token with the same chain ID and address. ```typescript const tokenA = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) const tokenB = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) const tokenC = new Token(1, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6) tokenA.equals(tokenB) // true (same address) tokenA.equals(tokenC) // false (different address) ``` #### `sortsBefore(other)` ```typescript sortsBefore(other: Token): boolean ``` Returns `true` if this token's address sorts before the other token's address. Used for ordering tokens in pairs/pools. ```typescript const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) const WETH = new Token(1, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', 18) USDC.sortsBefore(WETH) // true (0xA0... < 0xC0...) ``` **Throws**: If the tokens have the same address or different chain IDs. ### Address Validation By default, addresses are validated and checksummed: ```typescript // Valid - will be checksummed new Token(1, '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 6) // Results in address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // Invalid checksum - throws error new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB49', 6) // Bypass checksum validation new Token(1, '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 6, 'USDC', 'USD Coin', true) ``` ## validateAndParseAddress Validates an Ethereum address and returns the checksummed version. ### Import ```typescript import { validateAndParseAddress, checkValidAddress } from '@uniswap/sdk-core-next' ``` ### Functions #### `validateAndParseAddress(address)` Validates an address and returns the checksummed (EIP-55) version. ```typescript function validateAndParseAddress(address: string): Address.Address ``` ##### Parameters | Name | Type | Description | | --------- | -------- | --------------------------- | | `address` | `string` | The hex address to validate | ##### Returns `Address.Address` - The checksummed address. ##### Throws Error if the address is invalid. #### `checkValidAddress(address)` A lighter validation that only checks format (0x prefix, length, hex characters) without computing the checksum. ```typescript function checkValidAddress(address: string): Address.Address ``` ##### Parameters | Name | Type | Description | | --------- | -------- | --------------------------- | | `address` | `string` | The hex address to validate | ##### Returns `Address.Address` - The address as-is (not checksummed). ##### Throws Error if the address format is invalid. ### Example ```typescript import { validateAndParseAddress, checkValidAddress } from '@uniswap/sdk-core-next' // Valid address - returns checksummed const checksummed = validateAndParseAddress('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') console.log(checksummed) // '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // Already checksummed - returns same const same = validateAndParseAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48') console.log(same) // '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // Invalid checksum - throws error try { validateAndParseAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB49') } catch (e) { console.log(e.message) // "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB49 is not a valid address." } // Light validation (no checksum verification) const quick = checkValidAddress('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') console.log(quick) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' (lowercase preserved) // Invalid format - throws try { checkValidAddress('0xinvalid') } catch (e) { console.log(e.message) // "0xinvalid is not a valid address." } ``` ### Validation Rules #### `validateAndParseAddress` * Must be a valid hex string * Must be 42 characters (including 0x prefix) * Returns EIP-55 checksummed address * Validates checksum if mixed case #### `checkValidAddress` * Must start with `0x` (case insensitive) * Must be exactly 42 characters * Must contain only hex characters (0-9, a-f, A-F) * Does NOT validate or compute checksum ### When to Use Each ```typescript // Use validateAndParseAddress for: // - User input validation // - Ensuring consistent address format // - Security-critical operations const userInput = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' const token = new Token(1, validateAndParseAddress(userInput), 6) // Use checkValidAddress for: // - Faster validation when checksum isn't critical // - Processing large batches of addresses // - When addresses come from trusted sources const trustedAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' const quickCheck = checkValidAddress(trustedAddress) ``` ### EIP-55 Checksum The checksum is encoded in the capitalization of the hex characters: ``` 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 ^ ^ ^ Capital A Capital D Capital E ``` This allows detecting typos in addresses. An address with incorrect capitalization will fail validation. ## WETH9 The `WETH9` mapping provides the Wrapped Ether (WETH) token addresses for supported chains. ### Import ```typescript import { WETH9 } from '@uniswap/sdk-core-next' ``` ### Type ```typescript const WETH9: { [chainId: number]: Token } ``` ### Usage ```typescript import { WETH9 } from '@uniswap/sdk-core-next' // Get WETH on Ethereum mainnet const weth = WETH9[1] console.log(weth.address) // '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' console.log(weth.symbol) // 'WETH' console.log(weth.name) // 'Wrapped Ether' // Get WETH on Arbitrum const arbWeth = WETH9[42161] console.log(arbWeth.address) // '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1' ``` ### Supported Chains | Chain | Chain ID | Symbol | Address | | ---------------- | -------- | ------ | -------------------------------------------- | | Ethereum | 1 | WETH | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` | | Sepolia | 11155111 | WETH | `0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14` | | Optimism | 10 | WETH | `0x4200000000000000000000000000000000000006` | | Optimism Sepolia | 11155420 | WETH | `0x4200000000000000000000000000000000000006` | | Arbitrum | 42161 | WETH | `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1` | | Arbitrum Sepolia | 421614 | WETH | `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73` | | Base | 8453 | WETH | `0x4200000000000000000000000000000000000006` | | Base Sepolia | 84532 | WETH | `0x4200000000000000000000000000000000000006` | | BNB Chain | 56 | WBNB | `0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c` | | Polygon | 137 | WMATIC | `0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270` | | Avalanche | 43114 | WAVAX | `0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7` | | Zora | 7777777 | WETH | `0x4200000000000000000000000000000000000006` | | Blast | 81457 | WETH | `0x4300000000000000000000000000000000000004` | | zkSync Era | 324 | WETH | `0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91` | | World Chain | 480 | WETH | `0x4200000000000000000000000000000000000006` | | Unichain | 130 | WETH | `0x4200000000000000000000000000000000000006` | ### Usage with Ether The `WETH9` mapping is used internally by the [Ether](/sdk-core/ether) class: ```typescript import { Ether } from '@uniswap/sdk-core-next' const eth = Ether.onChain(1) const weth = eth.wrapped // Uses WETH9[1] internally // This is equivalent to: import { WETH9 } from '@uniswap/sdk-core-next' const weth2 = WETH9[1] weth.equals(weth2) // true ``` ### Checking Support ```typescript import { WETH9 } from '@uniswap/sdk-core-next' function isChainSupported(chainId: number): boolean { return WETH9[chainId] !== undefined } isChainSupported(1) // true isChainSupported(12345) // false ```