Skip to content

slvDev/dexap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dexap

Query any DEX, any chain, one simple API

Decentralized price queries from DEXes across multiple chains

Installation | Quick Start | Core Concepts | API Reference | Usage Guides


Why dexap?

Finding the best price across multiple DEXes and chains is complex. Different protocols, different APIs, different pool structures. dexap abstracts all of this complexity into a clean, type-safe interface.

  • Truly Decentralized - Query prices directly from onchain liquidity pools instead of relying on centralized price oracles. Keep your Web3 stack decentralized end-to-end.
  • One API, Many DEXes - Query UniswapV3-based DEXes (Uniswap, SushiSwap, PancakeSwap) and Slipstream DEXes (Velodrome, Aerodrome) with identical syntax
  • 11 Chains Supported - Ethereum, Base, Optimism, Arbitrum, Polygon, BSC, Avalanche, and more
  • Best Price Discovery - Automatically find the optimal DEX for your trade
  • Price Aggregation - Get average, median, min/max prices with outlier filtering
  • TypeScript First - Full type definitions with IntelliSense support
  • Minimal Dependencies - Only requires viem as a peer dependency
  • Symbol Resolution - Use token symbols directly, no need to look up addresses

Installation

# npm
npm install dexap viem

# yarn
yarn add dexap viem

# pnpm
pnpm add dexap viem

Note: viem is a peer dependency and must be installed alongside dexap.


Methods Overview

Method Returns
getPrice 1 price from 1 DEX
getPrices N prices from all DEXes on 1 chain
getBestPrice 1 best price from 1 chain
getAggregatedPrice avg/median/min/max from 1 chain
getMultiChainPrices N prices from N chains
getMultiChainBestPrices 1 best per chain (array)
getMultiChainBestPrice 1 global best across chains
getMultiChainAggregatedPrices avg/median/min/max per chain

Quick Start

import { createClient, ETHEREUM, UNISWAP_V3 } from "dexap";

const client = createClient({
  alchemyKey: "your-api-key", // Optional
});

// Minimal - defaults to USDC, amount=1
const price = await client.getPrice("WETH", ETHEREUM, UNISWAP_V3);
console.log(price.formatted); // "1 WETH = 3,245.67 USDC"

// With all options
const detailed = await client.getPrice(
  "WETH",
  ETHEREUM,
  UNISWAP_V3,
  "DAI",  // tokenOut (default: "USDC")
  "10",   // amount (default: "1")
  true    // includePriceImpact (default: false)
);

See Usage Guides for more examples.


Core Concepts

Understanding DEX Protocols

dexap supports two types of concentrated liquidity protocols with different pool configurations:

UniswapV3 Protocol

Used by: Uniswap V3, SushiSwap V3, PancakeSwap V3

Pool Tiers: Based on fee percentages

  • 100 = 0.01% fee (stablecoin pairs like USDC/USDT)
  • 500 = 0.05% fee (correlated pairs like ETH/WETH)
  • 3000 = 0.30% fee (standard pairs like ETH/USDC)
  • 10000 = 1.00% fee (volatile/exotic pairs)

Available on: All 11 chains

Slipstream Protocol

Used by: Velodrome (Optimism), Aerodrome (Base)

Pool Tiers: Based on tick spacing

  • 1 = Tightest spacing (stablecoin pairs)
  • 50 = Tight spacing (correlated assets)
  • 100 = Standard spacing (common pairs)
  • 200 = Wide spacing (volatile pairs)
  • 2000 = Widest spacing (exotic pairs)

Key Difference: Slipstream is Velodrome's concentrated liquidity implementation optimized for OP Stack chains. It's NOT a UniswapV3 fork - it uses tick spacing parameters instead of fee tiers for pool configuration.

Available on: Optimism (Velodrome), Base (Aerodrome)

Important: dexap abstracts these protocol differences completely. You use the same API methods regardless of whether you're querying UniswapV3 or Slipstream pools. The poolTier in results will show the appropriate tier type for each protocol.


Chain & DEX Availability

dexap automatically handles protocol selection based on your query method:

Best Price Mode (getBestPrice)

  • Queries all available DEXes on the specified chain
  • Returns the best price with DEX identifier
  • Optimal for finding the most favorable rate

Specific DEX Mode (getPrice)

  • Queries a single specified DEX
  • Use when you need prices from a particular protocol
  • Faster than querying all DEXes

Aggregation Mode (getAggregatedPrice)

  • Queries all DEXes and provides statistical analysis
  • Returns average, median, min, max prices
  • Includes outlier filtering (IQR method)
  • Best for market overview and price discovery

Check availability: Use getSupportedDexTypes(chainId) to find which DEXes are available on a specific chain.


Token Symbol Resolution

dexap includes a built-in token registry that simplifies token handling:

  • Automatic resolution - Use symbols like "WETH", "USDC" instead of addresses
  • Multi-chain support - Same symbol works across all supported chains
  • Decimal handling - Automatically handles tokens with different decimals per chain
  • Common tokens - WETH, WBTC, USDC, USDT, DAI, and more pre-configured

API Reference

Client Creation

createClient(config?)

Creates a dexap client instance for querying DEX prices.

Parameters:

interface ClientConfig {
  clients?: Partial<Record<ChainId, PublicClient>>; // Pre-configured viem clients
  alchemyKey?: string; // Alchemy API key
  infuraKey?: string; // Infura API key
  rpcUrls?: Partial<Record<ChainKey, string>>; // Custom RPC URLs
}

Returns: Client instance

Example:

const client = createClient({
  alchemyKey: "your-key",
});

Price Query Methods

client.getPrice(tokenIn, chainId, dexType, [tokenOut], [amountIn], [includePriceImpact])

Get a price quote from a specific DEX.

Parameters:

Parameter Type Default Description
tokenIn string | TokenInfo - Input token symbol or address
chainId ChainId - Target blockchain
dexType DexType - Specific DEX to query
tokenOut string | TokenInfo "USDC" Output token symbol or address
amountIn string "1" Amount in human-readable format
includePriceImpact boolean false Calculate price impact

Returns: Promise<PriceResult>


client.getBestPrice(tokenIn, chainId, [tokenOut], [amountIn], [includePriceImpact])

Find the best price across all available DEXes on a chain.

Parameters: Same as getPrice except no dexType parameter

Returns: Promise<PriceResult & { dexType: DexType }>

The result includes a dexType field indicating which DEX provided the best price.


client.getPrices(tokenIn, chainId, [tokenOut], [amountIn], [includePriceImpact])

Get price quotes from all available DEXes on a chain.

Parameters: Same as getPrice except no dexType parameter

Returns: Promise<Array<PriceResult & { dexType: DexType }>>

Returns an array of price results, one for each available DEX.


client.getAggregatedPrice(tokenIn, chainId, [tokenOut], [amountIn], [filterOutliers], [includePriceImpact])

Get aggregated price statistics across all DEXes with optional outlier filtering.

Parameters:

Parameter Type Default Description
tokenIn string | TokenInfo - Input token
chainId ChainId - Target chain
tokenOut string | TokenInfo "USDC" Output token
amountIn string "1" Amount to query
filterOutliers boolean true Apply IQR outlier filtering
includePriceImpact boolean false Calculate price impact

Returns: Promise<AggregatedPrice>


Multi-Chain Methods

Query prices across multiple chains in parallel.

client.getMultiChainPrices(tokenIn, chainIds, [tokenOut], [amountIn], [includePriceImpact])

Get all DEX prices from multiple chains.

Parameters:

Parameter Type Default Description
tokenIn string | TokenInfo - Input token
chainIds ChainId[] - Array of chains to query
tokenOut string | TokenInfo "USDC" Output token
amountIn string "1" Amount to query
includePriceImpact boolean false Calculate price impact

Returns: Promise<Array<PriceResult & { dexType: DexType }>>

Chains that fail (token not available, RPC error) are silently skipped.


client.getMultiChainBestPrices(tokenIn, chainIds, [tokenOut], [amountIn], [includePriceImpact])

Get best price per chain from multiple chains.

Returns: Promise<Array<PriceResult & { dexType: DexType }>>

One result per chain (the best on that chain).


client.getMultiChainBestPrice(tokenIn, chainIds, [tokenOut], [amountIn], [includePriceImpact])

Get THE single best price across all specified chains.

Returns: Promise<PriceResult & { dexType: DexType }>

Returns the absolute best price with chainId indicating the winning chain.


client.getMultiChainAggregatedPrices(tokenIn, chainIds, [tokenOut], [amountIn], [filterOutliers], [includePriceImpact])

Get aggregated prices per chain from multiple chains.

Returns: Promise<AggregatedPrice[]>


Token Utilities

Utility functions for working with tokens across chains.

resolveToken(symbol, chainId)

Resolve a token symbol to chain-specific address and decimals.

function resolveToken(symbol: string, chainId: ChainId): TokenInfo;

getTokenMetadata(symbol)

Get token metadata without specifying a chain.

function getTokenMetadata(symbol: string): TokenMetadata | undefined;

Returns name, symbol, and decimals (chain-agnostic).


getSupportedChains(symbol)

Find which chains support a specific token.

function getSupportedChains(symbol: string): ChainId[];

getChainTokens(chainId)

Get all tokens available on a specific chain.

function getChainTokens(chainId: ChainId): TokenInfo[];

getWrappedNativeToken(chainId)

Get the wrapped native token for a chain (WETH, WBNB, WMATIC, etc.).

function getWrappedNativeToken(chainId: ChainId): TokenInfo | undefined;

DEX Utilities

Utility functions for discovering and checking DEX availability.

getSupportedDexTypes(chainId)

Get all DEX types available on a specific chain.

import { getSupportedDexTypes, BASE } from "dexap";

const baseDexes = getSupportedDexTypes(BASE);
// => [DexType.UNISWAP_V3, DexType.SUSHISWAP_V3,
//     DexType.PANCAKESWAP_V3, DexType.AERODROME]

getDexProtocol(dexType)

Get protocol metadata for a DEX type.

import { getDexProtocol, VELODROME } from "dexap";

const protocol = getDexProtocol(VELODROME);
// => { type: "velodrome", name: "Velodrome", website: "https://velodrome.finance" }

isDexSupported(chainId, dexType)

Check if a specific DEX is available on a chain.

import { isDexSupported, BASE, VELODROME } from "dexap";

const supported = isDexSupported(BASE, VELODROME);
// => false (Velodrome is only on Optimism)

Types

PriceResult

The result of a price query.

interface PriceResult {
  tokenIn: TokenInfo; // Input token details
  tokenOut: TokenInfo; // Output token details
  amountIn: string; // Input amount in wei
  amountOut: string; // Output amount in wei
  price: number; // Numeric price (tokenOut per tokenIn)
  formatted: string; // Human-readable: "1 WETH = 3,245.67 USDC"
  poolTier: PoolTier; // Pool tier information
  chainId: ChainId; // Chain identifier
  gasEstimate: string; // Estimated gas in wei
  priceImpact: number; // Price impact percentage
}

AggregatedPrice

Aggregated price statistics across multiple DEXes.

interface AggregatedPrice {
  average: number; // Average price
  median: number; // Median price
  min: number; // Minimum price
  max: number; // Maximum price
  best: PriceResult & { dexType: DexType }; // Best price with DEX
  all: Array<PriceResult & { dexType: DexType }>; // All prices
  tokenIn: TokenInfo;
  tokenOut: TokenInfo;
  chainId: ChainId;
  timestamp: number; // Query timestamp
}

PoolTier

Pool tier information (fee or tick spacing).

interface PoolTier {
  type: "fee" | "tickSpacing"; // Tier type
  value: number; // Fee (e.g., 3000) or tick spacing (e.g., 100)
  display: string; // Human-readable: "0.30% fee" or "100 tick spacing"
}

TokenInfo

Token information including address and decimals.

interface TokenInfo {
  symbol: string; // Token symbol (e.g., "WETH")
  address: `0x${string}`; // Contract address
  decimals: number; // Token decimals
}

Enums

enum ChainId {
  ETHEREUM = 1,
  BSC = 56,
  POLYGON = 137,
  ARBITRUM = 42161,
  AVALANCHE = 43114,
  OPTIMISM = 10,
  BASE = 8453,
  ZORA = 7777777,
  UNICHAIN = 130,
  WORLD_CHAIN = 480,
  SONEIUM = 1868,
}

enum DexType {
  UNISWAP_V3 = "uniswap-v3",
  SUSHISWAP_V3 = "sushiswap-v3",
  PANCAKESWAP_V3 = "pancakeswap-v3",
  VELODROME = "velodrome",
  AERODROME = "aerodrome",
}

Usage Guides

Getting Started

Scenario: Check the current WETH/USDC price on Ethereum.

import { createClient, ETHEREUM, UNISWAP_V3 } from "dexap";

const client = createClient({
  alchemyKey: "your-api-key",
});

// Minimal - defaults to USDC, amount=1
const result = await client.getPrice("WETH", ETHEREUM, UNISWAP_V3);

console.log(result.formatted); // "1 WETH = 3,245.67 USDC"
console.log(result.poolTier.display); // "0.30% fee"
console.log(result.price); // 3245.67
console.log(result.gasEstimate); // "150000"

// With price impact calculation
const withImpact = await client.getPrice("WETH", ETHEREUM, UNISWAP_V3, "USDC", "100", true);
console.log(withImpact.priceImpact); // 0.0234

Multi-DEX Comparison

Scenario: Find which DEX offers the best WETH price on Ethereum.

import { createClient, ETHEREUM } from "dexap";

const client = createClient({ alchemyKey: "your-api-key" });

// Option 1: Get best price directly (defaults to USDC, amount=1)
const best = await client.getBestPrice("WETH", ETHEREUM);

console.log(`Best: ${best.formatted}`);
console.log(`DEX: ${best.dexType}`);
console.log(`Pool: ${best.poolTier.display}`);

// Option 2: Compare all DEXes with price impact
const allPrices = await client.getPrices("WETH", ETHEREUM, "USDC", "1", true);

allPrices.forEach((quote) => {
  console.log(`${quote.dexType}: ${quote.formatted} (impact: ${quote.priceImpact?.toFixed(4)}%)`);
});

Multi-Chain Operations

Scenario: Check WETH/USDC price across multiple chains.

import { createClient, ETHEREUM, BASE, ARBITRUM, OPTIMISM, POLYGON, ChainId } from "dexap";

const client = createClient({ alchemyKey: "your-api-key" });

const chains = [ETHEREUM, BASE, ARBITRUM, OPTIMISM, POLYGON];

// Get best price per chain (defaults to USDC, amount=1)
const bestPrices = await client.getMultiChainBestPrices("WETH", chains);

bestPrices.forEach((price) => {
  console.log(`${ChainId[price.chainId]}: $${price.price.toFixed(2)} (${price.dexType})`);
});

// Get THE best price across all chains
const globalBest = await client.getMultiChainBestPrice("WETH", chains);

console.log(`\nBest overall: $${globalBest.price.toFixed(2)} on ${ChainId[globalBest.chainId]}`);

Price Aggregation

Scenario: Get statistical analysis of WETH price across all DEXes on Base.

import { createClient, BASE } from "dexap";

const client = createClient({ alchemyKey: "your-api-key" });

// Defaults to USDC, amount=1, filterOutliers=true
const agg = await client.getAggregatedPrice("WETH", BASE);

console.log(`Average: $${agg.average.toFixed(2)}`);
console.log(`Median:  $${agg.median.toFixed(2)}`);
console.log(`Range:   $${agg.min.toFixed(2)} - $${agg.max.toFixed(2)}`);
console.log(`Best:    ${agg.best.formatted} (${agg.best.dexType})`);
console.log(`Spread:  ${(((agg.max - agg.min) / agg.min) * 100).toFixed(2)}%`);

// Analyze individual DEX prices
agg.all.forEach((quote) => {
  const spread = ((quote.price - agg.min) / agg.min) * 100;
  console.log(`${quote.dexType}: $${quote.price.toFixed(2)} (+${spread.toFixed(2)}% above min)`);
});

Working with Tokens

Scenario: Discover token availability and resolve addresses.

import {
  resolveToken,
  getTokenMetadata,
  getSupportedChains,
  getChainTokens,
  getWrappedNativeToken,
  ETHEREUM,
  BASE,
  BSC,
} from "dexap";

// Get token metadata (chain-agnostic)
const meta = getTokenMetadata("WETH");
console.log(`${meta.name} - ${meta.decimals} decimals`);

// Find which chains support USDC
const usdcChains = getSupportedChains("USDC");
console.log(`USDC available on ${usdcChains.length} chains`);

// Get token address for specific chain
const weth = resolveToken("WETH", BASE);
console.log(`WETH on Base: ${weth.address}`);

// Get wrapped native token
const wrapped = getWrappedNativeToken(BSC);
console.log(`BSC wrapped native: ${wrapped.symbol}`); // "WBNB"

// List all tokens on a chain
const baseTokens = getChainTokens(BASE);
console.log(`Tokens on Base: ${baseTokens.map((t) => t.symbol).join(", ")}`);

Configuration

Scenario: Configure RPC providers for optimal performance.

import { createClient } from "dexap";

// Use Alchemy
const alchemyClient = createClient({
  alchemyKey: "your-alchemy-key",
});

// Use Infura
const infuraClient = createClient({
  infuraKey: "your-infura-key",
});

// Mix custom RPCs with API keys
const customClient = createClient({
  alchemyKey: "your-key", // Use Alchemy for most chains
  rpcUrls: {
    mainnet: "https://your-private-eth-rpc.com", // Override Ethereum
    base: "https://your-private-base-rpc.com", // Override Base
  },
});

// Public RPCs only (rate limited, not recommended for production)
const publicClient = createClient();

Error Handling

Scenario: Handle common errors gracefully.

import { createClient, ETHEREUM, UNISWAP_V3 } from "dexap";

const client = createClient({ alchemyKey: "your-api-key" });

try {
  const result = await client.getPrice("WETH", ETHEREUM, UNISWAP_V3);
  console.log("Price:", result.formatted);
} catch (error) {
  if (error instanceof Error) {
    if (error.message.includes("Token") && error.message.includes("not found")) {
      console.log("Token not supported on this chain");
    } else if (error.message.includes("not configured")) {
      console.log("DEX not available on this chain");
    } else if (error.message.includes("No liquidity found")) {
      console.log("No liquidity available for this pair");
    } else {
      console.error("Unexpected error:", error.message);
    }
  }
}

Common error patterns:

  • Token "${symbol}" not found on chain ${chainId} - Token not deployed on this chain
  • DEX ${dexType} not configured for chain ${chainId} - DEX not available on this chain
  • No liquidity found for ${tokenIn}/${tokenOut} on ${dexType} - Insufficient liquidity

Supported Chains

Chain Chain ID DEXes Available
Ethereum 1 UniswapV3, SushiSwapV3, PancakeSwapV3
Base 8453 UniswapV3, SushiSwapV3, PancakeSwapV3, Aerodrome
Optimism 10 UniswapV3, SushiSwapV3, Velodrome
Arbitrum 42161 UniswapV3, SushiSwapV3, PancakeSwapV3
Polygon 137 UniswapV3, SushiSwapV3
BNB Smart Chain 56 UniswapV3, SushiSwapV3, PancakeSwapV3
Avalanche 43114 UniswapV3, SushiSwapV3
Zora 7777777 UniswapV3
Unichain 130 UniswapV3
World Chain 480 UniswapV3
Soneium 1868 UniswapV3

Supported DEXes

DEX Protocol Pool Tiers Chains
Uniswap V3 UniswapV3 Fee-based (0.01% - 1.00%) All 11 chains
SushiSwap V3 UniswapV3 Fee-based (0.01% - 1.00%) Ethereum, Base, Optimism, Arbitrum, Polygon, BSC, Avalanche
PancakeSwap V3 UniswapV3 Fee-based (0.01% - 1.00%) Ethereum, Base, Arbitrum, BSC
Velodrome Slipstream Tick Spacing (1 - 2000) Optimism
Aerodrome Slipstream Tick Spacing (1 - 2000) Base

License

MIT

About

Query any DEX, any chain, one simple API. Decentralized price queries from DEXes across many chains.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published