Skip to content

useQuote

The useQuote hook provides optimized bridge quotes by comparing multiple providers (Relay.link and deBridge) and selecting the best option based on retention rate.

Import

import { useQuote } from '@silentswap/react';

Basic Usage

import { useQuote } from '@silentswap/react';
import { useAccount } from 'wagmi';
 
function BridgeComponent() {
  const { address } = useAccount();
  
  const {
    getQuote,
    isLoading,
    error,
    ingressEstimates,
    egressEstimates,
  } = useQuote({
    address: address || undefined,
    maxImpactPercent: 5, // Optional, default from SDK
  });
 
  const handleGetQuote = async () => {
    const quote = await getQuote(
      1, // Source chain ID (Ethereum)
      '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Source token (USDC)
      '1000000', // Amount in token units (1 USDC = 1e6)
      43114, // Destination chain ID (Avalanche)
      '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E' // Destination token (USDC.e)
    );
 
    if (quote) {
      console.log('Provider:', quote.provider);
      console.log('Output Amount:', quote.outputAmount);
      console.log('Fee (USD):', quote.feeUsd);
      console.log('Slippage:', quote.slippage);
      console.log('Retention Rate:', quote.retentionRate);
    }
  };
 
  return (
    <div>
      {isLoading && <div>Getting quote...</div>}
      {error && <div>Error: {error.message}</div>}
      <button onClick={handleGetQuote} disabled={isLoading}>
        Get Quote
      </button>
    </div>
  );
}

API Reference

Options

interface useQuoteOptions {
  /** User's EVM address */
  address?: `0x${string}`;
  /** Maximum price impact percentage allowed (default from SDK constants) */
  maxImpactPercent?: number;
  /** Timeout for quote requests in milliseconds (default: 30000) */
  quoteTimeout?: number;
}

Return Value

interface useQuoteReturn {
  // State
  isLoading: boolean;
  error: Error | null;
  
  // Estimates cache
  ingressEstimates: Record<string, Estimate>;
  egressEstimates: Record<string, Estimate>;
 
  // Methods
  getQuote: (
    srcChainId: number,
    srcToken: string,
    srcAmount: string,
    dstChainId: number,
    dstToken: string
  ) => Promise<BridgeQuoteResult>;
  
  solveUsdcAmount: (
    srcChainId: number,
    srcToken: string,
    srcAmount: string,
    depositCalldata?: string
  ) => Promise<SolveResult>;
  
  estimateLive: (
    direction: 'ingress' | 'egress',
    assetCaip19: string,
    chainId: number,
    tokenAddress: string,
    amount: number,
    usdPrice: number
  ) => Promise<EstimateResult>;
  
  interpolateSamples: (
    samples: EstimateSample[],
    usdValue: number,
    marginHi?: number
  ) => number;
}

BridgeQuoteResult

interface BridgeQuoteResult {
  /** Selected bridge provider ('relay' or 'debridge') */
  provider: BridgeProvider;
  /** Output amount in destination token units (as string) */
  outputAmount: string;
  /** Input amount required in source token units (as string) */
  inputAmount: string;
  /** Total fee in USD */
  feeUsd: number;
  /** Price slippage/impact percentage */
  slippage: number;
  /** Estimated time in seconds */
  estimatedTime: number;
  /** Retention rate (how much value is retained after fees, 0-1) */
  retentionRate: number;
  /** Number of transactions required */
  txCount: number;
  /** Raw response from the provider */
  rawResponse: RelayQuoteResponse | DeBridgeOrderResponse;
}

Advanced Usage

Auto-fetch Quote on Amount Change

import { useEffect, useState } from 'react';
import { useQuote } from '@silentswap/react';
 
function AutoQuoteComponent() {
  const [amount, setAmount] = useState('');
  const [quote, setQuote] = useState(null);
  
  const { getQuote, isLoading } = useQuote({ address });
 
  useEffect(() => {
    if (!amount || parseFloat(amount) <= 0) {
      setQuote(null);
      return;
    }
 
    const fetchQuote = async () => {
      const result = await getQuote(
        1, // Ethereum
        '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
        parseUnits(amount, 6).toString(), // Convert to token units
        43114, // Avalanche
        '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E' // USDC.e
      );
      setQuote(result);
    };
 
    // Debounce quote fetching
    const timeout = setTimeout(fetchQuote, 800);
    return () => clearTimeout(timeout);
  }, [amount, getQuote]);
 
  return (
    <div>
      <input
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Amount"
      />
      {isLoading && <div>Loading quote...</div>}
      {quote && (
        <div>
          <p>You'll receive: {formatUnits(quote.outputAmount, 6)} USDC</p>
          <p>Fee: ${quote.feeUsd.toFixed(2)}</p>
        </div>
      )}
    </div>
  );
}

Using Estimates Cache

The hook maintains a cache of ingress and egress estimates that can be used for quick lookups:

const { ingressEstimates, egressEstimates, estimateLive } = useQuote({ address });
 
// Get live estimate for a specific direction
const estimate = await estimateLive(
  'ingress', // or 'egress'
  'eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  1, // Chain ID
  '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Token address
  100, // Amount
  1.0 // USD price per token
);

Error Handling

The hook automatically handles errors from both providers and returns the best available quote:

const { getQuote, error } = useQuote({ address });
 
try {
  const quote = await getQuote(/* ... */);
  if (!quote) {
    // Both providers failed
    console.error('Failed to get quote from any provider');
  }
} catch (err) {
  // Handle error
  console.error('Quote error:', err);
}

Best Practices

  1. Debounce Quote Requests - Don't fetch quotes on every keystroke
  2. Handle Loading States - Show loading indicators while fetching
  3. Cache Quotes - Store quotes locally to avoid unnecessary requests
  4. Validate Amounts - Check that amounts are valid before fetching quotes
  5. Handle Errors Gracefully - Provide fallback UI when quotes fail

Next Steps