Skip to main content

Overview

The useQuotes hook manages the complete lifecycle of token swaps, from fetching quotes to executing transactions and monitoring their status. It handles wallet integration, quote expiration, and automatic status polling.

Import

import { useQuotes } from '@/lib/hooks';

Signature

const useQuotes: () => {
  quote: Quote | null;
  status: QuoteStatus | null;
  loading: boolean;
  error: string | null;
  isPolling: boolean;
  predictedAddress: string | null;
  getPredictedAddress: () => Promise<string | null>;
  getQuote: (request: SimpleQuoteRequest) => Promise<Quote | void>;
  executeQuote: () => Promise<void>;
  resetQuote: () => void;
}

Return Values

quote
Quote | null
The current quote object containing swap details, pricing, and chain operations. null when no quote is active.
status
QuoteStatus | null
Real-time transaction status after quote execution. Updates automatically via polling. Includes transaction hashes and explorer URLs.
loading
boolean
Indicates if a quote fetch or transaction execution is in progress.
error
string | null
Error message if quote fetching or execution fails. null when no errors.
isPolling
boolean
Indicates if the hook is actively polling for transaction status updates.
predictedAddress
string | null
The user’s predicted account address (smart contract wallet). Required for balance checks and quote requests.
getPredictedAddress
() => Promise<string | null>
Async function to fetch the user’s predicted account address. Called automatically when needed.
getQuote
(request: SimpleQuoteRequest) => Promise<Quote | void>
Fetches a new swap quote based on the provided parameters.Parameters:
request
SimpleQuoteRequest
required
Quote request parameters
executeQuote
() => Promise<void>
Executes the current quote. Signs the quote using the embedded wallet and submits it for processing. Automatically starts polling for transaction status.Requirements:
  • User must be authenticated
  • Quote must exist and not be expired
  • Embedded wallet must be available
resetQuote
() => void
Clears the current quote, status, errors, and stops any active polling. Use when canceling a quote or resetting the swap form.

Usage Examples

Basic Swap Flow

import { useQuotes } from '@/lib/hooks';
import { parseTokenAmount } from '@/lib/utils/token';

function SwapForm() {
  const {
    quote,
    loading,
    error,
    getQuote,
    executeQuote,
    resetQuote
  } = useQuotes();

  const handleGetQuote = async () => {
    const amount = parseTokenAmount('100', 18); // 100 tokens
    
    await getQuote({
      fromTokenAmount: amount,
      fromAggregatedAssetId: 'ob:usdc',
      toAggregatedAssetId: 'ob:eth'
    });
  };

  const handleSwap = async () => {
    await executeQuote();
  };

  return (
    <div>
      <button onClick={handleGetQuote} disabled={loading}>
        Get Quote
      </button>
      
      {quote && (
        <>
          <div>Rate: {quote.destinationToken.amount}</div>
          <button onClick={handleSwap} disabled={loading}>
            Execute Swap
          </button>
          <button onClick={resetQuote}>Cancel</button>
        </>
      )}
      
      {error && <div>Error: {error}</div>}
    </div>
  );
}

With Transaction Status Tracking

import { useQuotes } from '@/lib/hooks';

function SwapWithStatus() {
  const {
    quote,
    status,
    isPolling,
    executeQuote,
    resetQuote
  } = useQuotes();

  useEffect(() => {
    if (status?.status === 'COMPLETED') {
      console.log('Swap completed!');
      // Refresh balances, show success message, etc.
      resetQuote();
    }
  }, [status]);

  return (
    <div>
      {isPolling && (
        <div>
          Transaction Status: {status?.status}
          {status?.originChainOperations.map(op => (
            <a key={op.hash} href={op.explorerUrl} target="_blank">
              View on Explorer: {op.hash}
            </a>
          ))}
        </div>
      )}
    </div>
  );
}

Debounced Quote Fetching

import { useQuotes } from '@/lib/hooks';
import { useCallback } from 'react';
import debounce from 'lodash.debounce';

function SwapForm() {
  const { getQuote } = useQuotes();
  const [amount, setAmount] = useState('');

  // Debounce quote fetching to reduce API calls
  const debouncedGetQuote = useCallback(
    debounce(async (request) => {
      await getQuote(request);
    }, 1000),
    [getQuote]
  );

  const handleAmountChange = (value: string) => {
    setAmount(value);
    
    if (value) {
      const parsed = parseTokenAmount(value, 18);
      debouncedGetQuote({
        fromTokenAmount: parsed,
        fromAggregatedAssetId: 'ob:usdc',
        toAggregatedAssetId: 'ob:eth'
      });
    }
  };

  return (
    <input
      type="text"
      value={amount}
      onChange={(e) => handleAmountChange(e.target.value)}
      placeholder="Enter amount"
    />
  );
}

Quote Expiration Handling

import { useQuotes } from '@/lib/hooks';

function QuoteWithExpiration() {
  const { quote, getQuote } = useQuotes();

  const handleQuoteExpire = async () => {
    // Re-fetch quote when it expires
    if (sourceAsset && targetAsset && amount) {
      await getQuote({
        fromTokenAmount: amount,
        fromAggregatedAssetId: sourceAsset,
        toAggregatedAssetId: targetAsset
      });
    }
  };

  return (
    <div>
      {quote && (
        <QuoteCountdown
          expirationTimestamp={parseInt(quote.expirationTimestamp)}
          onExpire={handleQuoteExpire}
        />
      )}
    </div>
  );
}

Types

Quote

interface Quote {
  id: string;
  account: Account;
  originToken: TokenInfo;
  destinationToken: TokenInfo;
  expirationTimestamp: string;
  tamperProofSignature: string;
  originChainsOperations: ChainOperation[];
  destinationChainOperation?: ChainOperation;
}

QuoteStatus

interface QuoteStatus {
  quoteId: string;
  status: 'PENDING' | 'COMPLETED' | 'FAILED' | 'IN_PROGRESS' | 'REFUNDED';
  user: string;
  recipientAccountId: string;
  originChainOperations: Array<{
    hash: string;
    chainId: number;
    explorerUrl: string;
  }>;
  destinationChainOperations: Array<{
    hash: string;
    chainId: number;
    explorerUrl: string;
  }>;
}

Notes

  • The hook automatically polls for transaction status every 1 second after execution
  • Polling stops when the transaction reaches COMPLETED or FAILED status
  • Quote validation checks expiration time before execution
  • Requires Privy authentication and embedded wallet
  • Uses the PredictedAddressContext for account management

See Also

Build docs developers (and LLMs) love