Skip to main content

useQuote

The useQuote hook fetches bridge quotes with built-in debouncing, automatic refetching when parameters change, and proper loading state management.

Import

import { useQuote } from '@siphoyawe/mina-sdk/react';

Signature

function useQuote(params: UseQuoteParams): UseQuoteReturn

Parameters

UseQuoteParams

ParameterTypeRequiredDefaultDescription
fromChainnumberYes-Source chain ID
toChainnumberYes-Destination chain ID (typically 999 for HyperEVM)
fromTokenstringYes-Source token contract address
toTokenstringYes-Destination token contract address
amountstringYes-Amount in smallest unit (wei)
fromAddressstringYes-User’s wallet address
slippageTolerancenumberNoSDK defaultSlippage tolerance (e.g., 0.5 for 0.5%)
routePreferenceRoutePreferenceNo'recommended''recommended' | 'fastest' | 'cheapest'
enabledbooleanNotrueEnable/disable automatic fetching

Returns

UseQuoteReturn

PropertyTypeDescription
quoteQuote | nullThe fetched quote, or null if not available
isLoadingbooleantrue while a quote request is in flight
errorError | nullAny error that occurred during fetch
refetch() => Promise<void>Manually trigger a new quote request

Features

  • 500ms debounce - Prevents excessive API calls when parameters change rapidly
  • Auto-refetch - Automatically fetches a new quote when any parameter changes
  • Stale-while-revalidate - Keeps the previous quote visible during refetch
  • Controlled fetching - Use enabled to pause/resume automatic fetching

Basic Usage

'use client';

import { useQuote } from '@siphoyawe/mina-sdk/react';

function QuoteDisplay() {
  const { quote, isLoading, error } = useQuote({
    fromChain: 42161,        // Arbitrum
    toChain: 999,            // HyperEVM
    fromToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC on Arbitrum
    toToken: '0xb88339cb7199b77e23db6e890353e22632ba630f',   // USDC on HyperEVM
    amount: '1000000000',    // 1000 USDC (6 decimals)
    fromAddress: '0x...',    // User's wallet
  });

  if (isLoading) return <div>Getting quote...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!quote) return <div>Enter amount to get quote</div>;

  return (
    <div>
      <p>You will receive: {quote.toAmount}</p>
      <p>Estimated fees: ${quote.fees.totalUsd.toFixed(2)}</p>
    </div>
  );
}

Form Integration

Integrate with form inputs for a complete bridge interface:
'use client';

import { useState } from 'react';
import { useQuote } from '@siphoyawe/mina-sdk/react';
import { parseUnits } from 'viem';

function BridgeForm({ walletAddress }: { walletAddress: string }) {
  const [amount, setAmount] = useState('');
  const [fromChain, setFromChain] = useState(42161);
  const [slippage, setSlippage] = useState(0.5);

  // Convert display amount to wei
  const amountWei = amount ? parseUnits(amount, 6).toString() : '';

  const { quote, isLoading, error, refetch } = useQuote({
    fromChain,
    toChain: 999,
    fromToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
    toToken: '0xb88339cb7199b77e23db6e890353e22632ba630f',
    amount: amountWei,
    fromAddress: walletAddress,
    slippageTolerance: slippage,
    routePreference: 'recommended',
  });

  return (
    <div>
      <input
        type="number"
        value={amount}
        onChange={(e) => setAmount(e.target.value)}
        placeholder="Enter amount"
      />

      <select
        value={fromChain}
        onChange={(e) => setFromChain(Number(e.target.value))}
      >
        <option value={42161}>Arbitrum</option>
        <option value={8453}>Base</option>
        <option value={10}>Optimism</option>
      </select>

      <select
        value={slippage}
        onChange={(e) => setSlippage(Number(e.target.value))}
      >
        <option value={0.1}>0.1%</option>
        <option value={0.5}>0.5%</option>
        <option value={1}>1%</option>
      </select>

      {isLoading && <p>Fetching quote...</p>}
      {error && <p className="error">{error.message}</p>}

      {quote && (
        <div className="quote-details">
          <p>Receive: {quote.toAmountFormatted} {quote.toToken.symbol}</p>
          <p>Rate: 1 {quote.fromToken.symbol} = {quote.rate} {quote.toToken.symbol}</p>
          <p>Fee: ${quote.fees.totalUsd.toFixed(2)}</p>
          <p>Time: ~{quote.estimatedTime}s</p>
          <button onClick={refetch}>Refresh Quote</button>
        </div>
      )}
    </div>
  );
}

Conditional Fetching

Use the enabled parameter to control when quotes are fetched:
'use client';

import { useQuote } from '@siphoyawe/mina-sdk/react';

function ConditionalQuote({
  amount,
  fromAddress,
  isWalletConnected
}: {
  amount: string;
  fromAddress: string;
  isWalletConnected: boolean;
}) {
  const { quote, isLoading } = useQuote({
    fromChain: 42161,
    toChain: 999,
    fromToken: '0x...',
    toToken: '0x...',
    amount,
    fromAddress,
    // Only fetch when wallet is connected and amount is valid
    enabled: isWalletConnected && amount !== '' && amount !== '0',
  });

  if (!isWalletConnected) {
    return <p>Connect wallet to see quote</p>;
  }

  if (!amount) {
    return <p>Enter an amount</p>;
  }

  if (isLoading) {
    return <p>Loading...</p>;
  }

  return quote ? (
    <p>Receive: {quote.toAmountFormatted}</p>
  ) : null;
}

Route Preferences

Choose how routes are selected:
'use client';

import { useState } from 'react';
import { useQuote, type RoutePreference } from '@siphoyawe/mina-sdk/react';

function RouteSelector() {
  const [preference, setPreference] = useState<RoutePreference>('recommended');

  const { quote } = useQuote({
    fromChain: 42161,
    toChain: 999,
    fromToken: '0x...',
    toToken: '0x...',
    amount: '1000000000',
    fromAddress: '0x...',
    routePreference: preference,
  });

  return (
    <div>
      <div className="route-options">
        <button
          onClick={() => setPreference('recommended')}
          className={preference === 'recommended' ? 'active' : ''}
        >
          Recommended
        </button>
        <button
          onClick={() => setPreference('fastest')}
          className={preference === 'fastest' ? 'active' : ''}
        >
          Fastest
        </button>
        <button
          onClick={() => setPreference('cheapest')}
          className={preference === 'cheapest' ? 'active' : ''}
        >
          Cheapest
        </button>
      </div>

      {quote && (
        <div>
          <p>Route: {quote.route.provider}</p>
          <p>Time: ~{quote.estimatedTime}s</p>
          <p>Fee: ${quote.fees.totalUsd.toFixed(2)}</p>
        </div>
      )}
    </div>
  );
}

Manual Refetch

Use refetch to manually trigger a new quote:
'use client';

import { useQuote } from '@siphoyawe/mina-sdk/react';

function QuoteWithRefresh() {
  const { quote, isLoading, refetch } = useQuote({
    fromChain: 42161,
    toChain: 999,
    fromToken: '0x...',
    toToken: '0x...',
    amount: '1000000000',
    fromAddress: '0x...',
  });

  return (
    <div>
      {quote && <p>Receive: {quote.toAmountFormatted}</p>}

      <button
        onClick={refetch}
        disabled={isLoading}
      >
        {isLoading ? 'Refreshing...' : 'Refresh Quote'}
      </button>
    </div>
  );
}
Manual refetch bypasses the debounce timer and fetches immediately.

Best Practices

Performance and UX Tips:
  1. Debouncing is automatic - The hook waits 500ms after the last parameter change before fetching. Do not add your own debounce.
  2. Handle all states - Always render appropriate UI for loading, error, and empty states.
  3. Use enabled wisely - Disable fetching when the user hasn’t entered valid input yet.
  4. Validate amounts - Ensure the amount is a valid positive number before enabling the hook.
  5. Keep quotes fresh - Quotes expire. Consider auto-refreshing or prompting users to refresh before execution.

Error Handling

'use client';

import { useQuote } from '@siphoyawe/mina-sdk/react';

function RobustQuoteDisplay() {
  const { quote, isLoading, error, refetch } = useQuote({
    fromChain: 42161,
    toChain: 999,
    fromToken: '0x...',
    toToken: '0x...',
    amount: '1000000000',
    fromAddress: '0x...',
  });

  if (error) {
    return (
      <div className="error-state">
        <p>Failed to get quote</p>
        <p className="error-message">{error.message}</p>
        <button onClick={refetch}>Try Again</button>
      </div>
    );
  }

  // Note: Previous quote is preserved during refetch (stale-while-revalidate)
  return (
    <div className={isLoading ? 'opacity-50' : ''}>
      {quote ? (
        <p>Receive: {quote.toAmountFormatted}</p>
      ) : (
        <p>Enter details to see quote</p>
      )}
      {isLoading && <span className="loading-indicator" />}
    </div>
  );
}

Next Steps

useTokenBalance

Track wallet token balances

useTransactionStatus

Monitor transaction progress