Quotes & swaps
Use the Doppler SDK to discover a pool and quote a swap. Then pass the resulting pool, direction, and amounts to Uniswap's Universal Router SDK to construct and execute the transaction.
This guide focuses on the information Doppler provides for:
Dynamic auctions
Multicurve
Multicurve Rehype
All three are Uniswap V4 pools. They use the same quoting API but expose their initialized PoolKey differently.
Install
pnpm add @whetstone-research/doppler-sdk viemSet up the SDK
Only a public client is required to discover pools and request quotes:
import {
DopplerSDK,
getAddresses,
} from '@whetstone-research/doppler-sdk/evm'
import { createPublicClient, http } from 'viem'
import { base } from 'viem/chains'
const publicClient = createPublicClient({
chain: base,
transport: http(rpcUrl),
})
const sdk = new DopplerSDK({
publicClient,
chainId: base.id,
})
const addresses = getAddresses(base.id)Use addresses.universalRouter when executing the swap. It is the Doppler-compatible Universal Router for the selected chain.
Use Universal Router version:
2.1.1on Robinhood (chain ID4663)2.0on every other supported network
Do not substitute a same-chain Universal Router from another address registry. Each Universal Router deployment is connected to a specific V4 PoolManager. Another router on the same chain may use a different PoolManager, where the Doppler pool is not initialized.
Get the V4 PoolKey
The PoolKey contains the exact currencies, fee configuration, tick spacing, and hook address of an initialized V4 pool. Use the key returned from onchain state without reconstructing or modifying it.
Multicurve and Multicurve Rehype
Look up either pool type by its Doppler asset address:
For a buy, the input is normally the pool's numeraire:
For a sell, the input is the Doppler asset:
Use poolState.poolKey unchanged for both Multicurve and Multicurve Rehype pools.
Dynamic auctions
A Dynamic auction stores its initialized PoolKey on its hook:
The returned key already contains the Dynamic auction's fee flag, tick spacing, currencies, and hook address.
Determine the swap direction
Uniswap V4 uses zeroForOne to identify the input side:
true: swapcurrency0forcurrency1false: swapcurrency1forcurrency0
Derive it from the requested input currency:
V4 represents native currency as the zero address. Wrapped native currency uses its ERC-20 address.
Quote an exact-input swap
Use base units for amountIn:
For example, use parseUnits('1', decimals) for an ERC-20 or parseEther('0.01') for an 18-decimal native or wrapped-native input.
Select the Universal Router SDK encoding version for the current chain:
The values required for a single-pool exact-input V4 swap are now:
Apply your application's slippage policy to the quote when constructing the router transaction.
Quote an exact-output swap
To calculate the input required for an exact output:
Apply your application's slippage policy to exactOutputQuote.amountIn when determining the maximum input.
Execute with Uniswap Universal Router
Use the values above with Uniswap's official Universal Router SDK. Its documentation covers transaction construction, currency objects, Permit2 or token approvals, slippage protection, native value, simulation, and submission.
When building the transaction:
Use
addresses.universalRouter.Select version
2.1.1on Robinhood (chain ID4663).Select version
2.0on every other supported network.Pass the exact
poolKeyreturned by the Doppler SDK.Pass the derived
zeroForOnevalue.Use empty hook data (
0x) for these swaps.Simulate the final transaction before submitting it.
V2 and V3 quotes
V2 and V3 are relevant for migrated pools and older Doppler deployments. New Dynamic, Multicurve, and Multicurve Rehype integrations should use the V4 path above.
V3 exact-input quote
Use the initialized V3 pool's actual fee tier.
V2 exact-input quote
Use the resulting route and quote with the corresponding V2 or V3 operation in the Universal Router SDK.
Quote troubleshooting
The pool cannot be quoted. Read the PoolKey from getState() or the Dynamic hook and use it unchanged. Do not guess the fee, tick spacing, currency order, or hook address.
The quoter returns NotEnoughLiquidity. Verify currencyInAddress, zeroForOne, amount units, and current pool state. The requested amount may also be outside the pool's active liquidity.
The quote succeeds but transaction construction or execution fails. Verify that the Universal Router integration uses getAddresses(chainId).universalRouter. Use version 2.1.1 on Robinhood and version 2.0 on every other supported network. Then refer to the Universal Router SDK documentation for approvals, encoding, and execution.
Last updated