@1delta/aggregators
v0.1.7
Published
Aggregators for 1Delta
Downloads
229
Readme
@1delta/aggregators
Unified wrapper around 17+ DEX aggregator APIs. Provides a single entry point (fetchAggregatorTrade) that accepts a common set of parameters and returns a normalized GenericTrade object, regardless of which underlying aggregator is used.
Quick Start
import { fetchAggregatorTrade, TradeAggregator } from '@1delta/aggregators'
import { TradeType } from '@1delta/lib-utils'
const trade = await fetchAggregatorTrade(TradeAggregator.Odos, {
chainId: '1',
fromCurrency: { address: '0xA0b8...', decimals: 18, symbol: 'WETH' },
toCurrency: { address: '0xA0b8...', decimals: 6, symbol: 'USDC' },
swapAmount: '1000000000000000000', // 1 WETH in wei
caller: '0xYourAddress',
receiver: '0xYourAddress',
slippage: 0.3, // 0.3%
tradeType: TradeType.EXACT_INPUT,
})
// Get calldata for on-chain execution
const callInfo = await trade?.assemble?.()
// Re-quote with updated slippage
const refreshed = await trade?.refresh?.({ slippage: 0.5 })How It Works
Architecture
fetchAggregatorTrade(aggregator, input)
|
v
Fetcher Registry <-- Map<TradeAggregator, FetcherFn>
|
+---------+---------+
| | |
OneDelta Wrapper External (Odos, 1inch, Paraswap, ...)
| | |
v v v
GenericTrade (unified output)- Caller picks an aggregator from the
TradeAggregatorenum and passes unifiedAggregatorApiInput. - Router (
aggregator.ts) looks up the registered fetcher and dispatches the call. - Fetcher normalizes the input (token addresses, slippage format), calls the aggregator API, and returns a
GenericTrade.
Fetcher Categories
| Category | Aggregator | Behavior |
|----------|-----------|----------|
| Internal | OneDelta | Uses 1delta routing API. Accepts extended OneDeltaInput. |
| Wrapper | NativeWrapper | Synchronous wrap/unwrap of native token (ETH/MATIC/etc). No external API call. |
| External | All others | Calls a third-party aggregator API, returns quote + lazy assemble() for calldata. |
Unified Input
All fetchers accept AggregatorApiInput (from @1delta/lib-utils):
| Field | Type | Description |
|-------|------|-------------|
| chainId | string | Target chain ID |
| fromCurrency | RawCurrency | Source token (address, decimals, symbol) |
| toCurrency | RawCurrency | Destination token |
| swapAmount | string | Amount in smallest unit (wei) |
| caller | string | Transaction sender |
| receiver | string | Token recipient |
| slippage | number | Slippage tolerance as percent (e.g. 0.3 = 0.3%) |
| tradeType | TradeType | EXACT_INPUT or EXACT_OUTPUT |
| marginParams? | MarginParameters | Flash loan configuration for margin trades |
| usePendleMintRedeem? | boolean | Enable Pendle PT/YT mint/redeem routing |
| simpleRoute? | boolean | Request simpler routing (Odos) |
Slippage Normalization
Slippage is always provided as percent (e.g. 0.3 = 0.3%). Callers should never convert slippage themselves -- pass the raw percent value and convertSlippageForAggregator() handles the rest.
Each aggregator API expects slippage in a different format. The conversion is handled automatically inside every fetcher via convertSlippageForAggregator(slippage, aggregator) (defined in src/utils/misc.ts):
| Target format | Example (0.3% in) | Example (out) | Aggregators |
|---------------|-------------------|---------------|-------------|
| Decimal | 0.3 | 0.003 | SushiSwap, Magpie, Pendle, OogaBooga, Eisen |
| Basis points | 0.3 | 30 | Kyberswap, Paraswap, 0x, Enso, Uniswap |
| Percent (passthrough) | 0.3 | 0.3 | OpenOcean, Odos, 1inch |
When adding a new aggregator, check the API docs for the expected slippage format and add a case to the switch in convertSlippageForAggregator(). If the aggregator uses percent (the input format), no case is needed -- the default branch passes the value through.
Unified Output
Every fetcher returns GenericTrade:
| Field | Type | Description |
|-------|------|-------------|
| tradeType | TradeType | EXACT_INPUT or EXACT_OUTPUT |
| inputAmount | CurrencyAmount | Parsed input amount |
| outputAmount | CurrencyAmount | Parsed output amount |
| aggregator | TradeAggregator | Which aggregator produced this quote |
| target | string | Contract to send the transaction to |
| approvalTarget | string | Contract to approve tokens against |
| slippage | number | Applied slippage (percent) |
| flashLoanSource? | FlashLoanProvider | Flash loan provider (margin trades) |
| assemble? | () => Promise<GenericCallInfo> | Lazily builds calldata for execution |
| refresh? | (overrides?) => Promise<GenericTrade> | Re-fetches the quote |
| order? | Order | Bebop-specific signing order |
Two-Step Quote Flow
Most aggregators use a quote-then-assemble pattern:
- Quote -- fetcher calls the aggregator API and returns a
GenericTradewith price/amount info. - Assemble -- calling
trade.assemble()makes a second API call to get the actual transaction calldata (to,calldata,value).
This avoids building calldata until the user confirms the trade.
Supported Aggregators
| Aggregator | Enum Value | Chains |
|-----------|------------|--------|
| NativeWrapper | Wrapper | All |
| 1delta | 1delta | Polygon, Base, Arbitrum, Optimism, Mantle, Taiko, Core, Hemi, Moonbeam, Metis, Fuel |
| 1inch | 1inch | Ethereum, Polygon, BNB, Arbitrum, Optimism, Avalanche, Linea, Fantom, Kaia, Unichain |
| Paraswap | Paraswap | Ethereum, Polygon, BNB, Arbitrum, Optimism, Scroll, Sonic, Fantom, Gnosis |
| Odos | Odos | Ethereum, Polygon, BNB, Arbitrum, Optimism, Base, Avalanche, Mantle, Linea, Scroll, Sonic, Fantom, Mode, Unichain |
| Kyberswap | Kyberswap | Ethereum, Polygon, BNB, Arbitrum, Optimism, Base, Mantle, Linea, Scroll, Sonic, Fantom, Blast, Gnosis, Berachain, Metis, HyperEVM, Unichain, Plasma, Monad |
| Bebop | Bebop | Ethereum, Polygon, BNB, Arbitrum, Optimism, Base, Blast, Taiko, Mode, Berachain, HyperEVM, Unichain |
| Nordstern | Nordstern | Most chains |
| Magpie | Magpie | Ethereum, Polygon, BNB, Arbitrum, Optimism, Base, Avalanche, Blast, Scroll, Sonic, Fantom, Manta, Berachain, Metis |
| 0x | 0x | Ethereum, Polygon, BNB, Arbitrum, Base, Mantle, Linea, Blast, Mode, Scroll, Plasma, Monad |
| SushiSwap | Sushiswap | Most chains |
| OpenOcean | OpenOcean | Most chains |
| Pendle | Pendle | Ethereum, BNB, Arbitrum, Optimism, Base, Mantle, Sonic, Berachain, HyperEVM, Plasma |
| Wowmax | Wowmax | (currently disabled) |
| Eisen | Eisen | BNB, Arbitrum, Base, Mantle, Linea, Taiko, Blast, Scroll, Morph, Hemi, Mode, Berachain, HyperEVM, Soneium, Katana, Zircuit, Abstract, Plume, Flow, Rootstock, Monad, Core |
| Enso | Enso | Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, Linea, Sonic, Gnosis, Berachain, Soneium, Katana, HyperEVM, Unichain, World Chain |
| OogaBooga | OogaBooga | Berachain, HyperEVM, Monad |
| Uniswap | Uniswap | Ethereum, Polygon, BNB, Arbitrum, Base, Optimism, Avalanche, Blast, Linea, Unichain, Soneium, Monad, World Chain, Celo |
Use getAvailableAggregators(chainId) to get the list for a specific chain at runtime.
Margin / Flash Loan Integration
When marginParams is set on the input, the fetcher adjusts the swap amount to account for flash loan fees before quoting. This enables margin trading where the swap is funded by a flash loan.
const trade = await fetchAggregatorTrade(TradeAggregator.Odos, {
...baseInput,
marginParams: {
flashSources: {
canUseMorpho: true,
canUseBalancerV3: false,
balancersAvailable: [],
aaveFee: 5n, // 5 bps
aaveFork: '0x...',
},
adjustForFlashFee: true,
maxInput: false,
},
})Flash loan provider priority: Morpho Blue > Balancer V3 > Balancer V2 > Aave fork.
If margin params are provided but no flash sources are available, the fetcher returns undefined (no quote).
Fetcher Registry
Fetchers are registered in a Map and can be replaced or extended at runtime:
import { registerFetcher, getFetcher, getAllFetchers } from '@1delta/aggregators'
// Register a custom fetcher
registerFetcher('MyAggregator', myFetcherFn)
// Retrieve a fetcher
const fetcher = getFetcher('Odos')The default fetchers are registered via getAllAggregatorFetchers() in fetcher/index.ts.
Adding a New Aggregator
- Create
src/fetcher/myAggregator.tsimplementingExternalAggregatorFetcher. - Add an entry to the
TradeAggregatorenum insrc/types/tradeAggregator.ts. - Register it in the
fetchersmap insrc/fetcher/index.ts. - Add chain availability in
src/types/basics.ts. - Add the aggregator to
PENDLE_AGGREGATOR_CAPABILITIESinsrc/utils/pendle/index.ts(set toundefinedunless it supports Pendle tokens). - If the aggregator expects slippage in decimal or basis points (not percent), add a
casetoconvertSlippageForAggregator()insrc/utils/misc.ts. See Slippage Normalization for the formats.
A typical fetcher follows this pattern:
export const fetchMyTrade = async (
input: AggregatorApiInput,
controller?: AbortController
): Promise<GenericTrade | undefined> => {
// 1. Normalize token addresses (native → zero/wrapped)
// 2. Convert slippage via convertSlippageForAggregator()
// 3. Adjust amount for margin if marginParams present
// 4. Call aggregator quote API
// 5. Build GenericTrade with assemble() and refresh()
// 6. Return trade
}