Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.usemina.co/llms.txt

Use this file to discover all available pages before exploring further.

The Quote Service provides functions for fetching bridge quotes from the LI.FI API, calculating price impact, and managing quote caching.

Exports

import {
  getQuote,
  getQuotes,
  estimatePriceImpact,
  invalidateQuoteCache,
  createQuoteCache,
  QuoteCache,
  QuoteFetchError,
  InvalidQuoteParamsError,
  NoRouteFoundError,
  isQuoteFetchError,
  isInvalidQuoteParamsError,
  isNoRouteFoundError,
} from '@mina-bridge/sdk/services/quote';

Functions

getQuote(params, integrator, autoDeposit?, cache?, timeoutMs?)

Get a single optimal bridge quote.
async function getQuote(
  params: QuoteParams,
  integrator: string,
  autoDeposit?: boolean,
  cache?: QuoteCache,
  timeoutMs?: number
): Promise<Quote>
ParameterTypeRequiredDefaultDescription
paramsQuoteParamsYes-Quote parameters
integratorstringYes-Integrator identifier
autoDepositbooleanNotrueInclude auto-deposit step
cacheQuoteCacheNo-Optional cache instance
timeoutMsnumberNo30000Request timeout in ms
QuoteParams:
ParameterTypeRequiredDefaultDescription
fromChainIdnumberYes-Source chain ID
toChainIdnumberNo999Destination chain ID (HyperEVM)
fromTokenstringYes-Source token address
toTokenstringYes-Destination token address
fromAmountstringYes-Amount in smallest unit
fromAddressstringYes-User’s wallet address
toAddressstringNofromAddressDestination address
slippageTolerancenumberNo0.5Slippage as percentage (0.5 = 0.5%)
routePreferenceRoutePreferenceNo'recommended'Route priority
Returns: Quote Throws:
  • InvalidQuoteParamsError if parameters are invalid
  • NoRouteFoundError if no route is available
  • QuoteFetchError if API request fails
Example:
const quote = await getQuote(
  {
    fromChainId: 1,
    toChainId: 999,
    fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
    toToken: '0xb88339cb7199b77e23db6e890353e22632ba630f',   // HyperEVM USDC
    fromAmount: '1000000000', // 1000 USDC (6 decimals)
    fromAddress: '0x...',
    slippageTolerance: 0.5, // 0.5%
    routePreference: 'recommended',
  },
  'my-app'
);

console.log('Quote Details:');
console.log(`  ID: ${quote.id}`);
console.log(`  Input: ${quote.fromAmount}`);
console.log(`  Output: ${quote.toAmount}`);
console.log(`  Min Received: ${quote.minimumReceivedFormatted}`);
console.log(`  Time: ${quote.estimatedTime}s`);
console.log(`  Fees: $${quote.fees.totalUsd}`);
console.log(`  Price Impact: ${(quote.priceImpact * 100).toFixed(2)}%`);
console.log(`  High Impact: ${quote.highImpact}`);
console.log(`  Expires: ${new Date(quote.expiresAt).toISOString()}`);

getQuotes(params, integrator, autoDeposit?, cache?, timeoutMs?)

Get multiple bridge quotes for comparison.
async function getQuotes(
  params: QuoteParams,
  integrator: string,
  autoDeposit?: boolean,
  cache?: QuoteCache,
  timeoutMs?: number
): Promise<QuotesResponse>
Returns: QuotesResponse
PropertyTypeDescription
quotesQuote[]Array of quotes (up to 5)
recommendedIndexnumberIndex of recommended quote
Example:
const { quotes, recommendedIndex } = await getQuotes(
  {
    fromChainId: 42161, // Arbitrum
    toChainId: 999,
    fromToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC
    toToken: '0xb88339cb7199b77e23db6e890353e22632ba630f',
    fromAmount: '500000000', // 500 USDC
    fromAddress: '0x...',
  },
  'my-app'
);

console.log(`Found ${quotes.length} routes`);
console.log(`Recommended: Route ${recommendedIndex + 1}`);

// Display all routes
quotes.forEach((quote, i) => {
  const isRecommended = i === recommendedIndex;
  console.log(`\nRoute ${i + 1}${isRecommended ? ' (Recommended)' : ''}:`);
  console.log(`  Bridge: ${quote.steps[0]?.tool}`);
  console.log(`  Time: ${quote.estimatedTime}s`);
  console.log(`  Output: ${quote.toAmount}`);
  console.log(`  Fees: $${quote.fees.totalUsd.toFixed(2)}`);
});

estimatePriceImpact(fromToken, toToken, fromAmount, toAmount)

Calculate price impact for a swap or bridge.
function estimatePriceImpact(
  fromToken: Token,
  toToken: Token,
  fromAmount: string,
  toAmount: string
): PriceImpactResult
ParameterTypeDescription
fromTokenTokenSource token with price
toTokenTokenDestination token with price
fromAmountstringInput amount (smallest unit)
toAmountstringOutput amount (smallest unit)
Returns: PriceImpactResult
PropertyTypeDescription
priceImpactnumberPrice impact as decimal (0.01 = 1%)
impactPercentagestringFormatted percentage string
severity'low' | 'medium' | 'high' | 'very_high'Severity level
highImpactbooleanWhether impact exceeds 1% threshold
Severity Thresholds:
SeverityImpact
low< 0.5%
medium0.5% - 1%
high1% - 3%
very_high> 3%
Example:
const impact = estimatePriceImpact(
  { ...usdcToken, priceUsd: 1.0 },
  { ...hyperliquidUsdc, priceUsd: 1.0 },
  '1000000000', // 1000 USDC
  '997000000'   // 997 USDC (0.3% impact)
);

console.log(`Price Impact: ${impact.impactPercentage}`); // "0.30%"
console.log(`Severity: ${impact.severity}`); // "low"
console.log(`High Impact: ${impact.highImpact}`); // false

if (impact.severity === 'high' || impact.severity === 'very_high') {
  console.warn('Consider using a smaller amount');
}

invalidateQuoteCache(cache?)

Manually invalidate the quote cache.
function invalidateQuoteCache(cache?: QuoteCache): void
Example:
// Invalidate default cache
invalidateQuoteCache();

// Invalidate specific cache
const myCache = createQuoteCache();
invalidateQuoteCache(myCache);

createQuoteCache()

Factory function to create a new cache instance.
function createQuoteCache(): QuoteCache
Example:
const cache = createQuoteCache();
const quote = await getQuote(params, 'my-app', true, cache);

Error Types

QuoteFetchError

Thrown when quote fetching fails.
class QuoteFetchError extends MinaError {
  readonly code: 'QUOTE_FETCH_FAILED';
  readonly recoverable: true;
  readonly recoveryAction: 'retry';
  readonly statusCode?: number;
  readonly endpoint: string;
}
Example:
try {
  const quote = await getQuote(params, 'my-app');
} catch (error) {
  if (isQuoteFetchError(error)) {
    console.error(`API Error (${error.statusCode}): ${error.message}`);
    console.log('Retry recommended');
  }
}

InvalidQuoteParamsError

Thrown when quote parameters are invalid.
class InvalidQuoteParamsError extends MinaError {
  readonly code: 'INVALID_QUOTE_PARAMS';
  readonly recoverable: false;
  readonly field: string;
  readonly reason: string;
}
Example:
try {
  const quote = await getQuote({
    fromChainId: -1, // Invalid
    ...
  }, 'my-app');
} catch (error) {
  if (isInvalidQuoteParamsError(error)) {
    console.error(`Invalid ${error.field}: ${error.reason}`);
  }
}

NoRouteFoundError

Thrown when no bridge route is available.
class NoRouteFoundError extends MinaError {
  readonly code: 'NO_ROUTE_FOUND';
  readonly recoverable: true;
  readonly recoveryAction: 'try_different_route';
  readonly fromChainId: number;
  readonly toChainId: number;
  readonly fromToken: string;
  readonly toToken: string;
}
Example:
try {
  const quote = await getQuote(params, 'my-app');
} catch (error) {
  if (isNoRouteFoundError(error)) {
    console.error(
      `No route from chain ${error.fromChainId} to ${error.toChainId}`
    );
    console.log('Try a different token or chain');
  }
}

QuoteCache Class

The QuoteCache class manages caching for quote data with a 30-second TTL.

Methods

class QuoteCache {
  /** Get cached quote if not expired (30 second TTL) */
  getQuote(params: QuoteParams): {
    data: Quote;
    cachedAt: number;
  } | null;

  /** Store quote in cache */
  setQuote(params: QuoteParams, quote: Quote): void;

  /** Get cached quotes list */
  getQuotes(params: QuoteParams): {
    data: Quote[];
    recommendedIndex: number;
    cachedAt: number;
  } | null;

  /** Store quotes list in cache */
  setQuotes(
    params: QuoteParams,
    quotes: Quote[],
    recommendedIndex: number
  ): void;

  /** Invalidate all cached quotes */
  invalidate(): void;

  /** Check if any cached quotes exist */
  hasCached(): boolean;
}

Example Usage

const cache = createQuoteCache();

// First request - fetches from API
const quote1 = await getQuote(params, 'my-app', true, cache);
console.log('Fresh quote from API');

// Same request within 30 seconds - uses cache
const quote2 = await getQuote(params, 'my-app', true, cache);
console.log('Quote from cache (same ID):', quote1.id === quote2.id);

// Different amount - fetches new quote
const quote3 = await getQuote(
  { ...params, fromAmount: '2000000000' },
  'my-app',
  true,
  cache
);
console.log('New quote for different amount');

// Force refresh
cache.invalidate();
const quote4 = await getQuote(params, 'my-app', true, cache);
console.log('Fresh quote after invalidation');

Types

Quote

interface Quote {
  /** Unique quote ID */
  id: string;
  /** Route steps */
  steps: Step[];
  /** Fee breakdown */
  fees: Fees;
  /** Estimated total time in seconds */
  estimatedTime: number;
  /** Input amount */
  fromAmount: string;
  /** Expected output amount */
  toAmount: string;
  /** Slippage tolerance applied (percentage format) */
  slippageTolerance: number;
  /** Minimum amount to receive after slippage */
  minimumReceived: string;
  /** Minimum amount formatted with decimals */
  minimumReceivedFormatted: string;
  /** Price impact as decimal (0.01 = 1%) */
  priceImpact: number;
  /** Whether impact exceeds HIGH threshold (1%) */
  highImpact: boolean;
  /** Price impact severity level */
  impactSeverity: 'low' | 'medium' | 'high' | 'very_high';
  /** Quote expiration timestamp */
  expiresAt: number;
  /** Source token */
  fromToken: Token;
  /** Destination token */
  toToken: Token;
  /** Whether auto-deposit is included */
  includesAutoDeposit: boolean;
  /** Whether manual deposit is required */
  manualDepositRequired: boolean;
  /** Route preference used */
  routePreference: RoutePreference;
  /** Alternative routes for comparison */
  alternativeRoutes?: RouteComparison[];
}

Step

interface Step {
  id: string;
  type: 'swap' | 'bridge' | 'deposit' | 'approve';
  tool: string;
  toolLogoUrl?: string;
  fromChainId: number;
  toChainId: number;
  fromToken: Token;
  toToken: Token;
  fromAmount: string;
  toAmount: string;
  estimatedTime: number;
}

Fees

interface Fees {
  totalUsd: number;
  gasUsd: number;
  bridgeFeeUsd: number;
  protocolFeeUsd: number;
  gasEstimate: GasEstimate;
  gasFee?: FeeItem;
  bridgeFee?: FeeItem;
  protocolFee?: FeeItem;
}

RoutePreference

type RoutePreference = 'recommended' | 'fastest' | 'cheapest';

RouteComparison

interface RouteComparison {
  type: RoutePreference;
  estimatedTime: number;
  totalFees: string;
  outputAmount: string;
  routeId: string;
}

Common Patterns

Compare Route Options

async function compareRoutes(baseParams: QuoteParams) {
  const preferences: RoutePreference[] = ['recommended', 'fastest', 'cheapest'];

  const quotes = await Promise.all(
    preferences.map(pref =>
      getQuote({ ...baseParams, routePreference: pref }, 'my-app')
    )
  );

  console.log('Route Comparison:');
  quotes.forEach((quote, i) => {
    console.log(`\n${preferences[i].toUpperCase()}:`);
    console.log(`  Time: ${quote.estimatedTime}s`);
    console.log(`  Fees: $${quote.fees.totalUsd.toFixed(2)}`);
    console.log(`  Output: ${quote.toAmount}`);
  });
}

Handle High Price Impact

async function safeGetQuote(params: QuoteParams) {
  const quote = await getQuote(params, 'my-app');

  if (quote.highImpact) {
    console.warn(`High price impact detected: ${quote.priceImpact * 100}%`);

    if (quote.impactSeverity === 'very_high') {
      throw new Error(
        `Price impact too high (${quote.priceImpact * 100}%). ` +
        'Consider using a smaller amount.'
      );
    }
  }

  return quote;
}

Auto-Refresh Quotes

function useQuoteRefresh(params: QuoteParams, intervalMs = 25000) {
  const cache = createQuoteCache();
  let currentQuote: Quote | null = null;

  const refresh = async () => {
    try {
      cache.invalidate(); // Force fresh quote
      currentQuote = await getQuote(params, 'my-app', true, cache);
      console.log('Quote refreshed:', currentQuote.id);
    } catch (error) {
      console.error('Failed to refresh quote:', error);
    }
  };

  // Initial fetch
  refresh();

  // Set up refresh interval (before 30s expiry)
  const interval = setInterval(refresh, intervalMs);

  return {
    getQuote: () => currentQuote,
    stop: () => clearInterval(interval),
  };
}