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
| Parameter | Type | Required | Default | Description |
|---|
fromChain | number | Yes | - | Source chain ID |
toChain | number | Yes | - | Destination chain ID (typically 999 for HyperEVM) |
fromToken | string | Yes | - | Source token contract address |
toToken | string | Yes | - | Destination token contract address |
amount | string | Yes | - | Amount in smallest unit (wei) |
fromAddress | string | Yes | - | User’s wallet address |
slippageTolerance | number | No | SDK default | Slippage tolerance (e.g., 0.5 for 0.5%) |
routePreference | RoutePreference | No | 'recommended' | 'recommended' | 'fastest' | 'cheapest' |
enabled | boolean | No | true | Enable/disable automatic fetching |
Returns
UseQuoteReturn
| Property | Type | Description |
|---|
quote | Quote | null | The fetched quote, or null if not available |
isLoading | boolean | true while a quote request is in flight |
error | Error | null | Any 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>
);
}
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:
-
Debouncing is automatic - The hook waits 500ms after the last parameter change before fetching. Do not add your own debounce.
-
Handle all states - Always render appropriate UI for loading, error, and empty states.
-
Use
enabled wisely - Disable fetching when the user hasn’t entered valid input yet.
-
Validate amounts - Ensure the amount is a valid positive number before enabling the hook.
-
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