AAPLon, TSLAon - and settles the proceeds in USDC. It runs on the same ondo::swap offer type as buying, through the same contract, with the same two-call order.
Recommended: render
CheckoutContainer. It detects ondo::swap, reads the direction from your config, and renders the whole sell flow. This page covers what is specific to selling, and the rungs below the component.One field switches direction
There is no separate sell container. The sameCheckoutContainer, the same offer, the same config object - side is what picks the flow:
side, or closes the thunk over whatever selects the direction - a route, a tab, a toggle.
Everything else on the config - the symbol resolver and its totality requirement, onOrderConfirmed - works exactly as it does on the buy page.
What a sale approves
A purchase approves the funding coin, USDC, and receives the asset. A sale is the mirror: it approves the asset and receives USDC. That matters because the SDK ships no registry entry for a provider’s asset.TOKEN_REGISTRY knows the stablecoins swaps are funded with and nothing else, so on a sale:
- the contract address the balance is read on and the approval is granted for, and
- the decimals the typed amount is parsed at
OndoQuote.assetAddress, OndoQuote.asset.decimals) and nowhere else. useOndoSellCheckoutViewModel does that resolution for you; a host composing its own viewmodel has to read the quote before it can read a balance.
The settlement coin is USDC, and it is display-only: the scale of every amount on a built sale comes off the response’s receive_output_decimals, which is the only authority on how the proceeds are counted.
Skipping the wallet step
A sell page is usually reached from a position, and a position already names the wallet that holds it. SetCheckoutWalletSelection.preselected and the checkout opens on the amount, renumbering the two cards that remain:
embedded or external - you supply a ready EvmWallet either way. Like side, it is read once at mount.
The Ondo sell checkout is the only flow that honours
preselected today. The field sits on the wallet seam rather than in Ondo’s config because nothing about it is one provider’s, but a provider that has not adopted it ignores it rather than half-implementing it.Placing an order still takes two calls
The split is the same as a purchase, and for the same reason: an approval takes most of a built transaction’s ~60-second life, so bundling both behind one button would hand the seller an expired quote.prepareSellapproves the swap contract to pull the asset, then builds the sale that delivers it. The result is a committed quote: firm calldata with anexpiresAt.- The seller reviews firm numbers - what goes, the fee, what arrives, and the floor below which the fill reverts.
executeSwapbroadcasts that calldata verbatim and waits for it to mine. It is one method for both directions, because broadcasting reads calldata and a deadline and knows about neither.
Sell caps are independent of buy caps.
getTradingStatus takes a required side and reports tradable with size limits for that side only - a working buy does not imply a working sell, and the market can be open one way and closed the other.Build your own UI with hooks (L2)
Build your own UI with hooks (L2)
useOndoSellCheckoutViewModel wraps the whole flow - trading status, sell quotes, the wallet step, the approval, the review and the broadcast - and returns { state, onEvent }. It takes the same options as its buy counterpart.OndoSellCheckoutUiState is a discriminated union with a flow-level error arm: an offer that names no CoinList swap contract on the chain you passed has no checkout to render, and the viewmodel discovers that before any step runs, so nothing is fetched and no timer starts. switch exhaustively and assign the default to const exhaustive: never = state.Inside the content arm, wallet is null exactly when the host preselected a wallet. That null is the whole skip - it is what you render nothing for, and the single fact both remaining step numbers derive from.The smaller hooks it composes are exported too, so you can assemble your own viewmodel instead:useErc20Balance is the address-keyed counterpart to useErc20TokenBalances: a token whose contract address arrives at runtime has no registry symbol to look up, which is exactly the sell case. A tokenAddress of null fetches nothing, which is the normal state before the first quote lands.Every hook that fetches or polls takes enabled, and all of them must be called unconditionally. See SDK structure for the conventions they share.Drive it yourself with the client (L1)
Drive it yourself with the client (L1)
coinlist.ondo is a plain namespace with no React. The reads and the two builders exist on both the browser client and CoinListServer; the two wallet-driven halves are client-only.prepareSell returns the same OndoSwapPreparationError a purchase does - every arm names a remedy, and an unsupported chain or a refused approval is fixed the same way whichever token was being approved.prepareSell phases, in order. An allowance that already covers the sale skips the approval phases:checking-allowance → (resetting-allowance → confirming-allowance-reset, for stale non-zero allowances) → approving (wallet popup) → confirming-approval → building-transactionexecuteSwap phases: broadcasting-swap (wallet popup) → confirming-swapexecuteSwap broadcasts the calldata verbatim. Never re-encode it: the contract verifies a signature over the exact arguments inside.expected is what the sale should return; minimum is the floor the calldata enforces on chain. A fill below minimum reverts, so that - not expected - is what a seller is actually guaranteed. Show both.Which contract the seller approves
The ERC-20 spender comes off the offer, the same way it does for a purchase:swapSpender(offer.swapContracts, chain) answers the CoinList contract that chain settles through, or null where this offer cannot be swapped there. See Which contract the buyer approves.
Next steps
Ondo Swap Buy
The other direction: the funding coin, the committed quote, the two-call order.
Building the Checkout flow
One container for every provider, and the config both Ondo products share.
Wallets
The
EvmWallet seam, and preselected for skipping the wallet step.Errors and edge cases
Every error shape the flows return, and how to handle it.