Skip to main content

Overview

By default, the Mobula Swap API automatically finds the best route across all available liquidity sources. However, you may want to target a specific pool or restrict routing to certain protocols — for example, to:
  • Execute a swap directly through a specific Aerodrome CL pool on Base
  • Restrict routing to only Uniswap V3 pools
  • Avoid certain factory contracts
  • Force routing through a specific DEX for compliance or analytics
The Swap API provides three parameters for pool targeting:
ParameterRoutingDescription
poolAddressDirect on-chainTarget a specific pool by address — bypasses aggregators, executes directly via MobulaRouter
onlyProtocolsVia aggregatorRestrict to specific pool types (e.g., uniswap-v3) — routed through KyberSwap/Jupiter
excludedProtocolsVia aggregatorExclude specific factory addresses from routing
Key difference: poolAddress routes the swap directly on-chain through MobulaRouter’s executeRoute function. onlyProtocols passes the restriction to an external aggregator (KyberSwap, Jupiter) which handles the routing.

Direct Pool Access (poolAddress)

Use poolAddress when you know the exact pool contract address and want to swap directly through it, without going through an external aggregator. The swap is executed on-chain via MobulaRouter’s internal routing engine.

Basic Example

Route a USDC → WETH swap directly through a specific Aerodrome CL pool on Base:
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm:8453\
&tokenIn=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&tokenOut=0x4200000000000000000000000000000000000006\
&amount=100\
&walletAddress=0xYourWallet\
&slippage=1\
&poolAddress=0xb4cb800910b228ed3d0834cf79d697127bbb00e5"

Concrete Example — USDC to TKFG on Aerodrome CL (Base)

This example swaps ~300 USDC (raw units) to TKFG on Base, routed directly through the Aerodrome CL pool:
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm%3A8453\
&tokenIn=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\
&tokenOut=0xe9d139df6212fde346ec650e83039f322018f60d\
&amountRaw=300539874\
&walletAddress=0xYourWallet\
&slippage=1\
&poolAddress=0x66fbdb0b14a889b3735da163843289a55d28bb97"
The response transaction will use MobulaRouter’s executeRoute selector (0xa564dfa4), executing the swap directly on-chain without any aggregator intermediary.
You can discover pool addresses using the Token Markets endpoint, which returns all pools for a given token pair along with their addresses, types, and liquidity.

When to Use poolAddress

  • You want zero aggregator fees — the swap goes directly through the pool
  • You need deterministic routing — always the exact same pool, no fallback
  • You’re building a pool-specific UI (e.g., showing swap for a specific market)
  • Multiple pools exist for the same pair (e.g., different fee tiers) and you want a specific one

Filtering by Protocol (onlyProtocols)

Use onlyProtocols to restrict the swap to pools of a specific type. The swap is routed through an external aggregator (KyberSwap on EVM, Jupiter on Solana) which applies the filter.

Single Protocol

Route a swap exclusively through Uniswap V3 pools:
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm:1\
&tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\
&tokenOut=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\
&amount=0.5\
&walletAddress=0xYourWallet\
&slippage=1\
&onlyProtocols=uniswap-v3"

Multiple Protocols

Route through either Aerodrome CL or Uniswap V3 pools on Base:
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm:8453\
&tokenIn=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&tokenOut=0x4200000000000000000000000000000000000006\
&amount=100\
&walletAddress=0xYourWallet\
&slippage=1\
&onlyProtocols=aerodrome-cl-2,uniswap-v3"

Excluding Protocols (excludedProtocols)

Use excludedProtocols to exclude specific factory addresses from routing. Unlike onlyProtocols which takes pool type names, this parameter takes factory contract addresses:
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm:1\
&tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\
&tokenOut=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\
&amount=1\
&walletAddress=0xYourWallet\
&slippage=1\
&excludedProtocols=0x1F98431c8aD98523631AE4a59f267346ea31F984"

Common Pool Types

EVM Chains

Pool TypeDescription
uniswap-v2Uniswap V2 and forks (SushiSwap, PancakeSwap V2, etc.)
uniswap-v3Uniswap V3 concentrated liquidity pools
uniswap-v4Uniswap V4 pools with hooks
aerodromeAerodrome V2 pools (Base)
aerodrome-cl-2Aerodrome CL (concentrated liquidity) pools (Base)
pancakeswap-v3PancakeSwap V3 pools
solidly-v2Solidly V2 pools and forks
solidly-v3Solidly V3 pools (CL)
trader-joe-v2.1Trader Joe Liquidity Book pools
maverick-v2Maverick V2 pools

Solana

Pool TypeDescription
raydium-ammRaydium AMM pools
raydium-clmmRaydium concentrated liquidity pools
raydium-cpmmRaydium constant product pools
orca-whirlpoolOrca Whirlpool concentrated liquidity pools
meteora-dlmmMeteora DLMM pools
pumpfunPumpFun bonding curve pools
pumpswapPumpSwap pools
Only tradable pool types are accepted by onlyProtocols. Non-tradable types are automatically filtered out. If no valid pool types remain after filtering, the API returns a “No route found” error.

Choosing a Router (onlyRouters)

You can also restrict which aggregator/router handles the swap, independently from pool targeting:
RouterChainsDescription
kyberswapEVMKyberSwap aggregator (no extra fees)
lifiEVMLI.FI cross-chain aggregator
jupiterSolanaJupiter aggregator
curl -X GET "https://api.mobula.io/api/2/swap/quoting?\
chainId=evm:8453\
&tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\
&tokenOut=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&amount=0.01\
&walletAddress=0xYourWallet\
&slippage=1\
&onlyRouters=kyberswap"

TypeScript Example

// Direct pool access — swap through a specific pool on-chain
async function swapViaSpecificPool() {
  const params = new URLSearchParams({
    chainId: 'evm:8453',
    tokenIn: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
    tokenOut: '0x4200000000000000000000000000000000000006', // WETH
    amount: '100', // 100 USDC
    walletAddress: '0xYourWallet',
    slippage: '1',
    poolAddress: '0xb4cb800910b228ed3d0834cf79d697127bbb00e5', // Specific pool
  });

  const response = await fetch(
    `https://api.mobula.io/api/2/swap/quoting?${params}`,
    { headers: { Authorization: 'YOUR_API_KEY' } }
  );

  const { data } = await response.json();

  // Transaction uses MobulaRouter's executeRoute (direct on-chain)
  console.log('Route:', data.route);
  console.log('Estimated output:', data.estimatedAmountOut);
  console.log('Transaction:', data.evm?.transaction);
}

// Protocol-filtered — restrict aggregator to specific pool types
async function swapWithProtocolFilter() {
  const params = new URLSearchParams({
    chainId: 'evm:8453',
    tokenIn: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
    tokenOut: '0x4200000000000000000000000000000000000006',
    amount: '100',
    walletAddress: '0xYourWallet',
    slippage: '1',
    onlyProtocols: 'aerodrome-cl-2', // Only Aerodrome CL pools
  });

  const response = await fetch(
    `https://api.mobula.io/api/2/swap/quoting?${params}`,
    { headers: { Authorization: 'YOUR_API_KEY' } }
  );

  const { data } = await response.json();

  // Transaction uses aggregator (KyberSwap) with protocol filter
  console.log('Route:', data.route);
  console.log('Estimated output:', data.estimatedAmountOut);
  console.log('Transaction:', data.evm?.transaction);
}

Troubleshooting

IssueCauseSolution
"No route found"No pool of the requested type exists for this pairCheck the pool type name is correct, or try without onlyProtocols
"Pool not found"The poolAddress doesn’t exist in Mobula’s indexVerify the pool address on a block explorer
Swap uses aggregator instead of direct accessUsed onlyProtocols instead of poolAddressUse poolAddress for direct on-chain routing
"Invalid protocol"Typo in the pool type nameCheck the Common Pool Types table above