Appearance
Amount & quote
Source crypto is what submit accepts — the token the user is sending, from a resolved transfer plan. Fiat (currently USD) is available from the token’s exchangeRate and from the min / quote hooks.
The demo binds two fields with useDualAmountInput and labels the min from useWalletTransferMinAmount.
useWalletTransferMinAmount
tsx
const { minAmount, min, isLoading, error, refetch } =
useWalletTransferMinAmount(plan)Options
| Option | Meaning |
|---|---|
plan | Resolved plan, or null |
Returns
| Field | Meaning |
|---|---|
min | { crypto, fiat? }. crypto is already ceiled to display decimals; fiat is ceiled to cents |
minAmount | Number(min.crypto) when it is a positive finite number, else null (handy for useDualAmountInput) |
isLoading / error / refetch | Fetch state |
Idle when plan is null or plan.flow === 'unavailable'.
When min.fiat is missing, convertCryptoToFiatCeil({ amount: min.crypto, exchangeRate: token.exchangeRate }) produces a fiat min.
useDualAmountInput
Shared amount hook from @swapped/connect-sdk/react (also used by Coinbase). Keeps crypto and fiat in sync.
tsx
import { useDualAmountInput } from '@swapped/connect-sdk/react'
const {
amount,
amountDisplay,
setAmount,
setAmountExact,
amountFiat,
setAmountFiat,
touched,
setTouched,
onBlur,
error: amountError,
isValid,
isFiatAvailable,
reset,
} = useDualAmountInput({
exchangeRate: token.exchangeRate,
token: token.symbol,
tokenDecimals: token.decimals,
minAmount,
maxAmount: Number(token.displayBalance),
balanceAmount: Number(token.displayBalance),
maxAmountMode: 'balance',
clampToMax: true,
formatCryptoValue: value => `${value} ${token.symbol}`,
})Options
| Option | Meaning |
|---|---|
exchangeRate | Token → fiat rate. null disables fiat |
token? | Token symbol (formatting + default decimals) |
maxDecimals? | Max fraction digits while typing crypto |
tokenDecimals? | Max fraction digits when converting from fiat |
minAmount? | Minimum in crypto units |
maxAmount? | Spendable ceiling in crypto units |
balanceAmount? | Raw balance in crypto units |
maxAmountMode? | 'balance' (default) or 'spendable' |
clampToMax? | Clamp typing to the ceiling. Default false |
formatCryptoValue? | Format min / max / balance in error messages |
touchedDelay? | ms before blur marks touched. Default 0 |
Returns
| Result | Meaning |
|---|---|
amount | Full-precision crypto string — pass this to quote / submit |
amountDisplay | Crypto string for the input |
setAmount / setAmountFiat | Edit one side; the other updates |
setAmountExact | Max button (skips the typing sanitizer) |
amountFiat | Fiat string (2 dp) |
isFiatAvailable | exchangeRate is usable |
error | Blocking validation after touch (below_min, …) |
warning | Soft above_spendable in 'balance' mode |
isValid | No blocking failure (ignores touched) |
amountError.code === 'below_min' is what the demo uses for “Minimum amount is …” on both fields.
Core helpers convertCryptoToFiat, convertFiatToCrypto, validateAmountInput are also on @swapped/connect-sdk. See Amount & quote (Core).
useWalletTransferQuote
tsx
const { quote, isFetching, error, refetch } = useWalletTransferQuote({
plan,
amount,
debounceMs: 300,
})Idle when plan is null, plan.flow === 'unavailable', or amount is empty / invalid (including below the plan min). enabled: false skips fetching entirely.
Options
| Option | Meaning |
|---|---|
plan | Resolved plan, or null |
amount | Source crypto string |
enabled? | Skip fetching when false. Default true |
debounceMs? | Default 300 |
Returns
| Result | Meaning |
|---|---|
quote | WalletTransferQuote or null |
isFetching | Quote in flight |
error / refetch | Fetch state |
quote.amountIn, quote.amountOut, quote.networkFee, quote.protocolFeeFiat, quote.estimatedTimeSeconds — Amount & quote (Core).
Pass the whole quote object into submit. Do not build or edit fields. Direct can omit the quote. Swap and bridge need a current quote — if the amount changed, refetch and do not submit a stale one.
The demo shows amountOut as “You receive ≈ …”, estimatedTimeSeconds, and networkFee (prefix $ when symbol === 'USD').