@coinlist-co/react 0.11.0 → 0.11.1-rc.10770e8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/{chunk-UIIXXLA7.js → chunk-7CTH4KPU.js} +734 -198
  2. package/dist/chunk-7CTH4KPU.js.map +1 -0
  3. package/dist/{chunk-B2HCVPCQ.js → chunk-LSPZETDH.js} +81 -33
  4. package/dist/chunk-LSPZETDH.js.map +1 -0
  5. package/dist/chunk-UZUQALFY.js +279 -0
  6. package/dist/chunk-UZUQALFY.js.map +1 -0
  7. package/dist/client/index.cjs +5415 -2413
  8. package/dist/client/index.cjs.map +1 -1
  9. package/dist/client/index.d.cts +2439 -1209
  10. package/dist/client/index.d.ts +2439 -1209
  11. package/dist/client/index.js +4457 -2178
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/collections-BBI_XydI.d.cts +116 -0
  14. package/dist/collections-BrX9rRWc.d.ts +116 -0
  15. package/dist/{config-B5mwS_2l.d.cts → config-CMl1bR3F.d.cts} +1183 -150
  16. package/dist/{config-B5mwS_2l.d.ts → config-CMl1bR3F.d.ts} +1183 -150
  17. package/dist/server/index.cjs +1005 -265
  18. package/dist/server/index.cjs.map +1 -1
  19. package/dist/server/index.d.cts +81 -4
  20. package/dist/server/index.d.ts +81 -4
  21. package/dist/server/index.js +120 -51
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/shared/index.cjs +798 -204
  24. package/dist/shared/index.cjs.map +1 -1
  25. package/dist/shared/index.d.cts +98 -16
  26. package/dist/shared/index.d.ts +98 -16
  27. package/dist/shared/index.js +22 -6
  28. package/package.json +3 -2
  29. package/dist/chunk-B2HCVPCQ.js.map +0 -1
  30. package/dist/chunk-KDGNDAHA.js +0 -146
  31. package/dist/chunk-KDGNDAHA.js.map +0 -1
  32. package/dist/chunk-UIIXXLA7.js.map +0 -1
  33. package/dist/collections-BhDkYmzV.d.cts +0 -65
  34. package/dist/collections-CZhHoQHr.d.ts +0 -65
@@ -1,10 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, ButtonHTMLAttributes } from 'react';
4
- import { A as AuthorizationCode, C as CodeVerifier, E as EvmWalletAddress, a as EthereumChain, T as Tx, b as Erc20Namespace, c as EvmContractAddress, B as BlockchainAmount, d as CoinListTokenSaleNamespace, O as OfferId, e as OfferOptionId, f as AssetId, P as Participation, g as CoinListTokenSaleNamespaceImpl, S as SharedNamespaceContext, h as OndoNamespace, i as AssetSymbol, j as OndoSwapTransaction, k as OndoNamespaceImpl, l as SuperstateSwapNamespace, W as WalletsNamespace, m as Bps, n as SuperstateSwapNamespaceImpl, R as RequirementsNamespace, o as Requirement, p as RequirementsNamespaceImpl, q as Config, r as OAuthAccessToken, s as OffersNamespace, t as TokensNamespace, u as Erc20Asset, v as OfferDetail, w as StablecoinSymbol, x as OfferType, y as Offer, z as RequirementStatusInfo, D as RequirementType, F as RequirementStatusValue, G as OfferOptionAddress, H as RequirementId, K as KycLevelName, I as WalletChallengeType, J as DocumentSubmission, L as OndoTradingStatus, M as AssetDecimals, N as OndoQuote, Q as OrderBookSide, U as OndoQuoteSize, V as BuildOndoSwapTransactionParams, X as OfferOptionAddressId, Y as TokenMetadata, Z as TokenIdentifier } from '../config-B5mwS_2l.cjs';
5
- export { _ as HttpError, $ as HttpResponse, a0 as KycToken } from '../config-B5mwS_2l.cjs';
6
- import { P as PKCEConfig, S as SwapQuote, A as AssetIconUrl, a as ShortenedWalletAddress, F as FormattedAmountAssetUi, b as FormattedPercentUi, T as TxExplorerUrl, N as NonEmptyArray } from '../collections-BhDkYmzV.cjs';
7
- import { Hash, Hex, Abi, TransactionReceipt } from 'viem';
4
+ import { A as AuthorizationCode, C as CodeVerifier, L as Logger, W as WalletError, E as Erc20Namespace, a as EthereumChain, b as EvmContractAddress, B as BlockchainAmount, c as CoinListTokenSaleNamespace, O as OfferId, d as OfferOptionId, e as AssetId, P as Participation, f as CoinListTokenSaleNamespaceImpl, S as SharedNamespaceContext, g as OndoNamespace, h as AssetSymbol, i as OndoBuyTransaction, j as OndoSellTransaction, k as OndoSwapTransactionCore, l as OrderBookSide, m as OndoNamespaceImpl, n as SuperstateSwapNamespace, o as WalletsNamespace, p as Bps, q as EvmWalletAddress, r as SuperstateSwapNamespaceImpl, R as RequirementsNamespace, s as Requirement, t as RequirementsNamespaceImpl, u as Config, v as OAuthAccessToken, w as OffersNamespace, T as TokensNamespace, x as StablecoinSymbol, y as Erc20Asset, z as OfferDetail, D as OfferType, F as Offer, G as RequirementStatusInfo, H as RequirementType, I as RequirementStatusValue, J as OfferOptionAddress, K as RequirementId, M as KycLevelName, N as DocumentSubmission, Q as WalletChallengeType, U as PinoLoggerOptions, V as OndoTradingStatus, X as AssetDecimals, Y as BuildOndoBuyParams, Z as BuildOndoSellParams, _ as OndoQuote, $ as OndoQuoteSize, a0 as OfferOptionAddressId, a1 as TokenMetadata, a2 as TokenIdentifier } from '../config-CMl1bR3F.cjs';
5
+ export { a3 as DebugEvent, a4 as FrontlineEventId, a5 as HttpError, a6 as HttpResponse, a7 as KycToken, a8 as LogBinding, a9 as LogBindings, aa as LogCause, ab as LogLevel, ac as LogScope, ad as LogValue, ae as ProductionLogLevel, af as RedactedWalletError, ag as RequestId, ah as SafeEvent, ai as SafeFields, aj as UnredactedFields } from '../config-CMl1bR3F.cjs';
6
+ import { P as PKCEConfig, E as EvmWallet, S as SwapQuote, A as AssetIconUrl, a as ShortenedWalletAddress, F as FormattedAmountAssetUi, b as FormattedPercentUi, T as TxExplorerUrl, C as ConnectWallet, N as NonEmptyArray } from '../collections-BBI_XydI.cjs';
7
+ export { B as BroadcastTxParams, c as EvmSigner, W as WriteContractParams } from '../collections-BBI_XydI.cjs';
8
+ import { Hash } from 'viem';
8
9
  import * as class_variance_authority_types from 'class-variance-authority/types';
9
10
  import { VariantProps } from 'class-variance-authority';
10
11
 
@@ -94,84 +95,24 @@ type ClientAuthSession = {
94
95
  */
95
96
  type ClientAuthConfig = PKCEConfig & {
96
97
  readonly coinlistBaseUrl?: string;
98
+ readonly logger?: Logger;
97
99
  };
98
100
  declare class ClientAuthNamespaceImpl implements ClientAuthNamespace {
99
101
  private readonly config;
100
102
  private readonly session;
103
+ private readonly log;
101
104
  constructor(config: ClientAuthConfig, session: ClientAuthSession);
102
105
  getState(): AuthState;
103
106
  startOAuth(): Promise<void>;
107
+ private redirectToOAuth;
108
+ /**
109
+ * Every failure here is silent from the browser's side - a state mismatch
110
+ * and a missing verifier both just leave the user logged out - so the
111
+ * reason is logged rather than left for the host to infer from a callback.
112
+ */
104
113
  completeOAuth(): OauthClientResult;
105
114
  logout(): void;
106
- }
107
-
108
- /**
109
- * A classified wallet/transaction failure. The SDK derives this from whatever
110
- * the {@link EvmWallet} throws, so consumers get a stable, typed error
111
- * shape regardless of the underlying wallet library.
112
- */
113
- type WalletError = {
114
- type: 'user_rejected';
115
- } | {
116
- type: 'insufficient_funds';
117
- } | {
118
- type: 'contract_reverted';
119
- reason: string;
120
- } | {
121
- type: 'timeout';
122
- hash: Hash;
123
- } | {
124
- type: 'unknown';
125
- cause: unknown;
126
- };
127
- /**
128
- * Classifies an error thrown by an {@link EvmWallet} into a typed
129
- * {@link WalletError}. Pass the transaction `hash` when awaiting a receipt so a
130
- * timeout can be reported against it.
131
- */
132
- declare function classifyWalletError(error: unknown, ctx?: {
133
- hash?: Hash;
134
- }): WalletError;
135
-
136
- type WriteContractParams = {
137
- abi: Abi;
138
- address: `0x${string}`;
139
- functionName: string;
140
- args?: readonly unknown[];
141
- value?: bigint;
142
- chain: EthereumChain;
143
- };
144
- type BroadcastTxParams = Tx & {
145
- chain: EthereumChain;
146
- };
147
- /**
148
- * The signing-only wallet capability: address + `signMessage`. This is all the
149
- * external-wallet ownership proof needs (see `useConnectWallet`), so hosts can
150
- * satisfy that flow without implementing on-chain capabilities. The richer
151
- * {@link EvmWallet} extends this for swap flows.
152
- *
153
- * SDK users implement this against their own wallet stack (e.g. viem, wagmi,
154
- * Privy). `signMessage` throws on failure and the SDK classifies it.
155
- */
156
- interface EvmSigner {
157
- readonly address: EvmWalletAddress;
158
- signMessage(message: string): Promise<Hex>;
159
- }
160
- /**
161
- * The full on-chain wallet the SDK needs to run the swap flows: an
162
- * {@link EvmSigner} plus contract writes, raw-tx broadcast, and confirmation.
163
- * SDK users implement this against their own wallet stack (e.g. viem, wagmi,
164
- * Privy).
165
- *
166
- * Methods throw on failure. The SDK catches and classifies the thrown error
167
- * (viem's `UserRejectedRequestError`, `InsufficientFundsError`, timeouts, …)
168
- * into a typed {@link WalletError}, so implementers can simply let their wallet
169
- * library's errors propagate.
170
- */
171
- interface EvmWallet extends EvmSigner {
172
- writeContract(params: WriteContractParams): Promise<Hash>;
173
- broadcastRawTx(params: BroadcastTxParams): Promise<Hash>;
174
- awaitTx(hash: Hash, chain: EthereumChain): Promise<TransactionReceipt>;
115
+ private readOauthCallback;
175
116
  }
176
117
 
177
118
  type Erc20AllowancePhase = 'checking-allowance' | 'resetting-allowance' | 'confirming-allowance-reset' | 'approving' | 'confirming-approval';
@@ -315,12 +256,16 @@ declare class ClientCoinListTokenSaleNamespaceImpl extends CoinListTokenSaleName
315
256
  }
316
257
 
317
258
  /**
318
- * Progress phases emitted by {@link prepareOndoSwap}, in the order they occur.
319
- * An allowance that already covers the order skips the approval phases.
259
+ * Progress phases emitted while an order is being prepared, in the order they
260
+ * occur. An allowance that already covers the order skips the approval phases.
320
261
  */
321
262
  type OndoSwapPreparationPhase = Erc20AllowancePhase | 'building-transaction';
322
263
  /**
323
- * A step-tagged reason {@link prepareOndoSwap} failed.
264
+ * A step-tagged reason a preparation failed.
265
+ *
266
+ * Shared by both directions because every arm names a *remedy* rather than a
267
+ * trade: an unsupported chain, a refused approval and a build that would not
268
+ * complete are fixed the same way whichever token was being approved.
324
269
  *
325
270
  * `insufficient-allowance` is separated from the generic build failure because
326
271
  * it is the one with a remedy: frontline reads the allowance before asking
@@ -336,14 +281,24 @@ type OndoSwapPreparationError = {
336
281
  } | {
337
282
  step: 'build-transaction';
338
283
  };
339
- type OndoSwapPreparationResult = {
284
+ /**
285
+ * A prepared order of whichever kind was asked for, or the step that stopped
286
+ * it.
287
+ *
288
+ * Generic in the transaction rather than a union over the two, so a caller
289
+ * that asked for a sale cannot be handed a purchase to narrow.
290
+ */
291
+ type OndoSwapPreparationResult<T> = {
340
292
  type: 'success';
341
- transaction: OndoSwapTransaction;
293
+ transaction: T;
342
294
  } | {
343
295
  type: 'error';
344
296
  error: OndoSwapPreparationError;
345
297
  };
346
- type PrepareOndoSwapParams = {
298
+ type OndoBuyPreparationResult = OndoSwapPreparationResult<OndoBuyTransaction>;
299
+ type OndoSellPreparationResult = OndoSwapPreparationResult<OndoSellTransaction>;
300
+ /** What both preparations take, before the two fields whose meaning forks. */
301
+ type PrepareOndoSwapParamsCore = {
347
302
  ondo: OndoNamespace;
348
303
  erc20: Erc20Namespace;
349
304
  wallet: EvmWallet;
@@ -351,21 +306,36 @@ type PrepareOndoSwapParams = {
351
306
  symbol: AssetSymbol;
352
307
  /** The chain the swap executes on, which the swap contract lives on. */
353
308
  chain: EthereumChain;
309
+ onProgress?: (phase: OndoSwapPreparationPhase) => void;
310
+ };
311
+ type PrepareOndoBuyParams = PrepareOndoSwapParamsCore & {
354
312
  /**
355
- * The ERC-20 being spent, e.g. USDC on `chain`.
313
+ * The funding token being spent - USDC on `chain`.
356
314
  *
357
- * Approval only - it is not sent to frontline, which resolves the funding
358
- * token from the offer. The two agreeing is what the allowance check on the
359
- * far side is confirming.
315
+ * Approval only - it is not sent to frontline, which resolves both tokens
316
+ * from the offer. The two agreeing is what the allowance check on the far
317
+ * side is confirming.
360
318
  */
361
319
  tokenAddress: EvmContractAddress;
362
- /** How much of `tokenAddress` to spend, in its base units. */
320
+ /** How much of the funding token to spend, in its base units. */
321
+ amount: BlockchainAmount;
322
+ };
323
+ type PrepareOndoSellParams = PrepareOndoSwapParamsCore & {
324
+ /**
325
+ * The **asset** being sold, on `chain` - not a stablecoin. A sale delivers
326
+ * the asset, so this is what the swap contract must be approved to pull.
327
+ *
328
+ * Approval only, as on a purchase. Unlike a purchase, the SDK has no
329
+ * registry entry to fall back on: the address comes off the sell quote and
330
+ * nowhere else.
331
+ */
332
+ tokenAddress: EvmContractAddress;
333
+ /** How much of the asset to sell, in the asset's base units. */
363
334
  amount: BlockchainAmount;
364
- onProgress?: (phase: OndoSwapPreparationPhase) => void;
365
335
  };
366
336
  /**
367
- * Gets an order ready to place: ensures the swap contract may pull `amount` of
368
- * `tokenAddress`, then builds the transaction that spends it.
337
+ * Gets a purchase ready to place: ensures the swap contract may pull `amount`
338
+ * of the funding token, then builds the transaction that spends it.
369
339
  *
370
340
  * The approval comes first deliberately. Built calldata is only good for about
371
341
  * a minute and an approval takes most of one to mine, so building first would
@@ -378,7 +348,16 @@ type PrepareOndoSwapParams = {
378
348
  * Total: every failure is returned step-tagged rather than thrown, so a caller
379
349
  * can map each one to its own copy.
380
350
  */
381
- declare function prepareOndoSwap(params: PrepareOndoSwapParams): Promise<OndoSwapPreparationResult>;
351
+ declare function prepareOndoBuy(params: PrepareOndoBuyParams): Promise<OndoBuyPreparationResult>;
352
+ /**
353
+ * Gets a sale ready to place: ensures the swap contract may pull `amount` of
354
+ * the **asset**, then builds the transaction that spends it.
355
+ *
356
+ * Identical in shape to {@link prepareOndoBuy} and different in what it
357
+ * approves, which is the only thing about a sale that is not the purchase
358
+ * inverted. Same ordering, and for the same reason.
359
+ */
360
+ declare function prepareOndoSell(params: PrepareOndoSellParams): Promise<OndoSellPreparationResult>;
382
361
  /** Progress phases emitted by {@link executeOndoSwap}, in order. */
383
362
  type OndoSwapExecutionPhase = 'broadcasting-swap' | 'confirming-swap';
384
363
  /**
@@ -399,21 +378,28 @@ type OndoSwapExecutionError = {
399
378
  } | {
400
379
  step: 'swap-reverted';
401
380
  };
402
- type OndoSwapExecutionResult = {
381
+ type OndoSwapExecutionResult<T> = {
403
382
  type: 'success';
404
383
  txHash: Hash;
405
- transaction: OndoSwapTransaction;
384
+ transaction: T;
406
385
  } | {
407
386
  type: 'error';
408
387
  error: OndoSwapExecutionError;
409
388
  };
410
- type ExecuteOndoSwapParams = {
389
+ type OndoBuyExecutionResult = OndoSwapExecutionResult<OndoBuyTransaction>;
390
+ type OndoSellExecutionResult = OndoSwapExecutionResult<OndoSellTransaction>;
391
+ type ExecuteOndoSwapParams<T> = {
411
392
  wallet: EvmWallet;
412
393
  /**
413
- * The transaction to fill, from {@link prepareOndoSwap} or
414
- * `ondo.buildSwapTransaction`.
394
+ * The transaction to fill, from {@link prepareOndoBuy},
395
+ * {@link prepareOndoSell}, or either namespace builder.
396
+ *
397
+ * Typed by what it carries rather than by which direction built it:
398
+ * broadcasting reads the calldata, the deadline and nothing else, so a
399
+ * purchase and a sale are the same job here. The concrete type travels
400
+ * through to the result so a caller gets back what it handed in.
415
401
  */
416
- transaction: OndoSwapTransaction;
402
+ transaction: T;
417
403
  /**
418
404
  * The chain it was built for.
419
405
  *
@@ -431,8 +417,12 @@ type ExecuteOndoSwapParams = {
431
417
  onProgress?: (phase: OndoSwapExecutionPhase) => void;
432
418
  };
433
419
  /**
434
- * Fills a built transaction: broadcasts the calldata Ondo encoded and waits
435
- * for it to mine.
420
+ * Fills a built transaction, whichever direction built it: broadcasts the
421
+ * calldata Ondo encoded and waits for it to mine.
422
+ *
423
+ * The one function both directions share, because it is the one step that does
424
+ * not depend on which token moves - {@link OndoSwapTransactionCore} is exactly
425
+ * what it reads.
436
426
  *
437
427
  * The calldata is broadcast verbatim - the SDK never re-encodes it, because
438
428
  * the contract verifies a signature over the exact arguments inside it.
@@ -442,39 +432,61 @@ type ExecuteOndoSwapParams = {
442
432
  * encoded in the calldata), and its `to` must be the contract the approval
443
433
  * named, since anything else cannot pull the funds.
444
434
  */
445
- declare function executeOndoSwap(params: ExecuteOndoSwapParams): Promise<OndoSwapExecutionResult>;
435
+ declare function executeOndoSwap<T extends OndoSwapTransactionCore>(params: ExecuteOndoSwapParams<T>): Promise<OndoSwapExecutionResult<T>>;
446
436
 
447
437
  /**
448
- * The Ondo namespace plus the two halves of placing an order, which need a
449
- * wallet and so cannot live on the shared namespace.
438
+ * The Ondo namespace plus the halves of placing an order that need a wallet,
439
+ * and so cannot live on the shared namespace.
450
440
  *
451
- * They are two calls rather than one because the flow is two user decisions:
452
- * the buyer commits to an amount (approving the spend), reviews firm numbers,
453
- * and only then places the order. Bundling them would mean approving and
454
- * filling behind a single button, and would burn most of the transaction's
455
- * ~60-second life on the approval.
441
+ * Preparing and executing are two calls rather than one because the flow is
442
+ * two user decisions: the trader commits to an amount (approving the spend),
443
+ * reviews firm numbers, and only then places the order. Bundling them would
444
+ * mean approving and filling behind a single button, and would burn most of
445
+ * the transaction's ~60-second life on the approval.
446
+ *
447
+ * Preparing is two methods and executing is one, mirroring where the two
448
+ * directions actually differ: a purchase approves the funding token and a sale
449
+ * approves the asset, while broadcasting reads calldata and a deadline and
450
+ * knows nothing about either.
456
451
  *
457
452
  * `erc20` is supplied internally, so callers hand over only a wallet and an
458
453
  * order.
459
454
  */
460
455
  interface ClientOndoNamespace extends OndoNamespace {
461
456
  /**
462
- * Approves the swap contract to spend `amount`, then builds the transaction
463
- * that spends it. Returns a step-tagged result rather than throwing.
457
+ * Approves the swap contract to spend `amount` of the funding token, then
458
+ * builds the purchase that spends it. Returns a step-tagged result rather
459
+ * than throwing.
460
+ */
461
+ prepareBuy(params: Omit<PrepareOndoBuyParams, 'ondo' | 'erc20'>): Promise<OndoBuyPreparationResult>;
462
+ /**
463
+ * Approves the swap contract to pull `amount` of the **asset**, then builds
464
+ * the sale that delivers it. Returns a step-tagged result rather than
465
+ * throwing.
464
466
  */
465
- prepareSwap(params: Omit<PrepareOndoSwapParams, 'ondo' | 'erc20'>): Promise<OndoSwapPreparationResult>;
467
+ prepareSell(params: Omit<PrepareOndoSellParams, 'ondo' | 'erc20'>): Promise<OndoSellPreparationResult>;
466
468
  /**
467
469
  * Broadcasts a built transaction and waits for it to mine, refusing one that
468
470
  * has expired or points at an unexpected contract. Returns a step-tagged
469
471
  * result rather than throwing.
472
+ *
473
+ * Takes either direction's transaction and hands the same one back. The
474
+ * `side` tag is required here and not by {@link executeOndoSwap} itself
475
+ * because this is the layer that logs: a flow event without a direction
476
+ * cannot be read back.
470
477
  */
471
- executeSwap(params: ExecuteOndoSwapParams): Promise<OndoSwapExecutionResult>;
478
+ executeSwap<T extends OndoSwapTransactionCore & {
479
+ side: OrderBookSide;
480
+ }>(params: ExecuteOndoSwapParams<T>): Promise<OndoSwapExecutionResult<T>>;
472
481
  }
473
482
  declare class ClientOndoNamespaceImpl extends OndoNamespaceImpl implements ClientOndoNamespace {
474
483
  private readonly erc20;
475
484
  constructor(ctx: SharedNamespaceContext, erc20: Erc20Namespace);
476
- prepareSwap(params: Omit<PrepareOndoSwapParams, 'ondo' | 'erc20'>): Promise<OndoSwapPreparationResult>;
477
- executeSwap(params: ExecuteOndoSwapParams): Promise<OndoSwapExecutionResult>;
485
+ prepareBuy(params: Omit<PrepareOndoBuyParams, 'ondo' | 'erc20'>): Promise<OndoBuyPreparationResult>;
486
+ prepareSell(params: Omit<PrepareOndoSellParams, 'ondo' | 'erc20'>): Promise<OndoSellPreparationResult>;
487
+ executeSwap<T extends OndoSwapTransactionCore & {
488
+ side: OrderBookSide;
489
+ }>(params: ExecuteOndoSwapParams<T>): Promise<OndoSwapExecutionResult<T>>;
478
490
  }
479
491
 
480
492
  /**
@@ -660,6 +672,8 @@ interface ClientSupportNamespace {
660
672
  contact(): void;
661
673
  }
662
674
  declare class ClientSupportNamespaceImpl implements ClientSupportNamespace {
675
+ private readonly log;
676
+ constructor(logger?: Logger | null);
663
677
  contact(): void;
664
678
  }
665
679
 
@@ -742,10 +756,15 @@ interface CoinListClient {
742
756
  /**
743
757
  * Ondo swaps: whether an asset is tradable right now and what it costs - e.g.
744
758
  * `coinlist.ondo.getQuote({ ... })` - plus placing an order, in the two
745
- * halves the flow actually has: `prepareSwap` (approve, then commit a firm
746
- * quote) and `executeSwap` (broadcast it).
759
+ * halves the flow actually has: `prepareBuy` / `prepareSell` (approve, then
760
+ * commit a firm quote) and `executeSwap` (broadcast it).
747
761
  *
748
- * The reads are free to poll while the user edits an order. `prepareSwap` is
762
+ * Preparing is two methods because the directions approve different tokens -
763
+ * the funding coin on a purchase, the asset on a sale - and commit to
764
+ * different terms; broadcasting is one, because it reads calldata and a
765
+ * deadline and knows about neither.
766
+ *
767
+ * The reads are free to poll while the user edits an order. Preparing is
749
768
  * not: committing a quote spends an attestation.
750
769
  *
751
770
  * No CoinList fee is applied to a read quote; see
@@ -756,7 +775,7 @@ interface CoinListClient {
756
775
  * Token display metadata (name, symbol, decimals, logos) from CoinList's
757
776
  * public token registry, keyed by chain + contract address — e.g.
758
777
  * `coinlist.tokens.get({ chain, address })` for an entry of
759
- * `OfferDetail.tokens`, or `coinlist.tokens.list(chain)` for a whole
778
+ * `Offer.tokens`, or `coinlist.tokens.list()` for the whole
760
779
  * catalogue in one request.
761
780
  *
762
781
  * Public and unauthenticated: unlike the other namespaces, its methods never
@@ -917,6 +936,124 @@ interface CoinListSignInCardViewProps {
917
936
  */
918
937
  declare function CoinListSignInCardView({ state, onEvent, className, }: CoinListSignInCardViewProps): ReactNode;
919
938
 
939
+ /**
940
+ * A filled Ondo order, as the confirmation dialog and the host's
941
+ * `onOrderConfirmed` callback need it.
942
+ *
943
+ * It lives here rather than beside either review viewmodel because both
944
+ * products produce one. Declaring it in `ondo/buy/` would make the sell
945
+ * viewmodel import a sibling product's module - which the `shared/` ladder
946
+ * forbids for the reason it always does: two products that reach sideways can
947
+ * no longer be moved or deleted on their own.
948
+ *
949
+ * It names no asset beyond the one that was spent. The transaction does not
950
+ * carry one, and rebuilding an `Erc20Asset` here would mean inventing a
951
+ * `decimals` - the quote's answers for a different quantity, and the
952
+ * transaction's is a scale rather than a property of the token. A host that
953
+ * wants to know what was traded has the `offer` and `ondoSymbol` it passed in.
954
+ */
955
+ type OndoOrderPlaced = OndoBuyOrderPlaced | OndoSellOrderPlaced;
956
+ /**
957
+ * The common half of an {@link OndoOrderPlaced}, before its side's terms.
958
+ *
959
+ * The transaction that was broadcast is not here, because it is not common:
960
+ * it carries the same `side` this order does, and saying so in prose left a
961
+ * sell order holding a buy transaction constructible and its
962
+ * `minimumReceiveOutputAmount` unreachable behind a narrowed `side`. Each arm
963
+ * names its own instead.
964
+ */
965
+ type OndoOrderPlacedCore = {
966
+ txHash: Hash;
967
+ /** What the trader spent, in the input asset's base units. */
968
+ amount: BlockchainAmount;
969
+ wallet: EvmWallet;
970
+ };
971
+ /** A filled purchase: a stablecoin spent, the asset received. */
972
+ type OndoBuyOrderPlaced = OndoOrderPlacedCore & OndoBuyOrderTerms;
973
+ /** A filled sale: the asset spent, the settlement coin received. */
974
+ type OndoSellOrderPlaced = OndoOrderPlacedCore & OndoSellOrderTerms;
975
+ /**
976
+ * A buy spends a stablecoin the SDK ships a registry entry for, so its input
977
+ * asset is narrowed to one - which is what keeps `TOKEN_REGISTRY.erc20` total
978
+ * at the call sites that name it.
979
+ */
980
+ type OndoBuyOrderTerms = {
981
+ side: 'buy';
982
+ inputAsset: StablecoinSymbol;
983
+ /** The purchase that was broadcast, and the deposit it was struck against. */
984
+ transaction: OndoBuyTransaction;
985
+ };
986
+ /**
987
+ * A sell spends the Ondo asset, which is in no registry: its address and
988
+ * decimals come off the quote, and only its symbol is carried here. Hence the
989
+ * wider `AssetSymbol`, and hence a SUM rather than one widened field - a buy
990
+ * that lost its stablecoin guarantee would be the cost of sharing one.
991
+ */
992
+ type OndoSellOrderTerms = {
993
+ side: 'sell';
994
+ inputAsset: AssetSymbol;
995
+ /** The sale that was broadcast, and the floor under the proceeds it names. */
996
+ transaction: OndoSellTransaction;
997
+ };
998
+
999
+ /**
1000
+ * The wallets a checkout can spend from, supplied by the host.
1001
+ *
1002
+ * The SDK ships no wallet stack and is not coupled to Privy, AppKit or
1003
+ * anything else - a partner may be a wallet provider themselves - so wallet
1004
+ * discovery and connection are inverted onto the host. It hands over ready
1005
+ * {@link EvmWallet}s and two lambdas; the SDK decides nothing about how they
1006
+ * came to exist.
1007
+ *
1008
+ * There is no separate wallet model here on purpose: `EvmWallet` already
1009
+ * carries the `address`, so a `{ address, signer }` pair would be a second
1010
+ * wallet type to keep in sync with the first.
1011
+ *
1012
+ * Everything the row displays beyond the address - the network name - comes
1013
+ * from the checkout's execution chain rather than from the wallet, because
1014
+ * that is the chain the transaction goes to whatever the wallet is currently
1015
+ * pointed at.
1016
+ */
1017
+ type CheckoutWalletSelection = {
1018
+ /**
1019
+ * The user's embedded (custodial) wallets, in display order. Empty when they
1020
+ * have none, which is a normal state, not an error.
1021
+ */
1022
+ embedded: EvmWallet[];
1023
+ /** The connected external wallet, or `null` while none is connected. */
1024
+ external: EvmWallet | null;
1025
+ /**
1026
+ * A wallet the host has already settled on, or `null` to let the user pick.
1027
+ *
1028
+ * When set, a checkout that supports it skips its wallet step entirely and
1029
+ * opens on the amount, renumbering the steps that remain. That is for the
1030
+ * host that already knows the answer - a sell page reached from a position
1031
+ * knows which wallet holds it, and asking again would be a question with one
1032
+ * possible answer.
1033
+ *
1034
+ * It does not have to appear in `embedded` or `external`. The host supplies a
1035
+ * ready {@link EvmWallet} either way, and the SDK never resolves this back to
1036
+ * a row.
1037
+ *
1038
+ * **Only the Ondo sell checkout honours it today.** The field is on this seam
1039
+ * rather than on one provider's config because nothing about it is Ondo's -
1040
+ * any flow that opens on a wallet step could skip one - but a provider that
1041
+ * has not adopted it ignores it rather than half-implementing it, so do not
1042
+ * assume a skip from the field being set.
1043
+ */
1044
+ preselected: EvmWallet | null;
1045
+ /**
1046
+ * Opens the host's wallet connector. Resolves once the attempt finishes; the
1047
+ * SDK reads the outcome from `external` on the next render rather than from
1048
+ * a return value, so a host that connects through a redirect still works.
1049
+ *
1050
+ * Rejecting is how a declined or failed connection is reported.
1051
+ */
1052
+ connectExternal: () => Promise<void>;
1053
+ /** Disconnects the external wallet. Resolves when it is gone. */
1054
+ disconnectExternal: () => Promise<void>;
1055
+ };
1056
+
920
1057
  /**
921
1058
  * UI models every checkout provider needs. Provider-specific models stay in
922
1059
  * that provider's `use{X}ViewModel.types`; these live here because Ondo and
@@ -1093,294 +1230,104 @@ type CheckoutSelectableInputAssetUi = {
1093
1230
  };
1094
1231
 
1095
1232
  /**
1096
- * Step 3 of the Ondo checkout: what the order comes to, and placing it.
1233
+ * Step 3 of the Superstate checkout: what the swap comes to, the slippage it
1234
+ * will tolerate, and placing it.
1097
1235
  *
1098
- * `loading` is a separate arm from `active` rather than a flag inside it, so
1099
- * the skeleton renders from a state that carries no order details at all —
1100
- * there is nothing for the viewmodel to invent while the first quote is in
1101
- * flight. Once details exist they stay on screen through every later refresh,
1102
- * and it is `quote` that reports whether they can still be acted on.
1236
+ * `loading` is its own arm rather than a flag inside `active`, so the skeleton
1237
+ * renders from a state that carries no figures at all — there is nothing for
1238
+ * the viewmodel to invent while a quote for the confirmed amount is in flight.
1239
+ * The quote is repriced on a poll, and the amount the user committed to is only
1240
+ * quoted once that poll catches up, so this arm is entered again on every
1241
+ * amount change rather than only on first load.
1242
+ *
1243
+ * `error` is where a quote that cannot be honoured lands: no quote at all, or
1244
+ * one asking for more than the user offered.
1103
1245
  */
1104
- type OndoReviewUiState = {
1246
+ type SuperstateReviewUiState = {
1105
1247
  type: 'incomplete';
1106
1248
  }
1107
- /** The first quote is in flight; nothing to show yet. */
1249
+ /** No quote yet for the confirmed amount; nothing to show. */
1108
1250
  | {
1109
1251
  type: 'loading';
1110
1252
  }
1111
- /** No quote could be loaded at all. */
1253
+ /** No quote could be produced, or the one produced cannot be honoured. */
1112
1254
  | {
1113
1255
  type: 'error';
1114
1256
  } | {
1115
1257
  type: 'active';
1116
1258
  /** What the user is buying. */
1117
1259
  outputAsset: CheckoutAssetUi;
1118
- /** The quantity, e.g. `2.639 AAPLon`. */
1260
+ /** The quantity the quote offers, e.g. `981.2431 USTB`. */
1119
1261
  outputAmount: FormattedAmountAssetUi;
1120
- /** Where the asset lands — the wallet confirmed in step 1. */
1121
- recipientAddress: ShortenedWalletAddress;
1122
- /** Price of one whole token, e.g. `$378.99`. */
1123
- pricePerShare: FormattedAmountAssetUi;
1124
1262
  /**
1125
- * `null` while no CoinList fee is disclosed: no Ondo endpoint returns one
1126
- * and none is applied to the quote (ENG-1680). The row is hidden rather
1127
- * than showing a placeholder.
1263
+ * The least the user can end up with once slippage is applied — what
1264
+ * `minOut` is set to on-chain, so the swap reverts rather than filling
1265
+ * below it.
1128
1266
  */
1129
- coinlistFee: FormattedAmountAssetUi | null;
1130
- /** What the user pays in the input asset, e.g. `1,000.00 USDC`. */
1267
+ minOutputAmount: FormattedAmountAssetUi;
1268
+ /** Where the asset lands — the wallet authorized in step 1. */
1269
+ recipientAddress: ShortenedWalletAddress;
1270
+ /** Price of one whole output token, e.g. `$10.19`. */
1271
+ pricePerShare: FormattedAmountAssetUi;
1272
+ /** The protocol fee the quote carries, in the input asset. */
1273
+ coinlistFee: FormattedAmountAssetUi;
1274
+ /** Input plus fee: what leaves the wallet, e.g. `$1,000.00`. */
1131
1275
  total: FormattedAmountAssetUi;
1132
- quote: OndoQuoteStatusUi;
1276
+ slippage: SuperstateSlippageUi;
1133
1277
  placeOrderCta: CheckoutCtaUi;
1134
1278
  /** A failure from placing the order, distinct from a quote problem. */
1135
1279
  error: string | null;
1136
1280
  };
1137
1281
  /**
1138
- * Whether the shown numbers can still be traded on.
1282
+ * The slippage tolerance, and the picker that changes it.
1139
1283
  *
1140
- * A quote is only good for a few seconds, so this drives the line above the CTA
1141
- * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
1142
- * rather than folding into the step's `error`, because the remedy differs: a
1143
- * failed refresh is fixed by refreshing again, a failed order is not.
1284
+ * `expanded` lives here rather than in the View because the tolerance and the
1285
+ * disclosure that sets it are one control: the button's label is the current
1286
+ * percent, and the description below explains what that percent does. Splitting
1287
+ * them would make the View re-derive copy the viewmodel already formatted.
1144
1288
  */
1145
- type OndoQuoteStatusUi =
1146
- /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
1147
- {
1148
- type: 'valid';
1149
- expiresInLabel: string;
1150
- }
1151
- /** A refresh is in flight; the previous numbers are still on screen. */
1152
- | {
1153
- type: 'refreshing';
1154
- }
1155
- /** Too old to trade on. The user must refresh before placing the order. */
1156
- | {
1157
- type: 'expired';
1158
- }
1159
- /** The refresh failed. `message` says why. */
1160
- | {
1161
- type: 'refresh-failed';
1162
- message: string;
1289
+ type SuperstateSlippageUi = {
1290
+ /** The tolerance in force, e.g. `0.5%`. */
1291
+ percent: FormattedPercentUi;
1292
+ expanded: boolean;
1293
+ /** What this tolerance means, already interpolated with `percent`. */
1294
+ description: string;
1295
+ options: SuperstateSlippageOptionUi[];
1163
1296
  };
1164
- type OndoReviewUiEvent = {
1165
- type: 'ON_REFRESH_QUOTE';
1166
- }
1167
- /** Retry from the `error` arm, where there is no quote to refresh. */
1168
- | {
1169
- type: 'ON_RETRY';
1297
+ type SuperstateSlippageOptionUi = {
1298
+ /**
1299
+ * The value this option sets. Carried rather than the formatted percent so
1300
+ * the event names an exact tolerance rather than a rendering of one.
1301
+ */
1302
+ bps: Bps;
1303
+ percent: FormattedPercentUi;
1304
+ selected: boolean;
1305
+ };
1306
+ type SuperstateReviewUiEvent = {
1307
+ type: 'ON_SLIPPAGE_CLICK';
1308
+ } | {
1309
+ type: 'ON_SLIPPAGE_SELECT';
1310
+ bps: Bps;
1170
1311
  } | {
1171
1312
  type: 'ON_PLACE_ORDER';
1172
1313
  };
1173
1314
 
1174
- type OndoReviewStepInput = {
1175
- type: 'incomplete';
1176
- } | {
1177
- type: 'active';
1178
- /** The wallet that signs, pays, and receives. */
1315
+ /** What the swap actually filled at, once it has mined. */
1316
+ type SuperstateOrderPlaced = {
1317
+ swapTxHash: Hash;
1179
1318
  wallet: EvmWallet;
1180
- /** What the user is spending, in the input asset's base units. */
1181
- amount: BlockchainAmount;
1182
1319
  inputAsset: StablecoinSymbol;
1320
+ /** The input the contract pulled, excluding the fee. */
1321
+ inputAmount: BlockchainAmount;
1322
+ fee: BlockchainAmount;
1323
+ outputAsset: Erc20Asset;
1183
1324
  /**
1184
- * The transaction `prepareSwap` already built for this order. Omitting
1185
- * it makes this step build one itself, which is the path a partner
1186
- * driving the review on its own takes - and the only way its `loading`
1187
- * and `error` states are reached.
1188
- */
1189
- transaction?: OndoSwapTransaction;
1190
- };
1191
- /**
1192
- * A filled order, as the confirmation dialog needs it.
1193
- *
1194
- * It names no asset. The transaction does not carry one, and rebuilding an
1195
- * `Erc20Asset` here would mean inventing a `decimals` - the quote's answers
1196
- * for a different quantity, and the transaction's is a scale rather than a
1197
- * property of the token. A host that wants to know what was bought has the
1198
- * `offer` and `ondoSymbol` it passed in.
1199
- */
1200
- type OndoOrderPlaced = {
1201
- txHash: Hash;
1202
- transaction: OndoSwapTransaction;
1203
- /** What the buyer paid, in the input asset. */
1204
- amount: BlockchainAmount;
1205
- inputAsset: StablecoinSymbol;
1206
- wallet: EvmWallet;
1207
- };
1208
- interface UseOndoReviewViewModelOptions {
1209
- stepInput: OndoReviewStepInput;
1210
- /**
1211
- * Ondo's API symbol, e.g. `AAPLon`. Rebuilds the transaction, and names the
1212
- * bought asset on the card.
1325
+ * How much arrived. Decoded from the `Swapped` event, except on the fallback
1326
+ * path `outputAmountConfirmed` marks.
1213
1327
  */
1214
- ondoSymbol: AssetSymbol;
1215
- /** The chain the order executes on. */
1216
- chain: EthereumChain;
1328
+ outputAmount: BlockchainAmount;
1217
1329
  /**
1218
- * The offer being bought: the asset's name and its only icon.
1219
- *
1220
- * The identity comes from here rather than from the price poll, so the card
1221
- * agrees with the reference panel beside it and a dropped poll cannot leave
1222
- * the review unable to say what was bought.
1223
- */
1224
- offer: OfferDetail;
1225
- /** Called once the swap has mined. */
1226
- onComplete: (order: OndoOrderPlaced) => void;
1227
- }
1228
- interface UseOndoReviewViewModelResult {
1229
- state: OndoReviewUiState;
1230
- onEvent: (event: OndoReviewUiEvent) => void;
1231
- }
1232
- /**
1233
- * Drives step 3 of the Ondo checkout: what the order comes to, how long the
1234
- * price holds, and placing it.
1235
- *
1236
- * The quote is firm and short-lived, so most of this is about time. The
1237
- * countdown drives the line above the CTA, and a quote inside
1238
- * {@link ONDO_QUOTE_EXPIRY_THRESHOLD_MS} of its deadline is treated as already
1239
- * gone: placing an order is not instant, and a transaction that arrives after
1240
- * the deadline reverts at the user's expense.
1241
- *
1242
- * Refreshing is always something the user asks for. Each refresh builds a new
1243
- * transaction, which spends an attestation, so nothing here is on a timer.
1244
- */
1245
- declare function useOndoReviewViewModel({ stepInput, ondoSymbol, chain, offer, onComplete, }: UseOndoReviewViewModelOptions): UseOndoReviewViewModelResult;
1246
-
1247
- /**
1248
- * The wallets a checkout can spend from, supplied by the host.
1249
- *
1250
- * The SDK ships no wallet stack and is not coupled to Privy, AppKit or
1251
- * anything else - a partner may be a wallet provider themselves - so wallet
1252
- * discovery and connection are inverted onto the host. It hands over ready
1253
- * {@link EvmWallet}s and two lambdas; the SDK decides nothing about how they
1254
- * came to exist.
1255
- *
1256
- * There is no separate wallet model here on purpose: `EvmWallet` already
1257
- * carries the `address`, so a `{ address, signer }` pair would be a second
1258
- * wallet type to keep in sync with the first.
1259
- *
1260
- * Everything the row displays beyond the address - the network name - comes
1261
- * from the checkout's execution chain rather than from the wallet, because
1262
- * that is the chain the transaction goes to whatever the wallet is currently
1263
- * pointed at.
1264
- */
1265
- type CheckoutWalletSelection = {
1266
- /**
1267
- * The user's embedded (custodial) wallets, in display order. Empty when they
1268
- * have none, which is a normal state, not an error.
1269
- */
1270
- embedded: EvmWallet[];
1271
- /** The connected external wallet, or `null` while none is connected. */
1272
- external: EvmWallet | null;
1273
- /**
1274
- * Opens the host's wallet connector. Resolves once the attempt finishes; the
1275
- * SDK reads the outcome from `external` on the next render rather than from
1276
- * a return value, so a host that connects through a redirect still works.
1277
- *
1278
- * Rejecting is how a declined or failed connection is reported.
1279
- */
1280
- connectExternal: () => Promise<void>;
1281
- /** Disconnects the external wallet. Resolves when it is gone. */
1282
- disconnectExternal: () => Promise<void>;
1283
- };
1284
-
1285
- /**
1286
- * Step 3 of the Superstate checkout: what the swap comes to, the slippage it
1287
- * will tolerate, and placing it.
1288
- *
1289
- * `loading` is its own arm rather than a flag inside `active`, so the skeleton
1290
- * renders from a state that carries no figures at all — there is nothing for
1291
- * the viewmodel to invent while a quote for the confirmed amount is in flight.
1292
- * The quote is repriced on a poll, and the amount the user committed to is only
1293
- * quoted once that poll catches up, so this arm is entered again on every
1294
- * amount change rather than only on first load.
1295
- *
1296
- * `error` is where a quote that cannot be honoured lands: no quote at all, or
1297
- * one asking for more than the user offered.
1298
- */
1299
- type SuperstateReviewUiState = {
1300
- type: 'incomplete';
1301
- }
1302
- /** No quote yet for the confirmed amount; nothing to show. */
1303
- | {
1304
- type: 'loading';
1305
- }
1306
- /** No quote could be produced, or the one produced cannot be honoured. */
1307
- | {
1308
- type: 'error';
1309
- } | {
1310
- type: 'active';
1311
- /** What the user is buying. */
1312
- outputAsset: CheckoutAssetUi;
1313
- /** The quantity the quote offers, e.g. `981.2431 USTB`. */
1314
- outputAmount: FormattedAmountAssetUi;
1315
- /**
1316
- * The least the user can end up with once slippage is applied — what
1317
- * `minOut` is set to on-chain, so the swap reverts rather than filling
1318
- * below it.
1319
- */
1320
- minOutputAmount: FormattedAmountAssetUi;
1321
- /** Where the asset lands — the wallet authorized in step 1. */
1322
- recipientAddress: ShortenedWalletAddress;
1323
- /** Price of one whole output token, e.g. `$10.19`. */
1324
- pricePerShare: FormattedAmountAssetUi;
1325
- /** The protocol fee the quote carries, in the input asset. */
1326
- coinlistFee: FormattedAmountAssetUi;
1327
- /** Input plus fee: what leaves the wallet, e.g. `$1,000.00`. */
1328
- total: FormattedAmountAssetUi;
1329
- slippage: SuperstateSlippageUi;
1330
- placeOrderCta: CheckoutCtaUi;
1331
- /** A failure from placing the order, distinct from a quote problem. */
1332
- error: string | null;
1333
- };
1334
- /**
1335
- * The slippage tolerance, and the picker that changes it.
1336
- *
1337
- * `expanded` lives here rather than in the View because the tolerance and the
1338
- * disclosure that sets it are one control: the button's label is the current
1339
- * percent, and the description below explains what that percent does. Splitting
1340
- * them would make the View re-derive copy the viewmodel already formatted.
1341
- */
1342
- type SuperstateSlippageUi = {
1343
- /** The tolerance in force, e.g. `0.5%`. */
1344
- percent: FormattedPercentUi;
1345
- expanded: boolean;
1346
- /** What this tolerance means, already interpolated with `percent`. */
1347
- description: string;
1348
- options: SuperstateSlippageOptionUi[];
1349
- };
1350
- type SuperstateSlippageOptionUi = {
1351
- /**
1352
- * The value this option sets. Carried rather than the formatted percent so
1353
- * the event names an exact tolerance rather than a rendering of one.
1354
- */
1355
- bps: Bps;
1356
- percent: FormattedPercentUi;
1357
- selected: boolean;
1358
- };
1359
- type SuperstateReviewUiEvent = {
1360
- type: 'ON_SLIPPAGE_CLICK';
1361
- } | {
1362
- type: 'ON_SLIPPAGE_SELECT';
1363
- bps: Bps;
1364
- } | {
1365
- type: 'ON_PLACE_ORDER';
1366
- };
1367
-
1368
- /** What the swap actually filled at, once it has mined. */
1369
- type SuperstateOrderPlaced = {
1370
- swapTxHash: Hash;
1371
- wallet: EvmWallet;
1372
- inputAsset: StablecoinSymbol;
1373
- /** The input the contract pulled, excluding the fee. */
1374
- inputAmount: BlockchainAmount;
1375
- fee: BlockchainAmount;
1376
- outputAsset: Erc20Asset;
1377
- /**
1378
- * How much arrived. Decoded from the `Swapped` event, except on the fallback
1379
- * path `outputAmountConfirmed` marks.
1380
- */
1381
- outputAmount: BlockchainAmount;
1382
- /**
1383
- * Whether `outputAmount` came from the receipt rather than from the quote.
1330
+ * Whether `outputAmount` came from the receipt rather than from the quote.
1384
1331
  *
1385
1332
  * `false` means the swap mined but its `Swapped` event would not decode, so
1386
1333
  * the quote's estimate is standing in. A host that shows the number owes the
@@ -1490,8 +1437,13 @@ declare function quoteIsStale({ total, inputAmount, isQuoteRefreshing, }: QuoteA
1490
1437
  * arriving in a catalogue is a thing they have to decide about, not a blank
1491
1438
  * screen their users find first.
1492
1439
  *
1493
- * Nothing here is per-offer. It is per-*integration*, so a host builds it once
1494
- * and passes the same object for every offer it renders.
1440
+ * Almost nothing here is per-offer: it is per-*integration*, so a host builds
1441
+ * it once and passes the same object for every offer it renders. The one
1442
+ * exception is `ondo::swap`'s `side`, which is per-*render* rather than per
1443
+ * offer or per integration - the same Ondo offer is both buyable and sellable -
1444
+ * so a host with a buy page and a sell page rebuilds the object, or closes its
1445
+ * `side` thunk over whatever selects the direction. See
1446
+ * {@link OndoCheckoutConfig}.
1495
1447
  */
1496
1448
  type CheckoutConfig = {
1497
1449
  [K in OfferType]: CheckoutConfigByOfferType[K];
@@ -1534,7 +1486,32 @@ type OndoCheckoutConfig = {
1534
1486
  * recognise would take down a checkout Ondo has no part in; return anything.
1535
1487
  */
1536
1488
  symbol: (offer: OfferDetail) => AssetSymbol;
1537
- /** Fired once an Ondo swap has mined. The dialog shows either way. */
1489
+ /**
1490
+ * Which way the trade runs: `buy` invests in the asset, `sell` liquidates a
1491
+ * holding of it.
1492
+ *
1493
+ * A thunk rather than a resolver like `symbol` above, because no offer can
1494
+ * answer it: `offer.type` is `ondo::swap` for both directions, since
1495
+ * frontline exposes one Ondo offer type and the side is a property of the
1496
+ * page rather than of the catalogue. A host closes over whatever selects the
1497
+ * direction - a route, a tab - and returns it.
1498
+ *
1499
+ * Still called for every offer, Superstate's and the token sale's included,
1500
+ * because both Ondo viewmodels are called unconditionally; on those its
1501
+ * answer is handed to a viewmodel that is `enabled: false` and never reads
1502
+ * it. Nothing to be total over, so nothing to get wrong.
1503
+ *
1504
+ * Required, with no default. The wire parameter behind it defaults to `buy`
1505
+ * silently, and the day sell ships an unstated direction should be a compile
1506
+ * error rather than a purchase.
1507
+ *
1508
+ * **Read once, at mount.** The Ondo flow holds a committed quote and an
1509
+ * approval granted for one specific token, so a resolver that starts
1510
+ * answering differently mid-flow is ignored rather than obeyed - see the
1511
+ * remount note on {@link CheckoutContainer}.
1512
+ */
1513
+ side: () => OrderBookSide;
1514
+ /** Fired once an Ondo swap has mined, either way. The dialog shows anyway. */
1538
1515
  onOrderConfirmed?: (order: OndoOrderPlaced) => void;
1539
1516
  };
1540
1517
  /**
@@ -1575,7 +1552,10 @@ type RequiredCheckoutConfig = Pick<CheckoutConfig, 'ondo::swap' | 'coinlist::tok
1575
1552
  *
1576
1553
  * ```ts
1577
1554
  * const config = defaultCheckoutConfig({
1578
- * 'ondo::swap': { symbol: (offer) => AssetSymbol(offer.asset.code) },
1555
+ * 'ondo::swap': {
1556
+ * symbol: (offer) => AssetSymbol(offer.asset.code),
1557
+ * side: () => 'buy',
1558
+ * },
1579
1559
  * 'coinlist::token_sale': { render: (offer) => <MyTokenSalePage offer={offer} /> },
1580
1560
  * });
1581
1561
  * ```
@@ -1616,31 +1596,35 @@ interface CheckoutContainerProps {
1616
1596
  * provider's flow.
1617
1597
  *
1618
1598
  * Every provider's viewmodel is called on every render, because React hooks
1619
- * cannot be called conditionally. Only the one matching `offer.type` is
1620
- * `enabled`, so the other providers fetch nothing and run no timers — that
1599
+ * cannot be called conditionally — and both Ondo products, since `side` picks
1600
+ * between them at the same level. Only the one matching `offer.type` and
1601
+ * `side` is `enabled`, so the rest fetch nothing and run no timers — that
1621
1602
  * `enabled` flag is why every checkout viewmodel has one.
1622
1603
  *
1623
1604
  * The `switch` is exhaustive against `OfferType`, and the `default` branch
1624
1605
  * assigns to `const exhaustive: never`, so a new offer type is a compile error
1625
1606
  * here as well as in {@link CheckoutConfig}.
1626
1607
  *
1627
- * ## One mount, one offer, one chain
1608
+ * ## One mount, one offer, one chain, one side
1628
1609
  *
1629
- * `offer` and `chain` are read as fixed for the lifetime of the mount. Each
1630
- * provider's viewmodel owns a step machine — which wallet was authorized, how
1631
- * much is being spent — and that progress is bound to the offer it was made
1632
- * against: a Superstate wallet authorization is allow-listed per offer, and an
1633
- * ERC-20 approval is granted per chain. Changing either prop in place would
1634
- * carry a completed step from one offer onto another, so the container does not
1635
- * try to; a swap could also land mid-execution, between an approval and the
1636
- * broadcast it was granted for, which is worse than not switching at all.
1610
+ * `offer`, `chain` and the Ondo `side` are read as fixed for the lifetime of
1611
+ * the mount. Each provider's viewmodel owns a step machine — which wallet was
1612
+ * authorized, how much is being spent — and that progress is bound to the order
1613
+ * it was made against: a Superstate wallet authorization is allow-listed per
1614
+ * offer, and an ERC-20 approval is granted per chain, for one specific token.
1615
+ * Changing any of the three in place would carry a completed step onto an order
1616
+ * it was never made for — a flipped side most sharply of all, since the
1617
+ * approval covers the coin the *old* direction spent. So the container does not
1618
+ * try to: `side` is resolved once into state and later answers are ignored. A
1619
+ * swap could also land mid-execution, between an approval and the broadcast it
1620
+ * was granted for, which is worse than not switching at all.
1637
1621
  *
1638
- * **To render a different offer or chain, remount rather than reassign** — give
1639
- * the container a `key` that changes with them:
1622
+ * **To render a different offer, chain or side, remount rather than
1623
+ * reassign** — give the container a `key` that changes with them:
1640
1624
  *
1641
1625
  * ```tsx
1642
1626
  * <CheckoutContainer
1643
- * key={`${offer.id}:${chain}`}
1627
+ * key={`${offer.id}:${chain}:${side}`}
1644
1628
  * offer={offer}
1645
1629
  * chain={chain}
1646
1630
  * wallets={wallets}
@@ -1651,6 +1635,61 @@ interface CheckoutContainerProps {
1651
1635
  * React then discards the old flow's state along with its component instance,
1652
1636
  * which is exactly the reset that is wanted and the only one that cannot strand
1653
1637
  * an in-flight transaction.
1638
+ *
1639
+ * ### A page per side
1640
+ *
1641
+ * The simplest way to ship both Ondo directions, and the one that needs no
1642
+ * `key` at all: each page hard-codes its own direction, and a mount only ever
1643
+ * sees one of them.
1644
+ *
1645
+ * ```tsx
1646
+ * // The sell page. `side: () => 'buy'` on the buy page, everything else equal.
1647
+ * const config = defaultCheckoutConfig({
1648
+ * 'ondo::swap': { symbol: (o) => AssetSymbol(o.asset.code), side: () => 'sell' },
1649
+ * 'coinlist::token_sale': { render: (o) => <MyTokenSalePage offer={o} /> },
1650
+ * });
1651
+ * ```
1652
+ *
1653
+ * A sell page reached from a position also knows which wallet holds it, so it
1654
+ * usually sets {@link CheckoutWalletSelection.preselected} and opens on the
1655
+ * amount.
1656
+ *
1657
+ * ### A buy/sell toggle on one page
1658
+ *
1659
+ * Also supported, but **React state alone will not switch it**: `side` is
1660
+ * latched at mount, so a re-render with a new answer is ignored by design. Put
1661
+ * the direction in the `key` and the toggle works, because the container
1662
+ * remounts rather than reassigns.
1663
+ *
1664
+ * ```tsx
1665
+ * const [side, setSide] = useState<OrderBookSide>('buy');
1666
+ *
1667
+ * <BuySellTabs value={side} onChange={setSide} />
1668
+ * <CheckoutContainer
1669
+ * key={`${offer.id}:${chain}:${side}`} // `side` in the key, or the toggle is inert
1670
+ * offer={offer}
1671
+ * chain={chain}
1672
+ * wallets={wallets}
1673
+ * config={{
1674
+ * ...config,
1675
+ * 'ondo::swap': { ...config['ondo::swap'], side: () => side },
1676
+ * }}
1677
+ * />
1678
+ * ```
1679
+ *
1680
+ * Rebuilding the config object on every render costs nothing here: `side` is
1681
+ * called once per mount, so the thunk's identity never matters.
1682
+ *
1683
+ * Two things a host owns rather than the SDK:
1684
+ *
1685
+ * - **The remount clears the flow** — chosen wallet, entered amount, granted
1686
+ * approval. That is the point, but it is visible, so expect the card to reset
1687
+ * under a user who flips the tabs half way down it.
1688
+ * - **A swap already in flight is not cancelled by unmounting it.** It still
1689
+ * mines; the UI just stops following it, and `onOrderConfirmed` never fires
1690
+ * for it. The container cannot tell a host that one is in flight, so gate the
1691
+ * toggle where it can reach an executing flow — disable the tabs once the
1692
+ * user is past the amount step, or confirm before switching.
1654
1693
  */
1655
1694
  declare function CheckoutContainer({ offer, chain, wallets, config, enabled, className, }: CheckoutContainerProps): ReactNode;
1656
1695
 
@@ -1661,7 +1700,7 @@ declare function CheckoutContainer({ offer, chain, wallets, config, enabled, cla
1661
1700
  * `CheckoutCtaUi` — it reports the on-chain phase back as loading copy while
1662
1701
  * the approval is mined.
1663
1702
  */
1664
- type OndoAmountUiState = {
1703
+ type OndoBuyAmountUiState = {
1665
1704
  type: 'incomplete';
1666
1705
  } | {
1667
1706
  type: 'active';
@@ -1686,7 +1725,7 @@ type OndoAmountUiState = {
1686
1725
  /** The confirmed amount with its symbol, e.g. `1,000.00 USDC`. */
1687
1726
  amountFormatted: FormattedAmountAssetUi;
1688
1727
  };
1689
- type OndoAmountUiEvent = {
1728
+ type OndoBuyAmountUiEvent = {
1690
1729
  type: 'ON_AMOUNT_CHANGE';
1691
1730
  value: string;
1692
1731
  } | {
@@ -1700,9 +1739,9 @@ type OndoAmountUiEvent = {
1700
1739
  type: 'ON_EDIT_AMOUNT';
1701
1740
  };
1702
1741
 
1703
- interface OndoAmountViewProps {
1704
- state: OndoAmountUiState;
1705
- onEvent: (event: OndoAmountUiEvent) => void;
1742
+ interface OndoBuyAmountViewProps {
1743
+ state: OndoBuyAmountUiState;
1744
+ onEvent: (event: OndoBuyAmountUiEvent) => void;
1706
1745
  className?: string;
1707
1746
  }
1708
1747
  /**
@@ -1712,49 +1751,128 @@ interface OndoAmountViewProps {
1712
1751
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
1713
1752
  * needed around it.
1714
1753
  */
1715
- declare function OndoAmountView(props: OndoAmountViewProps): ReactNode;
1754
+ declare function OndoBuyAmountView(props: OndoBuyAmountViewProps): ReactNode;
1716
1755
 
1717
1756
  /**
1718
- * The reference panel beside the Ondo checkout: which asset is being bought,
1719
- * what it costs, and the facts about it that do not move while the order is
1720
- * filled in.
1721
- *
1722
- * Read-only, so there is no `UiEvent`. Whether the mobile disclosure is open is
1723
- * the View's own business.
1757
+ * Step 3 of the Ondo checkout: what the order comes to, and placing it.
1724
1758
  *
1725
- * A product type rather than a union: the identity half comes from the offer
1726
- * and is known the moment the checkout renders, so there is no state in which
1727
- * the panel has nothing to show. Only the price corner waits on the network,
1728
- * and it carries its own arms.
1759
+ * `loading` is a separate arm from `active` rather than a flag inside it, so
1760
+ * the skeleton renders from a state that carries no order details at all —
1761
+ * there is nothing for the viewmodel to invent while the first quote is in
1762
+ * flight. Once details exist they stay on screen through every later refresh,
1763
+ * and it is `quote` that reports whether they can still be acted on.
1729
1764
  */
1730
- type OndoSidebarUiState = {
1731
- asset: CheckoutAssetUi;
1765
+ type OndoBuyReviewUiState = {
1766
+ type: 'incomplete';
1767
+ }
1768
+ /** The first quote is in flight; nothing to show yet. */
1769
+ | {
1770
+ type: 'loading';
1771
+ }
1772
+ /** No quote could be loaded at all. */
1773
+ | {
1774
+ type: 'error';
1775
+ } | {
1776
+ type: 'active';
1777
+ /** What the user is buying. */
1778
+ outputAsset: CheckoutAssetUi;
1779
+ /** The quantity, e.g. `2.639 AAPLon`. */
1780
+ outputAmount: FormattedAmountAssetUi;
1781
+ /** Where the asset lands — the wallet confirmed in step 1. */
1782
+ recipientAddress: ShortenedWalletAddress;
1783
+ /** Price of one whole token, e.g. `$378.99`. */
1784
+ pricePerShare: FormattedAmountAssetUi;
1732
1785
  /**
1733
- * Who issues the asset, e.g. `Ondo Global Markets`.
1734
- *
1735
- * `null` hides the row. No frontline endpoint carries an issuer today, so
1736
- * absence is the normal case rather than an edge one — the same reasoning as
1737
- * `coinlistFee` on the review step.
1786
+ * `null` while no CoinList fee is disclosed: no Ondo endpoint returns one
1787
+ * and none is applied to the quote (ENG-1680). The row is hidden rather
1788
+ * than showing a placeholder.
1738
1789
  */
1739
- issuer: string | null;
1740
- /** The underlying's ticker, e.g. `AAPL` — not the token symbol. `null` hides the row. */
1741
- tickerSymbol: string | null;
1742
- /** The underlying's ISIN, e.g. `US0378331005`. `null` hides the row. */
1743
- isin: string | null;
1744
- /** What kind of instrument it is, e.g. `Common Stock`. `null` hides the row. */
1745
- assetType: string | null;
1746
- /** Display name of the chain the token lives on, e.g. `Ethereum`. */
1747
- networkName: string;
1748
- price: OndoSidebarPriceUi;
1790
+ coinlistFee: FormattedAmountAssetUi | null;
1791
+ /** What the user pays in the input asset, e.g. `1,000.00 USDC`. */
1792
+ total: FormattedAmountAssetUi;
1793
+ quote: OndoBuyQuoteStatusUi;
1794
+ placeOrderCta: CheckoutCtaUi;
1795
+ /** A failure from placing the order, distinct from a quote problem. */
1796
+ error: string | null;
1749
1797
  };
1750
1798
  /**
1751
- * The price corner of the panel.
1799
+ * Whether the shown numbers can still be traded on.
1752
1800
  *
1753
- * Its own SUM rather than nullable fields on the state, because price and
1754
- * market status arrive together from the quote and trading-status polls, and
1755
- * they arrive later than everything else on the panel. Keeping them here means
1756
- * a refresh that is in flight, or one that failed, never blanks the asset's
1757
- * identity.
1801
+ * A quote is only good for a few seconds, so this drives the line above the CTA
1802
+ * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
1803
+ * rather than folding into the step's `error`, because the remedy differs: a
1804
+ * failed refresh is fixed by refreshing again, a failed order is not.
1805
+ */
1806
+ type OndoBuyQuoteStatusUi =
1807
+ /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
1808
+ {
1809
+ type: 'valid';
1810
+ expiresInLabel: string;
1811
+ }
1812
+ /** A refresh is in flight; the previous numbers are still on screen. */
1813
+ | {
1814
+ type: 'refreshing';
1815
+ }
1816
+ /** Too old to trade on. The user must refresh before placing the order. */
1817
+ | {
1818
+ type: 'expired';
1819
+ }
1820
+ /** The refresh failed. `message` says why. */
1821
+ | {
1822
+ type: 'refresh-failed';
1823
+ message: string;
1824
+ };
1825
+ type OndoBuyReviewUiEvent = {
1826
+ type: 'ON_REFRESH_QUOTE';
1827
+ }
1828
+ /** Retry from the `error` arm, where there is no quote to refresh. */
1829
+ | {
1830
+ type: 'ON_RETRY';
1831
+ } | {
1832
+ type: 'ON_PLACE_ORDER';
1833
+ };
1834
+
1835
+ /**
1836
+ * The reference panel beside the Ondo checkout: which asset is being bought,
1837
+ * what it costs, and the facts about it that do not move while the order is
1838
+ * filled in.
1839
+ *
1840
+ * Read-only, so there is no `UiEvent`. Whether the mobile disclosure is open is
1841
+ * the View's own business.
1842
+ *
1843
+ * A product type rather than a union: the identity half comes from the offer
1844
+ * and is known the moment the checkout renders, so there is no state in which
1845
+ * the panel has nothing to show. Only the price corner waits on the network,
1846
+ * and it carries its own arms.
1847
+ */
1848
+ type OndoSidebarUiState = {
1849
+ asset: CheckoutAssetUi;
1850
+ /**
1851
+ * Who issues the asset, e.g. `Ondo Global Markets`.
1852
+ *
1853
+ * `null` hides the row. No frontline endpoint carries an issuer today, so
1854
+ * absence is the normal case rather than an edge one — the same reasoning as
1855
+ * `coinlistFee` on the review step.
1856
+ */
1857
+ issuer: string | null;
1858
+ /** The underlying's ticker, e.g. `AAPL` — not the token symbol. `null` hides the row. */
1859
+ tickerSymbol: string | null;
1860
+ /** The underlying's ISIN, e.g. `US0378331005`. `null` hides the row. */
1861
+ isin: string | null;
1862
+ /** What kind of instrument it is, e.g. `Common Stock`. `null` hides the row. */
1863
+ assetType: string | null;
1864
+ /** Display name of the chain the token lives on, e.g. `Ethereum`. */
1865
+ networkName: string;
1866
+ price: OndoSidebarPriceUi;
1867
+ };
1868
+ /**
1869
+ * The price corner of the panel.
1870
+ *
1871
+ * Its own SUM rather than nullable fields on the state, because price and
1872
+ * market status arrive together from the quote and trading-status polls, and
1873
+ * they arrive later than everything else on the panel. Keeping them here means
1874
+ * a refresh that is in flight, or one that failed, never blanks the asset's
1875
+ * identity.
1758
1876
  */
1759
1877
  type OndoSidebarPriceUi =
1760
1878
  /** No price yet. The corner renders placeholders. */
@@ -1831,8 +1949,8 @@ type OndoWalletSelectUiEvent = {
1831
1949
  */
1832
1950
  type OndoBuyCheckoutUiState = {
1833
1951
  wallet: OndoWalletSelectUiState;
1834
- amount: OndoAmountUiState;
1835
- review: OndoReviewUiState;
1952
+ amount: OndoBuyAmountUiState;
1953
+ review: OndoBuyReviewUiState;
1836
1954
  /** The asset panel. Read-only, so it raises no events. */
1837
1955
  sidebar: OndoSidebarUiState;
1838
1956
  orderConfirmed: OndoOrderConfirmedUiState;
@@ -1847,7 +1965,7 @@ type OndoBuyCheckoutUiState = {
1847
1965
  * tags must stay globally unique, which is why the edit events are
1848
1966
  * `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared `ON_EDIT`.
1849
1967
  */
1850
- type OndoBuyCheckoutUiEvent = OndoWalletSelectUiEvent | OndoAmountUiEvent | OndoReviewUiEvent | OndoOrderConfirmedUiEvent;
1968
+ type OndoBuyCheckoutUiEvent = OndoWalletSelectUiEvent | OndoBuyAmountUiEvent | OndoBuyReviewUiEvent | OndoOrderConfirmedUiEvent;
1851
1969
  /**
1852
1970
  * The dialog that closes the Ondo checkout, once the swap is mined.
1853
1971
  *
@@ -1907,7 +2025,7 @@ interface OndoOrderConfirmedProps {
1907
2025
  * Self-scoped: renders fully styled on its own. It bails before the scope while
1908
2026
  * hidden, so a closed dialog leaves nothing in the DOM.
1909
2027
  */
1910
- declare function OndoOrderConfirmed({ state, onEvent, className, }: OndoOrderConfirmedProps): ReactNode;
2028
+ declare function OndoBuyOrderConfirmed({ state, onEvent, className, }: OndoOrderConfirmedProps): ReactNode;
1911
2029
 
1912
2030
  interface OndoBuyCheckoutContainerProps {
1913
2031
  /** The offer being bought: names the asset and supplies its logo. */
@@ -1973,9 +2091,9 @@ interface OndoBuyCheckoutViewProps {
1973
2091
  */
1974
2092
  declare function OndoBuyCheckoutView({ state, onEvent, className, }: OndoBuyCheckoutViewProps): ReactNode;
1975
2093
 
1976
- interface OndoReviewViewProps {
1977
- state: OndoReviewUiState;
1978
- onEvent: (event: OndoReviewUiEvent) => void;
2094
+ interface OndoBuyReviewViewProps {
2095
+ state: OndoBuyReviewUiState;
2096
+ onEvent: (event: OndoBuyReviewUiEvent) => void;
1979
2097
  className?: string;
1980
2098
  }
1981
2099
  /**
@@ -1986,49 +2104,23 @@ interface OndoReviewViewProps {
1986
2104
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
1987
2105
  * needed around it.
1988
2106
  */
1989
- declare function OndoReviewView(props: OndoReviewViewProps): ReactNode;
1990
-
1991
- interface OndoSidebarViewProps {
1992
- state: OndoSidebarUiState;
1993
- className?: string;
1994
- }
1995
- /**
1996
- * The panel beside the Ondo checkout: what is being bought, what one share
1997
- * costs, and the reference facts about the asset.
1998
- *
1999
- * Read-only, so it takes no `onEvent`. Rows the SDK has no source for arrive as
2000
- * `null` and are dropped by `CheckoutDetailList` rather than rendered empty.
2001
- *
2002
- * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2003
- * needed around it.
2004
- */
2005
- declare function OndoSidebarView({ state, className, }: OndoSidebarViewProps): ReactNode;
2107
+ declare function OndoBuyReviewView(props: OndoBuyReviewViewProps): ReactNode;
2006
2108
 
2007
- interface OndoWalletSelectViewProps {
2008
- state: OndoWalletSelectUiState;
2009
- onEvent: (event: OndoWalletSelectUiEvent) => void;
2010
- className?: string;
2011
- }
2012
2109
  /**
2013
- * Step 1 of the Ondo checkout. Pure: the wallets arrive already shaped, and
2014
- * every interaction leaves through `onEvent`.
2110
+ * The amount step of the Ondo sell checkout: how much of the asset to sell.
2015
2111
  *
2016
- * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2017
- * needed around it.
2018
- */
2019
- declare function OndoWalletSelectView(props: OndoWalletSelectViewProps): ReactNode;
2020
-
2021
- /**
2022
- * Step 2 of the Superstate checkout: how much to spend, and which asset to
2023
- * spend.
2112
+ * Confirming submits an ERC-20 approval on the *asset*, so the CTA is a
2113
+ * `CheckoutCtaUi` reporting the on-chain phase back as loading copy - the same
2114
+ * shape the buy step's carries, for the same reason.
2024
2115
  *
2025
- * Nothing here touches the chain. Unlike Ondo's amount step, which approves and
2026
- * commits a quote, this one only validates locally and hands the amount up — a
2027
- * Superstate swap approves and executes together on the review step. Hence a
2028
- * plain `confirmEnabled` rather than a `CheckoutCtaUi` with loading copy: there
2029
- * is no phase to report.
2116
+ * It is a separate state machine from the buy step's rather than a shared one
2117
+ * with a flag, because the two screens differ in what the user is choosing.
2118
+ * A buy picks a funding coin from a list and holds a balance per candidate; a
2119
+ * sell has exactly one input, the asset the offer names, and renders its
2120
+ * balance as a statement. Sharing an ADT would have made this difference a
2121
+ * breaking change for both.
2030
2122
  */
2031
- type SuperstateAmountUiState = {
2123
+ type OndoSellAmountUiState = {
2032
2124
  type: 'incomplete';
2033
2125
  } | {
2034
2126
  type: 'active';
@@ -2037,275 +2129,286 @@ type SuperstateAmountUiState = {
2037
2129
  * mid-edit, and `'1.'` is a legal thing to be holding.
2038
2130
  */
2039
2131
  amountInput: string;
2040
- /** The wallet the funds come from, per step 1. */
2041
- walletAddress: ShortenedWalletAddress;
2042
2132
  /**
2043
- * Every supported input asset, in display order, whether or not the user
2044
- * holds any. One entry renders as a plain card, two or more as a picker.
2045
- */
2046
- inputAssets: CheckoutSelectableInputAssetUi[];
2047
- confirmEnabled: boolean;
2048
- /** Validation copy, e.g. `Amount must be greater than 0.` */
2133
+ * The asset being sold, with the user's holding of it.
2134
+ *
2135
+ * `null` until the sell quote lands. The asset's contract address and
2136
+ * decimals come off that quote - the SDK ships no registry entry for an
2137
+ * Ondo token - so until it does there is no balance to read and nothing
2138
+ * honest to render. The CTA is `disabled` throughout.
2139
+ */
2140
+ balance: OndoSellBalanceUi | null;
2141
+ /** Where the asset is held and where the proceeds land, per the wallet step. */
2142
+ wallet: OndoSellSourceWalletUi;
2143
+ confirmCta: CheckoutCtaUi;
2144
+ /** Validation or approval failure, e.g. `Insufficient TSLAon`. */
2049
2145
  error: string | null;
2050
2146
  } | {
2051
2147
  type: 'complete';
2052
- inputAsset: CheckoutAssetUi;
2053
- /**
2054
- * What the user is spending, as the field asked for it: dollars, e.g.
2055
- * `$1,000.00`. The Superstate field is dollar-denominated, which is why
2056
- * this is prefixed rather than suffixed with a symbol.
2057
- */
2148
+ asset: CheckoutAssetUi;
2149
+ /** The confirmed amount with its symbol, e.g. `1.204 TSLAon`. */
2058
2150
  amountFormatted: FormattedAmountAssetUi;
2059
- /**
2060
- * The same figure in the asset actually being paid, e.g. `1,000.00 USDC`.
2061
- *
2062
- * Both are shown because the two are only equal while the funding asset
2063
- * is a dollar stablecoin — the day a non-dollar one is fundable, the
2064
- * summary would otherwise silently claim it was.
2065
- */
2066
- inputAmountFormatted: FormattedAmountAssetUi;
2067
2151
  };
2068
- type SuperstateAmountUiEvent = {
2069
- type: 'ON_AMOUNT_CHANGE';
2152
+ /** The asset being sold and how much of it the wallet holds. */
2153
+ type OndoSellBalanceUi = {
2154
+ asset: CheckoutAssetUi;
2155
+ /** The holding, formatted, e.g. `1.204 TSLAon`. */
2156
+ balance: FormattedAmountAssetUi;
2157
+ /** Base units, so `Max` can fill the field without re-parsing the display. */
2158
+ rawBalance: bigint;
2159
+ };
2160
+ /**
2161
+ * How the balance card names where the asset is held.
2162
+ *
2163
+ * A SUM rather than a formatted string, because the two read differently: a
2164
+ * CoinList wallet is named, an external one is shown by address. The View
2165
+ * composes the `from …` copy from whichever arm it is handed.
2166
+ */
2167
+ type OndoSellSourceWalletUi = {
2168
+ type: 'embedded';
2169
+ } | {
2170
+ type: 'external';
2171
+ address: ShortenedWalletAddress;
2172
+ };
2173
+ type OndoSellAmountUiEvent = {
2174
+ type: 'ON_SELL_AMOUNT_CHANGE';
2070
2175
  value: string;
2071
2176
  } | {
2072
- type: 'ON_MAX_AMOUNT_CLICK';
2177
+ type: 'ON_SELL_MAX_AMOUNT_CLICK';
2073
2178
  } | {
2074
- type: 'ON_SELECT_PAY_WITH';
2075
- value: AssetSymbol;
2076
- }
2077
- /**
2078
- * Named for what it does rather than for the step: confirming here previews
2079
- * the order on step 3, it does not place or pay for anything.
2080
- */
2081
- | {
2082
- type: 'ON_PREVIEW_ORDER';
2179
+ type: 'ON_CONFIRM_SELL_AMOUNT';
2083
2180
  } | {
2084
- type: 'ON_EDIT_AMOUNT';
2181
+ type: 'ON_EDIT_SELL_AMOUNT';
2085
2182
  };
2086
2183
 
2087
- interface SuperstateAmountViewProps {
2088
- state: SuperstateAmountUiState;
2089
- onEvent: (event: SuperstateAmountUiEvent) => void;
2184
+ interface OndoSellAmountViewProps {
2185
+ state: OndoSellAmountUiState;
2186
+ onEvent: (event: OndoSellAmountUiEvent) => void;
2187
+ /**
2188
+ * Where this card sits in the flow, which is 2 normally and 1 when the host
2189
+ * preselected a wallet and the step above was skipped.
2190
+ *
2191
+ * A prop rather than a constant because the sell flow has two lengths. The
2192
+ * god View derives it from the one fact that decides it, so the two cards
2193
+ * cannot disagree about how many steps there are.
2194
+ */
2195
+ stepNumber: number;
2090
2196
  className?: string;
2091
2197
  }
2092
2198
  /**
2093
- * Step 2 of the Superstate checkout. Pure: amounts arrive already formatted,
2094
- * and every interaction leaves through `onEvent`.
2199
+ * The amount step of the Ondo sell checkout. Pure: amounts arrive already
2200
+ * formatted, and every interaction leaves through `onEvent`.
2095
2201
  *
2096
- * The field is dollar-denominated, so the `$` goes in `CheckoutAmountInput`'s
2097
- * `prefix` slot — where Ondo puts its asset symbol in `suffix`. Nothing here is
2098
- * submitted: confirming only moves the flow to the review step.
2202
+ * The balance is a statement rather than a choice - a sell has exactly one
2203
+ * input, the asset the offer names - so it renders as a static card where the
2204
+ * buy step renders a picker. `Max` is offered all the same, and means more
2205
+ * here than there: selling a whole position is the common case.
2099
2206
  *
2100
2207
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2101
2208
  * needed around it.
2102
2209
  */
2103
- declare function SuperstateAmountView(props: SuperstateAmountViewProps): ReactNode;
2210
+ declare function OndoSellAmountView(props: OndoSellAmountViewProps): ReactNode;
2104
2211
 
2105
2212
  /**
2106
- * The reference panel beside the Superstate checkout: which asset is being
2107
- * bought, what a share costs, and the facts about the sale that do not move
2108
- * while the order is filled in.
2213
+ * The review step of the Ondo sell checkout: what the sale comes to, and
2214
+ * placing it.
2109
2215
  *
2110
- * Read-only, so there is no `UiEvent`. Whether the mobile disclosure is open is
2111
- * the View's own business.
2112
- *
2113
- * A product type rather than a union: the identity half comes from the offer
2114
- * and is known the moment the checkout renders, so there is no state in which
2115
- * the panel has nothing to show. Only the price waits on the network, and it
2116
- * carries its own arms.
2216
+ * `loading` is a separate arm from `active` rather than a flag inside it, so
2217
+ * the skeleton renders from a state that carries no order details at all —
2218
+ * there is nothing for the viewmodel to invent while the first quote is in
2219
+ * flight. Once details exist they stay on screen through every later refresh,
2220
+ * and it is `quote` that reports whether they can still be acted on.
2117
2221
  *
2118
- * Different rows from Ondo's panel, which is why the two are not one screen:
2119
- * Superstate has a sale window and a funding menu, and no ticker, ISIN or
2120
- * instrument type.
2222
+ * The rows are the buy step's inverted, not a subset of them: the hero is the
2223
+ * *proceeds* rather than the asset, and there is no total, because a sell has
2224
+ * nothing for the user to pay. Hence a second state machine rather than a
2225
+ * shared one - the day either screen grows a row, it should not be the other
2226
+ * screen's problem.
2121
2227
  */
2122
- type SuperstateSidebarUiState = {
2123
- asset: CheckoutAssetUi;
2124
- /** Who issues the asset, e.g. `Superstate`. */
2125
- issuer: string;
2228
+ type OndoSellReviewUiState = {
2229
+ type: 'incomplete';
2230
+ }
2231
+ /** The first quote is in flight; nothing to show yet. */
2232
+ | {
2233
+ type: 'loading';
2234
+ }
2235
+ /** No quote could be loaded at all. */
2236
+ | {
2237
+ type: 'error';
2238
+ } | {
2239
+ type: 'active';
2240
+ /** What the proceeds arrive in, e.g. USDC. */
2241
+ outputAsset: CheckoutAssetUi;
2126
2242
  /**
2127
- * Whether the sale is still running, and the copy that says so — a live
2128
- * countdown, or `Sale ended`.
2243
+ * What the sale is expected to return, and what CoinList takes to get
2244
+ * there. An expectation, not a guarantee.
2245
+ */
2246
+ expected: OndoSellOutcomeUi;
2247
+ /**
2248
+ * What the calldata guarantees, and the cut at that outcome.
2129
2249
  *
2130
- * A countdown ticking down is a `label` change, not a state change, until the
2131
- * window actually closes.
2250
+ * Shown rather than hidden, although no Ondo design calls for the row.
2251
+ * On a sell {@link expected} is an expectation and this is the
2252
+ * guarantee - Ondo settles through USDon before converting - so a screen
2253
+ * that showed only the first would present a firm-looking number the
2254
+ * contract may legitimately fill below.
2255
+ */
2256
+ minimum: OndoSellOutcomeUi;
2257
+ /** Where the proceeds land, the wallet that holds the asset. */
2258
+ recipientAddress: ShortenedWalletAddress;
2259
+ /**
2260
+ * Price of one whole token, e.g. `$378.99`.
2261
+ *
2262
+ * Struck against {@link expected} alone: pricing the floor would answer
2263
+ * "the worst price this could fill at", which no screen asks for. Flat
2264
+ * rather than per-outcome for that reason, and the row discloses that it
2265
+ * is what the order is expected to fill at.
2132
2266
  */
2133
- sale: CheckoutStatusUi;
2134
- /** Display name of the chain the token lives on, e.g. `Ethereum`. */
2135
- networkName: string;
2136
- /** What the sale can be funded with, e.g. `USDC`. */
2137
- purchaseOptionsLabel: string;
2138
- /** The offer's minimum, e.g. `$100.00`. `-` when it publishes none. */
2139
- minPurchase: FormattedAmountAssetUi;
2140
- price: SuperstateSidebarPriceUi;
2267
+ pricePerShare: FormattedAmountAssetUi;
2268
+ quote: OndoSellQuoteStatusUi;
2269
+ placeOrderCta: CheckoutCtaUi;
2270
+ /** A failure from placing the order, distinct from a quote problem. */
2271
+ error: string | null;
2141
2272
  };
2142
2273
  /**
2143
- * The price corner of the panel.
2274
+ * One end of the range a sale commits to, ready to render: what arrives, and
2275
+ * what CoinList took to get it there.
2144
2276
  *
2145
- * Its own SUM rather than nullable fields on the state, because the price is
2146
- * derived from the swap quote and the output token, and both arrive later than
2147
- * everything else on the panel. Keeping them here means a poll in flight never
2148
- * blanks the asset's identity or the sale window.
2277
+ * Paired for the same reason `OndoSellOutcome` is, one layer down. A flat
2278
+ * `{ outputAmount, minimumOutputAmount, coinlistFee }` leaves the crossing -
2279
+ * the expected quantity beside the floor's fee - reachable at every call site,
2280
+ * and a review screen renders the two as adjacent rows, so the layer that
2281
+ * flattens them is the layer that shows a seller the wrong disclosure. Keeping
2282
+ * the pair together makes it unsayable here as well.
2283
+ *
2284
+ * Both halves are in the *proceeds*' decimals, unlike a buy's, because a sell
2285
+ * takes its fee from the token it prices in.
2149
2286
  */
2150
- type SuperstateSidebarPriceUi =
2151
- /** No quote or output token yet. The corner renders placeholders. */
2152
- {
2153
- type: 'loading';
2154
- } | {
2155
- type: 'known';
2156
- /** Price of one whole token, e.g. `$10.19`. */
2157
- price: FormattedAmountAssetUi;
2287
+ type OndoSellOutcomeUi = {
2288
+ /** What the wallet receives at this outcome, net of {@link fee}. */
2289
+ amount: FormattedAmountAssetUi;
2290
+ /**
2291
+ * CoinList's cut at this outcome, e.g. `0.42 USDC`.
2292
+ *
2293
+ * `null` while no fee is disclosed: frontline rejects a non-zero one on
2294
+ * either side today (ENG-1718), and a row reading "0.00 USDC" would imply a
2295
+ * fee exists and happens to round away. Nullable per outcome rather than
2296
+ * once for the pair, so a cut that rounds to zero at one outcome and not the
2297
+ * other still renders honestly.
2298
+ */
2299
+ fee: FormattedAmountAssetUi | null;
2158
2300
  };
2159
-
2160
2301
  /**
2161
- * Step 1 of the Superstate checkout: which wallet funds the swap and receives
2162
- * the asset.
2163
- *
2164
- * There is no `incomplete` arm. This step is the first one, so it is either
2165
- * being filled in or already answered — it is never waiting on a step above it.
2166
- *
2167
- * Confirming here is not a local decision the way Ondo's is: the wallet has to
2168
- * prove ownership and be allow-listed on the swap contract before it may trade,
2169
- * which is a signature and possibly a transaction. That is why the CTA is a
2170
- * {@link CheckoutCtaUi} carrying the phase as loading copy, and why `error` can
2171
- * hold an allow-listing failure as well as a failed connect.
2302
+ * Whether the shown numbers can still be traded on.
2172
2303
  *
2173
- * The allow-listing is invisible in the copy — the step still reads "Choose
2174
- * your wallet" — because from the user's side it is the cost of choosing, not a
2175
- * separate decision. `allowlisted` on the completed arm is the only trace of it.
2176
- */
2177
- type SuperstateWalletUiState = {
2178
- type: 'active';
2179
- /** The user's CoinList wallets. Empty when they have none. */
2180
- embeddedWallets: CheckoutEmbeddedWalletUi[];
2181
- /** `null` until an external wallet is connected. The row still renders. */
2182
- externalWallet: CheckoutWalletUi | null;
2183
- /** Whether the connected external wallet may be disconnected here. */
2184
- canDisconnect: boolean;
2185
- /**
2186
- * Confirming runs the authorization, so this reports its phase as
2187
- * loading copy — `Sign the message in your wallet…` and the rest.
2188
- */
2189
- confirmCta: CheckoutCtaUi;
2190
- /** A failed connect, or a failed step of the authorization. */
2191
- error: string | null;
2192
- } | {
2193
- type: 'completed';
2194
- wallet: CheckoutConfirmedWalletUi;
2304
+ * A quote is only good for a few seconds, so this drives the line above the CTA
2305
+ * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
2306
+ * rather than folding into the step's `error`, because the remedy differs: a
2307
+ * failed refresh is fixed by refreshing again, a failed order is not.
2308
+ */
2309
+ type OndoSellQuoteStatusUi =
2310
+ /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
2311
+ {
2312
+ type: 'valid';
2313
+ expiresInLabel: string;
2314
+ }
2315
+ /** A refresh is in flight; the previous numbers are still on screen. */
2316
+ | {
2317
+ type: 'refreshing';
2318
+ }
2319
+ /** Too old to trade on. The user must refresh before placing the order. */
2320
+ | {
2321
+ type: 'expired';
2322
+ }
2323
+ /** The refresh failed. `message` says why. */
2324
+ | {
2325
+ type: 'refresh-failed';
2326
+ message: string;
2195
2327
  };
2196
- type SuperstateWalletUiEvent = {
2197
- type: 'ON_SELECT_WALLET';
2198
- value: CheckoutWalletTypeUi;
2328
+ type OndoSellReviewUiEvent = {
2329
+ type: 'ON_REFRESH_SELL_QUOTE';
2199
2330
  }
2200
- /**
2201
- * Tapping the external row while nothing is connected. Split from
2202
- * `ON_SELECT_WALLET` because it opens the host's wallet connector rather than
2203
- * changing the selection.
2204
- */
2331
+ /** Retry from the `error` arm, where there is no quote to refresh. */
2205
2332
  | {
2206
- type: 'ON_CONNECT_WALLET';
2333
+ type: 'ON_SELL_RETRY';
2207
2334
  } | {
2208
- type: 'ON_DISCONNECT_WALLET';
2209
- } | {
2210
- type: 'ON_CONFIRM_WALLET';
2211
- } | {
2212
- type: 'ON_EDIT_WALLET';
2335
+ type: 'ON_PLACE_SELL_ORDER';
2213
2336
  };
2214
2337
 
2215
2338
  /**
2216
- * The whole Superstate swap checkout.
2339
+ * The whole Ondo sell checkout: the step cards, the reference panel beside
2340
+ * them, and the dialog that closes the flow.
2217
2341
  *
2218
- * A SUM at the top, unlike Ondo's, because a Superstate checkout has one
2219
- * failure it cannot localise to a region: the swap's output token. Without it
2220
- * there is no quote, no price, no minimum received and no asset name, so three
2221
- * of the four regions would have to invent something. `error` says so once and
2222
- * offers the retry.
2342
+ * A product type rather than a union, because every step that exists is always
2343
+ * on screen — a step that is not the current one renders collapsed, not absent.
2344
+ * Which one is live is carried by the steps themselves, and whether the flow is
2345
+ * finished by `orderConfirmed`.
2223
2346
  */
2224
- type SuperstateSwapCheckoutUiState = {
2225
- type: 'content';
2226
- wallet: SuperstateWalletUiState;
2227
- amount: SuperstateAmountUiState;
2228
- review: SuperstateReviewUiState;
2229
- /** The sale panel. Read-only, so it raises no events. */
2230
- sidebar: SuperstateSidebarUiState;
2231
- orderConfirmed: SuperstateOrderConfirmedUiState;
2232
- }
2233
- /** The swap could not be loaded at all. */
2234
- | {
2235
- type: 'error';
2236
- reason: SuperstateSwapLoadErrorReason;
2347
+ type OndoSellCheckoutUiState = {
2348
+ /**
2349
+ * The wallet step, or `null` when the host preselected a wallet and the flow
2350
+ * skipped it.
2351
+ *
2352
+ * `null` is the whole skip: it is what the View renders nothing for, and the
2353
+ * single fact both remaining step numbers are derived from, so a two-step
2354
+ * flow numbered `1, 2` and a three-step flow numbered `1, 2, 3` cannot
2355
+ * disagree. A boolean beside a non-null state would have let them.
2356
+ */
2357
+ wallet: OndoWalletSelectUiState | null;
2358
+ amount: OndoSellAmountUiState;
2359
+ review: OndoSellReviewUiState;
2360
+ /** The asset panel. Read-only, so it raises no events. */
2361
+ sidebar: OndoSidebarUiState;
2362
+ orderConfirmed: OndoSellOrderConfirmedUiState;
2237
2363
  };
2238
- /**
2239
- * Why the whole flow failed to load.
2240
- *
2241
- * The two differ in whether retrying can help, which is the only thing the View
2242
- * does with this: a read that failed is worth another go, a chain with no
2243
- * contract deployed on it is not, and offering a button that provably cannot
2244
- * help is worse than offering none.
2245
- */
2246
- type SuperstateSwapLoadErrorReason =
2247
- /** The swap's output token would not read. Retrying may work. */
2248
- 'load-failed'
2249
- /** No Superstate swap contract is deployed on this chain. Retrying cannot. */
2250
- | 'unsupported-chain';
2251
2364
  /**
2252
2365
  * Every event any step can raise, flattened into one union.
2253
2366
  *
2254
2367
  * Flat rather than wrapped (`{ step, event }`) so that a single
2255
- * `onEvent: (e: SuperstateSwapCheckoutUiEvent) => void` is assignable to each
2256
- * step's narrower handler prop and can be passed straight down — no wrapping
2257
- * lambdas in the View, no nested `switch` in the viewmodel. The cost is that
2258
- * step event tags must stay globally unique within this union, which is why the
2259
- * edit events are `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared
2260
- * `ON_EDIT`.
2261
- */
2262
- type SuperstateSwapCheckoutUiEvent = SuperstateWalletUiEvent | SuperstateAmountUiEvent | SuperstateReviewUiEvent | SuperstateOrderConfirmedUiEvent | SuperstateSwapCheckoutRetryUiEvent;
2263
- /**
2264
- * Retrying the load behind the flow-level `error` arm.
2265
- *
2266
- * The SDK does not own the page it is mounted in, so this re-runs the fetch
2267
- * rather than reloading the document the way the host app it was ported from
2268
- * did.
2368
+ * `onEvent: (e: OndoSellCheckoutUiEvent) => void` is assignable to each step's
2369
+ * narrower handler prop and can be passed straight down — no wrapping lambdas
2370
+ * in the View, no nested `switch` in the viewmodel. The cost is that step event
2371
+ * tags must stay globally unique, which is why the sell steps' tags carry
2372
+ * `SELL` where the buy steps' do not: the two products' step viewmodels are
2373
+ * separate, and a shared tag would make one product's event dispatch into the
2374
+ * other's handler in any host that composed both.
2269
2375
  */
2270
- type SuperstateSwapCheckoutRetryUiEvent = {
2271
- type: 'ON_RETRY_LOAD';
2272
- };
2376
+ type OndoSellCheckoutUiEvent = OndoWalletSelectUiEvent | OndoSellAmountUiEvent | OndoSellReviewUiEvent | OndoSellOrderConfirmedUiEvent;
2273
2377
  /**
2274
- * The dialog that closes the Superstate checkout, once the swap is mined.
2378
+ * The dialog that closes the Ondo sell checkout, once the swap is mined.
2275
2379
  *
2276
2380
  * A SUM rather than a nullable model, so a dialog on screen with no order
2277
2381
  * behind it is unrepresentable. Every figure is already formatted: the dialog
2278
2382
  * reports what happened and has nothing left to compute.
2279
2383
  */
2280
- type SuperstateOrderConfirmedUiState = {
2384
+ type OndoSellOrderConfirmedUiState = {
2281
2385
  type: 'hidden';
2282
2386
  } | {
2283
2387
  type: 'visible';
2284
- /** What was bought. */
2285
- asset: CheckoutAssetUi;
2286
- /** Who issues it, e.g. `Superstate`. */
2287
- issuer: string;
2288
- /** How much of it arrived, e.g. `981.2431 USTB`. */
2289
- outputAmount: FormattedAmountAssetUi;
2290
2388
  /**
2291
- * Whether `outputAmount` and `pricePerShare` are what the chain reported,
2292
- * rather than what the quote predicted.
2389
+ * What was sold.
2293
2390
  *
2294
- * `false` only on the fallback path: the swap mined, but its `Swapped`
2295
- * event would not decode and the quote's estimate is standing in. The
2296
- * dialog labels those two rows as estimates when it is, because a figure
2297
- * captioned `Shares received` is a claim about what is in the user's
2298
- * wallet and the fallback cannot support it.
2391
+ * Named for the direction, not just for being an asset: `proceeds` below
2392
+ * is denominated in the settlement coin, so the two sit side by side in
2393
+ * this type.
2299
2394
  */
2300
- outputAmountConfirmed: boolean;
2301
- /** What the user paid, input plus fee, e.g. `$1,000.00`. */
2302
- totalCost: FormattedAmountAssetUi;
2395
+ soldAsset: CheckoutAssetUi;
2396
+ /** How much of it went, e.g. `1.204 TSLAon`. */
2397
+ soldAmount: FormattedAmountAssetUi;
2398
+ /** What arrived, in the settlement coin, e.g. `378.99 USDC`. */
2399
+ proceeds: FormattedAmountAssetUi;
2303
2400
  /**
2304
- * Price of one whole token at the fill, e.g. `$10.19`. Derived from
2305
- * `outputAmount`, so `outputAmountConfirmed` covers it too.
2401
+ * The settlement coin's symbol on its own, e.g. `USDC`.
2402
+ *
2403
+ * Carried rather than parsed back out of {@link proceeds}: the dialog's
2404
+ * whole contract is that it has nothing left to compute, and a subtitle
2405
+ * that took the last word of a formatted amount would break on the first
2406
+ * locale that puts the unit first.
2306
2407
  */
2408
+ proceedsSymbol: AssetSymbol;
2409
+ /** Price of one whole token at the time of the fill, e.g. `$378.99`. */
2307
2410
  pricePerShare: FormattedAmountAssetUi;
2308
- /** The wallet the asset was delivered to. */
2411
+ /** The wallet the proceeds were delivered to. */
2309
2412
  recipientAddress: ShortenedWalletAddress;
2310
2413
  /**
2311
2414
  * The settled swap on a block explorer. Always present: the dialog only
@@ -2320,18 +2423,18 @@ type SuperstateOrderConfirmedUiState = {
2320
2423
  * `txExplorerUrl`, not an event: the URL is already built, and an anchor keeps
2321
2424
  * middle-click, copy-link and the browser's own handling working.
2322
2425
  */
2323
- type SuperstateOrderConfirmedUiEvent = {
2324
- type: 'ON_CLOSE_ORDER_CONFIRMED';
2426
+ type OndoSellOrderConfirmedUiEvent = {
2427
+ type: 'ON_CLOSE_SELL_ORDER_CONFIRMED';
2325
2428
  };
2326
2429
 
2327
- interface SuperstateOrderConfirmedProps {
2328
- state: SuperstateOrderConfirmedUiState;
2329
- onEvent: (event: SuperstateOrderConfirmedUiEvent) => void;
2430
+ interface OndoSellOrderConfirmedProps {
2431
+ state: OndoSellOrderConfirmedUiState;
2432
+ onEvent: (event: OndoSellOrderConfirmedUiEvent) => void;
2330
2433
  className?: string;
2331
2434
  }
2332
2435
  /**
2333
- * The dialog that closes the Superstate checkout: what arrived, what it cost,
2334
- * and where it went.
2436
+ * The dialog that closes the Ondo sell checkout: what went, what came back,
2437
+ * and where it landed.
2335
2438
  *
2336
2439
  * Pure: every figure is handed over formatted, and the explorer link is
2337
2440
  * rendered from the URL the viewmodel built rather than raised as an event.
@@ -2339,78 +2442,34 @@ interface SuperstateOrderConfirmedProps {
2339
2442
  * Self-scoped: renders fully styled on its own. It bails before the scope while
2340
2443
  * hidden, so a closed dialog leaves nothing in the DOM.
2341
2444
  */
2342
- declare function SuperstateOrderConfirmed({ state, onEvent, className, }: SuperstateOrderConfirmedProps): ReactNode;
2445
+ declare function OndoSellOrderConfirmed({ state, onEvent, className, }: OndoSellOrderConfirmedProps): ReactNode;
2343
2446
 
2344
- interface SlippagePickerProps {
2345
- slippage: SuperstateSlippageUi;
2447
+ interface OndoSellCheckoutContainerProps {
2448
+ /** The offer being sold: names the asset and supplies its logo. */
2449
+ offer: OfferDetail;
2346
2450
  /**
2347
- * What the tolerance applies to, rendered to the left of the toggle: the
2348
- * amount the user receives, in practice.
2451
+ * Ondo's API symbol for the asset, e.g. `TSLAon`.
2349
2452
  *
2350
- * A slot, and the reason this component owns a row at all. The toggle has to
2351
- * sit beside the summary while the options have to span the full width
2352
- * beneath both - a picker that rendered only itself would put the options in
2353
- * whatever narrow column the toggle landed in. Taking the summary is what
2354
- * lets one component place both, and keeps `aria-controls` pointing at a
2355
- * panel it still owns.
2453
+ * Explicit rather than derived from the offer: Ondo's symbol tracks the
2454
+ * underlying ticker and changes on a rebrand, and on Sepolia the two already
2455
+ * disagree, where a mock asset stands in.
2356
2456
  */
2357
- summary: ReactNode;
2358
- /** Toggles the disclosure. Open/closed is viewmodel state, not View state. */
2359
- onToggle: () => void;
2360
- onSelect: (bps: Bps) => void;
2361
- className?: string;
2362
- }
2363
- /**
2364
- * The slippage tolerance, and the disclosure that changes it: a pill showing
2365
- * the tolerance in force beside {@link SlippagePickerProps.summary}, and - once
2366
- * opened - the options and what they mean, on their own line below both.
2367
- *
2368
- * Superstate-only, so it lives beside the review step rather than in
2369
- * `checkout/shared`. Ondo quotes firm prices and has no tolerance to set, and a
2370
- * shared component shaped entirely by one provider's `SLIPPAGE_OPTIONS_BPS`
2371
- * would be that provider's component in a shared directory.
2372
- *
2373
- * Pure: it renders the options it is handed and reports which was picked. It
2374
- * does not know what a basis point is.
2375
- *
2376
- * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2377
- * needed around it.
2378
- */
2379
- declare function SlippagePicker({ slippage, summary, onToggle, onSelect, className, }: SlippagePickerProps): ReactNode;
2380
-
2381
- interface SuperstateReviewViewProps {
2382
- state: SuperstateReviewUiState;
2383
- onEvent: (event: SuperstateReviewUiEvent) => void;
2384
- className?: string;
2385
- }
2386
- /**
2387
- * Step 3 of the Superstate checkout. Pure: every number arrives formatted, and
2388
- * whether the order can be placed is decided by `placeOrderCta` rather than
2389
- * re-derived here.
2390
- *
2391
- * The CTA covers a status check, an approval and the swap, which is why the
2392
- * "don't close this page" notice appears only while it runs — a Superstate
2393
- * order is several wallet prompts long, and leaving mid-flight strands the
2394
- * approval.
2395
- *
2396
- * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2397
- * needed around it.
2398
- */
2399
- declare function SuperstateReviewView(props: SuperstateReviewViewProps): ReactNode;
2400
-
2401
- interface SuperstateSwapCheckoutContainerProps {
2402
- /** The offer being bought: names the asset, the window and the minimum. */
2403
- offer: OfferDetail;
2457
+ ondoSymbol: AssetSymbol;
2404
2458
  /**
2405
- * The chain the order executes on: the balance reads, the approval and the
2406
- * swap. The swap contract is looked up from it, so a chain with none
2407
- * deployed renders the flow's error state rather than a broken checkout.
2459
+ * The chain the order executes on: the balance read, the approval and the
2460
+ * broadcast. Ondo prices against production whatever this says, since it
2461
+ * runs no sandbox.
2408
2462
  */
2409
2463
  chain: EthereumChain;
2410
2464
  /**
2411
- * The wallets the buyer can spend from, and the lambdas that connect and
2412
- * disconnect an external one. The SDK ships no wallet stack, so this is how
2413
- * a host plugs in Privy, AppKit, or its own.
2465
+ * The wallets the seller can sell from, the lambdas that connect and
2466
+ * disconnect an external one, and optionally the one the host has already
2467
+ * settled on.
2468
+ *
2469
+ * Setting `wallets.preselected` skips the wallet step and opens the flow on
2470
+ * the amount, with the two remaining cards renumbered. It is read once, at
2471
+ * mount: the approval that follows the amount step is granted by one
2472
+ * specific wallet.
2414
2473
  */
2415
2474
  wallets: CheckoutWalletSelection;
2416
2475
  /**
@@ -2419,30 +2478,33 @@ interface SuperstateSwapCheckoutContainerProps {
2419
2478
  */
2420
2479
  enabled?: boolean;
2421
2480
  /** Fired once the swap has mined. The dialog shows either way. */
2422
- onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;
2481
+ onOrderConfirmed?: (order: OndoOrderPlaced) => void;
2423
2482
  className?: string;
2424
2483
  }
2425
2484
  /**
2426
- * The Superstate swap checkout, ready to drop in: three steps, the sale panel
2427
- * beside them, and the dialog that closes the flow.
2428
- *
2429
- * Takes no contract address: it is looked up from `chain`, the way Ondo's is.
2430
- * A partner who needs to point at a different deployment is below this rung and
2431
- * calls `coinlist.superstate.execute` directly.
2485
+ * The Ondo sell checkout, ready to drop in: the steps, the asset panel beside
2486
+ * them, and the dialog that closes the flow.
2432
2487
  *
2433
2488
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2434
2489
  * needed around it.
2435
2490
  */
2436
- declare function SuperstateSwapCheckoutContainer({ offer, chain, wallets, enabled, onOrderConfirmed, className, }: SuperstateSwapCheckoutContainerProps): ReactNode;
2491
+ declare function OndoSellCheckoutContainer({ offer, ondoSymbol, chain, wallets, enabled, onOrderConfirmed, className, }: OndoSellCheckoutContainerProps): ReactNode;
2437
2492
 
2438
- interface SuperstateSwapCheckoutViewProps {
2439
- state: SuperstateSwapCheckoutUiState;
2440
- onEvent: (event: SuperstateSwapCheckoutUiEvent) => void;
2493
+ interface OndoSellCheckoutViewProps {
2494
+ state: OndoSellCheckoutUiState;
2495
+ onEvent: (event: OndoSellCheckoutUiEvent) => void;
2441
2496
  className?: string;
2442
2497
  }
2443
2498
  /**
2444
- * The whole Superstate swap checkout: the three step cards, the sale panel
2445
- * beside them, and the dialog that closes the flow.
2499
+ * The whole Ondo sell checkout: the step cards, the asset panel beside them,
2500
+ * and the dialog that closes the flow.
2501
+ *
2502
+ * **Two or three cards, depending on `state.wallet`.** A host that already
2503
+ * knows which wallet holds the position preselects it, and the flow opens on
2504
+ * the amount. That one nullable field is where both remaining step numbers
2505
+ * come from, so a two-step flow reading `1, 2` and a three-step flow reading
2506
+ * `1, 2, 3` cannot disagree - a second source for "is there a wallet step"
2507
+ * would be the way they could.
2446
2508
  *
2447
2509
  * `onEvent` is handed to each step unwrapped. A handler that accepts the wider
2448
2510
  * union is assignable where a step's narrower one is expected, so there is no
@@ -2450,97 +2512,601 @@ interface SuperstateSwapCheckoutViewProps {
2450
2512
  *
2451
2513
  * The panel leads on a phone and moves to the right column from `md` up, where
2452
2514
  * it is reference material rather than the first thing to read. No page heading
2453
- * and no back button — the host titles and navigates its own page.
2515
+ * is rendered — the host titles its own page.
2454
2516
  *
2455
2517
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2456
2518
  * needed around it. The steps scope themselves too, and the scope is
2457
2519
  * idempotent, so nesting costs nothing.
2458
2520
  */
2459
- declare function SuperstateSwapCheckoutView({ state, onEvent, className, }: SuperstateSwapCheckoutViewProps): ReactNode;
2521
+ declare function OndoSellCheckoutView({ state, onEvent, className, }: OndoSellCheckoutViewProps): ReactNode;
2460
2522
 
2461
- interface SuperstateSidebarViewProps {
2462
- state: SuperstateSidebarUiState;
2523
+ interface OndoSellReviewViewProps {
2524
+ state: OndoSellReviewUiState;
2525
+ onEvent: (event: OndoSellReviewUiEvent) => void;
2526
+ /** Where this card sits in the flow: 3 normally, 2 when the wallet step was skipped. */
2527
+ stepNumber: number;
2463
2528
  className?: string;
2464
2529
  }
2465
2530
  /**
2466
- * The panel beside the Superstate checkout: whether the sale is still running,
2467
- * what is being bought, what one share costs, and the terms of the sale.
2531
+ * The review step of the Ondo sell checkout. Pure: every number arrives
2532
+ * formatted, and whether the order can be placed is decided by
2533
+ * `placeOrderCta` rather than re-derived here from the quote's status.
2468
2534
  *
2469
- * Read-only, so it takes no `onEvent`. The sale banner sits above the card
2470
- * rather than inside it — it is the first thing to read on a phone, where the
2471
- * card's own contents fold away behind a disclosure.
2535
+ * It carries no total. A sell has nothing for the user to pay - the proceeds
2536
+ * are the headline, and the fee comes out of them - so the buy step's
2537
+ * gross/fee/total ladder has no counterpart here. What it carries instead is
2538
+ * the floor: the proceeds above are what Ondo expects to deliver, and only the
2539
+ * minimum is what the calldata enforces.
2472
2540
  *
2473
2541
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2474
2542
  * needed around it.
2475
2543
  */
2476
- declare function SuperstateSidebarView({ state, className, }: SuperstateSidebarViewProps): ReactNode;
2544
+ declare function OndoSellReviewView(props: OndoSellReviewViewProps): ReactNode;
2477
2545
 
2478
- interface SuperstateWalletViewProps {
2479
- state: SuperstateWalletUiState;
2480
- onEvent: (event: SuperstateWalletUiEvent) => void;
2546
+ interface OndoSidebarViewProps {
2547
+ state: OndoSidebarUiState;
2481
2548
  className?: string;
2482
2549
  }
2483
2550
  /**
2484
- * Step 1 of the Superstate checkout. Pure: the wallets arrive already shaped,
2485
- * and every interaction leaves through `onEvent`.
2551
+ * The panel beside the Ondo checkout: what is being bought, what one share
2552
+ * costs, and the reference facts about the asset.
2486
2553
  *
2487
- * Confirming allow-lists the wallet on-chain, which is why the CTA renders a
2488
- * loading message rather than a spinner alone — the copy is what tells the user
2489
- * their wallet is about to ask them to sign. The completed step says
2490
- * `Allowlisted`, the only place the flow admits that anything happened.
2554
+ * Read-only, so it takes no `onEvent`. Rows the SDK has no source for arrive as
2555
+ * `null` and are dropped by `CheckoutDetailList` rather than rendered empty.
2491
2556
  *
2492
2557
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2493
2558
  * needed around it.
2494
2559
  */
2495
- declare function SuperstateWalletView(props: SuperstateWalletViewProps): ReactNode;
2560
+ declare function OndoSidebarView({ state, className, }: OndoSidebarViewProps): ReactNode;
2496
2561
 
2497
- type OffersGridUiState = {
2562
+ interface OndoWalletSelectViewProps {
2563
+ state: OndoWalletSelectUiState;
2564
+ onEvent: (event: OndoWalletSelectUiEvent) => void;
2565
+ /**
2566
+ * The line under the heading. Defaults to the buy copy.
2567
+ *
2568
+ * A plain string rather than a slot: every Ondo product renders one sentence
2569
+ * here in the same style, and the only thing that varies is what the wallet
2570
+ * is for.
2571
+ */
2572
+ description?: string;
2573
+ className?: string;
2574
+ }
2575
+ /**
2576
+ * The wallet step of an Ondo checkout: which wallet the order runs through.
2577
+ * Pure - the wallets arrive already shaped, and every interaction leaves
2578
+ * through `onEvent`.
2579
+ *
2580
+ * Shared by both Ondo products, because nothing about choosing a wallet
2581
+ * differs between them: an Ondo wallet is not allow-listed either way, so the
2582
+ * decision is local and synchronous on both. Only the sentence under the
2583
+ * heading changes, and that is a prop.
2584
+ *
2585
+ * It is always step 1 where it renders at all. A sell that skips it does not
2586
+ * render this component, rather than rendering it with another number.
2587
+ *
2588
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2589
+ * needed around it.
2590
+ */
2591
+ declare function OndoWalletSelectView(props: OndoWalletSelectViewProps): ReactNode;
2592
+
2593
+ /**
2594
+ * Step 2 of the Superstate checkout: how much to spend, and which asset to
2595
+ * spend.
2596
+ *
2597
+ * Nothing here touches the chain. Unlike Ondo's amount step, which approves and
2598
+ * commits a quote, this one only validates locally and hands the amount up — a
2599
+ * Superstate swap approves and executes together on the review step. Hence a
2600
+ * plain `confirmEnabled` rather than a `CheckoutCtaUi` with loading copy: there
2601
+ * is no phase to report.
2602
+ */
2603
+ type SuperstateAmountUiState = {
2604
+ type: 'incomplete';
2605
+ } | {
2606
+ type: 'active';
2607
+ /**
2608
+ * Exactly what the user has typed, not a parsed number: the field is
2609
+ * mid-edit, and `'1.'` is a legal thing to be holding.
2610
+ */
2611
+ amountInput: string;
2612
+ /** The wallet the funds come from, per step 1. */
2613
+ walletAddress: ShortenedWalletAddress;
2614
+ /**
2615
+ * Every supported input asset, in display order, whether or not the user
2616
+ * holds any. One entry renders as a plain card, two or more as a picker.
2617
+ */
2618
+ inputAssets: CheckoutSelectableInputAssetUi[];
2619
+ confirmEnabled: boolean;
2620
+ /** Validation copy, e.g. `Amount must be greater than 0.` */
2621
+ error: string | null;
2622
+ } | {
2623
+ type: 'complete';
2624
+ inputAsset: CheckoutAssetUi;
2625
+ /**
2626
+ * What the user is spending, as the field asked for it: dollars, e.g.
2627
+ * `$1,000.00`. The Superstate field is dollar-denominated, which is why
2628
+ * this is prefixed rather than suffixed with a symbol.
2629
+ */
2630
+ amountFormatted: FormattedAmountAssetUi;
2631
+ /**
2632
+ * The same figure in the asset actually being paid, e.g. `1,000.00 USDC`.
2633
+ *
2634
+ * Both are shown because the two are only equal while the funding asset
2635
+ * is a dollar stablecoin — the day a non-dollar one is fundable, the
2636
+ * summary would otherwise silently claim it was.
2637
+ */
2638
+ inputAmountFormatted: FormattedAmountAssetUi;
2639
+ };
2640
+ type SuperstateAmountUiEvent = {
2641
+ type: 'ON_AMOUNT_CHANGE';
2642
+ value: string;
2643
+ } | {
2644
+ type: 'ON_MAX_AMOUNT_CLICK';
2645
+ } | {
2646
+ type: 'ON_SELECT_PAY_WITH';
2647
+ value: AssetSymbol;
2648
+ }
2649
+ /**
2650
+ * Named for what it does rather than for the step: confirming here previews
2651
+ * the order on step 3, it does not place or pay for anything.
2652
+ */
2653
+ | {
2654
+ type: 'ON_PREVIEW_ORDER';
2655
+ } | {
2656
+ type: 'ON_EDIT_AMOUNT';
2657
+ };
2658
+
2659
+ interface SuperstateAmountViewProps {
2660
+ state: SuperstateAmountUiState;
2661
+ onEvent: (event: SuperstateAmountUiEvent) => void;
2662
+ className?: string;
2663
+ }
2664
+ /**
2665
+ * Step 2 of the Superstate checkout. Pure: amounts arrive already formatted,
2666
+ * and every interaction leaves through `onEvent`.
2667
+ *
2668
+ * The field is dollar-denominated, so the `$` goes in `CheckoutAmountInput`'s
2669
+ * `prefix` slot — where Ondo puts the symbol of the token it charges. Nothing
2670
+ * here is submitted: confirming only moves the flow to the review step.
2671
+ *
2672
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2673
+ * needed around it.
2674
+ */
2675
+ declare function SuperstateAmountView(props: SuperstateAmountViewProps): ReactNode;
2676
+
2677
+ /**
2678
+ * The reference panel beside the Superstate checkout: which asset is being
2679
+ * bought, what a share costs, and the facts about the sale that do not move
2680
+ * while the order is filled in.
2681
+ *
2682
+ * Read-only, so there is no `UiEvent`. Whether the mobile disclosure is open is
2683
+ * the View's own business.
2684
+ *
2685
+ * A product type rather than a union: the identity half comes from the offer
2686
+ * and is known the moment the checkout renders, so there is no state in which
2687
+ * the panel has nothing to show. Only the price waits on the network, and it
2688
+ * carries its own arms.
2689
+ *
2690
+ * Different rows from Ondo's panel, which is why the two are not one screen:
2691
+ * Superstate has a sale window and a funding menu, and no ticker, ISIN or
2692
+ * instrument type.
2693
+ */
2694
+ type SuperstateSidebarUiState = {
2695
+ asset: CheckoutAssetUi;
2696
+ /** Who issues the asset, e.g. `Superstate`. */
2697
+ issuer: string;
2698
+ /**
2699
+ * Whether the sale is still running, and the copy that says so — a live
2700
+ * countdown, or `Sale ended`.
2701
+ *
2702
+ * A countdown ticking down is a `label` change, not a state change, until the
2703
+ * window actually closes.
2704
+ */
2705
+ sale: CheckoutStatusUi;
2706
+ /** Display name of the chain the token lives on, e.g. `Ethereum`. */
2707
+ networkName: string;
2708
+ /** What the sale can be funded with, e.g. `USDC`. */
2709
+ purchaseOptionsLabel: string;
2710
+ /** The offer's minimum, e.g. `$100.00`. `-` when it publishes none. */
2711
+ minPurchase: FormattedAmountAssetUi;
2712
+ price: SuperstateSidebarPriceUi;
2713
+ };
2714
+ /**
2715
+ * The price corner of the panel.
2716
+ *
2717
+ * Its own SUM rather than nullable fields on the state, because the price is
2718
+ * derived from the swap quote and the output token, and both arrive later than
2719
+ * everything else on the panel. Keeping them here means a poll in flight never
2720
+ * blanks the asset's identity or the sale window.
2721
+ */
2722
+ type SuperstateSidebarPriceUi =
2723
+ /** No quote or output token yet. The corner renders placeholders. */
2724
+ {
2498
2725
  type: 'loading';
2499
2726
  } | {
2500
- type: 'error';
2501
- message: string;
2727
+ type: 'known';
2728
+ /** Price of one whole token, e.g. `$10.19`. */
2729
+ price: FormattedAmountAssetUi;
2730
+ };
2731
+
2732
+ /**
2733
+ * Step 1 of the Superstate checkout: which wallet funds the swap and receives
2734
+ * the asset.
2735
+ *
2736
+ * There is no `incomplete` arm. This step is the first one, so it is either
2737
+ * being filled in or already answered — it is never waiting on a step above it.
2738
+ *
2739
+ * Confirming here is not a local decision the way Ondo's is: the wallet has to
2740
+ * prove ownership and be allow-listed on the swap contract before it may trade,
2741
+ * which is a signature and possibly a transaction. That is why the CTA is a
2742
+ * {@link CheckoutCtaUi} carrying the phase as loading copy, and why `error` can
2743
+ * hold an allow-listing failure as well as a failed connect.
2744
+ *
2745
+ * The allow-listing is invisible in the copy — the step still reads "Choose
2746
+ * your wallet" — because from the user's side it is the cost of choosing, not a
2747
+ * separate decision. `allowlisted` on the completed arm is the only trace of it.
2748
+ */
2749
+ type SuperstateWalletUiState = {
2750
+ type: 'active';
2751
+ /** The user's CoinList wallets. Empty when they have none. */
2752
+ embeddedWallets: CheckoutEmbeddedWalletUi[];
2753
+ /** `null` until an external wallet is connected. The row still renders. */
2754
+ externalWallet: CheckoutWalletUi | null;
2755
+ /** Whether the connected external wallet may be disconnected here. */
2756
+ canDisconnect: boolean;
2757
+ /**
2758
+ * Confirming runs the authorization, so this reports its phase as
2759
+ * loading copy — `Sign the message in your wallet…` and the rest.
2760
+ */
2761
+ confirmCta: CheckoutCtaUi;
2762
+ /** A failed connect, or a failed step of the authorization. */
2763
+ error: string | null;
2502
2764
  } | {
2503
- type: 'empty';
2765
+ type: 'completed';
2766
+ wallet: CheckoutConfirmedWalletUi;
2767
+ };
2768
+ type SuperstateWalletUiEvent = {
2769
+ type: 'ON_SELECT_WALLET';
2770
+ value: CheckoutWalletTypeUi;
2771
+ }
2772
+ /**
2773
+ * Tapping the external row while nothing is connected. Split from
2774
+ * `ON_SELECT_WALLET` because it opens the host's wallet connector rather than
2775
+ * changing the selection.
2776
+ */
2777
+ | {
2778
+ type: 'ON_CONNECT_WALLET';
2504
2779
  } | {
2780
+ type: 'ON_DISCONNECT_WALLET';
2781
+ } | {
2782
+ type: 'ON_CONFIRM_WALLET';
2783
+ } | {
2784
+ type: 'ON_EDIT_WALLET';
2785
+ };
2786
+
2787
+ /**
2788
+ * The whole Superstate swap checkout.
2789
+ *
2790
+ * A SUM at the top, unlike Ondo's, because a Superstate checkout has one
2791
+ * failure it cannot localise to a region: the swap's output token. Without it
2792
+ * there is no quote, no price, no minimum received and no asset name, so three
2793
+ * of the four regions would have to invent something. `error` says so once and
2794
+ * offers the retry.
2795
+ */
2796
+ type SuperstateSwapCheckoutUiState = {
2505
2797
  type: 'content';
2506
- offers: OfferCardUi[];
2507
- /** Cards render as buttons only when the host passed `onOfferClick`. */
2508
- interactive: boolean;
2798
+ wallet: SuperstateWalletUiState;
2799
+ amount: SuperstateAmountUiState;
2800
+ review: SuperstateReviewUiState;
2801
+ /** The sale panel. Read-only, so it raises no events. */
2802
+ sidebar: SuperstateSidebarUiState;
2803
+ orderConfirmed: SuperstateOrderConfirmedUiState;
2804
+ }
2805
+ /** The swap could not be loaded at all. */
2806
+ | {
2807
+ type: 'error';
2808
+ reason: SuperstateSwapLoadErrorReason;
2509
2809
  };
2510
- type OffersGridUiEvent = {
2511
- type: 'ON_OFFER_CLICK';
2512
- offerId: OfferId;
2810
+ /**
2811
+ * Why the whole flow failed to load.
2812
+ *
2813
+ * The two differ in whether retrying can help, which is the only thing the View
2814
+ * does with this: a read that failed is worth another go, a chain with no
2815
+ * contract deployed on it is not, and offering a button that provably cannot
2816
+ * help is worse than offering none.
2817
+ */
2818
+ type SuperstateSwapLoadErrorReason =
2819
+ /** The swap's output token would not read. Retrying may work. */
2820
+ 'load-failed'
2821
+ /** No Superstate swap contract is deployed on this chain. Retrying cannot. */
2822
+ | 'unsupported-chain';
2823
+ /**
2824
+ * Every event any step can raise, flattened into one union.
2825
+ *
2826
+ * Flat rather than wrapped (`{ step, event }`) so that a single
2827
+ * `onEvent: (e: SuperstateSwapCheckoutUiEvent) => void` is assignable to each
2828
+ * step's narrower handler prop and can be passed straight down — no wrapping
2829
+ * lambdas in the View, no nested `switch` in the viewmodel. The cost is that
2830
+ * step event tags must stay globally unique within this union, which is why the
2831
+ * edit events are `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared
2832
+ * `ON_EDIT`.
2833
+ */
2834
+ type SuperstateSwapCheckoutUiEvent = SuperstateWalletUiEvent | SuperstateAmountUiEvent | SuperstateReviewUiEvent | SuperstateOrderConfirmedUiEvent | SuperstateSwapCheckoutRetryUiEvent;
2835
+ /**
2836
+ * Retrying the load behind the flow-level `error` arm.
2837
+ *
2838
+ * The SDK does not own the page it is mounted in, so this re-runs the fetch
2839
+ * rather than reloading the document the way the host app it was ported from
2840
+ * did.
2841
+ */
2842
+ type SuperstateSwapCheckoutRetryUiEvent = {
2843
+ type: 'ON_RETRY_LOAD';
2844
+ };
2845
+ /**
2846
+ * The dialog that closes the Superstate checkout, once the swap is mined.
2847
+ *
2848
+ * A SUM rather than a nullable model, so a dialog on screen with no order
2849
+ * behind it is unrepresentable. Every figure is already formatted: the dialog
2850
+ * reports what happened and has nothing left to compute.
2851
+ */
2852
+ type SuperstateOrderConfirmedUiState = {
2853
+ type: 'hidden';
2854
+ } | {
2855
+ type: 'visible';
2856
+ /** What was bought. */
2857
+ asset: CheckoutAssetUi;
2858
+ /** Who issues it, e.g. `Superstate`. */
2859
+ issuer: string;
2860
+ /** How much of it arrived, e.g. `981.2431 USTB`. */
2861
+ outputAmount: FormattedAmountAssetUi;
2862
+ /**
2863
+ * Whether `outputAmount` and `pricePerShare` are what the chain reported,
2864
+ * rather than what the quote predicted.
2865
+ *
2866
+ * `false` only on the fallback path: the swap mined, but its `Swapped`
2867
+ * event would not decode and the quote's estimate is standing in. The
2868
+ * dialog labels those two rows as estimates when it is, because a figure
2869
+ * captioned `Shares received` is a claim about what is in the user's
2870
+ * wallet and the fallback cannot support it.
2871
+ */
2872
+ outputAmountConfirmed: boolean;
2873
+ /** What the user paid, input plus fee, e.g. `$1,000.00`. */
2874
+ totalCost: FormattedAmountAssetUi;
2875
+ /**
2876
+ * Price of one whole token at the fill, e.g. `$10.19`. Derived from
2877
+ * `outputAmount`, so `outputAmountConfirmed` covers it too.
2878
+ */
2879
+ pricePerShare: FormattedAmountAssetUi;
2880
+ /** The wallet the asset was delivered to. */
2881
+ recipientAddress: ShortenedWalletAddress;
2882
+ /**
2883
+ * The settled swap on a block explorer. Always present: the dialog only
2884
+ * exists once there is a mined transaction to point at.
2885
+ */
2886
+ txExplorerUrl: TxExplorerUrl;
2887
+ };
2888
+ /**
2889
+ * Closing is the only thing the dialog raises.
2890
+ *
2891
+ * `View transaction onchain` is a plain link the View renders from
2892
+ * `txExplorerUrl`, not an event: the URL is already built, and an anchor keeps
2893
+ * middle-click, copy-link and the browser's own handling working.
2894
+ */
2895
+ type SuperstateOrderConfirmedUiEvent = {
2896
+ type: 'ON_CLOSE_ORDER_CONFIRMED';
2513
2897
  };
2898
+
2899
+ interface SuperstateOrderConfirmedProps {
2900
+ state: SuperstateOrderConfirmedUiState;
2901
+ onEvent: (event: SuperstateOrderConfirmedUiEvent) => void;
2902
+ className?: string;
2903
+ }
2514
2904
  /**
2515
- * An offer as an offer card renders it: dates already formatted, nothing left
2516
- * to decide at render time.
2905
+ * The dialog that closes the Superstate checkout: what arrived, what it cost,
2906
+ * and where it went.
2907
+ *
2908
+ * Pure: every figure is handed over formatted, and the explorer link is
2909
+ * rendered from the URL the viewmodel built rather than raised as an event.
2910
+ *
2911
+ * Self-scoped: renders fully styled on its own. It bails before the scope while
2912
+ * hidden, so a closed dialog leaves nothing in the DOM.
2517
2913
  */
2518
- type OfferCardUi = {
2914
+ declare function SuperstateOrderConfirmed({ state, onEvent, className, }: SuperstateOrderConfirmedProps): ReactNode;
2915
+
2916
+ interface SlippagePickerProps {
2917
+ slippage: SuperstateSlippageUi;
2918
+ /**
2919
+ * What the tolerance applies to, rendered to the left of the toggle: the
2920
+ * amount the user receives, in practice.
2921
+ *
2922
+ * A slot, and the reason this component owns a row at all. The toggle has to
2923
+ * sit beside the summary while the options have to span the full width
2924
+ * beneath both - a picker that rendered only itself would put the options in
2925
+ * whatever narrow column the toggle landed in. Taking the summary is what
2926
+ * lets one component place both, and keeps `aria-controls` pointing at a
2927
+ * panel it still owns.
2928
+ */
2929
+ summary: ReactNode;
2930
+ /** Toggles the disclosure. Open/closed is viewmodel state, not View state. */
2931
+ onToggle: () => void;
2932
+ onSelect: (bps: Bps) => void;
2933
+ className?: string;
2934
+ }
2935
+ /**
2936
+ * The slippage tolerance, and the disclosure that changes it: a pill showing
2937
+ * the tolerance in force beside {@link SlippagePickerProps.summary}, and - once
2938
+ * opened - the options and what they mean, on their own line below both.
2939
+ *
2940
+ * Superstate-only, so it lives beside the review step rather than in
2941
+ * `checkout/shared`. Ondo quotes firm prices and has no tolerance to set, and a
2942
+ * shared component shaped entirely by one provider's `SLIPPAGE_OPTIONS_BPS`
2943
+ * would be that provider's component in a shared directory.
2944
+ *
2945
+ * Pure: it renders the options it is handed and reports which was picked. It
2946
+ * does not know what a basis point is.
2947
+ *
2948
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2949
+ * needed around it.
2950
+ */
2951
+ declare function SlippagePicker({ slippage, summary, onToggle, onSelect, className, }: SlippagePickerProps): ReactNode;
2952
+
2953
+ interface SuperstateReviewViewProps {
2954
+ state: SuperstateReviewUiState;
2955
+ onEvent: (event: SuperstateReviewUiEvent) => void;
2956
+ className?: string;
2957
+ }
2958
+ /**
2959
+ * Step 3 of the Superstate checkout. Pure: every number arrives formatted, and
2960
+ * whether the order can be placed is decided by `placeOrderCta` rather than
2961
+ * re-derived here.
2962
+ *
2963
+ * The CTA covers a status check, an approval and the swap, which is why the
2964
+ * "don't close this page" notice appears only while it runs — a Superstate
2965
+ * order is several wallet prompts long, and leaving mid-flight strands the
2966
+ * approval.
2967
+ *
2968
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2969
+ * needed around it.
2970
+ */
2971
+ declare function SuperstateReviewView(props: SuperstateReviewViewProps): ReactNode;
2972
+
2973
+ interface SuperstateSwapCheckoutContainerProps {
2974
+ /** The offer being bought: names the asset, the window and the minimum. */
2975
+ offer: OfferDetail;
2976
+ /**
2977
+ * The chain the order executes on: the balance reads, the approval and the
2978
+ * swap. The swap contract is looked up from it, so a chain with none
2979
+ * deployed renders the flow's error state rather than a broken checkout.
2980
+ */
2981
+ chain: EthereumChain;
2982
+ /**
2983
+ * The wallets the buyer can spend from, and the lambdas that connect and
2984
+ * disconnect an external one. The SDK ships no wallet stack, so this is how
2985
+ * a host plugs in Privy, AppKit, or its own.
2986
+ */
2987
+ wallets: CheckoutWalletSelection;
2988
+ /**
2989
+ * Default `true`. `false` turns off every request and timer, which is what
2990
+ * `CheckoutContainer` uses to call each provider's checkout unconditionally.
2991
+ */
2992
+ enabled?: boolean;
2993
+ /** Fired once the swap has mined. The dialog shows either way. */
2994
+ onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;
2995
+ className?: string;
2996
+ }
2997
+ /**
2998
+ * The Superstate swap checkout, ready to drop in: three steps, the sale panel
2999
+ * beside them, and the dialog that closes the flow.
3000
+ *
3001
+ * Takes no contract address: it is looked up from `chain`, the way Ondo's is.
3002
+ * A partner who needs to point at a different deployment is below this rung and
3003
+ * calls `coinlist.superstate.execute` directly.
3004
+ *
3005
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
3006
+ * needed around it.
3007
+ */
3008
+ declare function SuperstateSwapCheckoutContainer({ offer, chain, wallets, enabled, onOrderConfirmed, className, }: SuperstateSwapCheckoutContainerProps): ReactNode;
3009
+
3010
+ interface SuperstateSwapCheckoutViewProps {
3011
+ state: SuperstateSwapCheckoutUiState;
3012
+ onEvent: (event: SuperstateSwapCheckoutUiEvent) => void;
3013
+ className?: string;
3014
+ }
3015
+ /**
3016
+ * The whole Superstate swap checkout: the three step cards, the sale panel
3017
+ * beside them, and the dialog that closes the flow.
3018
+ *
3019
+ * `onEvent` is handed to each step unwrapped. A handler that accepts the wider
3020
+ * union is assignable where a step's narrower one is expected, so there is no
3021
+ * per-step lambda here and no re-dispatch on the way back up.
3022
+ *
3023
+ * The panel leads on a phone and moves to the right column from `md` up, where
3024
+ * it is reference material rather than the first thing to read. No page heading
3025
+ * and no back button — the host titles and navigates its own page.
3026
+ *
3027
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
3028
+ * needed around it. The steps scope themselves too, and the scope is
3029
+ * idempotent, so nesting costs nothing.
3030
+ */
3031
+ declare function SuperstateSwapCheckoutView({ state, onEvent, className, }: SuperstateSwapCheckoutViewProps): ReactNode;
3032
+
3033
+ interface SuperstateSidebarViewProps {
3034
+ state: SuperstateSidebarUiState;
3035
+ className?: string;
3036
+ }
3037
+ /**
3038
+ * The panel beside the Superstate checkout: whether the sale is still running,
3039
+ * what is being bought, what one share costs, and the terms of the sale.
3040
+ *
3041
+ * Read-only, so it takes no `onEvent`. The sale banner sits above the card
3042
+ * rather than inside it — it is the first thing to read on a phone, where the
3043
+ * card's own contents fold away behind a disclosure.
3044
+ *
3045
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
3046
+ * needed around it.
3047
+ */
3048
+ declare function SuperstateSidebarView({ state, className, }: SuperstateSidebarViewProps): ReactNode;
3049
+
3050
+ interface SuperstateWalletViewProps {
3051
+ state: SuperstateWalletUiState;
3052
+ onEvent: (event: SuperstateWalletUiEvent) => void;
3053
+ className?: string;
3054
+ }
3055
+ /**
3056
+ * Step 1 of the Superstate checkout. Pure: the wallets arrive already shaped,
3057
+ * and every interaction leaves through `onEvent`.
3058
+ *
3059
+ * Confirming allow-lists the wallet on-chain, which is why the CTA renders a
3060
+ * loading message rather than a spinner alone — the copy is what tells the user
3061
+ * their wallet is about to ask them to sign. The completed step says
3062
+ * `Allowlisted`, the only place the flow admits that anything happened.
3063
+ *
3064
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
3065
+ * needed around it.
3066
+ */
3067
+ declare function SuperstateWalletView(props: SuperstateWalletViewProps): ReactNode;
3068
+
3069
+ /**
3070
+ * An offer as {@link OfferAssetCard} renders it. Browse chrome: circular
3071
+ * `logoUrl`, company `name`, and asset `symbol` (`asset.code`). No wordmark.
3072
+ * `fromOffer` omits `name` and `symbol` — the list payload has neither — so a
3073
+ * list-mapped card is honest about being logo-only. Prefer
3074
+ * {@link OfferAssetCardUi.fromDetail} when the host has detail.
3075
+ */
3076
+ type OfferAssetCardUi = {
2519
3077
  id: OfferId;
2520
- tagline: string;
2521
- bannerUrl: string;
3078
+ /** Absent when the list payload has no display name. */
3079
+ name?: string;
3080
+ /** Absent when the list payload has no asset. Display form of `asset.code`. */
3081
+ symbol?: string;
2522
3082
  logoUrl: string;
2523
- formattedStartsAt: string;
2524
- formattedEndsAt: string | null;
2525
3083
  };
2526
- declare const OfferCardUi: {
2527
- fromDomain: (offer: Offer, locale: string) => OfferCardUi;
3084
+ declare const OfferAssetCardUi: {
3085
+ fromOffer: (offer: Offer) => OfferAssetCardUi;
3086
+ fromDetail: (detail: OfferDetail) => OfferAssetCardUi;
2528
3087
  };
2529
3088
 
2530
- interface Props {
2531
- offer: OfferCardUi;
2532
- /** Optional click handler. When provided, the card renders as interactive. */
2533
- onClick?: () => void;
2534
- /** Optional className applied to the card root element. */
3089
+ interface OffersAssetGridProps {
3090
+ offers: OfferAssetCardUi[];
3091
+ /**
3092
+ * When set, each card is the hit target and reports its `OfferId`. Omit to
3093
+ * render a non-interactive browse grid.
3094
+ */
3095
+ onOfferClick?: (offerId: OfferId) => void;
3096
+ /** Maximum number of columns when horizontal space allows. Caps at platform 3. */
3097
+ maxColumns?: number;
3098
+ /** Optional className applied to the grid element. */
2535
3099
  className?: string;
2536
- /** Optional className applied to an outer wrapper element. */
3100
+ /** Optional className applied to the outer wrapper element. */
2537
3101
  containerClassName?: string;
2538
3102
  }
2539
3103
  /**
2540
- * Offer card. Self-scoped: renders fully styled on its own, with no
2541
- * `CoinListStyleScope` needed. Also composed by {@link OffersGrid}.
3104
+ * Responsive browse grid of {@link OfferAssetCard} leaves. Pure: no fetch, no
3105
+ * provider. Distinct from {@link OffersGridView}, which lays out live-sale
3106
+ * cards — hosts pick which grid to embed. Self-scoped. Mobile is one column;
3107
+ * then 2 from `sm`, and up to 3 from `md` when `maxColumns` allows.
2542
3108
  */
2543
- declare function OfferCard({ offer, onClick, className, containerClassName, }: Props): ReactNode;
3109
+ declare function OffersAssetGrid({ offers, onOfferClick, maxColumns, className, containerClassName, }: OffersAssetGridProps): ReactNode;
2544
3110
 
2545
3111
  interface OffersGridContainerProps {
2546
3112
  /** Maximum number of columns to render when horizontal space allows. */
@@ -2565,8 +3131,10 @@ interface OffersGridContainerProps {
2565
3131
  data?: Offer[];
2566
3132
  }
2567
3133
  /**
2568
- * Displays a responsive grid of offers, backed by
2569
- * {@link useOffersGridViewModel}.
3134
+ * Displays a responsive live-sale grid of {@link OfferSaleCard}, backed by
3135
+ * {@link useOffersGridViewModel}. List offers have no display name — the card
3136
+ * shows logo + tagline until the host maps from detail. For equities /
3137
+ * past-sales browse rows, compose {@link OffersAssetGrid} instead.
2570
3138
  *
2571
3139
  * Pass `data` (pre-fetched server-side) to use that data as-is and skip the
2572
3140
  * client-side fetch entirely. Uses the `loading` / `error` / `emptyState` slots
@@ -2578,10 +3146,52 @@ interface OffersGridContainerProps {
2578
3146
  */
2579
3147
  declare function OffersGridContainer({ data, onOfferClick, ...viewProps }?: OffersGridContainerProps): ReactNode;
2580
3148
 
3149
+ /**
3150
+ * An offer as {@link OfferSaleCard} renders it. Countdown copy is derived in
3151
+ * the leaf from `startsAt` / `endsAt` so it can tick; the mapper does not
3152
+ * invent a name, price, FDV, unlock schedule, banner overlay, or wordmark.
3153
+ * `fromOffer` omits `name` because the list payload has none — do not derive
3154
+ * one from `slug`, and do not expect a wordmark. The card pairs `logoUrl` with
3155
+ * `name` as an h2 and renders the h2 only when the field is present. Prefer
3156
+ * {@link OfferSaleCardUi.fromDetail} when the host has a name. Missing logo
3157
+ * omits the icon — name and tagline only.
3158
+ */
3159
+ type OfferSaleCardUi = {
3160
+ id: OfferId;
3161
+ /** Absent when the list payload has no display name; only `fromDetail` sets it. */
3162
+ name?: string;
3163
+ tagline: string;
3164
+ logoUrl: string;
3165
+ startsAt: Date;
3166
+ endsAt: Date | null;
3167
+ };
3168
+ declare const OfferSaleCardUi: {
3169
+ fromOffer: (offer: Offer) => OfferSaleCardUi;
3170
+ fromDetail: (detail: OfferDetail) => OfferSaleCardUi;
3171
+ };
3172
+
3173
+ type OffersGridUiState = {
3174
+ type: 'loading';
3175
+ } | {
3176
+ type: 'error';
3177
+ message: string;
3178
+ } | {
3179
+ type: 'empty';
3180
+ } | {
3181
+ type: 'content';
3182
+ offers: OfferSaleCardUi[];
3183
+ /** Whole card is clickable only when the host passed `onOfferClick`. View offer always shows. */
3184
+ interactive: boolean;
3185
+ };
3186
+ type OffersGridUiEvent = {
3187
+ type: 'ON_OFFER_CLICK';
3188
+ offerId: OfferId;
3189
+ };
3190
+
2581
3191
  interface OffersGridViewProps {
2582
3192
  state: OffersGridUiState;
2583
3193
  onEvent: (event: OffersGridUiEvent) => void;
2584
- /** Maximum number of columns to render when horizontal space allows. */
3194
+ /** Maximum number of columns to render when horizontal space allows. Caps at platform 2. */
2585
3195
  maxColumns?: number;
2586
3196
  /** Optional className applied to the grid element. */
2587
3197
  className?: string;
@@ -2595,14 +3205,52 @@ interface OffersGridViewProps {
2595
3205
  emptyState?: ReactNode;
2596
3206
  }
2597
3207
  /**
2598
- * Renders every state of the offers grid. Pure: it holds no state, fetches
2599
- * nothing, and reports clicks through `onEvent`.
3208
+ * Renders every state of the live-sale offers grid ({@link OfferSaleCard}).
3209
+ * Pure: it holds no state, fetches nothing, and reports clicks through
3210
+ * `onEvent`. Platform layout is at most 2×2 with 24px gaps on desktop (16px on
3211
+ * mobile, single column). For equities / past-sales browse rows, embed
3212
+ * {@link OffersAssetGrid} instead.
2600
3213
  *
2601
3214
  * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
2602
3215
  * needed.
2603
3216
  */
2604
3217
  declare function OffersGridView(props: OffersGridViewProps): ReactNode;
2605
3218
 
3219
+ interface OfferAssetCardProps {
3220
+ offer: OfferAssetCardUi;
3221
+ /** When set, the whole card is the hit target. */
3222
+ onClick?: () => void;
3223
+ /** Optional className applied to the card root element. */
3224
+ className?: string;
3225
+ /** Optional className applied to an outer wrapper element. */
3226
+ containerClassName?: string;
3227
+ }
3228
+ /**
3229
+ * Light browse-row catalogue card. Self-scoped. Header is API `logoUrl`
3230
+ * beside company `name` (h2) and asset `symbol` under it — not a wordmark.
3231
+ * Responsive hug: tighter pad / logo / type below `md`, desktop keeps the
3232
+ * H4 + 48px logo row. Hosts compose this beside {@link OfferSaleCard}; the
3233
+ * card does not pick a variant itself.
3234
+ */
3235
+ declare function OfferAssetCard({ offer, onClick, className, containerClassName, }: OfferAssetCardProps): ReactNode;
3236
+
3237
+ interface OfferSaleCardProps {
3238
+ offer: OfferSaleCardUi;
3239
+ /** Host click handler. View offer always renders; this wires the hit target. */
3240
+ onClick?: () => void;
3241
+ /** Optional className applied to the card root element. */
3242
+ className?: string;
3243
+ /** Optional className applied to an outer wrapper element. */
3244
+ containerClassName?: string;
3245
+ }
3246
+ /**
3247
+ * Dark live-sale catalogue card. Self-scoped. Header is API `logoUrl` beside
3248
+ * the company `name` as an h2, then the tagline — not a wordmark. The same
3249
+ * logo is painted as a faint right-shifted watermark over the gradient.
3250
+ * Responsive hug layout; View offer always renders. No token price, FDV or unlock.
3251
+ */
3252
+ declare function OfferSaleCard({ offer, onClick, className, containerClassName, }: OfferSaleCardProps): ReactNode;
3253
+
2606
3254
  type RequirementsChecklistUiState = {
2607
3255
  type: 'loading';
2608
3256
  } | {
@@ -2774,137 +3422,6 @@ interface RequirementItemProps {
2774
3422
  */
2775
3423
  declare function RequirementItem({ ui, expanded, onToggle, className, onAction, onRemoveWallet, walletsStatus, onContactSupport, }: RequirementItemProps): react_jsx_runtime.JSX.Element;
2776
3424
 
2777
- /**
2778
- * The host-provided wallet the ownership flow signs with: the signing-only
2779
- * {@link EvmSigner} plus the {@link EthereumChain} the signature is proven on.
2780
- * `chain` rides on the wallet (not the offer) because the binding is
2781
- * chain-agnostic: it only records which EVM chain signed.
2782
- */
2783
- type ConnectWallet = EvmSigner & {
2784
- readonly chain: EthereumChain;
2785
- };
2786
- /**
2787
- * Machine-readable classification of a connect-wallet failure, so consumers can
2788
- * branch on the cause (e.g. hide a retry affordance on a terminal failure)
2789
- * instead of pattern-matching a display string.
2790
- */
2791
- type ConnectWalletErrorCode = 'not_authenticated' | 'user_rejected' | 'wallet_not_whitelisted' | 'max_wallets_reached' | 'unknown';
2792
- /**
2793
- * A classified connect-wallet failure. `retryable` is false when re-signing the
2794
- * same wallet can never succeed (a terminal binding rejection, or no signed-in
2795
- * session). Display copy is the caller's concern, kept out of the core.
2796
- */
2797
- type ConnectWalletFlowError = {
2798
- code: ConnectWalletErrorCode;
2799
- retryable: boolean;
2800
- };
2801
- /** Progress phases emitted by {@link connectExternalWalletFlow}, in order. */
2802
- type ConnectWalletPhase = 'requesting-challenge' | 'signing-message' | 'submitting-signature';
2803
- type ConnectWalletFlowResult = {
2804
- type: 'success';
2805
- binding: OfferOptionAddress;
2806
- } | {
2807
- type: 'cancelled';
2808
- } | {
2809
- type: 'error';
2810
- error: ConnectWalletFlowError;
2811
- };
2812
- /**
2813
- * The client surface the flow actually depends on, kept narrow on purpose.
2814
- *
2815
- * Named as a structural slice rather than `Pick<CoinListClient, 'wallets'>` so
2816
- * this feature does not import its layer's entry point: a flow takes the
2817
- * namespaces it needs, the way `@/client/core/checkout/**` flows do.
2818
- */
2819
- type ConnectWalletClient = {
2820
- wallets: WalletsNamespace;
2821
- };
2822
- type ConnectWalletFlowParams = {
2823
- coinlist: ConnectWalletClient;
2824
- /** Host-provided connected wallet the flow signs with. */
2825
- wallet: ConnectWallet;
2826
- offerId: OfferId;
2827
- offerOptionId: OfferOptionId;
2828
- /** Challenge framing; defaults to `'siwe'`. */
2829
- challengeType?: WalletChallengeType;
2830
- /** SIWE statement shown in the signing prompt. */
2831
- statement?: string;
2832
- /**
2833
- * Polled before each irreversible step (signing, binding). Return true to
2834
- * abandon a superseded attempt; the flow then resolves `{ type: 'cancelled' }`
2835
- * without prompting the wallet or binding. React hooks pass a generation
2836
- * check here; non-React callers can omit it.
2837
- */
2838
- isCancelled?: () => boolean;
2839
- /** Reports flow progress for consumers rendering loading states. */
2840
- onProgress?: (phase: ConnectWalletPhase) => void;
2841
- };
2842
- /**
2843
- * Drives the external-wallet ownership flow for one offer option:
2844
- * `createWalletOwnershipChallenge` -> host `wallet.signMessage` ->
2845
- * `connectExternalWallet`. Pure and signer-agnostic: signing is delegated to
2846
- * the host-provided {@link ConnectWallet}, and no React is involved so non-hook
2847
- * consumers can drive it directly (mirrors `authorizeWallet` in `swap-flows`).
2848
- * EVM / EOA + SIWE only for now.
2849
- */
2850
- declare function connectExternalWalletFlow(params: ConnectWalletFlowParams): Promise<ConnectWalletFlowResult>;
2851
-
2852
- /**
2853
- * A display-ready connect-wallet error: the core flow's machine-readable code
2854
- * and `retryable` flag, plus copy for the UI.
2855
- */
2856
- type ConnectWalletError = {
2857
- code: ConnectWalletErrorCode;
2858
- message: string;
2859
- retryable: boolean;
2860
- };
2861
- /**
2862
- * Signing-in-flight and the last sign error live inside the READY state (not a
2863
- * separate top-level state) so a failed attempt returns to READY and can be
2864
- * retried without re-opening the modal. Mirrors {@link SignState} in
2865
- * `useTaxDocument`.
2866
- */
2867
- type ConnectWalletSignState = {
2868
- type: 'idle';
2869
- error: ConnectWalletError | null;
2870
- } | {
2871
- type: 'signing';
2872
- };
2873
- type ConnectWalletState = {
2874
- type: 'NEEDS_WALLET';
2875
- } | {
2876
- type: 'READY';
2877
- address: EvmWalletAddress;
2878
- sign: ConnectWalletSignState;
2879
- } | {
2880
- type: 'CONNECTED';
2881
- binding: OfferOptionAddress;
2882
- };
2883
- interface UseConnectWalletOptions {
2884
- /** The hook resets state each time it opens. */
2885
- isOpen: boolean;
2886
- offerId: OfferId;
2887
- offerOptionId: OfferOptionId;
2888
- /** Host-provided connected wallet, or `null` while none is connected. */
2889
- wallet: ConnectWallet | null;
2890
- /** Challenge framing; defaults to `'siwe'`. */
2891
- challengeType?: WalletChallengeType;
2892
- /** SIWE statement shown in the signing prompt. */
2893
- statement?: string;
2894
- }
2895
- interface UseConnectWalletResult {
2896
- state: ConnectWalletState;
2897
- /** READY.sign: idle -> signing -> (CONNECTED | idle w/ error). No-op otherwise. */
2898
- onSign: () => void;
2899
- }
2900
- /**
2901
- * React wrapper over {@link connectExternalWalletFlow}. Owns the modal state
2902
- * machine, the display copy, and generation-token supersession (so a wallet
2903
- * switch, modal close, or unmount cancels an in-flight attempt). The flow logic
2904
- * itself lives in the framework-free core so non-React consumers can drive it.
2905
- */
2906
- declare function useConnectWallet({ isOpen, offerId, offerOptionId, wallet, challengeType, statement, }: UseConnectWalletOptions): UseConnectWalletResult;
2907
-
2908
3425
  type LoadRequirementsReason = 'not-authenticated' | 'generic-error';
2909
3426
  type LoadRequirementsState = {
2910
3427
  type: 'LOADING';
@@ -3008,8 +3525,7 @@ interface RequirementsChecklistContainerProps {
3008
3525
  */
3009
3526
  data?: RequirementsData;
3010
3527
  /**
3011
- * Options for the inline Sumsub verification flow shown for KYC-backed
3012
- * requirements (`identity_verified`, `kyc_approved`, `accreditation`) when
3528
+ * Options for the inline Sumsub verification flow, shown when
3013
3529
  * `onRequirementActionOverride` is not provided. The flow starts whenever
3014
3530
  * the requirement's status carries a `kycLevel` - the backend prescribes
3015
3531
  * both the level and whether the applicant must be reset first.
@@ -3118,8 +3634,8 @@ interface IdentityVerificationContainerProps {
3118
3634
  * Inline Sumsub identity verification flow, backed by
3119
3635
  * {@link useIdentityVerificationViewModel}, which fetches the Sumsub WebSDK
3120
3636
  * access token via {@link useKycToken}. Used by
3121
- * `RequirementsChecklistContainer` for `identity_verified` requirements, and
3122
- * can also be rendered standalone.
3637
+ * `RequirementsChecklistContainer` for KYC-backed requirements, and can also
3638
+ * be rendered standalone.
3123
3639
  */
3124
3640
  declare function IdentityVerificationContainer({ levelName, reset, locale, onSubmitted, onError, className, }: IdentityVerificationContainerProps): ReactNode;
3125
3641
 
@@ -3333,26 +3849,164 @@ type ConnectWalletScreenUi = {
3333
3849
  * never succeed by re-signing the same wallet, so the sign button is
3334
3850
  * disabled and only switching wallets helps.
3335
3851
  */
3336
- signDisabled: boolean;
3852
+ signDisabled: boolean;
3853
+ };
3854
+
3855
+ interface ConnectWalletModalViewProps {
3856
+ state: ConnectWalletModalUiState;
3857
+ onEvent: (event: ConnectWalletModalUiEvent) => void;
3858
+ className?: string;
3859
+ }
3860
+ /**
3861
+ * Modal for the external-wallet ownership flow: prompt for a wallet, then ask
3862
+ * the user to sign a message proving they own it. Pure: signing is requested
3863
+ * through `onEvent` and performed by the host's wallet, since the SDK never
3864
+ * bundles a wallet stack.
3865
+ *
3866
+ * No portal is used - rendering stays inside the normal DOM tree. Self-scoped:
3867
+ * renders fully styled on its own, with no `CoinListStyleScope` needed, so it
3868
+ * is styled wherever the host places it and wherever the checklist renders it
3869
+ * (as a sibling of `RequirementsChecklistView`, outside that View's scope).
3870
+ */
3871
+ declare function ConnectWalletModalView({ state, onEvent, className, }: ConnectWalletModalViewProps): ReactNode;
3872
+
3873
+ /**
3874
+ * Classifies an error thrown by an {@link EvmWallet} into a typed
3875
+ * {@link WalletError}. Pass the transaction `hash` when awaiting a receipt so a
3876
+ * timeout can be reported against it.
3877
+ *
3878
+ * **Every check walks the cause chain rather than testing the thrown object.**
3879
+ * viem never throws the error that says what happened: `sendTransaction` wraps
3880
+ * it in a `TransactionExecutionError` and `writeContract` wraps that again in a
3881
+ * `ContractFunctionExecutionError`, so a MetaMask 4001 arrives as a
3882
+ * `UserRejectedRequestError` two levels down. Testing the top level - which is
3883
+ * what this did until it was caught in a partner demo - classified every real
3884
+ * refusal and every real revert as `unknown`, and that is public API: a host
3885
+ * branching on `user_rejected` to stay quiet when a user simply cancels never
3886
+ * saw one.
3887
+ */
3888
+ declare function classifyWalletError(error: unknown, ctx?: {
3889
+ hash?: Hash;
3890
+ }): WalletError;
3891
+
3892
+ /**
3893
+ * A {@link Logger} that writes structured records to the browser console
3894
+ * through pino.
3895
+ *
3896
+ * ```ts
3897
+ * createCoinListClient({
3898
+ * ...config,
3899
+ * logger: pinoClientLogger({ isDev: false, level: 'info' }),
3900
+ * });
3901
+ * ```
3902
+ *
3903
+ * The browser counterpart of {@link pinoServerLogger}. Two factories rather
3904
+ * than one that sniffs `typeof window`, because the environment is the
3905
+ * outermost axis of this codebase: the client build resolves pino's browser
3906
+ * entry and the server build resolves its node entry, neither pays for the
3907
+ * other, and neither has a branch in it.
3908
+ *
3909
+ * `browser: { asObject: true }` is the one non-default: pino's browser default
3910
+ * hands its arguments to `console.info` unchanged, which is not a structured
3911
+ * record. With it, each line is a single object carrying `level`, `time`,
3912
+ * `name`, `scope`, the bindings and every field - the same shape the server
3913
+ * writes as ndjson, so a record read in devtools and a record read in a log
3914
+ * aggregator are the same record.
3915
+ *
3916
+ * ## Production
3917
+ *
3918
+ * **Running this in a production browser is not advised**, and the browser is
3919
+ * where that advice is easiest to justify. **A browser console is readable by
3920
+ * anyone with the page open**, and extensions can scrape it, so even the
3921
+ * redacted levels put SDK-authored classification and server-minted ids
3922
+ * somewhere you do not control. Nothing is transmitted anywhere either: pino's
3923
+ * browser build writes to the console and stops, so what you get for the risk
3924
+ * is a record only the end user can read.
3925
+ *
3926
+ * If you run one anyway, `isDev: false` restricts you to `'error'`, `'warn'`
3927
+ * and `'info'` - `{ isDev: false, level: 'debug' }` does not compile, see
3928
+ * {@link PinoLoggerOptions}. Those levels are redacted by construction; what
3929
+ * follows from that in your environment is your call to make, not a warranty
3930
+ * the SDK offers.
3931
+ *
3932
+ * If you want these records off the page, implement {@link Logger} yourself
3933
+ * over your own transport, or pass a pino instance configured with
3934
+ * `browser.transmit` - the seam is deliberately small enough to make that easy.
3935
+ *
3936
+ * Holds no module-level state: every call builds its own pino instance, and
3937
+ * the level is fixed at construction, so two loggers never interfere. Fixed is
3938
+ * this implementation's choice, not the seam's - the SDK re-reads
3939
+ * {@link Logger.level} before every log call - so if you want a level you can
3940
+ * change at runtime, implement {@link Logger} over your own pino instance
3941
+ * rather than calling this.
3942
+ */
3943
+ declare function pinoClientLogger(options: PinoLoggerOptions): Logger;
3944
+
3945
+ /**
3946
+ * Machine-readable classification of a connect-wallet failure, so consumers can
3947
+ * branch on the cause (e.g. hide a retry affordance on a terminal failure)
3948
+ * instead of pattern-matching a display string.
3949
+ */
3950
+ type ConnectWalletErrorCode = 'not_authenticated' | 'user_rejected' | 'wallet_not_whitelisted' | 'max_wallets_reached' | 'unknown';
3951
+ /**
3952
+ * A classified connect-wallet failure. `retryable` is false when re-signing the
3953
+ * same wallet can never succeed (a terminal binding rejection, or no signed-in
3954
+ * session). Display copy is the caller's concern, kept out of the core.
3955
+ */
3956
+ type ConnectWalletFlowError = {
3957
+ code: ConnectWalletErrorCode;
3958
+ retryable: boolean;
3959
+ };
3960
+ /** Progress phases emitted by {@link connectExternalWalletFlow}, in order. */
3961
+ type ConnectWalletPhase = 'requesting-challenge' | 'signing-message' | 'submitting-signature';
3962
+ type ConnectWalletFlowResult = {
3963
+ type: 'success';
3964
+ binding: OfferOptionAddress;
3965
+ } | {
3966
+ type: 'cancelled';
3967
+ } | {
3968
+ type: 'error';
3969
+ error: ConnectWalletFlowError;
3970
+ };
3971
+ /**
3972
+ * The client surface the flow actually depends on, kept narrow on purpose.
3973
+ *
3974
+ * Named as a structural slice rather than `Pick<CoinListClient, 'wallets'>` so
3975
+ * this feature does not import its layer's entry point: a flow takes the
3976
+ * namespaces it needs, the way `@/client/core/checkout/**` flows do.
3977
+ */
3978
+ type ConnectWalletClient = {
3979
+ wallets: WalletsNamespace;
3980
+ };
3981
+ type ConnectWalletFlowParams = {
3982
+ coinlist: ConnectWalletClient;
3983
+ /** Host-provided connected wallet the flow signs with. */
3984
+ wallet: ConnectWallet;
3985
+ offerId: OfferId;
3986
+ offerOptionId: OfferOptionId;
3987
+ /** Challenge framing; defaults to `'siwe'`. */
3988
+ challengeType?: WalletChallengeType;
3989
+ /** SIWE statement shown in the signing prompt. */
3990
+ statement?: string;
3991
+ /**
3992
+ * Polled before each irreversible step (signing, binding). Return true to
3993
+ * abandon a superseded attempt; the flow then resolves `{ type: 'cancelled' }`
3994
+ * without prompting the wallet or binding. React hooks pass a generation
3995
+ * check here; non-React callers can omit it.
3996
+ */
3997
+ isCancelled?: () => boolean;
3998
+ /** Reports flow progress for consumers rendering loading states. */
3999
+ onProgress?: (phase: ConnectWalletPhase) => void;
3337
4000
  };
3338
-
3339
- interface ConnectWalletModalViewProps {
3340
- state: ConnectWalletModalUiState;
3341
- onEvent: (event: ConnectWalletModalUiEvent) => void;
3342
- className?: string;
3343
- }
3344
4001
  /**
3345
- * Modal for the external-wallet ownership flow: prompt for a wallet, then ask
3346
- * the user to sign a message proving they own it. Pure: signing is requested
3347
- * through `onEvent` and performed by the host's wallet, since the SDK never
3348
- * bundles a wallet stack.
3349
- *
3350
- * No portal is used - rendering stays inside the normal DOM tree. Self-scoped:
3351
- * renders fully styled on its own, with no `CoinListStyleScope` needed, so it
3352
- * is styled wherever the host places it and wherever the checklist renders it
3353
- * (as a sibling of `RequirementsChecklistView`, outside that View's scope).
4002
+ * Drives the external-wallet ownership flow for one offer option:
4003
+ * `createWalletOwnershipChallenge` -> host `wallet.signMessage` ->
4004
+ * `connectExternalWallet`. Pure and signer-agnostic: signing is delegated to
4005
+ * the host-provided {@link ConnectWallet}, and no React is involved so non-hook
4006
+ * consumers can drive it directly (mirrors `authorizeWallet` in `swap-flows`).
4007
+ * EVM / EOA + SIWE only for now.
3354
4008
  */
3355
- declare function ConnectWalletModalView({ state, onEvent, className, }: ConnectWalletModalViewProps): ReactNode;
4009
+ declare function connectExternalWalletFlow(params: ConnectWalletFlowParams): Promise<ConnectWalletFlowResult>;
3356
4010
 
3357
4011
  interface UseCoinListSignInCardViewModelOptions {
3358
4012
  /** `error` renders the sign-in failure banner. Defaults to `idle`. */
@@ -3415,104 +4069,486 @@ interface UseCompleteOAuthOptions {
3415
4069
  *
3416
4070
  * Must be used within {@link CoinListProvider}.
3417
4071
  */
3418
- declare function useCompleteOAuth(options: UseCompleteOAuthOptions): void;
4072
+ declare function useCompleteOAuth(options: UseCompleteOAuthOptions): void;
4073
+
4074
+ type LoadParticipationsReason = 'not-authenticated' | 'generic-error';
4075
+ type LoadParticipationsState = {
4076
+ type: 'LOADING';
4077
+ } | {
4078
+ type: 'ERROR';
4079
+ reason: LoadParticipationsReason;
4080
+ } | {
4081
+ type: 'CONTENT';
4082
+ participations: Participation[];
4083
+ };
4084
+ interface UseParticipationsOptions {
4085
+ /**
4086
+ * Participations pre-fetched on the server (e.g. via `CoinListServer#tokenSale.list()`).
4087
+ * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
4088
+ */
4089
+ data?: Participation[];
4090
+ }
4091
+ interface UseParticipationsResult {
4092
+ participationsState: LoadParticipationsState;
4093
+ }
4094
+ /**
4095
+ * Loads all CoinList participations for the current user and exposes a UI-friendly state.
4096
+ * Optionally filters by offer when `offerId` is provided.
4097
+ *
4098
+ * Pass `data` (pre-fetched server-side) to use that data as-is and skip
4099
+ * the client-side fetch entirely.
4100
+ *
4101
+ * Returns `LOADING` while CoinList is initializing or while participations are being fetched.
4102
+ * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.
4103
+ * Returns `ERROR` with:
4104
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
4105
+ * - `generic-error` for any other failure
4106
+ */
4107
+ declare function useParticipations(offerId?: OfferId, options?: UseParticipationsOptions): UseParticipationsResult;
4108
+
4109
+ /**
4110
+ * How much the user is spending, and the transaction built for it.
4111
+ *
4112
+ * It names no asset. The transaction publishes the scale of every amount on
4113
+ * it, and the offer names what is being bought, so there is nothing about the
4114
+ * purchase left for this step to carry downstream.
4115
+ */
4116
+ type OndoBuyAmountConfirmed = {
4117
+ amount: BlockchainAmount;
4118
+ inputAsset: StablecoinSymbol;
4119
+ transaction: OndoBuyTransaction;
4120
+ };
4121
+ type OndoBuyAmountStepInput = {
4122
+ type: 'incomplete';
4123
+ } | {
4124
+ type: 'active';
4125
+ /** The wallet confirmed in step 1: it holds the funds and signs. */
4126
+ wallet: EvmWallet;
4127
+ /**
4128
+ * The market as last read, or `null` while it is unknown. Unknown does
4129
+ * not block: a dropped poll is not evidence the market is closed, and
4130
+ * building will fail with a real reason if it is.
4131
+ */
4132
+ tradingStatus: OndoTradingStatus | null;
4133
+ /** The offer's minimum, in whole USD. `null` when it publishes none. */
4134
+ minimumPurchaseUsd: number | null;
4135
+ } | {
4136
+ type: 'complete';
4137
+ wallet: EvmWallet;
4138
+ amount: BlockchainAmount;
4139
+ inputAsset: StablecoinSymbol;
4140
+ };
4141
+ interface UseOndoBuyAmountViewModelOptions {
4142
+ stepInput: OndoBuyAmountStepInput;
4143
+ /** Ondo's API symbol, e.g. `AAPLon`. */
4144
+ ondoSymbol: AssetSymbol;
4145
+ /** The chain the order executes on: balances, approval, and the contract. */
4146
+ chain: EthereumChain;
4147
+ /**
4148
+ * When false, the step neither fetches nor polls. Defaults to true.
4149
+ *
4150
+ * The step being `incomplete` is not the same thing and does not stand in
4151
+ * for it: a checkout switched off mid-flow leaves this step `active`, and
4152
+ * the balance poll would run on behind a screen nobody is looking at.
4153
+ */
4154
+ enabled?: boolean;
4155
+ /** Called once the approval has mined and the transaction has been built. */
4156
+ onComplete: (confirmed: OndoBuyAmountConfirmed) => void;
4157
+ /** Called when the user reopens this step from a later one. */
4158
+ onEdit: () => void;
4159
+ }
4160
+ interface UseOndoBuyAmountViewModelResult {
4161
+ state: OndoBuyAmountUiState;
4162
+ onEvent: (event: OndoBuyAmountUiEvent) => void;
4163
+ }
4164
+ /**
4165
+ * Drives step 2 of the Ondo checkout: how much to spend, and getting the order
4166
+ * ready to place.
4167
+ *
4168
+ * Confirming does real work - it approves the swap contract to pull the
4169
+ * amount, then builds the transaction that spends it - so the CTA reports the on-chain phase
4170
+ * as loading copy and every failure comes back as copy under the field.
4171
+ *
4172
+ * Everything checkable locally is checked before the wallet is asked to sign:
4173
+ * the balance, the offer's minimum, and Ondo's own order caps. Each of those
4174
+ * would otherwise cost the user a real approval transaction before failing.
4175
+ */
4176
+ declare function useOndoBuyAmountViewModel({ stepInput, ondoSymbol, chain, enabled, onComplete, onEdit, }: UseOndoBuyAmountViewModelOptions): UseOndoBuyAmountViewModelResult;
4177
+ type OndoBuyAmountValidation = {
4178
+ valid: true;
4179
+ amount: BlockchainAmount;
4180
+ } | {
4181
+ valid: false;
4182
+ error: string;
4183
+ };
4184
+ /**
4185
+ * The checks that can be made without asking the wallet for anything, in the
4186
+ * order a user would hit them: is it a number, is it more than nothing, can
4187
+ * they afford it, does the offer accept it, will Ondo fill it.
4188
+ *
4189
+ * Exported for the property tests: the ladder is money logic, and the property
4190
+ * that matters (nothing above the balance or the caps is ever accepted) is
4191
+ * about the whole ladder rather than any one rung.
4192
+ */
4193
+ declare function validateAmount({ input, decimals, balance, symbol, minimumPurchaseUsd, tradingStatus, locale, }: {
4194
+ input: string;
4195
+ decimals: AssetDecimals;
4196
+ /** `null` while no balance has been read; the check is then skipped. */
4197
+ balance: bigint | null;
4198
+ symbol: AssetSymbol;
4199
+ minimumPurchaseUsd: number | null;
4200
+ tradingStatus: OndoTradingStatus | null;
4201
+ locale: string;
4202
+ }): OndoBuyAmountValidation;
4203
+
4204
+ /**
4205
+ * Why an Ondo read failed, in the only two flavours a UI acts on differently.
4206
+ *
4207
+ * `not-authenticated` is split out because no retry helps until the user signs
4208
+ * in, and because the remedy is one the UI can name. Everything else collapses
4209
+ * into `generic-error` and is offered a retry.
4210
+ *
4211
+ * That is a deliberate over-offer, not a claim that every such failure is
4212
+ * retryable. A `ValidationError` from the DTO boundary - an unreadable expiry,
4213
+ * a zero output amount, a scale no amount could be denominated in - is
4214
+ * deterministic, and refreshing spends an attestation to fail again. It stays
4215
+ * lumped in because each one means frontline changed its encoding, which is
4216
+ * unreachable in a deployed pair and not worth a public union member and a
4217
+ * branch in every consumer to distinguish. Split it out if that stops being
4218
+ * true.
4219
+ */
4220
+ type OndoLoadErrorReason = 'not-authenticated' | 'generic-error';
4221
+ declare function ondoLoadErrorReason(error: unknown): OndoLoadErrorReason;
4222
+
4223
+ /**
4224
+ * The state of the built purchase a review step acts on.
4225
+ *
4226
+ * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in
4227
+ * flight never blanks the numbers the user is reading. A refresh that fails
4228
+ * keeps them too, and reports why alongside - the previous purchase may still
4229
+ * be good, and a failed refresh is fixed by refreshing again.
4230
+ */
4231
+ type LoadOndoBuyTransactionState = {
4232
+ type: 'LOADING';
4233
+ } | {
4234
+ type: 'ERROR';
4235
+ reason: OndoLoadErrorReason;
4236
+ } | {
4237
+ type: 'CONTENT';
4238
+ transaction: OndoBuyTransaction;
4239
+ isRefreshing: boolean;
4240
+ /** Why the last refresh failed; `null` when the purchase is fresh. */
4241
+ refreshError: OndoLoadErrorReason | null;
4242
+ };
4243
+ interface UseOndoBuyTransactionOptions {
4244
+ /**
4245
+ * The order to build, or `null` while there is not one yet - before the
4246
+ * amount step is confirmed. A `null` request fetches nothing.
4247
+ */
4248
+ request: BuildOndoBuyParams | null;
4249
+ /**
4250
+ * A purchase the caller already holds, typically the one `prepareBuy`
4251
+ * returned with the approval. When present the hook adopts it and skips the
4252
+ * initial fetch; `refetch` still fetches. This is what keeps the flow to one
4253
+ * attestation per order.
4254
+ */
4255
+ data?: OndoBuyTransaction;
4256
+ /** When false, the hook does not fetch. */
4257
+ enabled: boolean;
4258
+ }
4259
+ interface UseOndoBuyTransactionResult {
4260
+ state: LoadOndoBuyTransactionState;
4261
+ /** Builds a fresh purchase for the same order. Spends an attestation. */
4262
+ refetch: () => void;
4263
+ }
4264
+ /**
4265
+ * Holds the firm, expiring purchase the buy review step places an order
4266
+ * against, and rebuilds it on demand.
4267
+ *
4268
+ * **Never polls.** Building spends an attestation, so a new one is only ever
4269
+ * obtained when the caller asks - on `refetch`, or on the first render if no
4270
+ * `data` was supplied. That is also why an expired purchase is left expired
4271
+ * here: whether to replace it is the user's call, not a timer's.
4272
+ *
4273
+ * Disabled it fetches nothing and stays on whatever state it opened with. That
4274
+ * is `LOADING` and not an empty `CONTENT` because there is no empty
4275
+ * purchase: firm calldata for an order that does not exist is not
4276
+ * representable. A caller that switches this hook off should switch its own
4277
+ * rendering off with it - which is what the review step does, since a step
4278
+ * that is not active is `incomplete` and never reads this state at all.
4279
+ *
4280
+ * One of a pair with `useOndoSellTransaction`, and deliberately not one hook
4281
+ * over both. The two endpoints answer different shapes - a purchase commits to
4282
+ * an exact quantity, a sale to a range - so a shared hook would hand every
4283
+ * review step a union to narrow after its own directory had already settled
4284
+ * which trade it was. The machinery below is the price of that, and it is the
4285
+ * cheaper half: what a screen reads off `CONTENT` is the expensive half.
4286
+ */
4287
+ declare function useOndoBuyTransaction(options: UseOndoBuyTransactionOptions): UseOndoBuyTransactionResult;
4288
+
4289
+ type OndoBuyReviewStepInput = {
4290
+ type: 'incomplete';
4291
+ } | {
4292
+ type: 'active';
4293
+ /** The wallet that signs, pays, and receives. */
4294
+ wallet: EvmWallet;
4295
+ /** What the user is spending, in the input asset's base units. */
4296
+ amount: BlockchainAmount;
4297
+ inputAsset: StablecoinSymbol;
4298
+ /**
4299
+ * The purchase `prepareBuy` already built for this order. Omitting
4300
+ * it makes this step build one itself, which is the path a partner
4301
+ * driving the review on its own takes - and the only way its `loading`
4302
+ * and `error` states are reached.
4303
+ */
4304
+ transaction?: OndoBuyTransaction;
4305
+ };
4306
+ interface UseOndoBuyReviewViewModelOptions {
4307
+ stepInput: OndoBuyReviewStepInput;
4308
+ /**
4309
+ * Ondo's API symbol, e.g. `AAPLon`. Rebuilds the transaction, and names the
4310
+ * bought asset on the card.
4311
+ */
4312
+ ondoSymbol: AssetSymbol;
4313
+ /** The chain the order executes on. */
4314
+ chain: EthereumChain;
4315
+ /**
4316
+ * The offer being bought: the asset's name and its only icon.
4317
+ *
4318
+ * The identity comes from here rather than from the price poll, so the card
4319
+ * agrees with the reference panel beside it and a dropped poll cannot leave
4320
+ * the review unable to say what was bought.
4321
+ */
4322
+ offer: OfferDetail;
4323
+ /**
4324
+ * When false, the step neither builds a transaction nor counts down, and
4325
+ * neither refreshing the quote nor placing an order does anything. Defaults
4326
+ * to true.
4327
+ *
4328
+ * The step being `incomplete` is not the same thing and does not stand in
4329
+ * for it: a checkout switched off mid-flow leaves this step `active`, so the
4330
+ * committed quote is still here to render and its clock would tick on behind
4331
+ * a screen nobody is looking at.
4332
+ */
4333
+ enabled?: boolean;
4334
+ /** Called once the swap has mined. */
4335
+ /** Always a buy: this step only ever places one. */
4336
+ onComplete: (order: OndoBuyOrderPlaced) => void;
4337
+ }
4338
+ interface UseOndoBuyReviewViewModelResult {
4339
+ state: OndoBuyReviewUiState;
4340
+ onEvent: (event: OndoBuyReviewUiEvent) => void;
4341
+ }
4342
+ /**
4343
+ * Drives step 3 of the Ondo checkout: what the order comes to, how long the
4344
+ * price holds, and placing it.
4345
+ *
4346
+ * The quote is firm and short-lived, so most of this is about time. The
4347
+ * countdown drives the line above the CTA, and a quote inside
4348
+ * {@link ONDO_QUOTE_EXPIRY_THRESHOLD_MS} of its deadline is treated as already
4349
+ * gone: placing an order is not instant, and a transaction that arrives after
4350
+ * the deadline reverts at the user's expense.
4351
+ *
4352
+ * Refreshing is always something the user asks for. Each refresh builds a new
4353
+ * transaction, which spends an attestation, so nothing here is on a timer.
4354
+ */
4355
+ declare function useOndoBuyReviewViewModel({ stepInput, ondoSymbol, chain, offer, enabled, onComplete, }: UseOndoBuyReviewViewModelOptions): UseOndoBuyReviewViewModelResult;
3419
4356
 
3420
- type LoadParticipationsReason = 'not-authenticated' | 'generic-error';
3421
- type LoadParticipationsState = {
3422
- type: 'LOADING';
4357
+ /**
4358
+ * Which step is being filled in, carrying everything the ones before it
4359
+ * settled.
4360
+ *
4361
+ * A union rather than a step index plus nullable fields: the amount step
4362
+ * cannot run without a wallet, and the review step cannot run without a built
4363
+ * transaction, so neither is representable here.
4364
+ */
4365
+ type OndoBuyStep = {
4366
+ type: 'wallet';
3423
4367
  } | {
3424
- type: 'ERROR';
3425
- reason: LoadParticipationsReason;
4368
+ type: 'amount';
4369
+ wallet: EvmWallet;
3426
4370
  } | {
3427
- type: 'CONTENT';
3428
- participations: Participation[];
4371
+ type: 'review';
4372
+ wallet: EvmWallet;
4373
+ amount: BlockchainAmount;
4374
+ inputAsset: StablecoinSymbol;
4375
+ /** Built by `prepareBuy` when the amount was confirmed. */
4376
+ transaction: OndoBuyTransaction;
3429
4377
  };
3430
- interface UseParticipationsOptions {
4378
+ interface UseOndoBuyCheckoutViewModelOptions {
3431
4379
  /**
3432
- * Participations pre-fetched on the server (e.g. via `CoinListServer#tokenSale.list()`).
3433
- * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
4380
+ * The offer being bought: names the asset and supplies its logo.
4381
+ *
4382
+ * Fixed for the lifetime of the hook — see the note on
4383
+ * {@link useOndoBuyCheckoutViewModel} about switching offers.
3434
4384
  */
3435
- data?: Participation[];
4385
+ offer: OfferDetail;
4386
+ /**
4387
+ * Ondo's API symbol for the asset, e.g. `AAPLon`.
4388
+ *
4389
+ * Explicit rather than derived from `offer.asset.code`: Ondo's symbol tracks
4390
+ * the underlying ticker and changes on a rebrand, and the two already
4391
+ * disagree on Sepolia, where a mock asset stands in.
4392
+ */
4393
+ ondoSymbol: AssetSymbol;
4394
+ /**
4395
+ * The chain the order executes on: the balance read, the approval and the
4396
+ * broadcast. Quotes are priced against Ondo production whatever this says,
4397
+ * since Ondo runs no sandbox, so on a testnet the price is real and the
4398
+ * money is not.
4399
+ *
4400
+ * Fixed for the lifetime of the hook, as `offer` is.
4401
+ */
4402
+ chain: EthereumChain;
4403
+ /** The host's wallets, and the lambdas that connect and disconnect one. */
4404
+ wallets: CheckoutWalletSelection;
4405
+ /**
4406
+ * Default `true`. When `false` nothing is fetched and no timer runs, so the
4407
+ * hook can be called unconditionally beside other providers' viewmodels.
4408
+ */
4409
+ enabled?: boolean;
4410
+ /**
4411
+ * Fired once the swap has mined. The confirmation dialog shows either way;
4412
+ * this is for a host that wants to navigate, refresh a portfolio, or log.
4413
+ */
4414
+ onOrderConfirmed?: (order: OndoOrderPlaced) => void;
3436
4415
  }
3437
- interface UseParticipationsResult {
3438
- participationsState: LoadParticipationsState;
4416
+ interface UseOndoBuyCheckoutViewModelResult {
4417
+ state: OndoBuyCheckoutUiState;
4418
+ onEvent: (event: OndoBuyCheckoutUiEvent) => void;
3439
4419
  }
3440
4420
  /**
3441
- * Loads all CoinList participations for the current user and exposes a UI-friendly state.
3442
- * Optionally filters by offer when `offerId` is provided.
4421
+ * Drives the whole Ondo buy checkout: the three steps, the reference panel
4422
+ * beside them, and the dialog that closes the flow.
3443
4423
  *
3444
- * Pass `data` (pre-fetched server-side) to use that data as-is and skip
3445
- * the client-side fetch entirely.
4424
+ * It owns the step machine and the two polls; each step's own viewmodel owns
4425
+ * its screen. The polls live here because they are shared - the sidebar shows
4426
+ * the price and the amount step gates on the market - and because the price is
4427
+ * sized by whatever the flow has settled on so far.
3446
4428
  *
3447
- * Returns `LOADING` while CoinList is initializing or while participations are being fetched.
3448
- * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.
3449
- * Returns `ERROR` with:
3450
- * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
3451
- * - `generic-error` for any other failure
4429
+ * There is no flow-level error state. Every failure belongs to a region: a
4430
+ * price that will not load leaves the panel's corner unavailable, and an order
4431
+ * that will not go through is reported on the review step, next to the button
4432
+ * that caused it.
4433
+ *
4434
+ * `offer` and `chain` are read as fixed for the lifetime of the hook. The step
4435
+ * machine holds a committed quote and an approval granted on one chain for one
4436
+ * order, so changing either in place would carry them onto an order they were
4437
+ * never priced for. Remount instead: give the component holding this hook a
4438
+ * `key` that changes with the offer and the chain, as {@link CheckoutContainer}
4439
+ * documents. That discards the flow with its component instance, which is the
4440
+ * only reset that cannot land between an approval and the broadcast it was
4441
+ * granted for.
3452
4442
  */
3453
- declare function useParticipations(offerId?: OfferId, options?: UseParticipationsOptions): UseParticipationsResult;
4443
+ declare function useOndoBuyCheckoutViewModel({ offer, ondoSymbol, chain, wallets, enabled, onOrderConfirmed, }: UseOndoBuyCheckoutViewModelOptions): UseOndoBuyCheckoutViewModelResult;
3454
4444
 
3455
4445
  /**
3456
- * How much the user is spending, and the transaction built for it.
4446
+ * How much of the asset the user is selling, and the transaction built for it.
3457
4447
  *
3458
- * It names no asset. The transaction publishes the scale of every amount on
3459
- * it, and the offer names what is being bought, so there is nothing about the
3460
- * purchase left for this step to carry downstream.
4448
+ * It carries `inputAsset` where the buy step's counterpart carries a
4449
+ * stablecoin: the asset being sold is in no registry, so the symbol has to
4450
+ * travel with the amount for anything downstream to name it.
3461
4451
  */
3462
- type OndoAmountConfirmed = {
4452
+ type OndoSellAmountConfirmed = {
3463
4453
  amount: BlockchainAmount;
3464
- inputAsset: StablecoinSymbol;
3465
- transaction: OndoSwapTransaction;
4454
+ inputAsset: AssetSymbol;
4455
+ transaction: OndoSellTransaction;
4456
+ };
4457
+ /**
4458
+ * The asset a sell spends, as the quote resolves it.
4459
+ *
4460
+ * Both halves come off `GET /v1/ondo/swap/quote`, which is the SDK's only
4461
+ * source for either: `TOKEN_REGISTRY` knows the stablecoins swaps are funded
4462
+ * with and no provider's asset. The address is what the balance is read on and
4463
+ * what the swap contract is approved for; the decimals are what the typed
4464
+ * amount is parsed at.
4465
+ */
4466
+ type OndoSellAsset = {
4467
+ address: EvmContractAddress;
4468
+ asset: Erc20Asset;
3466
4469
  };
3467
- type OndoAmountStepInput = {
4470
+ type OndoSellAmountStepInput = {
3468
4471
  type: 'incomplete';
3469
4472
  } | {
3470
4473
  type: 'active';
3471
- /** The wallet confirmed in step 1: it holds the funds and signs. */
4474
+ /** The wallet holding the asset, and the one that signs. */
3472
4475
  wallet: EvmWallet;
4476
+ /**
4477
+ * Whether that wallet is one of the user's CoinList wallets, which
4478
+ * decides how the balance card names it: an embedded wallet reads
4479
+ * `from CoinList Wallet`, an external one `from 0x…`.
4480
+ *
4481
+ * Decided by the parent, which holds `wallets.embedded`. A preselected
4482
+ * wallet need not appear in that list at all, so this cannot be inferred
4483
+ * from how the step was reached.
4484
+ */
4485
+ walletIsEmbedded: boolean;
4486
+ /**
4487
+ * The asset as the sell quote resolves it, or `null` while the poll has
4488
+ * not answered. Without it there is no balance to read and no scale to
4489
+ * parse the field at, so the step renders but cannot be confirmed.
4490
+ */
4491
+ sellAsset: OndoSellAsset | null;
3473
4492
  /**
3474
4493
  * The market as last read, or `null` while it is unknown. Unknown does
3475
4494
  * not block: a dropped poll is not evidence the market is closed, and
3476
4495
  * building will fail with a real reason if it is.
3477
4496
  */
3478
4497
  tradingStatus: OndoTradingStatus | null;
3479
- /** The offer's minimum, in whole USD. `null` when it publishes none. */
3480
- minimumPurchaseUsd: number | null;
3481
4498
  } | {
3482
4499
  type: 'complete';
3483
4500
  wallet: EvmWallet;
3484
4501
  amount: BlockchainAmount;
3485
- inputAsset: StablecoinSymbol;
4502
+ inputAsset: AssetSymbol;
3486
4503
  };
3487
- interface UseOndoAmountViewModelOptions {
3488
- stepInput: OndoAmountStepInput;
3489
- /** Ondo's API symbol, e.g. `AAPLon`. */
4504
+ interface UseOndoSellAmountViewModelOptions {
4505
+ stepInput: OndoSellAmountStepInput;
4506
+ /** Ondo's API symbol, e.g. `TSLAon`. */
3490
4507
  ondoSymbol: AssetSymbol;
3491
- /** The chain the order executes on: balances, approval, and the contract. */
4508
+ /** The chain the order executes on: the balance read, the approval and the broadcast. */
3492
4509
  chain: EthereumChain;
4510
+ /** The offer being sold: supplies the asset's display name and its only icon. */
4511
+ offer: OfferDetail;
4512
+ /**
4513
+ * When false, the step neither fetches nor polls. Defaults to true.
4514
+ *
4515
+ * The step being `incomplete` is not the same thing and does not stand in
4516
+ * for it: a checkout switched off mid-flow leaves this step `active`, and
4517
+ * the parent's own data hooks hold their last `CONTENT` rather than
4518
+ * forgetting it - so the sell asset is still here to read a balance
4519
+ * against, and the poll would run on behind a screen nobody is looking at.
4520
+ */
4521
+ enabled?: boolean;
3493
4522
  /** Called once the approval has mined and the transaction has been built. */
3494
- onComplete: (confirmed: OndoAmountConfirmed) => void;
4523
+ onComplete: (confirmed: OndoSellAmountConfirmed) => void;
3495
4524
  /** Called when the user reopens this step from a later one. */
3496
4525
  onEdit: () => void;
3497
4526
  }
3498
- interface UseOndoAmountViewModelResult {
3499
- state: OndoAmountUiState;
3500
- onEvent: (event: OndoAmountUiEvent) => void;
4527
+ interface UseOndoSellAmountViewModelResult {
4528
+ state: OndoSellAmountUiState;
4529
+ onEvent: (event: OndoSellAmountUiEvent) => void;
3501
4530
  }
3502
4531
  /**
3503
- * Drives step 2 of the Ondo checkout: how much to spend, and getting the order
3504
- * ready to place.
4532
+ * Drives the amount step of the Ondo sell checkout: how much of the asset to
4533
+ * sell, and getting the order ready to place.
3505
4534
  *
3506
- * Confirming does real work - it approves the swap contract to pull the
3507
- * amount, then builds the transaction that spends it - so the CTA reports the on-chain phase
3508
- * as loading copy and every failure comes back as copy under the field.
4535
+ * Confirming does real work - it approves the swap contract to pull the asset,
4536
+ * then builds the transaction that spends it - so the CTA reports the on-chain
4537
+ * phase as loading copy and every failure comes back as copy under the field.
4538
+ * The approval is on the *asset*, not on a stablecoin, which is the one thing
4539
+ * that makes this materially different from the buy step rather than a mirror
4540
+ * of it: the token's address and decimals are not the SDK's to look up, so
4541
+ * everything here waits on the sell quote.
3509
4542
  *
3510
4543
  * Everything checkable locally is checked before the wallet is asked to sign:
3511
- * the balance, the offer's minimum, and Ondo's own order caps. Each of those
3512
- * would otherwise cost the user a real approval transaction before failing.
3513
- */
3514
- declare function useOndoAmountViewModel({ stepInput, ondoSymbol, chain, onComplete, onEdit, }: UseOndoAmountViewModelOptions): UseOndoAmountViewModelResult;
3515
- type OndoAmountValidation = {
4544
+ * the balance and Ondo's own token cap. There is no minimum - `minimumPurchaseUsd`
4545
+ * is an offer's minimum *purchase* and frontline enforces no floor on a sell
4546
+ * beyond a non-zero amount - and the USD caps are deliberately not converted,
4547
+ * because doing it through a price that moves between the check and the build
4548
+ * would reject fillable orders and pass unfillable ones.
4549
+ */
4550
+ declare function useOndoSellAmountViewModel({ stepInput, ondoSymbol, chain, offer, enabled, onComplete, onEdit, }: UseOndoSellAmountViewModelOptions): UseOndoSellAmountViewModelResult;
4551
+ type OndoSellAmountValidation = {
3516
4552
  valid: true;
3517
4553
  amount: BlockchainAmount;
3518
4554
  } | {
@@ -3520,43 +4556,265 @@ type OndoAmountValidation = {
3520
4556
  error: string;
3521
4557
  };
3522
4558
  /**
3523
- * The checks that can be made without asking the wallet for anything, in the
3524
- * order a user would hit them: is it a number, is it more than nothing, can
3525
- * they afford it, does the offer accept it, will Ondo fill it.
4559
+ * The checks that can be made without asking the wallet for anything, in the
4560
+ * order a user would hit them: is it a number, is it more than nothing, do they
4561
+ * hold that much, will Ondo fill it.
4562
+ *
4563
+ * Shorter than the buy ladder by two rungs, and deliberately so. There is no
4564
+ * offer minimum on a sell - `minimumPurchaseUsd` is a *purchase* minimum, and
4565
+ * frontline enforces nothing below a non-zero amount - and Ondo's two USD caps
4566
+ * are left to the server, because converting them into tokens needs a price
4567
+ * that has moved by the time the order is built. What survives is
4568
+ * `grossMaxTokens`, which is already in whole tokens and needs no conversion at
4569
+ * all.
4570
+ *
4571
+ * Exported for the property tests: the ladder is money logic, and the property
4572
+ * that matters (nothing above the balance or the cap is ever accepted) is about
4573
+ * the whole ladder rather than any one rung.
4574
+ */
4575
+ declare function validateSellAmount({ input, decimals, balance, symbol, tradingStatus, locale, }: {
4576
+ input: string;
4577
+ decimals: AssetDecimals;
4578
+ /** `null` while no balance has been read; the check is then skipped. */
4579
+ balance: bigint | null;
4580
+ symbol: AssetSymbol;
4581
+ tradingStatus: OndoTradingStatus | null;
4582
+ locale: string;
4583
+ }): OndoSellAmountValidation;
4584
+
4585
+ /**
4586
+ * The state of the built sale a review step acts on.
4587
+ *
4588
+ * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in
4589
+ * flight never blanks the numbers the user is reading. A refresh that fails
4590
+ * keeps them too, and reports why alongside - the previous sale may still
4591
+ * be good, and a failed refresh is fixed by refreshing again.
4592
+ */
4593
+ type LoadOndoSellTransactionState = {
4594
+ type: 'LOADING';
4595
+ } | {
4596
+ type: 'ERROR';
4597
+ reason: OndoLoadErrorReason;
4598
+ } | {
4599
+ type: 'CONTENT';
4600
+ transaction: OndoSellTransaction;
4601
+ isRefreshing: boolean;
4602
+ /** Why the last refresh failed; `null` when the sale is fresh. */
4603
+ refreshError: OndoLoadErrorReason | null;
4604
+ };
4605
+ interface UseOndoSellTransactionOptions {
4606
+ /**
4607
+ * The order to build, or `null` while there is not one yet - before the
4608
+ * amount step is confirmed. A `null` request fetches nothing.
4609
+ */
4610
+ request: BuildOndoSellParams | null;
4611
+ /**
4612
+ * A sale the caller already holds, typically the one `prepareSell`
4613
+ * returned with the approval. When present the hook adopts it and skips the
4614
+ * initial fetch; `refetch` still fetches. This is what keeps the flow to one
4615
+ * attestation per order.
4616
+ */
4617
+ data?: OndoSellTransaction;
4618
+ /** When false, the hook does not fetch. */
4619
+ enabled: boolean;
4620
+ }
4621
+ interface UseOndoSellTransactionResult {
4622
+ state: LoadOndoSellTransactionState;
4623
+ /** Builds a fresh sale for the same order. Spends an attestation. */
4624
+ refetch: () => void;
4625
+ }
4626
+ /**
4627
+ * Holds the firm, expiring sale the sell review step places an order
4628
+ * against, and rebuilds it on demand.
4629
+ *
4630
+ * **Never polls.** Building spends an attestation, so a new one is only ever
4631
+ * obtained when the caller asks - on `refetch`, or on the first render if no
4632
+ * `data` was supplied. That is also why an expired sale is left expired
4633
+ * here: whether to replace it is the user's call, not a timer's.
4634
+ *
4635
+ * Disabled it fetches nothing and stays on whatever state it opened with. That
4636
+ * is `LOADING` and not an empty `CONTENT` because there is no empty
4637
+ * sale: firm calldata for an order that does not exist is not
4638
+ * representable. A caller that switches this hook off should switch its own
4639
+ * rendering off with it - which is what the review step does, since a step
4640
+ * that is not active is `incomplete` and never reads this state at all.
4641
+ *
4642
+ * The sell half of the pair `useOndoBuyTransaction` opens - see there for why
4643
+ * the two are not one hook. What differs is entirely in what `CONTENT` carries:
4644
+ * an {@link OndoSellTransaction} publishes an expected outcome and a floor
4645
+ * beneath it rather than one attested quantity, and the review step renders
4646
+ * both.
4647
+ */
4648
+ declare function useOndoSellTransaction(options: UseOndoSellTransactionOptions): UseOndoSellTransactionResult;
4649
+
4650
+ type OndoSellReviewStepInput = {
4651
+ type: 'incomplete';
4652
+ } | {
4653
+ type: 'active';
4654
+ /** The wallet that signs, sends the asset, and receives the proceeds. */
4655
+ wallet: EvmWallet;
4656
+ /** What the user is selling, in the asset's base units. */
4657
+ amount: BlockchainAmount;
4658
+ inputAsset: AssetSymbol;
4659
+ /**
4660
+ * The sale `prepareSell` already built for this order. Omitting it makes
4661
+ * this step build one itself, which is the path a partner driving the
4662
+ * review on its own takes - and the only way its `loading` and `error`
4663
+ * states are reached.
4664
+ */
4665
+ transaction?: OndoSellTransaction;
4666
+ };
4667
+ interface UseOndoSellReviewViewModelOptions {
4668
+ stepInput: OndoSellReviewStepInput;
4669
+ /** Ondo's API symbol, e.g. `TSLAon`. Rebuilds the transaction. */
4670
+ ondoSymbol: AssetSymbol;
4671
+ /** The chain the order executes on. */
4672
+ chain: EthereumChain;
4673
+ /**
4674
+ * When false, the step neither builds a transaction nor counts down, and
4675
+ * neither refreshing the quote nor placing an order does anything. Defaults
4676
+ * to true.
4677
+ *
4678
+ * The step being `incomplete` is not the same thing and does not stand in
4679
+ * for it: a checkout switched off mid-flow leaves this step `active`, so the
4680
+ * committed quote is still here to render and its clock would tick on behind
4681
+ * a screen nobody is looking at.
4682
+ */
4683
+ enabled?: boolean;
4684
+ /** Called once the swap has mined. */
4685
+ /** Always a sell: this step only ever places one. */
4686
+ onComplete: (order: OndoSellOrderPlaced) => void;
4687
+ }
4688
+ interface UseOndoSellReviewViewModelResult {
4689
+ state: OndoSellReviewUiState;
4690
+ onEvent: (event: OndoSellReviewUiEvent) => void;
4691
+ }
4692
+ /**
4693
+ * Drives the review step of the Ondo sell checkout: what the sale comes to, how
4694
+ * long the price holds, and placing it.
4695
+ *
4696
+ * The same shape as its buy counterpart, and the same reasoning about time: the
4697
+ * quote is firm and short-lived, a quote inside
4698
+ * {@link ONDO_QUOTE_EXPIRY_THRESHOLD_MS} of its deadline is treated as already
4699
+ * gone, and refreshing is always something the user asks for because each
4700
+ * refresh spends an attestation.
4701
+ *
4702
+ * What differs is what it reads off the transaction. A sale has no
4703
+ * `notionalValue` and therefore no total to render; it publishes an expected
4704
+ * outcome and a floor beneath it where the buy publishes one attested
4705
+ * quantity; and its fee, if one ever lands, is denominated in the proceeds
4706
+ * rather than in what was spent, and comes in two - one per outcome. Those
4707
+ * facts are why this is a second viewmodel rather than a flag on the first,
4708
+ * and why the endpoint behind it is a second endpoint.
4709
+ */
4710
+ declare function useOndoSellReviewViewModel({ stepInput, ondoSymbol, chain, enabled, onComplete, }: UseOndoSellReviewViewModelOptions): UseOndoSellReviewViewModelResult;
4711
+
4712
+ /**
4713
+ * Which step is being filled in, carrying everything the ones before it
4714
+ * settled.
4715
+ *
4716
+ * A union rather than a step index plus nullable fields: the amount step cannot
4717
+ * run without a wallet, and the review step cannot run without a built
4718
+ * transaction, so neither is representable here.
4719
+ *
4720
+ * The `wallet` arm is only ever entered when the host preselected nothing. A
4721
+ * skipped wallet step is not a fourth arm: it is the flow *opening* on
4722
+ * `amount`, which is why `wallets.preselected` is read once to seed the state
4723
+ * and never again.
4724
+ */
4725
+ type OndoSellStep = {
4726
+ type: 'wallet';
4727
+ } | {
4728
+ type: 'amount';
4729
+ wallet: EvmWallet;
4730
+ } | {
4731
+ type: 'review';
4732
+ wallet: EvmWallet;
4733
+ amount: BlockchainAmount;
4734
+ inputAsset: AssetSymbol;
4735
+ /** Built by `prepareSell` when the amount was confirmed. */
4736
+ transaction: OndoSellTransaction;
4737
+ };
4738
+ interface UseOndoSellCheckoutViewModelOptions {
4739
+ /**
4740
+ * The offer being sold: names the asset and supplies its logo.
4741
+ *
4742
+ * Fixed for the lifetime of the hook — see the note on
4743
+ * {@link useOndoSellCheckoutViewModel} about switching offers.
4744
+ */
4745
+ offer: OfferDetail;
4746
+ /**
4747
+ * Ondo's API symbol for the asset, e.g. `TSLAon`.
4748
+ *
4749
+ * Explicit rather than derived from `offer.asset.code`: Ondo's symbol tracks
4750
+ * the underlying ticker and changes on a rebrand, and the two already
4751
+ * disagree on Sepolia, where a mock asset stands in.
4752
+ */
4753
+ ondoSymbol: AssetSymbol;
4754
+ /**
4755
+ * The chain the order executes on: the balance read, the approval and the
4756
+ * broadcast. Quotes are priced against Ondo production whatever this says,
4757
+ * since Ondo runs no sandbox, so on a testnet the price is real and the
4758
+ * money is not.
4759
+ *
4760
+ * Fixed for the lifetime of the hook, as `offer` is.
4761
+ */
4762
+ chain: EthereumChain;
4763
+ /**
4764
+ * The host's wallets, the lambdas that connect and disconnect one, and
4765
+ * optionally the wallet it has already settled on.
4766
+ *
4767
+ * `wallets.preselected` is read **once**, to seed the step machine. A host
4768
+ * that changes it mid-flow is ignored: the approval that follows the amount
4769
+ * step is granted by one specific wallet, and moving the flow onto another
4770
+ * one under it would strand that approval and build calldata the new wallet
4771
+ * cannot broadcast.
4772
+ */
4773
+ wallets: CheckoutWalletSelection;
4774
+ /**
4775
+ * Default `true`. When `false` nothing is fetched and no timer runs, so the
4776
+ * hook can be called unconditionally beside other providers' viewmodels.
4777
+ */
4778
+ enabled?: boolean;
4779
+ /**
4780
+ * Fired once the swap has mined. The confirmation dialog shows either way;
4781
+ * this is for a host that wants to navigate, refresh a portfolio, or log.
4782
+ */
4783
+ onOrderConfirmed?: (order: OndoOrderPlaced) => void;
4784
+ }
4785
+ interface UseOndoSellCheckoutViewModelResult {
4786
+ state: OndoSellCheckoutUiState;
4787
+ onEvent: (event: OndoSellCheckoutUiEvent) => void;
4788
+ }
4789
+ /**
4790
+ * Drives the whole Ondo sell checkout: the steps, the reference panel beside
4791
+ * them, and the dialog that closes the flow.
3526
4792
  *
3527
- * Exported for the property tests: the ladder is money logic, and the property
3528
- * that matters (nothing above the balance or the caps is ever accepted) is
3529
- * about the whole ladder rather than any one rung.
3530
- */
3531
- declare function validateAmount({ input, decimals, balance, symbol, minimumPurchaseUsd, tradingStatus, locale, }: {
3532
- input: string;
3533
- decimals: AssetDecimals;
3534
- /** `null` while no balance has been read; the check is then skipped. */
3535
- balance: bigint | null;
3536
- symbol: AssetSymbol;
3537
- minimumPurchaseUsd: number | null;
3538
- tradingStatus: OndoTradingStatus | null;
3539
- locale: string;
3540
- }): OndoAmountValidation;
3541
-
3542
- /**
3543
- * Why an Ondo read failed, in the only two flavours a UI acts on differently.
4793
+ * It owns the step machine and the two polls; each step's own viewmodel owns
4794
+ * its screen. The polls live here because they are shared - the sidebar shows
4795
+ * the price and the amount step gates on the market - and because the price is
4796
+ * sized by whatever the flow has settled on so far.
3544
4797
  *
3545
- * `not-authenticated` is split out because no retry helps until the user signs
3546
- * in, and because the remedy is one the UI can name. Everything else collapses
3547
- * into `generic-error` and is offered a retry.
4798
+ * The sell price poll is what names the asset being sold. `TOKEN_REGISTRY`
4799
+ * knows the stablecoins swaps are funded with and no provider's asset, so the
4800
+ * contract address the balance is read on and the approval is granted for, and
4801
+ * the decimals the typed amount is parsed at, both come off that quote and
4802
+ * nowhere else.
3548
4803
  *
3549
- * That is a deliberate over-offer, not a claim that every such failure is
3550
- * retryable. A `ValidationError` from the DTO boundary - an unreadable expiry,
3551
- * a zero output amount, a scale no amount could be denominated in - is
3552
- * deterministic, and refreshing spends an attestation to fail again. It stays
3553
- * lumped in because each one means frontline changed its encoding, which is
3554
- * unreachable in a deployed pair and not worth a public union member and a
3555
- * branch in every consumer to distinguish. Split it out if that stops being
3556
- * true.
4804
+ * There is no flow-level error state. Every failure belongs to a region: a
4805
+ * price that will not load leaves the panel's corner unavailable, and an order
4806
+ * that will not go through is reported on the review step, next to the button
4807
+ * that caused it.
4808
+ *
4809
+ * `offer` and `chain` are read as fixed for the lifetime of the hook, and so is
4810
+ * the wallet the flow opened on. The step machine holds a committed quote and
4811
+ * an approval granted on one chain by one wallet for one order, so changing any
4812
+ * of them in place would carry them onto an order they were never priced for.
4813
+ * Remount instead: give the component holding this hook a `key` that changes
4814
+ * with the offer, the chain and the side, as {@link CheckoutContainer}
4815
+ * documents.
3557
4816
  */
3558
- type OndoLoadErrorReason = 'not-authenticated' | 'generic-error';
3559
- declare function ondoLoadErrorReason(error: unknown): OndoLoadErrorReason;
4817
+ declare function useOndoSellCheckoutViewModel({ offer, ondoSymbol, chain, wallets, enabled, onOrderConfirmed, }: UseOndoSellCheckoutViewModelOptions): UseOndoSellCheckoutViewModelResult;
3560
4818
 
3561
4819
  /**
3562
4820
  * The state of the indicative-price poll.
@@ -3615,7 +4873,8 @@ interface UseOndoPriceResult {
3615
4873
  *
3616
4874
  * Free to poll: this quote spends no attestation and commits nothing, which is
3617
4875
  * why it may run while the user is still deciding. It also cannot be executed
3618
- * - committing a fillable quote is `coinlist.ondo.prepareSwap`.
4876
+ * - committing a fillable quote is `coinlist.ondo.prepareBuy` or
4877
+ * `coinlist.ondo.prepareSell`, whichever way the trade runs.
3619
4878
  *
3620
4879
  * Disabled (or before the provider is ready) it neither fetches nor holds a
3621
4880
  * timer, and stays on whatever state it opened with - `LOADING`, or the `data`
@@ -3730,94 +4989,6 @@ interface UseOndoSidebarViewModelResult {
3730
4989
  */
3731
4990
  declare function useOndoSidebarViewModel({ offer, ondoSymbol, chain, priceState, tradingStatusState, }: UseOndoSidebarViewModelOptions): UseOndoSidebarViewModelResult;
3732
4991
 
3733
- /**
3734
- * Which step is being filled in, carrying everything the ones before it
3735
- * settled.
3736
- *
3737
- * A union rather than a step index plus nullable fields: the amount step
3738
- * cannot run without a wallet, and the review step cannot run without a built
3739
- * transaction, so neither is representable here.
3740
- */
3741
- type OndoBuyStep = {
3742
- type: 'wallet';
3743
- } | {
3744
- type: 'amount';
3745
- wallet: EvmWallet;
3746
- } | {
3747
- type: 'review';
3748
- wallet: EvmWallet;
3749
- amount: BlockchainAmount;
3750
- inputAsset: StablecoinSymbol;
3751
- /** Built by `prepareSwap` when the amount was confirmed. */
3752
- transaction: OndoSwapTransaction;
3753
- };
3754
- interface UseOndoBuyCheckoutViewModelOptions {
3755
- /**
3756
- * The offer being bought: names the asset and supplies its logo.
3757
- *
3758
- * Fixed for the lifetime of the hook — see the note on
3759
- * {@link useOndoBuyCheckoutViewModel} about switching offers.
3760
- */
3761
- offer: OfferDetail;
3762
- /**
3763
- * Ondo's API symbol for the asset, e.g. `AAPLon`.
3764
- *
3765
- * Explicit rather than derived from `offer.asset.code`: Ondo's symbol tracks
3766
- * the underlying ticker and changes on a rebrand, and the two already
3767
- * disagree on Sepolia, where a mock asset stands in.
3768
- */
3769
- ondoSymbol: AssetSymbol;
3770
- /**
3771
- * The chain the order executes on: the balance read, the approval and the
3772
- * broadcast. Quotes are priced against Ondo production whatever this says,
3773
- * since Ondo runs no sandbox, so on a testnet the price is real and the
3774
- * money is not.
3775
- *
3776
- * Fixed for the lifetime of the hook, as `offer` is.
3777
- */
3778
- chain: EthereumChain;
3779
- /** The host's wallets, and the lambdas that connect and disconnect one. */
3780
- wallets: CheckoutWalletSelection;
3781
- /**
3782
- * Default `true`. When `false` nothing is fetched and no timer runs, so the
3783
- * hook can be called unconditionally beside other providers' viewmodels.
3784
- */
3785
- enabled?: boolean;
3786
- /**
3787
- * Fired once the swap has mined. The confirmation dialog shows either way;
3788
- * this is for a host that wants to navigate, refresh a portfolio, or log.
3789
- */
3790
- onOrderConfirmed?: (order: OndoOrderPlaced) => void;
3791
- }
3792
- interface UseOndoBuyCheckoutViewModelResult {
3793
- state: OndoBuyCheckoutUiState;
3794
- onEvent: (event: OndoBuyCheckoutUiEvent) => void;
3795
- }
3796
- /**
3797
- * Drives the whole Ondo buy checkout: the three steps, the reference panel
3798
- * beside them, and the dialog that closes the flow.
3799
- *
3800
- * It owns the step machine and the two polls; each step's own viewmodel owns
3801
- * its screen. The polls live here because they are shared - the sidebar shows
3802
- * the price and the amount step gates on the market - and because the price is
3803
- * sized by whatever the flow has settled on so far.
3804
- *
3805
- * There is no flow-level error state. Every failure belongs to a region: a
3806
- * price that will not load leaves the panel's corner unavailable, and an order
3807
- * that will not go through is reported on the review step, next to the button
3808
- * that caused it.
3809
- *
3810
- * `offer` and `chain` are read as fixed for the lifetime of the hook. The step
3811
- * machine holds a committed quote and an approval granted on one chain for one
3812
- * order, so changing either in place would carry them onto an order they were
3813
- * never priced for. Remount instead: give the component holding this hook a
3814
- * `key` that changes with the offer and the chain, as {@link CheckoutContainer}
3815
- * documents. That discards the flow with its component instance, which is the
3816
- * only reset that cannot land between an approval and the broadcast it was
3817
- * granted for.
3818
- */
3819
- declare function useOndoBuyCheckoutViewModel({ offer, ondoSymbol, chain, wallets, enabled, onOrderConfirmed, }: UseOndoBuyCheckoutViewModelOptions): UseOndoBuyCheckoutViewModelResult;
3820
-
3821
4992
  /**
3822
4993
  * Whether step 1 is being filled in or already answered.
3823
4994
  *
@@ -3861,70 +5032,6 @@ interface UseOndoWalletSelectViewModelResult {
3861
5032
  */
3862
5033
  declare function useOndoWalletSelectViewModel({ stepInput, wallets, chain, onComplete, onEdit, }: UseOndoWalletSelectViewModelOptions): UseOndoWalletSelectViewModelResult;
3863
5034
 
3864
- /**
3865
- * The state of the built transaction a review step acts on.
3866
- *
3867
- * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in
3868
- * flight never blanks the numbers the user is reading. A refresh that fails
3869
- * keeps them too, and reports why alongside - the previous transaction may
3870
- * still be good, and a failed refresh is fixed by refreshing again.
3871
- */
3872
- type LoadOndoSwapTransactionState = {
3873
- type: 'LOADING';
3874
- } | {
3875
- type: 'ERROR';
3876
- reason: OndoLoadErrorReason;
3877
- } | {
3878
- type: 'CONTENT';
3879
- transaction: OndoSwapTransaction;
3880
- isRefreshing: boolean;
3881
- /** Why the last refresh failed; `null` when the transaction is fresh. */
3882
- refreshError: OndoLoadErrorReason | null;
3883
- };
3884
- interface UseOndoSwapTransactionOptions {
3885
- /**
3886
- * The order to build, or `null` while there is not one yet - before the
3887
- * amount step is confirmed. A `null` request fetches nothing.
3888
- */
3889
- request: BuildOndoSwapTransactionParams | null;
3890
- /**
3891
- * A transaction the caller already holds, typically the one `prepareSwap`
3892
- * returned with the approval. When present the hook adopts it and skips the
3893
- * initial fetch; `refetch` still fetches. This is what keeps the flow to one
3894
- * attestation per order.
3895
- */
3896
- data?: OndoSwapTransaction;
3897
- /** When false, the hook does not fetch. */
3898
- enabled: boolean;
3899
- }
3900
- interface UseOndoSwapTransactionResult {
3901
- state: LoadOndoSwapTransactionState;
3902
- /** Builds a fresh transaction for the same order. Spends an attestation. */
3903
- refetch: () => void;
3904
- }
3905
- /**
3906
- * Holds the firm, expiring transaction a review step places an order against,
3907
- * and rebuilds it on demand.
3908
- *
3909
- * **Never polls.** Building spends an attestation, so a new one is only ever
3910
- * obtained when the caller asks - on `refetch`, or on the first render if no
3911
- * `data` was supplied. That is also why an expired transaction is left expired
3912
- * here: whether to replace it is the user's call, not a timer's.
3913
- *
3914
- * Disabled it fetches nothing and stays on whatever state it opened with. That
3915
- * is `LOADING` and not an empty `CONTENT` because there is no empty
3916
- * transaction: firm calldata for an order that does not exist is not
3917
- * representable. A caller that switches this hook off should switch its own
3918
- * rendering off with it - which is what the review step does, since a step
3919
- * that is not active is `incomplete` and never reads this state at all.
3920
- *
3921
- * Buy-only, like the endpoint behind it - the funding token goes in and the
3922
- * asset comes out, both resolved from the offer. It sits beside the two
3923
- * side-parameterised polls rather than under `buy/` because a sell will reach
3924
- * for the same seam, and moving it then is cheaper than forking it now.
3925
- */
3926
- declare function useOndoSwapTransaction(options: UseOndoSwapTransactionOptions): UseOndoSwapTransactionResult;
3927
-
3928
5035
  /** How much the user is spending, and what they are spending it in. */
3929
5036
  type SuperstateAmountConfirmed = {
3930
5037
  amount: BlockchainAmount;
@@ -4394,6 +5501,62 @@ interface UseRequirementsChecklistViewModelResult {
4394
5501
  */
4395
5502
  declare function useRequirementsChecklistViewModel(options: UseRequirementsChecklistViewModelOptions): UseRequirementsChecklistViewModelResult;
4396
5503
 
5504
+ /**
5505
+ * A display-ready connect-wallet error: the core flow's machine-readable code
5506
+ * and `retryable` flag, plus copy for the UI.
5507
+ */
5508
+ type ConnectWalletError = {
5509
+ code: ConnectWalletErrorCode;
5510
+ message: string;
5511
+ retryable: boolean;
5512
+ };
5513
+ /**
5514
+ * Signing-in-flight and the last sign error live inside the READY state (not a
5515
+ * separate top-level state) so a failed attempt returns to READY and can be
5516
+ * retried without re-opening the modal. Mirrors {@link SignState} in
5517
+ * `useTaxDocument`.
5518
+ */
5519
+ type ConnectWalletSignState = {
5520
+ type: 'idle';
5521
+ error: ConnectWalletError | null;
5522
+ } | {
5523
+ type: 'signing';
5524
+ };
5525
+ type ConnectWalletState = {
5526
+ type: 'NEEDS_WALLET';
5527
+ } | {
5528
+ type: 'READY';
5529
+ address: EvmWalletAddress;
5530
+ sign: ConnectWalletSignState;
5531
+ } | {
5532
+ type: 'CONNECTED';
5533
+ binding: OfferOptionAddress;
5534
+ };
5535
+ interface UseConnectWalletOptions {
5536
+ /** The hook resets state each time it opens. */
5537
+ isOpen: boolean;
5538
+ offerId: OfferId;
5539
+ offerOptionId: OfferOptionId;
5540
+ /** Host-provided connected wallet, or `null` while none is connected. */
5541
+ wallet: ConnectWallet | null;
5542
+ /** Challenge framing; defaults to `'siwe'`. */
5543
+ challengeType?: WalletChallengeType;
5544
+ /** SIWE statement shown in the signing prompt. */
5545
+ statement?: string;
5546
+ }
5547
+ interface UseConnectWalletResult {
5548
+ state: ConnectWalletState;
5549
+ /** READY.sign: idle -> signing -> (CONNECTED | idle w/ error). No-op otherwise. */
5550
+ onSign: () => void;
5551
+ }
5552
+ /**
5553
+ * React wrapper over {@link connectExternalWalletFlow}. Owns the modal state
5554
+ * machine, the display copy, and generation-token supersession (so a wallet
5555
+ * switch, modal close, or unmount cancels an in-flight attempt). The flow logic
5556
+ * itself lives in the framework-free core so non-React consumers can drive it.
5557
+ */
5558
+ declare function useConnectWallet({ isOpen, offerId, offerOptionId, wallet, challengeType, statement, }: UseConnectWalletOptions): UseConnectWalletResult;
5559
+
4397
5560
  type KycTokenErrorReason = 'not-authenticated' | 'generic-error';
4398
5561
  type KycTokenState = {
4399
5562
  type: 'IDLE';
@@ -4630,6 +5793,56 @@ interface UseConnectWalletModalViewModelResult {
4630
5793
  */
4631
5794
  declare function useConnectWalletModalViewModel({ isOpen, onClose, offerId, optionId, wallet, onConnected, onRequestConnect, challengeType, statement, }: UseConnectWalletModalViewModelOptions): UseConnectWalletModalViewModelResult;
4632
5795
 
5796
+ interface UseErc20BalanceOptions {
5797
+ /**
5798
+ * The token to read, by contract address.
5799
+ *
5800
+ * `null` when the caller does not know it yet, which fetches nothing. That is
5801
+ * the normal state for a token the SDK ships no registry entry for: an Ondo
5802
+ * asset's address arrives with its quote, so a sell screen renders before it
5803
+ * has one.
5804
+ */
5805
+ tokenAddress: EvmContractAddress | null;
5806
+ owner: EvmWalletAddress;
5807
+ chain: EthereumChain;
5808
+ /** How often to refresh. Defaults to {@link ERC20_BALANCE_POLL_INTERVAL_MS}. */
5809
+ pollIntervalMs?: number;
5810
+ /** When false, the hook neither fetches nor polls. */
5811
+ enabled: boolean;
5812
+ }
5813
+ interface UseErc20BalanceResult {
5814
+ /**
5815
+ * Raw base units of the token currently named by the options, or `null`.
5816
+ *
5817
+ * `null` covers every state that is not a settled read of *this* request:
5818
+ * before the first one settles, after one fails, while disabled, and from
5819
+ * the moment the token, owner or chain changes until the read for the new
5820
+ * one lands. A caller cannot tell those apart on purpose - none of them is a
5821
+ * number to size an order against - and `isLoading` is what says whether to
5822
+ * wait.
5823
+ */
5824
+ balance: bigint | null;
5825
+ isLoading: boolean;
5826
+ }
5827
+ /**
5828
+ * Polls one wallet's balance of one ERC-20, named by contract address.
5829
+ *
5830
+ * The address-keyed counterpart to `useErc20TokenBalances`, which reads a list
5831
+ * of tokens by symbol through `TOKEN_REGISTRY`. That registry knows the
5832
+ * stablecoins the SDK funds swaps with and nothing else, so a token whose
5833
+ * address arrives at runtime - a provider's asset, resolved from a quote - has
5834
+ * no symbol to look up and needs this instead. Two hooks rather than one
5835
+ * widened hook: the plural one exists to read a *set* concurrently and settle
5836
+ * each independently, which is a different job from following a single token
5837
+ * whose address may not be known yet.
5838
+ *
5839
+ * A poll tick is skipped while the previous read is in flight, so a slow one
5840
+ * cannot resolve last and overwrite a fresher balance. `isLoading` is true only
5841
+ * until the first read settles; background polls do not toggle it. Disabled, or
5842
+ * with no `tokenAddress`, it neither fetches nor holds a timer.
5843
+ */
5844
+ declare function useErc20Balance(options: UseErc20BalanceOptions): UseErc20BalanceResult;
5845
+
4633
5846
  /**
4634
5847
  * How often balances refresh when the caller names no interval. Matches the
4635
5848
  * cadence the checkout flows poll everything else at, and is slow enough that
@@ -4652,8 +5865,10 @@ interface UseErc20TokenBalancesOptions {
4652
5865
  interface UseErc20TokenBalancesResult {
4653
5866
  /**
4654
5867
  * Raw on-chain balances keyed by the requested assets. Each requested asset
4655
- * has an entry once a fetch settles (`bigint` on success, `null` on failure).
4656
- * Assets that were not requested are absent.
5868
+ * with a deployment on the chain has an entry once a fetch settles
5869
+ * (`bigint` on success, `null` on a failed read). Assets the chain has no
5870
+ * deployment for (e.g. USDT on Base Sepolia) are omitted entirely, so
5871
+ * absence and failure stay tellable apart.
4657
5872
  */
4658
5873
  balances: Map<StablecoinSymbol, bigint | null>;
4659
5874
  isLoading: boolean;
@@ -4661,9 +5876,11 @@ interface UseErc20TokenBalancesResult {
4661
5876
  /**
4662
5877
  * Polls the raw ERC-20 balances of `assets` for `address`, refreshing every
4663
5878
  * `pollIntervalMs`. Each asset settles independently: a failed read maps to
4664
- * `null` while the others still resolve. A poll tick is skipped while the
4665
- * previous fetch is still in flight. `assets` is compared by contents, so
4666
- * passing an inline array does not restart the poll.
5879
+ * `null` while the others still resolve, and an asset the chain has no
5880
+ * deployment for is omitted from the result rather than read at a fake
5881
+ * address. A poll tick is skipped while the previous fetch is still in
5882
+ * flight. `assets` is compared by contents, so passing an inline array does
5883
+ * not restart the poll.
4667
5884
  *
4668
5885
  * `isLoading` is true only until the first poll settles; background polls do
4669
5886
  * not toggle it. Disabled (or before the provider is ready) the hook does not
@@ -4835,6 +6052,19 @@ declare function formatMonthYear(date: Date, locale: string): string;
4835
6052
  * not a substitute — it renders one unit ("in 2 days"), not two.
4836
6053
  */
4837
6054
  declare function formatCountdown(totalSeconds: number): string;
6055
+ /**
6056
+ * Live-sale chrome countdown, e.g. `3D 19H 42M`.
6057
+ *
6058
+ * Always three uppercase units and no seconds, matching Clay's sale card.
6059
+ * Distinct from {@link formatCountdown}, which stays two mixed-case units for
6060
+ * checkout sidebars.
6061
+ *
6062
+ * A positive remainder under a minute clamps to `0D 0H 1M`: the card shows the
6063
+ * live dot next to this string, and a live sale reading `0D 0H 0M` would
6064
+ * contradict the dot. That all-zero string is reserved for `ended` — and the
6065
+ * status label for that never calls this function.
6066
+ */
6067
+ declare function formatSaleCardCountdown(totalSeconds: number): string;
4838
6068
 
4839
6069
  interface UseCountdownOptions {
4840
6070
  /**
@@ -4877,4 +6107,4 @@ interface UseCountdownOptions {
4877
6107
  */
4878
6108
  declare function useCountdown({ until, tickMs, enabled, }: UseCountdownOptions): number | null;
4879
6109
 
4880
- export { type AuthState, type AuthorizeWalletParams, type BroadcastTxParams, ChecklistStatus, CheckoutAssetUi, type CheckoutConfig, type CheckoutConfirmedWalletUi, CheckoutContainer, type CheckoutContainerProps, type CheckoutCtaUi, type CheckoutEmbeddedWalletUi, type CheckoutNetworkUi, type CheckoutSelectableInputAssetUi, type CheckoutStatusUi, type CheckoutWalletSelection, type CheckoutWalletTypeUi, type CheckoutWalletUi, type ClientAuthConfig, type ClientAuthNamespace, ClientAuthNamespaceImpl, type ClientAuthSession, type ClientCoinListTokenSaleNamespace, ClientCoinListTokenSaleNamespaceImpl, type ClientConfig, type ClientOndoNamespace, ClientOndoNamespaceImpl, type ClientRequirementsNamespace, ClientRequirementsNamespaceImpl, type ClientSuperstateSwapNamespace, ClientSuperstateSwapNamespaceImpl, type ClientSupportNamespace, ClientSupportNamespaceImpl, type CoinListClient, CoinListClientInitializationError, CoinListContext, CoinListContextProvider, type CoinListContextValue, CoinListProvider, type CoinListProviderProps, CoinListSignInButton, CoinListSignInCardContainer, type CoinListSignInCardContainerProps, type CoinListSignInCardUiEvent, type CoinListSignInCardUiState, CoinListSignInCardView, type CoinListSignInCardViewProps, CoinListStyleScope, type CoinListStyleScopeProps, type CoinListTokenSaleCheckoutConfig, type CompleteOAuthFailureReason, type ConnectWallet, type ConnectWalletError, type ConnectWalletErrorCode, type ConnectWalletFlowError, type ConnectWalletFlowParams, type ConnectWalletFlowResult, ConnectWalletModalContainer, type ConnectWalletModalContainerProps, type ConnectWalletModalUiEvent, type ConnectWalletModalUiState, ConnectWalletModalView, type ConnectWalletModalViewProps, type ConnectWalletPhase, type ConnectWalletScreenUi, type ConnectWalletSignState, type ConnectWalletState, ConnectedWalletList, type ConnectedWalletListProps, type ConnectedWalletUi, ERC20_BALANCE_POLL_INTERVAL_MS, type Erc20AllowanceError, type Erc20AllowancePhase, type Erc20AllowanceResult, type Erc20ApprovalError, type EvmSigner, type EvmWallet, type ExecuteOndoSwapParams, type ExecuteSwapParams, type ExecuteTokenSaleParams, IdentityVerificationContainer, type IdentityVerificationContainerProps, type IdentityVerificationUiEvent, type IdentityVerificationUiState, IdentityVerificationView, type IdentityVerificationViewProps, KycLevelName, type KycTokenErrorReason, type KycTokenState, type LoadOfferDetailsReason, type LoadOfferDetailsState, type LoadOffersReason, type LoadOffersState, type LoadOndoPriceState, type LoadOndoSwapTransactionState, type LoadOndoTradingStatusState, type LoadOptionAddressesReason, type LoadOptionAddressesState, type LoadParticipationsReason, type LoadParticipationsState, type LoadRequirementsReason, type LoadRequirementsState, type LoadTokenMetadataState, OAUTH_CODE_VERIFIER_KEY, OAUTH_STATE_KEY, type OauthClientErrorReason, type OauthClientResult, OfferCard, type Props as OfferCardProps, OfferCardUi, OffersGridContainer, type OffersGridContainerProps, type OffersGridUiEvent, type OffersGridUiState, OffersGridView, type OffersGridViewProps, type OndoAmountConfirmed, type OndoAmountStepInput, type OndoAmountUiEvent, type OndoAmountUiState, type OndoAmountValidation, OndoAmountView, type OndoAmountViewProps, OndoBuyCheckoutContainer, type OndoBuyCheckoutContainerProps, type OndoBuyCheckoutUiEvent, type OndoBuyCheckoutUiState, OndoBuyCheckoutView, type OndoBuyCheckoutViewProps, type OndoBuyStep, type OndoCheckoutConfig, type OndoLoadErrorReason, OndoOrderConfirmed, type OndoOrderConfirmedProps, type OndoOrderConfirmedUiEvent, type OndoOrderConfirmedUiState, type OndoOrderPlaced, type OndoQuoteStatusUi, type OndoReviewStepInput, type OndoReviewUiEvent, type OndoReviewUiState, OndoReviewView, type OndoReviewViewProps, type OndoSidebarPriceUi, type OndoSidebarUiState, OndoSidebarView, type OndoSidebarViewProps, type OndoSwapExecutionError, type OndoSwapExecutionPhase, type OndoSwapExecutionResult, type OndoSwapPreparationError, type OndoSwapPreparationPhase, type OndoSwapPreparationResult, type OndoWalletSelectStepInput, type OndoWalletSelectUiEvent, type OndoWalletSelectUiState, OndoWalletSelectView, type OndoWalletSelectViewProps, type PrepareOndoSwapParams, type RequiredCheckoutConfig, RequirementItem, type RequirementItemProps, RequirementItemUi, RequirementStatus, RequirementVariant, RequirementsChecklistContainer, type RequirementsChecklistContainerProps, type RequirementsChecklistItemUi, type RequirementsChecklistUiEvent, type RequirementsChecklistUiState, RequirementsChecklistView, type RequirementsChecklistViewProps, type RequirementsData, type RequirementsVerificationUi, type SignState, SlippagePicker, type SlippagePickerProps, type SubmitErc20ApprovalResult, type SuperstateAmountConfirmed, type SuperstateAmountStepInput, type SuperstateAmountUiEvent, type SuperstateAmountUiState, type SuperstateAmountValidation, SuperstateAmountView, type SuperstateAmountViewProps, type SuperstateCheckoutConfig, SuperstateOrderConfirmed, type SuperstateOrderConfirmedProps, type SuperstateOrderConfirmedUiEvent, type SuperstateOrderConfirmedUiState, type SuperstateOrderPlaced, type SuperstateReviewStepInput, type SuperstateReviewUiEvent, type SuperstateReviewUiState, SuperstateReviewView, type SuperstateReviewViewProps, type SuperstateSidebarPriceUi, type SuperstateSidebarUiState, SuperstateSidebarView, type SuperstateSidebarViewProps, type SuperstateSlippageOptionUi, type SuperstateSlippageUi, SuperstateSwapCheckoutContainer, type SuperstateSwapCheckoutContainerProps, type SuperstateSwapCheckoutRetryUiEvent, type SuperstateSwapCheckoutUiEvent, type SuperstateSwapCheckoutUiState, SuperstateSwapCheckoutView, type SuperstateSwapCheckoutViewProps, type SuperstateSwapLoadErrorReason, type SuperstateSwapStep, type SuperstateWalletStepInput, type SuperstateWalletUiEvent, type SuperstateWalletUiState, SuperstateWalletView, type SuperstateWalletViewProps, type SwapExecutionError, type SwapExecutionPhase, type SwapExecutionResult, type SwapOutputTokenState, type TaxDocumentAddressParts, type TaxDocumentFieldUi, type TaxDocumentFields, TaxDocumentModalContainer, type TaxDocumentModalContainerProps, type TaxDocumentModalUiEvent, type TaxDocumentModalUiState, TaxDocumentModalView, type TaxDocumentModalViewProps, type TaxDocumentScreenUi, type TaxDocumentState, type TokenSaleExecutionError, type TokenSaleExecutionPhase, type TokenSaleExecutionResult, USDC_ICON_URL, USDT_ICON_URL, type UseCoinListResult, type UseCoinListSignInCardViewModelOptions, type UseCoinListSignInCardViewModelResult, type UseCompleteOAuthOptions, type UseConnectWalletModalViewModelOptions, type UseConnectWalletModalViewModelResult, type UseConnectWalletOptions, type UseConnectWalletResult, type UseCountdownOptions, type UseErc20TokenBalancesOptions, type UseErc20TokenBalancesResult, type UseIdentityVerificationViewModelOptions, type UseIdentityVerificationViewModelResult, type UseKycTokenResult, type UseOfferDetailsOptions, type UseOfferDetailsResult, type UseOffersGridViewModelOptions, type UseOffersGridViewModelResult, type UseOffersOptions, type UseOffersResult, type UseOndoAmountViewModelOptions, type UseOndoAmountViewModelResult, type UseOndoBuyCheckoutViewModelOptions, type UseOndoBuyCheckoutViewModelResult, type UseOndoPriceOptions, type UseOndoPriceResult, type UseOndoReviewViewModelOptions, type UseOndoReviewViewModelResult, type UseOndoSidebarViewModelOptions, type UseOndoSidebarViewModelResult, type UseOndoSwapTransactionOptions, type UseOndoSwapTransactionResult, type UseOndoTradingStatusOptions, type UseOndoTradingStatusResult, type UseOndoWalletSelectViewModelOptions, type UseOndoWalletSelectViewModelResult, type UseOptionAddressesOptions, type UseOptionAddressesResult, type UseParticipationsOptions, type UseParticipationsResult, type UseRequirementsChecklistViewModelOptions, type UseRequirementsChecklistViewModelResult, type UseRequirementsOptions, type UseRequirementsResult, type UseSuperstateAmountViewModelOptions, type UseSuperstateAmountViewModelResult, type UseSuperstateReviewViewModelOptions, type UseSuperstateReviewViewModelResult, type UseSuperstateSidebarViewModelOptions, type UseSuperstateSidebarViewModelResult, type UseSuperstateSwapCheckoutViewModelOptions, type UseSuperstateSwapCheckoutViewModelResult, type UseSuperstateWalletViewModelOptions, type UseSuperstateWalletViewModelResult, type UseSwapOutputTokenOptions, type UseSwapOutputTokenResult, type UseSwapQuoteOptions, type UseSwapQuoteResult, type UseTaxDocumentModalViewModelOptions, type UseTaxDocumentModalViewModelResult, type UseTaxDocumentOptions, type UseTaxDocumentResult, type UseTokenMetadataOptions, type UseTokenMetadataResult, VerificationOverlay, type VerificationOverlayProps, type WalletAuthorizationError, type WalletAuthorizationPhase, type WalletAuthorizationResult, type WalletError, type WalletsStatus, type WriteContractParams, authorizeWallet, classifyWalletError, connectExternalWalletFlow, createCoinListClient, defaultCheckoutConfig, ensureErc20Allowance, executeOndoSwap, executeSwap, executeTokenSale, formatCountdown, formatMonthYear, offerIconUrl, ondoLoadErrorReason, prepareOndoSwap, quoteIsStale, quoteOverAsks, stablecoinIconUrl, submitErc20Approval, useCoinList, useCoinListSignInCardViewModel, useCompleteOAuth, useConnectWallet, useConnectWalletModalViewModel, useCountdown, useErc20TokenBalances, useIdentityVerificationViewModel, useKycToken, useOfferDetails, useOffers, useOffersGridViewModel, useOndoAmountViewModel, useOndoBuyCheckoutViewModel, useOndoPrice, useOndoReviewViewModel, useOndoSidebarViewModel, useOndoSwapTransaction, useOndoTradingStatus, useOndoWalletSelectViewModel, useOptionAddresses, useParticipations, useRequirements, useRequirementsChecklistViewModel, useSuperstateAmountViewModel, useSuperstateReviewViewModel, useSuperstateSidebarViewModel, useSuperstateSwapCheckoutViewModel, useSuperstateWalletViewModel, useSwapOutputToken, useSwapQuote, useTaxDocument, useTaxDocumentModalViewModel, useTokenMetadata, validateAmount, validateSuperstateAmount };
6110
+ export { type AuthState, type AuthorizeWalletParams, ChecklistStatus, CheckoutAssetUi, type CheckoutConfig, type CheckoutConfirmedWalletUi, CheckoutContainer, type CheckoutContainerProps, type CheckoutCtaUi, type CheckoutEmbeddedWalletUi, type CheckoutNetworkUi, type CheckoutSelectableInputAssetUi, type CheckoutStatusUi, type CheckoutWalletSelection, type CheckoutWalletTypeUi, type CheckoutWalletUi, type ClientAuthConfig, type ClientAuthNamespace, ClientAuthNamespaceImpl, type ClientAuthSession, type ClientCoinListTokenSaleNamespace, ClientCoinListTokenSaleNamespaceImpl, type ClientConfig, type ClientOndoNamespace, ClientOndoNamespaceImpl, type ClientRequirementsNamespace, ClientRequirementsNamespaceImpl, type ClientSuperstateSwapNamespace, ClientSuperstateSwapNamespaceImpl, type ClientSupportNamespace, ClientSupportNamespaceImpl, type CoinListClient, CoinListClientInitializationError, CoinListContext, CoinListContextProvider, type CoinListContextValue, CoinListProvider, type CoinListProviderProps, CoinListSignInButton, CoinListSignInCardContainer, type CoinListSignInCardContainerProps, type CoinListSignInCardUiEvent, type CoinListSignInCardUiState, CoinListSignInCardView, type CoinListSignInCardViewProps, CoinListStyleScope, type CoinListStyleScopeProps, type CoinListTokenSaleCheckoutConfig, type CompleteOAuthFailureReason, ConnectWallet, type ConnectWalletError, type ConnectWalletErrorCode, type ConnectWalletFlowError, type ConnectWalletFlowParams, type ConnectWalletFlowResult, ConnectWalletModalContainer, type ConnectWalletModalContainerProps, type ConnectWalletModalUiEvent, type ConnectWalletModalUiState, ConnectWalletModalView, type ConnectWalletModalViewProps, type ConnectWalletPhase, type ConnectWalletScreenUi, type ConnectWalletSignState, type ConnectWalletState, ConnectedWalletList, type ConnectedWalletListProps, type ConnectedWalletUi, ERC20_BALANCE_POLL_INTERVAL_MS, type Erc20AllowanceError, type Erc20AllowancePhase, type Erc20AllowanceResult, type Erc20ApprovalError, EvmWallet, type ExecuteOndoSwapParams, type ExecuteSwapParams, type ExecuteTokenSaleParams, IdentityVerificationContainer, type IdentityVerificationContainerProps, type IdentityVerificationUiEvent, type IdentityVerificationUiState, IdentityVerificationView, type IdentityVerificationViewProps, KycLevelName, type KycTokenErrorReason, type KycTokenState, type LoadOfferDetailsReason, type LoadOfferDetailsState, type LoadOffersReason, type LoadOffersState, type LoadOndoBuyTransactionState, type LoadOndoPriceState, type LoadOndoSellTransactionState, type LoadOndoTradingStatusState, type LoadOptionAddressesReason, type LoadOptionAddressesState, type LoadParticipationsReason, type LoadParticipationsState, type LoadRequirementsReason, type LoadRequirementsState, type LoadTokenMetadataState, Logger, OAUTH_CODE_VERIFIER_KEY, OAUTH_STATE_KEY, type OauthClientErrorReason, type OauthClientResult, OfferAssetCard, type OfferAssetCardProps, OfferAssetCardUi, OfferSaleCard, type OfferSaleCardProps, OfferSaleCardUi, OffersAssetGrid, type OffersAssetGridProps, OffersGridContainer, type OffersGridContainerProps, type OffersGridUiEvent, type OffersGridUiState, OffersGridView, type OffersGridViewProps, type OndoBuyAmountConfirmed, type OndoBuyAmountStepInput, type OndoBuyAmountUiEvent, type OndoBuyAmountUiState, type OndoBuyAmountValidation, OndoBuyAmountView, type OndoBuyAmountViewProps, OndoBuyCheckoutContainer, type OndoBuyCheckoutContainerProps, type OndoBuyCheckoutUiEvent, type OndoBuyCheckoutUiState, OndoBuyCheckoutView, type OndoBuyCheckoutViewProps, type OndoBuyExecutionResult, OndoBuyOrderConfirmed, type OndoBuyOrderPlaced, type OndoBuyOrderTerms, type OndoBuyPreparationResult, type OndoBuyQuoteStatusUi, type OndoBuyReviewStepInput, type OndoBuyReviewUiEvent, type OndoBuyReviewUiState, OndoBuyReviewView, type OndoBuyReviewViewProps, type OndoBuyStep, type OndoCheckoutConfig, type OndoLoadErrorReason, type OndoOrderConfirmedProps, type OndoOrderConfirmedUiEvent, type OndoOrderConfirmedUiState, type OndoOrderPlaced, type OndoOrderPlacedCore, type OndoSellAmountConfirmed, type OndoSellAmountStepInput, type OndoSellAmountUiEvent, type OndoSellAmountUiState, type OndoSellAmountValidation, OndoSellAmountView, type OndoSellAmountViewProps, type OndoSellAsset, type OndoSellBalanceUi, OndoSellCheckoutContainer, type OndoSellCheckoutContainerProps, type OndoSellCheckoutUiEvent, type OndoSellCheckoutUiState, OndoSellCheckoutView, type OndoSellCheckoutViewProps, type OndoSellExecutionResult, OndoSellOrderConfirmed, type OndoSellOrderConfirmedProps, type OndoSellOrderConfirmedUiEvent, type OndoSellOrderConfirmedUiState, type OndoSellOrderPlaced, type OndoSellOrderTerms, type OndoSellOutcomeUi, type OndoSellPreparationResult, type OndoSellQuoteStatusUi, type OndoSellReviewStepInput, type OndoSellReviewUiEvent, type OndoSellReviewUiState, OndoSellReviewView, type OndoSellReviewViewProps, type OndoSellSourceWalletUi, type OndoSellStep, type OndoSidebarPriceUi, type OndoSidebarUiState, OndoSidebarView, type OndoSidebarViewProps, type OndoSwapExecutionError, type OndoSwapExecutionPhase, type OndoSwapExecutionResult, type OndoSwapPreparationError, type OndoSwapPreparationPhase, type OndoSwapPreparationResult, type OndoWalletSelectStepInput, type OndoWalletSelectUiEvent, type OndoWalletSelectUiState, OndoWalletSelectView, type OndoWalletSelectViewProps, PinoLoggerOptions, type PrepareOndoBuyParams, type PrepareOndoSellParams, type PrepareOndoSwapParamsCore, type RequiredCheckoutConfig, RequirementItem, type RequirementItemProps, RequirementItemUi, RequirementStatus, RequirementVariant, RequirementsChecklistContainer, type RequirementsChecklistContainerProps, type RequirementsChecklistItemUi, type RequirementsChecklistUiEvent, type RequirementsChecklistUiState, RequirementsChecklistView, type RequirementsChecklistViewProps, type RequirementsData, type RequirementsVerificationUi, type SignState, SlippagePicker, type SlippagePickerProps, type SubmitErc20ApprovalResult, type SuperstateAmountConfirmed, type SuperstateAmountStepInput, type SuperstateAmountUiEvent, type SuperstateAmountUiState, type SuperstateAmountValidation, SuperstateAmountView, type SuperstateAmountViewProps, type SuperstateCheckoutConfig, SuperstateOrderConfirmed, type SuperstateOrderConfirmedProps, type SuperstateOrderConfirmedUiEvent, type SuperstateOrderConfirmedUiState, type SuperstateOrderPlaced, type SuperstateReviewStepInput, type SuperstateReviewUiEvent, type SuperstateReviewUiState, SuperstateReviewView, type SuperstateReviewViewProps, type SuperstateSidebarPriceUi, type SuperstateSidebarUiState, SuperstateSidebarView, type SuperstateSidebarViewProps, type SuperstateSlippageOptionUi, type SuperstateSlippageUi, SuperstateSwapCheckoutContainer, type SuperstateSwapCheckoutContainerProps, type SuperstateSwapCheckoutRetryUiEvent, type SuperstateSwapCheckoutUiEvent, type SuperstateSwapCheckoutUiState, SuperstateSwapCheckoutView, type SuperstateSwapCheckoutViewProps, type SuperstateSwapLoadErrorReason, type SuperstateSwapStep, type SuperstateWalletStepInput, type SuperstateWalletUiEvent, type SuperstateWalletUiState, SuperstateWalletView, type SuperstateWalletViewProps, type SwapExecutionError, type SwapExecutionPhase, type SwapExecutionResult, type SwapOutputTokenState, type TaxDocumentAddressParts, type TaxDocumentFieldUi, type TaxDocumentFields, TaxDocumentModalContainer, type TaxDocumentModalContainerProps, type TaxDocumentModalUiEvent, type TaxDocumentModalUiState, TaxDocumentModalView, type TaxDocumentModalViewProps, type TaxDocumentScreenUi, type TaxDocumentState, type TokenSaleExecutionError, type TokenSaleExecutionPhase, type TokenSaleExecutionResult, USDC_ICON_URL, USDT_ICON_URL, type UseCoinListResult, type UseCoinListSignInCardViewModelOptions, type UseCoinListSignInCardViewModelResult, type UseCompleteOAuthOptions, type UseConnectWalletModalViewModelOptions, type UseConnectWalletModalViewModelResult, type UseConnectWalletOptions, type UseConnectWalletResult, type UseCountdownOptions, type UseErc20BalanceOptions, type UseErc20BalanceResult, type UseErc20TokenBalancesOptions, type UseErc20TokenBalancesResult, type UseIdentityVerificationViewModelOptions, type UseIdentityVerificationViewModelResult, type UseKycTokenResult, type UseOfferDetailsOptions, type UseOfferDetailsResult, type UseOffersGridViewModelOptions, type UseOffersGridViewModelResult, type UseOffersOptions, type UseOffersResult, type UseOndoBuyAmountViewModelOptions, type UseOndoBuyAmountViewModelResult, type UseOndoBuyCheckoutViewModelOptions, type UseOndoBuyCheckoutViewModelResult, type UseOndoBuyReviewViewModelOptions, type UseOndoBuyReviewViewModelResult, type UseOndoBuyTransactionOptions, type UseOndoBuyTransactionResult, type UseOndoPriceOptions, type UseOndoPriceResult, type UseOndoSellAmountViewModelOptions, type UseOndoSellAmountViewModelResult, type UseOndoSellCheckoutViewModelOptions, type UseOndoSellCheckoutViewModelResult, type UseOndoSellReviewViewModelOptions, type UseOndoSellReviewViewModelResult, type UseOndoSellTransactionOptions, type UseOndoSellTransactionResult, type UseOndoSidebarViewModelOptions, type UseOndoSidebarViewModelResult, type UseOndoTradingStatusOptions, type UseOndoTradingStatusResult, type UseOndoWalletSelectViewModelOptions, type UseOndoWalletSelectViewModelResult, type UseOptionAddressesOptions, type UseOptionAddressesResult, type UseParticipationsOptions, type UseParticipationsResult, type UseRequirementsChecklistViewModelOptions, type UseRequirementsChecklistViewModelResult, type UseRequirementsOptions, type UseRequirementsResult, type UseSuperstateAmountViewModelOptions, type UseSuperstateAmountViewModelResult, type UseSuperstateReviewViewModelOptions, type UseSuperstateReviewViewModelResult, type UseSuperstateSidebarViewModelOptions, type UseSuperstateSidebarViewModelResult, type UseSuperstateSwapCheckoutViewModelOptions, type UseSuperstateSwapCheckoutViewModelResult, type UseSuperstateWalletViewModelOptions, type UseSuperstateWalletViewModelResult, type UseSwapOutputTokenOptions, type UseSwapOutputTokenResult, type UseSwapQuoteOptions, type UseSwapQuoteResult, type UseTaxDocumentModalViewModelOptions, type UseTaxDocumentModalViewModelResult, type UseTaxDocumentOptions, type UseTaxDocumentResult, type UseTokenMetadataOptions, type UseTokenMetadataResult, VerificationOverlay, type VerificationOverlayProps, type WalletAuthorizationError, type WalletAuthorizationPhase, type WalletAuthorizationResult, WalletError, type WalletsStatus, authorizeWallet, classifyWalletError, connectExternalWalletFlow, createCoinListClient, defaultCheckoutConfig, ensureErc20Allowance, executeOndoSwap, executeSwap, executeTokenSale, formatCountdown, formatMonthYear, formatSaleCardCountdown, offerIconUrl, ondoLoadErrorReason, pinoClientLogger, prepareOndoBuy, prepareOndoSell, quoteIsStale, quoteOverAsks, stablecoinIconUrl, submitErc20Approval, useCoinList, useCoinListSignInCardViewModel, useCompleteOAuth, useConnectWallet, useConnectWalletModalViewModel, useCountdown, useErc20Balance, useErc20TokenBalances, useIdentityVerificationViewModel, useKycToken, useOfferDetails, useOffers, useOffersGridViewModel, useOndoBuyAmountViewModel, useOndoBuyCheckoutViewModel, useOndoBuyReviewViewModel, useOndoBuyTransaction, useOndoPrice, useOndoSellAmountViewModel, useOndoSellCheckoutViewModel, useOndoSellReviewViewModel, useOndoSellTransaction, useOndoSidebarViewModel, useOndoTradingStatus, useOndoWalletSelectViewModel, useOptionAddresses, useParticipations, useRequirements, useRequirementsChecklistViewModel, useSuperstateAmountViewModel, useSuperstateReviewViewModel, useSuperstateSidebarViewModel, useSuperstateSwapCheckoutViewModel, useSuperstateWalletViewModel, useSwapOutputToken, useSwapQuote, useTaxDocument, useTaxDocumentModalViewModel, useTokenMetadata, validateAmount, validateSellAmount, validateSuperstateAmount };