@coinlist-co/react 0.12.2-rc.e1f6c82 → 0.12.2-rc.eea3be6

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.
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, MouseEventHandler } from 'react';
3
- import { A as AuthorizationCode, C as CodeVerifier, W as WalletError, a as AssetSymbol, E as EthereumChain, O as OfferVaultContract, b as EvmContractAddress, B as BlockchainAmount, c as CentrifugeVaultBuyTransaction, d as CentrifugeClaimDirection, e as CentrifugeNamespace, f as OfferId, g as OfferOptionId, h as AssetId, P as Participation, i as CoinListTokenSaleNamespace, j as OfferSwapContract, k as OndoBuyTransaction, l as OndoSellTransaction, m as OndoNamespace, n as OndoSwapTransactionCore, o as OrderBookSide, S as SwapQuote, p as Bps, q as EvmWalletAddress, r as SuperstateSwapNamespace, R as RequirementsNamespace, s as Requirement, t as WalletChallengeType, u as OfferOptionAddress, v as WalletsNamespace, w as Config, x as OAuthAccessToken, y as OffersNamespace, z as Erc20Namespace, T as TokensNamespace, D as StablecoinSymbol, F as Erc20Asset, G as CoinListTokenSaleOfferDetail, H as OfferDetail, I as CentrifugeVaultLegId, J as CentrifugeVaultOfferDetail, K as Seconds, L as AsyncOfferDetail, M as Offer, N as TokenMetadata, Q as RequirementStatusInfo, U as KycLevelName, V as RequirementType, X as RequirementStatusValue, Y as RequirementId, Z as PinoLoggerOptions, _ as Logger, $ as BuildCentrifugeVaultBuyParams, a0 as BuildOndoBuyParams, a1 as OndoSwapOfferDetail, a2 as BuildOndoSellParams, a3 as OndoQuote, a4 as OndoQuoteSize, a5 as OndoTradingStatus, a6 as AssetDecimals, a7 as SuperstateSwapOfferDetail, a8 as CentrifugeVaultLeg, a9 as CentrifugeVault, aa as OfferOptionAddressId, ab as DocumentSubmission, ac as CentrifugeVaultStatus, ad as CentrifugeVaultRef, ae as TokenIdentifier } from '../time-Bbqlt2x7.js';
3
+ import { A as AuthorizationCode, C as CodeVerifier, W as WalletError, E as EthereumChain, a as AssetSymbol, O as OfferVaultContract, b as EvmContractAddress, B as BlockchainAmount, c as CentrifugeVaultBuyTransaction, d as CentrifugeClaimDirection, e as CentrifugeNamespace, f as CoinListTokenSaleOfferDetail, g as OfferOptionId, S as StablecoinSymbol, P as Participation, h as CoinListTokenSaleNamespace, i as OfferSwapContract, j as OndoBuyTransaction, k as OndoSellTransaction, l as OndoNamespace, m as OndoSwapTransactionCore, n as OrderBookSide, o as OfferId, p as SwapQuote, q as Bps, r as EvmWalletAddress, s as SuperstateSwapNamespace, R as RequirementsNamespace, t as Requirement, u as WalletChallengeType, v as OfferOptionAddress, w as WalletsNamespace, x as Config, y as OAuthAccessToken, z as OffersNamespace, D as Erc20Namespace, T as TokensNamespace, F as Offer, G as TokenMetadata, H as OfferDetail, I as Erc20Asset, J as CentrifugeVaultLegId, K as CentrifugeVaultOfferDetail, L as Seconds, M as AsyncOfferDetail, N as RequirementStatusInfo, Q as KycLevelName, U as RequirementType, V as RequirementStatusValue, X as RequirementId, Y as PinoLoggerOptions, Z as Logger, _ as CentrifugeVaultStatus, $ as CentrifugeVaultRef, a0 as BuildOndoBuyParams, a1 as OndoSwapOfferDetail, a2 as BuildOndoSellParams, a3 as OndoQuote, a4 as OndoQuoteSize, a5 as OndoTradingStatus, a6 as AssetDecimals, a7 as SuperstateSwapOfferDetail, a8 as CentrifugeVaultLeg, a9 as CentrifugeVault, aa as OfferOptionAddressId, ab as DocumentSubmission, ac as TokenIdentifier } from '../time-qZW4aYYp.js';
4
4
  import { Hash } from 'viem';
5
- import { E as EvmWallet, C as ConnectWallet, F as FormattedAmountAssetUi, T as TxExplorerUrl, A as AssetIconUrl, W as WalletSelection, a as WalletLabelResolver, S as ShortenedWalletAddress, b as FormattedPercentUi, N as NonEmptyArray, c as TokenRegistrySnapshot } from '../token-registry-snapshot-DttZXGvY.js';
5
+ import { E as EvmWallet, C as ConnectWallet, W as WalletSelection, F as FormattedAmountAssetUi, T as TxExplorerUrl, A as AssetIconUrl, a as WalletLabelResolver, S as ShortenedWalletAddress, b as FormattedPercentUi, N as NonEmptyArray, c as TokenRegistrySnapshot } from '../token-registry-snapshot-CMrhSBun.js';
6
6
 
7
7
  type AuthState = 'unknown' | 'logged-in' | 'logged-out';
8
8
  /** Discriminated error reasons from {@link CoinListClient.completeOAuth}. */
@@ -73,7 +73,7 @@ interface ClientAuthNamespace {
73
73
  logout(): void;
74
74
  }
75
75
 
76
- type Erc20AllowancePhase = 'checking-allowance' | 'resetting-allowance' | 'confirming-allowance-reset' | 'approving' | 'confirming-approval';
76
+ type Erc20AllowancePhase = 'checking-allowance' | ResetThenApprovePhase;
77
77
  type Erc20AllowanceError = {
78
78
  step: 'allowance-check';
79
79
  } | Erc20ApprovalError;
@@ -84,24 +84,32 @@ type Erc20ApprovalError = {
84
84
  } | {
85
85
  step: 'approval-reverted';
86
86
  };
87
+ /**
88
+ * The phases {@link resetThenApprove} reports, in order. The two reset phases
89
+ * occur only when there is a non-zero allowance to reset.
90
+ */
91
+ type ResetThenApprovePhase = 'resetting-allowance' | 'confirming-allowance-reset' | 'approving' | 'confirming-approval';
87
92
 
88
93
  /**
89
- * Progress phases emitted while a request is being prepared, in order. An
90
- * allowance that already covers the deposit skips the approval phases.
91
- *
92
- * @alpha
94
+ * Progress phases emitted while a backend-built order is being prepared, in
95
+ * the order they occur. An allowance that already covers the order skips the
96
+ * approval phases.
93
97
  */
94
- type CentrifugeBuyPreparationPhase = Erc20AllowancePhase | 'building-transaction';
98
+ type ApproveThenBuildPhase = Erc20AllowancePhase | 'building-transaction';
95
99
  /**
96
100
  * A step-tagged reason a preparation failed.
97
101
  *
98
- * `insufficient-allowance` is the one with a remedy that is not a new
99
- * approval: the approval this flow just mined is not the one frontline sees,
100
- * usually because its node is a block behind. Retrying reads it again.
102
+ * Every arm names a *remedy* rather than a provider or a trade: an unsupported
103
+ * chain, a refused approval and a build that would not complete are fixed the
104
+ * same way whichever token was being approved, and whoever built it.
101
105
  *
102
- * @alpha
106
+ * `insufficient-allowance` is separated from the generic build failure because
107
+ * it is the one with a remedy: the backend reads the allowance itself before
108
+ * building, so reaching it means the approval this flow just mined is not the
109
+ * one the backend sees. That is usually its RPC node lagging a block behind,
110
+ * which retrying fixes - so it is a retry, not a re-approval.
103
111
  */
104
- type CentrifugeBuyPreparationError = {
112
+ type ApproveThenBuildError = {
105
113
  step: 'unsupported-chain';
106
114
  chain: EthereumChain;
107
115
  } | Erc20AllowanceError | {
@@ -109,14 +117,34 @@ type CentrifugeBuyPreparationError = {
109
117
  } | {
110
118
  step: 'build-transaction';
111
119
  };
112
- /** @alpha */
113
- type CentrifugeBuyPreparationResult = {
120
+ /**
121
+ * A prepared order of whichever kind was asked for, or the step that stopped
122
+ * it. Generic in the transaction, so a caller gets back the type its `build`
123
+ * returned.
124
+ */
125
+ type ApproveThenBuildResult<T> = {
114
126
  type: 'success';
115
- transaction: CentrifugeVaultBuyTransaction;
127
+ transaction: T;
116
128
  } | {
117
129
  type: 'error';
118
- error: CentrifugeBuyPreparationError;
130
+ error: ApproveThenBuildError;
119
131
  };
132
+
133
+ /**
134
+ * Progress phases emitted while a request is being prepared, in order. An
135
+ * allowance that already covers the deposit skips the approval phases.
136
+ *
137
+ * @alpha
138
+ */
139
+ type CentrifugeBuyPreparationPhase = ApproveThenBuildPhase;
140
+ /**
141
+ * A step-tagged reason a preparation failed - see {@link ApproveThenBuildError}.
142
+ *
143
+ * @alpha
144
+ */
145
+ type CentrifugeBuyPreparationError = ApproveThenBuildError;
146
+ /** @alpha */
147
+ type CentrifugeBuyPreparationResult = ApproveThenBuildResult<CentrifugeVaultBuyTransaction>;
120
148
  /** @alpha */
121
149
  type PrepareCentrifugeBuyParams = {
122
150
  wallet: EvmWallet;
@@ -326,6 +354,10 @@ type TokenSaleExecutionPhase = 'checking-allowance' | 'resetting-allowance' | 'c
326
354
  /**
327
355
  * A step-tagged reason `ClientCoinListTokenSaleNamespace.execute` failed.
328
356
  *
357
+ * The first three are refusals before anything is signed: the offer names no
358
+ * funding contract on the chain, does not accept the coin there, or has no
359
+ * option with that id.
360
+ *
329
361
  * The reset-to-zero step (`allowance-reset` / `allowance-reset-reverted`) is
330
362
  * reported distinctly from the main approval (`approval` /
331
363
  * `approval-reverted`, reused from {@link Erc20ApprovalError}) so consumers can
@@ -333,6 +365,12 @@ type TokenSaleExecutionPhase = 'checking-allowance' | 'resetting-allowance' | 'c
333
365
  * reverted on-chain.
334
366
  */
335
367
  type TokenSaleExecutionError = {
368
+ step: 'unsupported-chain';
369
+ } | {
370
+ step: 'unsupported-asset';
371
+ } | {
372
+ step: 'unknown-option';
373
+ } | {
336
374
  step: 'allowance-check';
337
375
  } | {
338
376
  step: 'allowance-reset';
@@ -351,17 +389,35 @@ type TokenSaleExecutionResult = {
351
389
  type: 'error';
352
390
  error: TokenSaleExecutionError;
353
391
  };
392
+ /**
393
+ * Which approval a participation is recorded against.
394
+ *
395
+ * `fresh` sends a new one, which is what every first attempt does. `mined`
396
+ * reuses one that already mined for this amount - the `approvalTxHash` of a
397
+ * `participation` failure - so retrying the write asks the wallet for nothing.
398
+ */
399
+ type TokenSaleApproval = {
400
+ type: 'fresh';
401
+ } | {
402
+ type: 'mined';
403
+ txHash: Hash;
404
+ };
354
405
  type ExecuteTokenSaleParams = {
355
406
  wallet: EvmWallet;
356
- offerId: OfferId;
357
- offerOptionId: OfferOptionId;
358
- assetId: AssetId;
359
- /** ERC-20 the user pays with (e.g. USDC/USDT). */
360
- paymentTokenAddress: EvmContractAddress;
361
- /** Contract that pulls the payment — the `approve()` spender. */
362
- fundingContractAddress: EvmContractAddress;
407
+ /**
408
+ * The sale being bought into. The funding contract, the coin's address and
409
+ * its asset id are all read off it, so the caller never supplies one.
410
+ */
411
+ offer: CoinListTokenSaleOfferDetail;
412
+ /** The option being bought, which sets the price. */
413
+ optionId: OfferOptionId;
363
414
  chain: EthereumChain;
415
+ /** The coin the user pays in. It must be one of the offer's funding assets. */
416
+ inputAsset: StablecoinSymbol;
417
+ /** How much of `inputAsset` to commit, in its base units. */
364
418
  amount: BlockchainAmount;
419
+ /** Defaults to `{ type: 'fresh' }`. */
420
+ approval?: TokenSaleApproval;
365
421
  onProgress?: (phase: TokenSaleExecutionPhase) => void;
366
422
  };
367
423
 
@@ -388,28 +444,13 @@ interface ClientCoinListTokenSaleNamespace extends CoinListTokenSaleNamespace {
388
444
  * Progress phases emitted while an order is being prepared, in the order they
389
445
  * occur. An allowance that already covers the order skips the approval phases.
390
446
  */
391
- type OndoSwapPreparationPhase = Erc20AllowancePhase | 'building-transaction';
447
+ type OndoSwapPreparationPhase = ApproveThenBuildPhase;
392
448
  /**
393
- * A step-tagged reason a preparation failed.
394
- *
395
- * Shared by both directions because every arm names a *remedy* rather than a
396
- * trade: an unsupported chain, a refused approval and a build that would not
397
- * complete are fixed the same way whichever token was being approved.
398
- *
399
- * `insufficient-allowance` is separated from the generic build failure because
400
- * it is the one with a remedy: frontline reads the allowance before asking
401
- * Ninshubur for anything, so reaching it means the approval this flow just
402
- * mined is not the one frontline sees. That is usually its RPC node lagging a
403
- * block behind, which retrying fixes - so it is a retry, not a re-approval.
449
+ * A step-tagged reason a preparation failed. Shared by both directions, and
450
+ * with every other backend-built checkout, because every arm names a remedy
451
+ * rather than a trade - see {@link ApproveThenBuildError}.
404
452
  */
405
- type OndoSwapPreparationError = {
406
- step: 'unsupported-chain';
407
- chain: EthereumChain;
408
- } | Erc20AllowanceError | {
409
- step: 'insufficient-allowance';
410
- } | {
411
- step: 'build-transaction';
412
- };
453
+ type OndoSwapPreparationError = ApproveThenBuildError;
413
454
  /**
414
455
  * A prepared order of whichever kind was asked for, or the step that stopped
415
456
  * it.
@@ -417,13 +458,7 @@ type OndoSwapPreparationError = {
417
458
  * Generic in the transaction rather than a union over the two, so a caller
418
459
  * that asked for a sale cannot be handed a purchase to narrow.
419
460
  */
420
- type OndoSwapPreparationResult<T> = {
421
- type: 'success';
422
- transaction: T;
423
- } | {
424
- type: 'error';
425
- error: OndoSwapPreparationError;
426
- };
461
+ type OndoSwapPreparationResult<T> = ApproveThenBuildResult<T>;
427
462
  type OndoBuyPreparationResult = OndoSwapPreparationResult<OndoBuyTransaction>;
428
463
  type OndoSellPreparationResult = OndoSwapPreparationResult<OndoSellTransaction>;
429
464
  /** What both preparations take, before the two fields whose meaning forks. */
@@ -477,12 +512,21 @@ type OndoSwapExecutionPhase = 'broadcasting-swap' | 'confirming-swap';
477
512
  * `quote-expired` is a refusal to broadcast rather than a failure of a
478
513
  * broadcast: it would revert on chain and cost the user gas, and it is fixed
479
514
  * by building a fresh transaction.
515
+ *
516
+ * `swap` means the wallet never sent it, so placing again is safe.
517
+ * `swap-unconfirmed` means it was sent and the receipt wait failed: the swap
518
+ * may still mine, and placing again can fill the order twice. `txHash` is
519
+ * the transaction to look up before doing anything else.
480
520
  */
481
521
  type OndoSwapExecutionError = {
482
522
  step: 'quote-expired';
483
523
  } | {
484
524
  step: 'swap';
485
525
  cause: WalletError;
526
+ } | {
527
+ step: 'swap-unconfirmed';
528
+ txHash: Hash;
529
+ cause: WalletError;
486
530
  } | {
487
531
  step: 'swap-reverted';
488
532
  };
@@ -585,9 +629,21 @@ type SwapExecutionError = {
585
629
  step: 'swap-paused';
586
630
  } | {
587
631
  step: 'swap-stopped';
588
- } | Erc20AllowanceError | {
632
+ } | Erc20AllowanceError
633
+ /** The wallet never sent the swap, so swapping again is safe. */
634
+ | {
589
635
  step: 'swap';
590
636
  cause: WalletError;
637
+ }
638
+ /**
639
+ * The swap was sent and the receipt wait failed. It may still mine, so
640
+ * swapping again can fill the order twice: `txHash` is the transaction to
641
+ * look up before doing anything else.
642
+ */
643
+ | {
644
+ step: 'swap-unconfirmed';
645
+ txHash: Hash;
646
+ cause: WalletError;
591
647
  } | {
592
648
  step: 'swap-reverted';
593
649
  };
@@ -642,9 +698,21 @@ type WalletAuthorizationError = {
642
698
  cause: WalletError;
643
699
  } | {
644
700
  step: 'allow-wallet';
645
- } | {
701
+ }
702
+ /** The wallet never sent the allow-list transaction. */
703
+ | {
646
704
  step: 'broadcast';
647
705
  cause: WalletError;
706
+ }
707
+ /**
708
+ * The allow-list transaction was sent and the receipt wait failed. It may
709
+ * still mine, so authorizing again would send a second one: `txHash` is the
710
+ * transaction to look up first.
711
+ */
712
+ | {
713
+ step: 'broadcast-unconfirmed';
714
+ txHash: Hash;
715
+ cause: WalletError;
648
716
  } | {
649
717
  step: 'not-authorized';
650
718
  };
@@ -1025,140 +1093,348 @@ interface CoinListSignInCardContainerProps {
1025
1093
  declare function CoinListSignInCardContainer({ state, onSignIn, onClose, className, }?: CoinListSignInCardContainerProps): ReactNode;
1026
1094
 
1027
1095
  /**
1028
- * A deposit request that has been broadcast and mined.
1029
- *
1030
- * Named without `Buy` so it does not collide with the dialog component when
1031
- * both are re-exported from the client barrel.
1032
- *
1033
- * Success means the request was placed. The fund fulfils it later, at a price
1034
- * set then.
1035
- *
1036
- * @alpha
1096
+ * What the grid fetches, pre-fetched on the server instead. Each half is
1097
+ * independent: seed `offers` (via `CoinListServer#offers.list()`) and the
1098
+ * client still fetches the registry, seed `tokens` (via
1099
+ * `CoinListServer#tokens.list()`) and it still fetches the offers, seed both
1100
+ * and the grid makes no request of its own.
1037
1101
  */
1038
- type CentrifugeOrderPlaced = {
1039
- wallet: EvmWallet;
1040
- /** What the request deposits, in the funding token's base units. */
1041
- amount: BlockchainAmount;
1042
- transaction: CentrifugeVaultBuyTransaction;
1043
- txHash: Hash;
1044
- };
1102
+ interface OffersGridData {
1103
+ offers?: Offer[];
1104
+ tokens?: TokenMetadata[];
1105
+ }
1045
1106
 
1107
+ interface OffersGridContainerProps {
1108
+ /** Maximum number of columns to render when horizontal space allows. */
1109
+ maxColumns?: number;
1110
+ /** Optional className applied to the grid element. */
1111
+ className?: string;
1112
+ /** Optional className applied to the outer wrapper element. */
1113
+ containerClassName?: string;
1114
+ /** Optional loading slot shown while offers are being fetched. */
1115
+ loading?: ReactNode;
1116
+ /** Optional error slot shown when loading offers fails. */
1117
+ error?: ReactNode;
1118
+ /** Optional empty state slot shown when there are no available offers. */
1119
+ emptyState?: ReactNode;
1120
+ /** Optional per-offer click handler; when omitted, cards are not clickable. */
1121
+ onOfferClick?: (offer: Offer) => void;
1122
+ /**
1123
+ * What the grid would otherwise fetch, pre-fetched on the server: `offers`
1124
+ * via `CoinListServer#offers.list()`, `tokens` via
1125
+ * `CoinListServer#tokens.list()`. Each half skips its own client-side
1126
+ * fetch; pass both for a grid that makes no request of its own.
1127
+ */
1128
+ data?: OffersGridData;
1129
+ /**
1130
+ * Default `true`. When `false` nothing is fetched, so the container can be
1131
+ * mounted while the grid is not needed yet.
1132
+ */
1133
+ enabled?: boolean;
1134
+ }
1046
1135
  /**
1047
- * A filled Ondo order, as the confirmation dialog and the host's
1048
- * `onOrderConfirmed` callback need it.
1136
+ * Displays a responsive live-sale grid of {@link OfferSaleCard}, backed by
1137
+ * {@link useOffersGridViewModel}. Each card is named and illustrated by the
1138
+ * public token registry where it lists the offer's token, and by the offer's
1139
+ * own fields otherwise - list offers carry no display name, so an unlisted
1140
+ * one shows logo + tagline until the host maps from detail. For equities /
1141
+ * past-sales browse rows, compose {@link OffersAssetGrid} instead.
1049
1142
  *
1050
- * It lives here rather than beside either review viewmodel because both
1051
- * products produce one. Declaring it in `ondo/buy/` would make the sell
1052
- * viewmodel import a sibling product's module - which the `shared/` ladder
1053
- * forbids for the reason it always does: two products that reach sideways can
1054
- * no longer be moved or deleted on their own.
1143
+ * Pass `data` (offers and tokens pre-fetched server-side) to use them as-is
1144
+ * and skip the client-side fetches. Pass `enabled={false}` to skip the fetches
1145
+ * when the container is mounted but the grid is not needed yet. Uses the
1146
+ * `loading` / `error` / `emptyState` slots when provided; otherwise renders
1147
+ * the standard fallbacks. Cards are interactive only when `onOfferClick` is
1148
+ * provided.
1055
1149
  *
1056
- * It names no asset beyond the one that was spent. The transaction does not
1057
- * carry one, and rebuilding an `Erc20Asset` here would mean inventing a
1058
- * `decimals` - the quote's answers for a different quantity, and the
1059
- * transaction's is a scale rather than a property of the token. A host that
1060
- * wants to know what was traded has the `offer` it passed in.
1150
+ * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
1151
+ * needed.
1061
1152
  */
1062
- type OndoOrderPlaced = OndoBuyOrderPlaced | OndoSellOrderPlaced;
1153
+ declare function OffersGridContainer({ data, onOfferClick, enabled, ...viewProps }?: OffersGridContainerProps): ReactNode;
1154
+
1063
1155
  /**
1064
- * The common half of an {@link OndoOrderPlaced}, before its side's terms.
1065
- *
1066
- * The transaction that was broadcast is not here, because it is not common:
1067
- * it carries the same `side` this order does, and saying so in prose left a
1068
- * sell order holding a buy transaction constructible and its
1069
- * `minimumReceiveOutputAmount` unreachable behind a narrowed `side`. Each arm
1070
- * names its own instead.
1156
+ * One image as an `<img>` renders it: a `src` for a consumer that takes a
1157
+ * single URL, and the `srcSet` candidates for one that also knows the size
1158
+ * it renders at. `srcSet` is absent for a vector logo and for the offer's own
1159
+ * artwork, neither of which offers the browser a choice.
1071
1160
  */
1072
- type OndoOrderPlacedCore = {
1073
- txHash: Hash;
1074
- /** What the trader spent, in the input asset's base units. */
1075
- amount: BlockchainAmount;
1076
- wallet: EvmWallet;
1161
+ type LogoImageUi = {
1162
+ src: string;
1163
+ srcSet?: string;
1077
1164
  };
1078
- /** A filled purchase: a stablecoin spent, the asset received. */
1079
- type OndoBuyOrderPlaced = OndoOrderPlacedCore & OndoBuyOrderTerms;
1080
- /** A filled sale: the asset spent, the settlement coin received. */
1081
- type OndoSellOrderPlaced = OndoOrderPlacedCore & OndoSellOrderTerms;
1082
1165
  /**
1083
- * A buy spends a stablecoin the SDK ships a registry entry for, so its input
1084
- * asset is narrowed to one - which is what keeps `TOKEN_REGISTRY.erc20` total
1085
- * at the call sites that name it.
1166
+ * The logo a catalogue card renders for an offer, with the registry's
1167
+ * dark-theme counterpart when it configures one.
1168
+ *
1169
+ * `dark` is `null` rather than absent so a renderer has to decide what to do
1170
+ * without one: fall back to `light`, which is the registry's own rule.
1086
1171
  */
1087
- type OndoBuyOrderTerms = {
1088
- side: 'buy';
1089
- inputAsset: StablecoinSymbol;
1090
- /** The purchase that was broadcast, and the deposit it was struck against. */
1091
- transaction: OndoBuyTransaction;
1172
+ type OfferLogoUi = {
1173
+ light: LogoImageUi;
1174
+ dark: LogoImageUi | null;
1092
1175
  };
1093
- /**
1094
- * A sell spends the Ondo asset, which is in no registry: its address and
1095
- * decimals come off the quote, and only its symbol is carried here. Hence the
1096
- * wider `AssetSymbol`, and hence a SUM rather than one widened field - a buy
1097
- * that lost its stablecoin guarantee would be the cost of sharing one.
1098
- */
1099
- type OndoSellOrderTerms = {
1100
- side: 'sell';
1101
- inputAsset: AssetSymbol;
1102
- /** The sale that was broadcast, and the floor under the proceeds it names. */
1103
- transaction: OndoSellTransaction;
1176
+ declare const OfferLogoUi: {
1177
+ /**
1178
+ * The registry's logo for the token an offer is about, or the offer's own
1179
+ * artwork otherwise, or `null` when neither exists.
1180
+ *
1181
+ * The registry wins when both exist because it is the token's real artwork
1182
+ * where `Offer.logoUrl` is catalogue artwork, and because a swap publishes
1183
+ * without artwork more often than not - which is why `logoUrl` is `null`
1184
+ * on the swap variants.
1185
+ */
1186
+ fromOffer: (offer: {
1187
+ logoUrl: string | null;
1188
+ }, tokenMetadata: TokenMetadata | null) => OfferLogoUi | null;
1104
1189
  };
1105
1190
 
1106
1191
  /**
1107
- * The wallets a checkout can spend from, supplied by the host.
1108
- *
1109
- * The SDK ships no wallet stack and is not coupled to Privy, AppKit or
1110
- * anything else - a partner may be a wallet provider themselves - so wallet
1111
- * discovery and connection are inverted onto the host. It hands over ready
1112
- * {@link EvmWallet}s and two lambdas; the SDK decides nothing about how they
1113
- * came to exist.
1114
- *
1115
- * There is no separate wallet model here on purpose: `EvmWallet` already
1116
- * carries the `address`, so a `{ address, signer }` pair would be a second
1117
- * wallet type to keep in sync with the first.
1192
+ * An offer as {@link OfferAssetCard} renders it. Browse chrome: circular
1193
+ * `logo`, `name`, and asset `symbol`. No wordmark.
1118
1194
  *
1119
- * Everything the row displays beyond the address - the network name - comes
1120
- * from the checkout's execution chain rather than from the wallet, because
1121
- * that is the chain the transaction goes to whatever the wallet is currently
1122
- * pointed at.
1195
+ * All three come from the public token registry when the caller hands over
1196
+ * the metadata of the token the offer is about. Without it, `fromOffer`
1197
+ * omits `name` and `symbol` - the list payload has neither - so a list-mapped
1198
+ * card is honest about being logo-only, and `fromDetail` reads them from the
1199
+ * detail payload (`name`, `asset.code`).
1123
1200
  */
1124
- type CheckoutWalletSelection = {
1125
- /**
1126
- * The user's embedded (custodial) wallets, in display order. Empty when they
1127
- * have none, which is a normal state, not an error.
1128
- */
1129
- embedded: EvmWallet[];
1130
- /** The connected external wallet, or `null` while none is connected. */
1131
- external: EvmWallet | null;
1201
+ type OfferAssetCardUi = {
1202
+ id: OfferId;
1203
+ /** Absent when neither the registry nor a detail payload names the offer. */
1204
+ name?: string;
1205
+ /** Absent when neither the registry nor a detail payload carries a ticker. */
1206
+ symbol?: string;
1207
+ /** `null` when neither the registry nor the offer carries artwork. */
1208
+ logo: OfferLogoUi | null;
1209
+ };
1210
+ declare const OfferAssetCardUi: {
1132
1211
  /**
1133
- * A wallet the host has already settled on, or `null` to let the user pick.
1134
- *
1135
- * When set, a checkout that supports it skips its wallet step entirely and
1136
- * opens on the amount, renumbering the steps that remain. That is for the
1137
- * host that already knows the answer - a sell page reached from a position
1138
- * knows which wallet holds it, and asking again would be a question with one
1139
- * possible answer.
1140
- *
1141
- * It does not have to appear in `embedded` or `external`. The host supplies a
1142
- * ready {@link EvmWallet} either way, and the SDK never resolves this back to
1143
- * a row.
1144
- *
1145
- * **Only the Ondo sell checkout honours it today.** The field is on this seam
1146
- * rather than on one provider's config because nothing about it is Ondo's -
1147
- * any flow that opens on a wallet step could skip one - but a provider that
1148
- * has not adopted it ignores it rather than half-implementing it, so do not
1149
- * assume a skip from the field being set.
1212
+ * `tokenMetadata` is the registry's entry for the token the offer is about
1213
+ * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The
1214
+ * registry names win over the offer's own where both exist: they are the
1215
+ * token's canonical name, ticker and artwork, where the offer's are
1216
+ * catalogue copy.
1150
1217
  */
1151
- preselected: EvmWallet | null;
1218
+ fromOffer: (offer: Offer, tokenMetadata?: TokenMetadata | null) => OfferAssetCardUi;
1219
+ fromDetail: (detail: OfferDetail, tokenMetadata?: TokenMetadata | null) => OfferAssetCardUi;
1220
+ };
1221
+
1222
+ interface OfferAssetCardProps {
1223
+ offer: OfferAssetCardUi;
1224
+ /** When set, the whole card is the hit target. */
1225
+ onClick?: () => void;
1226
+ /** Optional className applied to the card root element. */
1227
+ className?: string;
1228
+ /** Optional className applied to an outer wrapper element. */
1229
+ containerClassName?: string;
1230
+ }
1231
+ /**
1232
+ * Light browse-row catalogue card. Self-scoped. Header is the offer's `logo`
1233
+ * (the token registry's where it lists the token, with its dark-theme
1234
+ * variant, the catalogue's otherwise) beside `name` (h2) and asset `symbol`
1235
+ * under it — not a wordmark.
1236
+ * Responsive hug: tighter pad / logo / type below `md`, desktop keeps the
1237
+ * H4 + 48px logo row. Hosts compose this beside {@link OfferSaleCard}; the
1238
+ * card does not pick a variant itself.
1239
+ */
1240
+ declare function OfferAssetCard({ offer, onClick, className, containerClassName, }: OfferAssetCardProps): ReactNode;
1241
+
1242
+ /**
1243
+ * An offer as {@link OfferSaleCard} renders it. Countdown copy is derived in
1244
+ * the leaf from `startsAt` / `endsAt` so it can tick; the mapper does not
1245
+ * invent a price, FDV, unlock schedule, banner overlay, or wordmark.
1246
+ *
1247
+ * `name` and `logo` come from the public token registry when the caller
1248
+ * hands over the metadata of the token the offer is about, and from the
1249
+ * offer otherwise. The list payload carries no name, so `fromOffer` leaves
1250
+ * `name` absent without registry metadata - do not derive one from `slug`.
1251
+ * The card pairs `logo` with `name` as an h2 and renders each only when
1252
+ * present. Prefer {@link OfferSaleCardUi.fromDetail} when the host has a
1253
+ * name and no registry answer.
1254
+ *
1255
+ * `tagline` and `startsAt` are null for an offer that runs no sale window, an
1256
+ * Ondo swap: the card then omits the tagline and, with nothing to count down
1257
+ * to, reads as live.
1258
+ */
1259
+ type OfferSaleCardUi = {
1260
+ id: OfferId;
1261
+ /** Absent when neither the registry nor a detail payload names the offer. */
1262
+ name?: string;
1263
+ tagline: string | null;
1264
+ /** `null` when neither the registry nor the offer carries artwork. */
1265
+ logo: OfferLogoUi | null;
1266
+ startsAt: Date | null;
1267
+ endsAt: Date | null;
1268
+ };
1269
+ declare const OfferSaleCardUi: {
1270
+ /**
1271
+ * `tokenMetadata` is the registry's entry for the token the offer is about
1272
+ * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The
1273
+ * registry names win over the offer's own where both exist: they are the
1274
+ * token's canonical name and artwork, where the offer's are catalogue copy.
1275
+ */
1276
+ fromOffer: (offer: Offer, tokenMetadata?: TokenMetadata | null) => OfferSaleCardUi;
1277
+ fromDetail: (detail: OfferDetail, tokenMetadata?: TokenMetadata | null) => OfferSaleCardUi;
1278
+ };
1279
+
1280
+ interface OfferSaleCardProps {
1281
+ offer: OfferSaleCardUi;
1282
+ /** Host click handler. View offer always renders; this wires the hit target. */
1283
+ onClick?: () => void;
1284
+ /** Optional className applied to the card root element. */
1285
+ className?: string;
1286
+ /** Optional className applied to an outer wrapper element. */
1287
+ containerClassName?: string;
1288
+ }
1289
+ /**
1290
+ * Dark live-sale catalogue card. Self-scoped. Header is the offer's `logo`
1291
+ * (the token registry's where it lists the token, the catalogue's otherwise)
1292
+ * beside the `name` as an h2, then the tagline — not a wordmark. The same
1293
+ * logo is painted as a faint right-shifted watermark over the gradient.
1294
+ * Responsive hug layout; View offer always renders. No token price, FDV or unlock.
1295
+ */
1296
+ declare function OfferSaleCard({ offer, onClick, className, containerClassName, }: OfferSaleCardProps): ReactNode;
1297
+
1298
+ /**
1299
+ * A deposit request that has been broadcast and mined.
1300
+ *
1301
+ * Named without `Buy` so it does not collide with the dialog component when
1302
+ * both are re-exported from the client barrel.
1303
+ *
1304
+ * Success means the request was placed. The fund fulfils it later, at a price
1305
+ * set then.
1306
+ *
1307
+ * @alpha
1308
+ */
1309
+ type CentrifugeOrderPlaced = {
1310
+ wallet: EvmWallet;
1311
+ /** What the request deposits, in the funding token's base units. */
1312
+ amount: BlockchainAmount;
1313
+ transaction: CentrifugeVaultBuyTransaction;
1314
+ txHash: Hash;
1315
+ };
1316
+
1317
+ /**
1318
+ * A token-sale order the checkout placed: the approval mined and the
1319
+ * participation is recorded.
1320
+ *
1321
+ * It is a commitment, not a purchase. The sale pulls the payment through the
1322
+ * approval and allocates tokens when it settles, so `participation.status`
1323
+ * starts out pending.
1324
+ *
1325
+ * @alpha
1326
+ */
1327
+ type TokenSaleOrderPlaced = {
1328
+ /** The wallet that approved the payment, and that receives the tokens. */
1329
+ wallet: EvmWallet;
1330
+ /** What was committed, in `inputAsset`'s base units. */
1331
+ amount: BlockchainAmount;
1332
+ inputAsset: StablecoinSymbol;
1333
+ participation: Participation;
1334
+ /** The approval the participation was recorded against. */
1335
+ approvalTxHash: Hash;
1336
+ };
1337
+
1338
+ /**
1339
+ * A filled Ondo order, as the confirmation dialog and the host's
1340
+ * `onOrderConfirmed` callback need it.
1341
+ *
1342
+ * It lives here rather than beside either review viewmodel because both
1343
+ * products produce one. Declaring it in `ondo/buy/` would make the sell
1344
+ * viewmodel import a sibling product's module - which the `shared/` ladder
1345
+ * forbids for the reason it always does: two products that reach sideways can
1346
+ * no longer be moved or deleted on their own.
1347
+ *
1348
+ * It names no asset beyond the one that was spent. The transaction does not
1349
+ * carry one, and rebuilding an `Erc20Asset` here would mean inventing a
1350
+ * `decimals` - the quote's answers for a different quantity, and the
1351
+ * transaction's is a scale rather than a property of the token. A host that
1352
+ * wants to know what was traded has the `offer` it passed in.
1353
+ */
1354
+ type OndoOrderPlaced = OndoBuyOrderPlaced | OndoSellOrderPlaced;
1355
+ /**
1356
+ * The common half of an {@link OndoOrderPlaced}, before its side's terms.
1357
+ *
1358
+ * The transaction that was broadcast is not here, because it is not common:
1359
+ * it carries the same `side` this order does, and saying so in prose left a
1360
+ * sell order holding a buy transaction constructible and its
1361
+ * `minimumReceiveOutputAmount` unreachable behind a narrowed `side`. Each arm
1362
+ * names its own instead.
1363
+ */
1364
+ type OndoOrderPlacedCore = {
1365
+ txHash: Hash;
1366
+ /** What the trader spent, in the input asset's base units. */
1367
+ amount: BlockchainAmount;
1368
+ wallet: EvmWallet;
1369
+ };
1370
+ /** A filled purchase: a stablecoin spent, the asset received. */
1371
+ type OndoBuyOrderPlaced = OndoOrderPlacedCore & OndoBuyOrderTerms;
1372
+ /** A filled sale: the asset spent, the settlement coin received. */
1373
+ type OndoSellOrderPlaced = OndoOrderPlacedCore & OndoSellOrderTerms;
1374
+ /**
1375
+ * A buy spends a stablecoin the SDK ships a registry entry for, so its input
1376
+ * asset is narrowed to one - which is what keeps `TOKEN_REGISTRY.erc20` total
1377
+ * at the call sites that name it.
1378
+ */
1379
+ type OndoBuyOrderTerms = {
1380
+ side: 'buy';
1381
+ inputAsset: StablecoinSymbol;
1382
+ /** The purchase that was broadcast, and the deposit it was struck against. */
1383
+ transaction: OndoBuyTransaction;
1384
+ };
1385
+ /**
1386
+ * A sell spends the Ondo asset, which is in no registry: its address and
1387
+ * decimals come off the quote, and only its symbol is carried here. Hence the
1388
+ * wider `AssetSymbol`, and hence a SUM rather than one widened field - a buy
1389
+ * that lost its stablecoin guarantee would be the cost of sharing one.
1390
+ */
1391
+ type OndoSellOrderTerms = {
1392
+ side: 'sell';
1393
+ inputAsset: AssetSymbol;
1394
+ /** The sale that was broadcast, and the floor under the proceeds it names. */
1395
+ transaction: OndoSellTransaction;
1396
+ };
1397
+
1398
+ /**
1399
+ * The wallets a checkout can spend from, supplied by the host: the shared
1400
+ * {@link WalletSelection} every screen reads its wallets from, plus the one
1401
+ * thing only a checkout asks for.
1402
+ *
1403
+ * A `null` `externalAdapter` hides the external-wallet row entirely, for a
1404
+ * host that only offers embedded wallets.
1405
+ *
1406
+ * Everything a wallet row displays beyond the address - the network name -
1407
+ * comes from the checkout's execution chain rather than from the wallet,
1408
+ * because that is the chain the transaction goes to whatever the wallet is
1409
+ * currently pointed at.
1410
+ */
1411
+ type CheckoutWalletSelection = WalletSelection & {
1152
1412
  /**
1153
- * Opens the host's wallet connector. Resolves once the attempt finishes; the
1154
- * SDK reads the outcome from `external` on the next render rather than from
1155
- * a return value, so a host that connects through a redirect still works.
1413
+ * A wallet the host has already settled on, or `null` to let the user pick.
1156
1414
  *
1157
- * Rejecting is how a declined or failed connection is reported.
1415
+ * That is for the host that already knows the answer - a sell page reached
1416
+ * from a position knows which wallet holds it, and a host with a single
1417
+ * embedded wallet has only one answer on a buy too - so asking again would
1418
+ * be a question with one possible answer. Every checkout honours it, in one
1419
+ * of two ways:
1420
+ *
1421
+ * - **Ondo buy, Ondo sell and Centrifuge buy skip their wallet step** and
1422
+ * open on the amount, renumbering the steps that remain. The wallet does
1423
+ * not have to appear in `embedded` or `external`: the host supplies a
1424
+ * ready {@link EvmWallet}, and these flows never resolve it back to a row.
1425
+ * - **Superstate never skips its wallet step**, because that step
1426
+ * allow-lists the wallet on-chain and no preselection can stand in for it.
1427
+ * The step opens with the preselected wallet's row already selected, so
1428
+ * the user confirms it rather than finding it. That needs a row: a wallet
1429
+ * matching neither an `embedded` one nor the connected `external` one by
1430
+ * address selects nothing, and the user picks as if none was preselected.
1431
+ *
1432
+ * Read **once**, when the checkout mounts. The approval a checkout asks for
1433
+ * is granted by one specific wallet, so a change mid-flow is ignored; remount
1434
+ * the checkout (a `key`) to apply a new one. After an order the flow resets
1435
+ * to the step it opened on, so a skipped wallet step stays skipped.
1158
1436
  */
1159
- connectExternal: () => Promise<void>;
1160
- /** Disconnects the external wallet. Resolves when it is gone. */
1161
- disconnectExternal: () => Promise<void>;
1437
+ preselected: EvmWallet | null;
1162
1438
  };
1163
1439
 
1164
1440
  /** What the swap actually filled at, once it has mined. */
@@ -1196,10 +1472,8 @@ type SuperstateOrderPlaced = {
1196
1472
  *
1197
1473
  * Keyed by `OfferType` rather than by provider name. Every entry is optional,
1198
1474
  * and so is the whole object: a host that says nothing about a provider gets
1199
- * its defaults, and a token sale with no entry renders nothing, since the SDK
1200
- * ships no token-sale UI of its own. A new provider that needs config cannot be
1201
- * wired up without a key here, since its branch in {@link CheckoutContainer}
1202
- * has to index one.
1475
+ * its defaults. A new provider that needs config cannot be wired up without a
1476
+ * key here, since its branch in {@link CheckoutContainer} has to index one.
1203
1477
  *
1204
1478
  * Everything here is per-*integration*: a host builds it once and passes the
1205
1479
  * same object for every offer it renders. Which way the order runs is
@@ -1225,19 +1499,20 @@ type SuperstateCheckoutConfig = {
1225
1499
  onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;
1226
1500
  };
1227
1501
  /**
1228
- * The SDK ships no token-sale UI, so the host supplies it.
1229
- *
1230
- * A render function rather than a `ReactNode`, because the container knows
1231
- * which offer it is being asked about and a host with a working token-sale page
1232
- * of its own needs that offer to render it. Without this entry a token-sale
1233
- * offer renders nothing.
1234
- *
1235
- * Alpha: may change once the SDK ships its own token-sale checkout.
1502
+ * What a CoinList token-sale checkout can be configured with. Nothing is
1503
+ * required: the funding contract, the coins and the price are all read off
1504
+ * the offer. Which option is bought is per-render, so it is a prop - see
1505
+ * {@link CheckoutContainerProps.optionId}.
1236
1506
  *
1237
1507
  * @alpha
1238
1508
  */
1239
1509
  type CoinListTokenSaleCheckoutConfig = {
1240
- render: (offer: CoinListTokenSaleOfferDetail) => ReactNode;
1510
+ /**
1511
+ * Fired once the participation is recorded. The dialog shows either way.
1512
+ * The order is a commitment: the sale collects the payment and allocates
1513
+ * the tokens when it settles.
1514
+ */
1515
+ onOrderPlaced?: (order: TokenSaleOrderPlaced) => void;
1241
1516
  };
1242
1517
  /**
1243
1518
  * What a Centrifuge vault checkout can be configured with.
@@ -1285,14 +1560,46 @@ interface CheckoutContainerProps {
1285
1560
  */
1286
1561
  side?: OrderBookSide;
1287
1562
  /**
1288
- * The wallets the buyer can spend from, and the lambdas that connect and
1289
- * disconnect an external one. The SDK ships no wallet stack, so this is how
1290
- * a host plugs in Privy, AppKit, or its own.
1563
+ * Which of a token sale's options is bought - each sets its own price,
1564
+ * minimum and sale agreement. Default: the offer's first option. Every
1565
+ * other provider buys its offer's only option and ignores it.
1566
+ *
1567
+ * A prop rather than a config entry for the same reason as `side`: it is
1568
+ * per-render, chosen on the host's offer page.
1569
+ *
1570
+ * **Read once, at mount**, as `side` is. To switch options, remount with a
1571
+ * `key` covering it.
1572
+ */
1573
+ optionId?: OfferOptionId;
1574
+ /**
1575
+ * The wallets the buyer can spend from, and the host's connector for an
1576
+ * external one. The SDK ships no wallet stack, so this is how a host plugs
1577
+ * in Privy, AppKit, or its own.
1578
+ *
1579
+ * ```tsx
1580
+ * const wallets: CheckoutWalletSelection = {
1581
+ * embedded: myEmbeddedWallets,
1582
+ * external: myConnectedWallet, // or null
1583
+ * // `null` hides the external-wallet row, for a host with embedded
1584
+ * // wallets only.
1585
+ * externalAdapter: {
1586
+ * connect: () => myConnector.open(),
1587
+ * disconnect: () => myConnector.disconnect(),
1588
+ * },
1589
+ * preselected: null, // or the wallet the host already settled on
1590
+ * };
1591
+ * ```
1592
+ *
1593
+ * Every provider honours `wallets.preselected`. Ondo (buy and sell),
1594
+ * Centrifuge and the token sale skip their wallet step and open on the amount, renumbering the
1595
+ * cards that remain. Superstate never skips it, because that step
1596
+ * allow-lists the wallet on-chain: it opens the step with the preselected
1597
+ * wallet's row already selected instead. Read once, at mount - see below.
1291
1598
  */
1292
1599
  wallets: CheckoutWalletSelection;
1293
1600
  /**
1294
1601
  * What each offer type needs beyond the offer itself. Default `{}`: every
1295
- * provider runs on its defaults, and a token sale renders nothing.
1602
+ * provider runs on its defaults.
1296
1603
  */
1297
1604
  config?: CheckoutConfig;
1298
1605
  /**
@@ -1315,22 +1622,29 @@ interface CheckoutContainerProps {
1315
1622
  * assigns to `const exhaustive: never`, so a new offer type is a compile error
1316
1623
  * here as well as in {@link CheckoutConfig}.
1317
1624
  *
1318
- * ## One mount, one offer, one chain, one side
1319
- *
1320
- * `offer`, `chain` and the `side` are read as fixed for the lifetime of
1321
- * the mount. Each provider's viewmodel owns a step machine — which wallet was
1322
- * authorized, how much is being spent — and that progress is bound to the order
1323
- * it was made against: a Superstate wallet authorization is allow-listed per
1324
- * offer, and an ERC-20 approval is granted per chain, for one specific token.
1325
- * Changing any of the three in place would carry a completed step onto an order
1326
- * it was never made for — a flipped side most sharply of all, since the
1327
- * approval covers the coin the *old* direction spent. So the container does not
1328
- * try to: `side` is read once into state and later values are ignored. A
1329
- * swap could also land mid-execution, between an approval and the broadcast it
1625
+ * ## One mount, one offer, one chain, one side, one preselected wallet
1626
+ *
1627
+ * `offer`, `chain`, the `side`, the `optionId` and `wallets.preselected` are read as fixed for
1628
+ * the lifetime of the mount. Each provider's viewmodel owns a step machine -
1629
+ * which wallet was authorized, how much is being spent - and that progress is
1630
+ * bound to the order it was made against: a Superstate wallet authorization
1631
+ * is allow-listed per offer, and an ERC-20 approval is granted per chain, for
1632
+ * one specific token. Changing any of them in place would carry a completed
1633
+ * step onto an order it was never made for - a flipped side most sharply of
1634
+ * all, since the approval covers the coin the *old* direction spent. So the
1635
+ * container does not try to: `side` is read once into state and later values
1636
+ * are ignored. A swap could also land mid-execution, between an approval and the broadcast it
1330
1637
  * was granted for, which is worse than not switching at all.
1331
1638
  *
1332
- * **To render a different offer, chain or side, remount rather than
1333
- * reassign** — give the container a `key` that changes with them:
1639
+ * The preselected wallet is the same kind of progress: whether the flow has a
1640
+ * wallet step at all is decided from it at mount, and the approval that
1641
+ * follows is granted by that wallet. The rest of `wallets` stays live - a
1642
+ * newly connected external wallet appears as a row without a remount.
1643
+ *
1644
+ * **To render a different offer, chain, side, option or preselected wallet, remount
1645
+ * rather than reassign** - give the container a `key` that changes with them
1646
+ * (add `wallets.preselected?.address` to it if the host's preselection can
1647
+ * change on one page):
1334
1648
  *
1335
1649
  * ```tsx
1336
1650
  * <CheckoutContainer
@@ -1355,7 +1669,7 @@ interface CheckoutContainerProps {
1355
1669
  *
1356
1670
  * ```tsx
1357
1671
  * const config: CheckoutConfig = {
1358
- * 'coinlist::token_sale': { render: (o) => <MyTokenSalePage offer={o} /> },
1672
+ * 'ondo::swap': { onOrderConfirmed: (order) => track(order) },
1359
1673
  * };
1360
1674
  *
1361
1675
  * // The sell page. The buy page leaves `side` out.
@@ -1364,7 +1678,8 @@ interface CheckoutContainerProps {
1364
1678
  *
1365
1679
  * A sell page reached from a position also knows which wallet holds it, so it
1366
1680
  * usually sets {@link CheckoutWalletSelection.preselected} and opens on the
1367
- * amount.
1681
+ * amount. A buy page can do the same whenever the host has one answer - a
1682
+ * single embedded wallet, say.
1368
1683
  *
1369
1684
  * ### A buy/sell toggle on one page
1370
1685
  *
@@ -1398,7 +1713,7 @@ interface CheckoutContainerProps {
1398
1713
  * toggle where it can reach an executing flow — disable the tabs once the
1399
1714
  * user is past the amount step, or confirm before switching.
1400
1715
  */
1401
- declare function CheckoutContainer({ offer, chain, side, wallets, config, enabled, className, }: CheckoutContainerProps): ReactNode;
1716
+ declare function CheckoutContainer({ offer, chain, side, optionId, wallets, config, enabled, className, }: CheckoutContainerProps): ReactNode;
1402
1717
 
1403
1718
  /**
1404
1719
  * The claim card.
@@ -1692,244 +2007,41 @@ interface ClaimContainerProps {
1692
2007
  */
1693
2008
  declare function ClaimContainer({ offer, wallets, walletLabel, config, enabled, className, }: ClaimContainerProps): ReactNode;
1694
2009
 
1695
- /**
1696
- * What the grid fetches, pre-fetched on the server instead. Each half is
1697
- * independent: seed `offers` (via `CoinListServer#offers.list()`) and the
1698
- * client still fetches the registry, seed `tokens` (via
1699
- * `CoinListServer#tokens.list()`) and it still fetches the offers, seed both
1700
- * and the grid makes no request of its own.
1701
- */
1702
- interface OffersGridData {
1703
- offers?: Offer[];
1704
- tokens?: TokenMetadata[];
1705
- }
1706
-
1707
- interface OffersGridContainerProps {
1708
- /** Maximum number of columns to render when horizontal space allows. */
1709
- maxColumns?: number;
1710
- /** Optional className applied to the grid element. */
1711
- className?: string;
1712
- /** Optional className applied to the outer wrapper element. */
1713
- containerClassName?: string;
1714
- /** Optional loading slot shown while offers are being fetched. */
1715
- loading?: ReactNode;
1716
- /** Optional error slot shown when loading offers fails. */
1717
- error?: ReactNode;
1718
- /** Optional empty state slot shown when there are no available offers. */
1719
- emptyState?: ReactNode;
1720
- /** Optional per-offer click handler; when omitted, cards are not clickable. */
1721
- onOfferClick?: (offer: Offer) => void;
2010
+ type LoadRequirementsReason = 'not-authenticated' | 'generic-error';
2011
+ type LoadRequirementsState = {
2012
+ type: 'LOADING';
2013
+ } | {
2014
+ type: 'ERROR';
2015
+ reason: LoadRequirementsReason;
2016
+ } | {
2017
+ type: 'CONTENT';
2018
+ requirements: Record<OfferOptionId, Requirement[]>;
2019
+ statuses: RequirementStatusInfo[];
2020
+ };
2021
+ type RequirementsData = {
2022
+ requirements: Record<OfferOptionId, Requirement[]>;
2023
+ statuses: RequirementStatusInfo[];
2024
+ };
2025
+ interface UseRequirementsOptions {
1722
2026
  /**
1723
- * What the grid would otherwise fetch, pre-fetched on the server: `offers`
1724
- * via `CoinListServer#offers.list()`, `tokens` via
1725
- * `CoinListServer#tokens.list()`. Each half skips its own client-side
1726
- * fetch; pass both for a grid that makes no request of its own.
2027
+ * Requirements data pre-fetched on the server (e.g. via
2028
+ * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).
2029
+ * When provided, the hook uses this data as-is and skips the initial client-side fetch.
2030
+ * Calling `refetch()` will still trigger a fresh fetch.
1727
2031
  */
1728
- data?: OffersGridData;
2032
+ data?: RequirementsData;
1729
2033
  /**
1730
- * Default `true`. When `false` nothing is fetched, so the container can be
1731
- * mounted while the grid is not needed yet.
2034
+ * When `false`, the hook sends no request. A seeded or already-fetched
2035
+ * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
2036
+ * `refetch()` is a no-op while disabled.
1732
2037
  */
1733
2038
  enabled?: boolean;
1734
2039
  }
1735
- /**
1736
- * Displays a responsive live-sale grid of {@link OfferSaleCard}, backed by
1737
- * {@link useOffersGridViewModel}. Each card is named and illustrated by the
1738
- * public token registry where it lists the offer's token, and by the offer's
1739
- * own fields otherwise - list offers carry no display name, so an unlisted
1740
- * one shows logo + tagline until the host maps from detail. For equities /
1741
- * past-sales browse rows, compose {@link OffersAssetGrid} instead.
1742
- *
1743
- * Pass `data` (offers and tokens pre-fetched server-side) to use them as-is
1744
- * and skip the client-side fetches. Pass `enabled={false}` to skip the fetches
1745
- * when the container is mounted but the grid is not needed yet. Uses the
1746
- * `loading` / `error` / `emptyState` slots when provided; otherwise renders
1747
- * the standard fallbacks. Cards are interactive only when `onOfferClick` is
1748
- * provided.
1749
- *
1750
- * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`
1751
- * needed.
1752
- */
1753
- declare function OffersGridContainer({ data, onOfferClick, enabled, ...viewProps }?: OffersGridContainerProps): ReactNode;
1754
-
1755
- /**
1756
- * One image as an `<img>` renders it: a `src` for a consumer that takes a
1757
- * single URL, and the `srcSet` candidates for one that also knows the size
1758
- * it renders at. `srcSet` is absent for a vector logo and for the offer's own
1759
- * artwork, neither of which offers the browser a choice.
1760
- */
1761
- type LogoImageUi = {
1762
- src: string;
1763
- srcSet?: string;
1764
- };
1765
- /**
1766
- * The logo a catalogue card renders for an offer, with the registry's
1767
- * dark-theme counterpart when it configures one.
1768
- *
1769
- * `dark` is `null` rather than absent so a renderer has to decide what to do
1770
- * without one: fall back to `light`, which is the registry's own rule.
1771
- */
1772
- type OfferLogoUi = {
1773
- light: LogoImageUi;
1774
- dark: LogoImageUi | null;
1775
- };
1776
- declare const OfferLogoUi: {
1777
- /**
1778
- * The registry's logo for the token an offer is about, or the offer's own
1779
- * artwork otherwise, or `null` when neither exists.
1780
- *
1781
- * The registry wins when both exist because it is the token's real artwork
1782
- * where `Offer.logoUrl` is catalogue artwork, and because a swap publishes
1783
- * without artwork more often than not - which is why `logoUrl` is `null`
1784
- * on the swap variants.
1785
- */
1786
- fromOffer: (offer: {
1787
- logoUrl: string | null;
1788
- }, tokenMetadata: TokenMetadata | null) => OfferLogoUi | null;
1789
- };
1790
-
1791
- /**
1792
- * An offer as {@link OfferAssetCard} renders it. Browse chrome: circular
1793
- * `logo`, `name`, and asset `symbol`. No wordmark.
1794
- *
1795
- * All three come from the public token registry when the caller hands over
1796
- * the metadata of the token the offer is about. Without it, `fromOffer`
1797
- * omits `name` and `symbol` - the list payload has neither - so a list-mapped
1798
- * card is honest about being logo-only, and `fromDetail` reads them from the
1799
- * detail payload (`name`, `asset.code`).
1800
- */
1801
- type OfferAssetCardUi = {
1802
- id: OfferId;
1803
- /** Absent when neither the registry nor a detail payload names the offer. */
1804
- name?: string;
1805
- /** Absent when neither the registry nor a detail payload carries a ticker. */
1806
- symbol?: string;
1807
- /** `null` when neither the registry nor the offer carries artwork. */
1808
- logo: OfferLogoUi | null;
1809
- };
1810
- declare const OfferAssetCardUi: {
1811
- /**
1812
- * `tokenMetadata` is the registry's entry for the token the offer is about
1813
- * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The
1814
- * registry names win over the offer's own where both exist: they are the
1815
- * token's canonical name, ticker and artwork, where the offer's are
1816
- * catalogue copy.
1817
- */
1818
- fromOffer: (offer: Offer, tokenMetadata?: TokenMetadata | null) => OfferAssetCardUi;
1819
- fromDetail: (detail: OfferDetail, tokenMetadata?: TokenMetadata | null) => OfferAssetCardUi;
1820
- };
1821
-
1822
- interface OfferAssetCardProps {
1823
- offer: OfferAssetCardUi;
1824
- /** When set, the whole card is the hit target. */
1825
- onClick?: () => void;
1826
- /** Optional className applied to the card root element. */
1827
- className?: string;
1828
- /** Optional className applied to an outer wrapper element. */
1829
- containerClassName?: string;
1830
- }
1831
- /**
1832
- * Light browse-row catalogue card. Self-scoped. Header is the offer's `logo`
1833
- * (the token registry's where it lists the token, with its dark-theme
1834
- * variant, the catalogue's otherwise) beside `name` (h2) and asset `symbol`
1835
- * under it — not a wordmark.
1836
- * Responsive hug: tighter pad / logo / type below `md`, desktop keeps the
1837
- * H4 + 48px logo row. Hosts compose this beside {@link OfferSaleCard}; the
1838
- * card does not pick a variant itself.
1839
- */
1840
- declare function OfferAssetCard({ offer, onClick, className, containerClassName, }: OfferAssetCardProps): ReactNode;
1841
-
1842
- /**
1843
- * An offer as {@link OfferSaleCard} renders it. Countdown copy is derived in
1844
- * the leaf from `startsAt` / `endsAt` so it can tick; the mapper does not
1845
- * invent a price, FDV, unlock schedule, banner overlay, or wordmark.
1846
- *
1847
- * `name` and `logo` come from the public token registry when the caller
1848
- * hands over the metadata of the token the offer is about, and from the
1849
- * offer otherwise. The list payload carries no name, so `fromOffer` leaves
1850
- * `name` absent without registry metadata - do not derive one from `slug`.
1851
- * The card pairs `logo` with `name` as an h2 and renders each only when
1852
- * present. Prefer {@link OfferSaleCardUi.fromDetail} when the host has a
1853
- * name and no registry answer.
1854
- *
1855
- * `tagline` and `startsAt` are null for an offer that runs no sale window, an
1856
- * Ondo swap: the card then omits the tagline and, with nothing to count down
1857
- * to, reads as live.
1858
- */
1859
- type OfferSaleCardUi = {
1860
- id: OfferId;
1861
- /** Absent when neither the registry nor a detail payload names the offer. */
1862
- name?: string;
1863
- tagline: string | null;
1864
- /** `null` when neither the registry nor the offer carries artwork. */
1865
- logo: OfferLogoUi | null;
1866
- startsAt: Date | null;
1867
- endsAt: Date | null;
1868
- };
1869
- declare const OfferSaleCardUi: {
1870
- /**
1871
- * `tokenMetadata` is the registry's entry for the token the offer is about
1872
- * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The
1873
- * registry names win over the offer's own where both exist: they are the
1874
- * token's canonical name and artwork, where the offer's are catalogue copy.
1875
- */
1876
- fromOffer: (offer: Offer, tokenMetadata?: TokenMetadata | null) => OfferSaleCardUi;
1877
- fromDetail: (detail: OfferDetail, tokenMetadata?: TokenMetadata | null) => OfferSaleCardUi;
1878
- };
1879
-
1880
- interface OfferSaleCardProps {
1881
- offer: OfferSaleCardUi;
1882
- /** Host click handler. View offer always renders; this wires the hit target. */
1883
- onClick?: () => void;
1884
- /** Optional className applied to the card root element. */
1885
- className?: string;
1886
- /** Optional className applied to an outer wrapper element. */
1887
- containerClassName?: string;
1888
- }
1889
- /**
1890
- * Dark live-sale catalogue card. Self-scoped. Header is the offer's `logo`
1891
- * (the token registry's where it lists the token, the catalogue's otherwise)
1892
- * beside the `name` as an h2, then the tagline — not a wordmark. The same
1893
- * logo is painted as a faint right-shifted watermark over the gradient.
1894
- * Responsive hug layout; View offer always renders. No token price, FDV or unlock.
1895
- */
1896
- declare function OfferSaleCard({ offer, onClick, className, containerClassName, }: OfferSaleCardProps): ReactNode;
1897
-
1898
- type LoadRequirementsReason = 'not-authenticated' | 'generic-error';
1899
- type LoadRequirementsState = {
1900
- type: 'LOADING';
1901
- } | {
1902
- type: 'ERROR';
1903
- reason: LoadRequirementsReason;
1904
- } | {
1905
- type: 'CONTENT';
1906
- requirements: Record<OfferOptionId, Requirement[]>;
1907
- statuses: RequirementStatusInfo[];
1908
- };
1909
- type RequirementsData = {
1910
- requirements: Record<OfferOptionId, Requirement[]>;
1911
- statuses: RequirementStatusInfo[];
1912
- };
1913
- interface UseRequirementsOptions {
1914
- /**
1915
- * Requirements data pre-fetched on the server (e.g. via
1916
- * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).
1917
- * When provided, the hook uses this data as-is and skips the initial client-side fetch.
1918
- * Calling `refetch()` will still trigger a fresh fetch.
1919
- */
1920
- data?: RequirementsData;
1921
- /**
1922
- * When `false`, the hook sends no request. A seeded or already-fetched
1923
- * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
1924
- * `refetch()` is a no-op while disabled.
1925
- */
1926
- enabled?: boolean;
1927
- }
1928
- interface UseRequirementsResult {
1929
- requirementsState: LoadRequirementsState;
1930
- /** Triggers a re-fetch of requirements and statuses. */
1931
- refetch: () => void;
1932
- }
2040
+ interface UseRequirementsResult {
2041
+ requirementsState: LoadRequirementsState;
2042
+ /** Triggers a re-fetch of requirements and statuses. */
2043
+ refetch: () => void;
2044
+ }
1933
2045
  /**
1934
2046
  * Loads requirements (grouped by option ID) and requirement statuses for a
1935
2047
  * given offer, then exposes them via a state machine.
@@ -2325,37 +2437,268 @@ interface UseCompleteOAuthOptions {
2325
2437
  */
2326
2438
  declare function useCompleteOAuth(options: UseCompleteOAuthOptions): void;
2327
2439
 
2440
+ type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';
2441
+ type LoadOfferDetailsState = {
2442
+ type: 'LOADING';
2443
+ } | {
2444
+ type: 'ERROR';
2445
+ reason: LoadOfferDetailsReason;
2446
+ } | {
2447
+ type: 'CONTENT';
2448
+ offerDetail: OfferDetail;
2449
+ };
2450
+ interface UseOfferDetailsOptions {
2451
+ /**
2452
+ * Offer detail pre-fetched on the server (e.g. via `CoinListServer#offers.get()`).
2453
+ * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
2454
+ */
2455
+ data?: OfferDetail;
2456
+ /**
2457
+ * When `false`, the hook sends no request. A seeded or already-fetched
2458
+ * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
2459
+ */
2460
+ enabled?: boolean;
2461
+ }
2462
+ interface UseOfferDetailsResult {
2463
+ offerDetailsState: LoadOfferDetailsState;
2464
+ }
2328
2465
  /**
2329
- * UI models every checkout provider needs. Provider-specific models stay in
2330
- * that provider's `use{X}ViewModel.types`; these live here because Ondo and
2331
- * Superstate both render them.
2332
- *
2333
- * Models only. A screen's `{X}UiState` and `{X}UiEvent` stay in that screen's
2334
- * `use{X}ViewModel.types` even when two providers' happen to agree today: a
2335
- * state machine is where providers diverge, and sharing one would make the
2336
- * divergence a breaking change rather than a local edit. Ondo's wallet step
2337
- * confirms synchronously and Superstate's allow-lists on-chain, from the same
2338
- * rows and the same models.
2466
+ * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.
2339
2467
  *
2340
- * No React and no hooks: this is the module Views and leaf components import.
2341
- */
2342
- /**
2343
- * The state of a step's call-to-action.
2468
+ * Pass `data` (pre-fetched server-side) to use that data as-is and skip
2469
+ * the client-side fetch entirely. Pass `enabled: false` to skip the fetch
2470
+ * when the hook must be called but the data is not needed yet.
2344
2471
  *
2345
- * A SUM type rather than `disabled`/`isLoading` booleans, so "disabled while
2346
- * loading" and "loading without a message" are both unrepresentable. The
2347
- * message is what the user reads while an on-chain step runs (e.g. "Approving
2348
- * USDC…"), so it belongs to the loading arm alone.
2472
+ * Returns `LOADING` while CoinList is initializing or while details are being fetched.
2473
+ * Returns `CONTENT` with the offer when `offers.get()` succeeds.
2474
+ * Returns `ERROR` with:
2475
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
2476
+ * - `generic-error` for any other failure
2349
2477
  */
2350
- type CheckoutCtaUi = {
2351
- type: 'enabled';
2478
+ declare function useOfferDetails(offerId: OfferId, options?: UseOfferDetailsOptions): UseOfferDetailsResult;
2479
+
2480
+ type LoadOffersReason = 'not-authenticated' | 'generic-error';
2481
+ type LoadOffersState = {
2482
+ type: 'LOADING';
2352
2483
  } | {
2353
- type: 'disabled';
2484
+ type: 'ERROR';
2485
+ reason: LoadOffersReason;
2354
2486
  } | {
2355
- type: 'loading';
2356
- message: string;
2487
+ type: 'CONTENT';
2488
+ offers: Offer[];
2357
2489
  };
2358
- /**
2490
+ interface UseOffersOptions {
2491
+ /**
2492
+ * Offers pre-fetched on the server (e.g. via `CoinListServer#offers.list()`).
2493
+ * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
2494
+ */
2495
+ data?: Offer[];
2496
+ /**
2497
+ * When `false`, the hook sends no request. A seeded or already-fetched
2498
+ * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
2499
+ */
2500
+ enabled?: boolean;
2501
+ }
2502
+ interface UseOffersResult {
2503
+ offersState: LoadOffersState;
2504
+ }
2505
+ /**
2506
+ * Loads all CoinList offers for the current user and exposes a UI-friendly state.
2507
+ *
2508
+ * Pass `data` (pre-fetched server-side) to use that data as-is and skip
2509
+ * the client-side fetch entirely. Pass `enabled: false` to skip the fetch
2510
+ * when the hook must be called but the data is not needed yet.
2511
+ *
2512
+ * Returns `LOADING` while CoinList is initializing or while offers are being fetched.
2513
+ * Returns `CONTENT` with all offers when `fetchOffers()` succeeds.
2514
+ * Returns `ERROR` with:
2515
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
2516
+ * - `generic-error` for any other failure
2517
+ */
2518
+ declare function useOffers(options?: UseOffersOptions): UseOffersResult;
2519
+
2520
+ /**
2521
+ * Why a read failed, in the only two flavours every UI acts on differently.
2522
+ *
2523
+ * `not-authenticated` is split out because no retry helps until the user
2524
+ * signs in, and because the remedy is one the UI can name. Everything else
2525
+ * collapses into `generic-error` and is offered a retry. A provider that has a
2526
+ * third remedy of its own - Ondo's closed market - widens this union rather
2527
+ * than restating it.
2528
+ */
2529
+ type LoadErrorReason = 'not-authenticated' | 'generic-error';
2530
+
2531
+ /**
2532
+ * Why a Centrifuge read failed. Centrifuge has no remedy of its own to add,
2533
+ * so this is {@link LoadErrorReason} under the name its states already
2534
+ * publish, classified by `loadErrorReason`.
2535
+ *
2536
+ * @alpha
2537
+ */
2538
+ type CentrifugeLoadErrorReason = LoadErrorReason;
2539
+
2540
+ /**
2541
+ * The state of one vault's status poll.
2542
+ *
2543
+ * Stale-preserving: a failed tick with a status in hand keeps it, so a flaky
2544
+ * read never reads as "vault halted". `ERROR` means the status is unknown -
2545
+ * which is not the same as `CONTENT` carrying a blocked orderability, and
2546
+ * callers must not conflate them. A vault that is *known* to be unorderable
2547
+ * may block a request; one that is merely unknown may not.
2548
+ *
2549
+ * `below_minimum` never appears here: it needs an amount, which this
2550
+ * endpoint is never given.
2551
+ *
2552
+ * @alpha
2553
+ */
2554
+ type LoadCentrifugeVaultStatusState = {
2555
+ type: 'DISABLED';
2556
+ } | {
2557
+ type: 'LOADING';
2558
+ } | {
2559
+ type: 'ERROR';
2560
+ reason: CentrifugeLoadErrorReason;
2561
+ } | {
2562
+ type: 'CONTENT';
2563
+ status: CentrifugeVaultStatus;
2564
+ };
2565
+ /** @alpha */
2566
+ interface UseCentrifugeVaultStatusesOptions {
2567
+ /** The vaults to poll, typically one per chain an offer runs on. */
2568
+ vaults: CentrifugeVaultRef[];
2569
+ /** How often to refresh. Defaults to {@link CENTRIFUGE_POLL_INTERVAL_MS}. */
2570
+ pollIntervalMs?: number;
2571
+ /**
2572
+ * Statuses the caller already holds, typically fetched server-side, each
2573
+ * opening the state of the vault it names so a server-rendered panel needs
2574
+ * no loading pass.
2575
+ *
2576
+ * They seed the first render only: the poll still fetches immediately. A
2577
+ * vault that was orderable a minute ago can be unlinked now, so a seed
2578
+ * that suppressed the first read would be answering "can I act right now"
2579
+ * with whenever the page was rendered.
2580
+ */
2581
+ data?: CentrifugeVaultStatus[];
2582
+ /** When false, the hook neither fetches nor polls. */
2583
+ enabled: boolean;
2584
+ }
2585
+ /** @alpha */
2586
+ interface UseCentrifugeVaultStatusesResult {
2587
+ /** One entry per vault asked for, in the order asked. */
2588
+ statuses: {
2589
+ vault: CentrifugeVaultRef;
2590
+ state: LoadCentrifugeVaultStatusState;
2591
+ }[];
2592
+ }
2593
+ /**
2594
+ * Polls whether each of several Centrifuge vaults can be acted on right now,
2595
+ * independent of any wallet or amount.
2596
+ *
2597
+ * Free to poll - it spends no attestation. Centrifuge announces none of the
2598
+ * changes this reports, so the poll is the only way a screen notices a vault
2599
+ * halting under it. Each vault is read independently on one shared timer, so
2600
+ * one failing chain never holds back another.
2601
+ *
2602
+ * A seeded status opens its vault's state instead of `LOADING` and is
2603
+ * otherwise left to the poll: the first tick fires as it always does, and
2604
+ * only replaces the seed once it has a status of its own.
2605
+ *
2606
+ * Disabled it neither fetches nor holds a timer. A vault with no status in
2607
+ * hand reports `DISABLED`, not an empty `CONTENT`: there is no empty vault
2608
+ * status, and an invented one would be worse than none, since `CONTENT` here
2609
+ * is what a caller is allowed to block on. A status already in hand survives
2610
+ * being switched off.
2611
+ *
2612
+ * @alpha
2613
+ */
2614
+ declare function useCentrifugeVaultStatuses(options: UseCentrifugeVaultStatusesOptions): UseCentrifugeVaultStatusesResult;
2615
+
2616
+ /** @alpha */
2617
+ interface UseCentrifugeVaultStatusOptions {
2618
+ /** Share token symbol of the vault, e.g. `deJTRSY`. */
2619
+ symbol: AssetSymbol;
2620
+ chain: EthereumChain;
2621
+ /** How often to refresh. Defaults to `CENTRIFUGE_POLL_INTERVAL_MS`. */
2622
+ pollIntervalMs?: number;
2623
+ /**
2624
+ * A status the caller already holds, typically fetched server-side, used
2625
+ * as the state the hook opens on so a server-rendered panel needs no
2626
+ * loading pass.
2627
+ *
2628
+ * It seeds the first render only: the poll still fetches immediately. A
2629
+ * vault that was orderable a minute ago can be unlinked now, so a seed
2630
+ * that suppressed the first read would be answering "can I invest right
2631
+ * now" with whenever the page was rendered.
2632
+ */
2633
+ data?: CentrifugeVaultStatus;
2634
+ /** When false, the hook neither fetches nor polls. */
2635
+ enabled: boolean;
2636
+ }
2637
+ /** @alpha */
2638
+ interface UseCentrifugeVaultStatusResult {
2639
+ state: LoadCentrifugeVaultStatusState;
2640
+ }
2641
+ /**
2642
+ * Polls whether a Centrifuge vault can take a request at all right now,
2643
+ * independent of any amount.
2644
+ *
2645
+ * Free to poll - it spends no attestation. Centrifuge announces none of the
2646
+ * changes this reports, so the poll is the only way a checkout notices
2647
+ * mid-order.
2648
+ *
2649
+ * The one-vault case of {@link useCentrifugeVaultStatuses}, which carries the
2650
+ * seeding, stale-preserving and disabled semantics.
2651
+ *
2652
+ * @alpha
2653
+ */
2654
+ declare function useCentrifugeVaultStatus(options: UseCentrifugeVaultStatusOptions): UseCentrifugeVaultStatusResult;
2655
+
2656
+ /**
2657
+ * UI models every checkout provider needs. Provider-specific models stay in
2658
+ * that provider's `use{X}ViewModel.types`; these live here because Ondo and
2659
+ * Superstate both render them.
2660
+ *
2661
+ * Models only. A provider screen's `{X}UiState` and `{X}UiEvent` stay in that
2662
+ * screen's `use{X}ViewModel.types` even when two providers' happen to agree
2663
+ * today: a state machine is where providers diverge, and sharing one would
2664
+ * make the divergence a breaking change rather than a local edit. A step with
2665
+ * zero provider input is the exception and is shared whole, in its own
2666
+ * `shared/` screen directory - the wallet step Ondo and Centrifuge render as
2667
+ * it stands, while Superstate's allow-lists on-chain from the same rows and
2668
+ * the same models; and the validate-only amount step Centrifuge and
2669
+ * Superstate render as it stands, while Ondo's approves on confirm and builds
2670
+ * its own from the same rules and leaves.
2671
+ *
2672
+ * No React and no hooks: this is the module Views and leaf components import.
2673
+ */
2674
+ /**
2675
+ * The state of a step's call-to-action.
2676
+ *
2677
+ * A SUM type rather than `disabled`/`isLoading` booleans, so "disabled while
2678
+ * loading" and "loading without a message" are both unrepresentable. The
2679
+ * message is what the user reads while an on-chain step runs (e.g. "Approving
2680
+ * USDC…"), so it belongs to the loading arm alone.
2681
+ */
2682
+ type CheckoutCtaUi = {
2683
+ type: 'enabled';
2684
+ } | {
2685
+ type: 'disabled';
2686
+ } | {
2687
+ type: 'loading';
2688
+ message: string;
2689
+ };
2690
+ /**
2691
+ * What an amount field's number is denominated in, drawn beside it.
2692
+ *
2693
+ * A token symbol follows the number as its unit (`1,000 USDC`); a currency
2694
+ * sign leads it (`$1,000`). One closed variant rather than a `prefix` and a
2695
+ * `suffix` that could both be set, because a figure has one unit.
2696
+ */
2697
+ type CheckoutAmountAdornmentUi = {
2698
+ type: 'prefix' | 'suffix';
2699
+ text: string;
2700
+ };
2701
+ /**
2359
2702
  * A status and the copy that names it: an Ondo market that is open, a sale
2360
2703
  * still running, a window that has closed.
2361
2704
  *
@@ -2461,6 +2804,42 @@ type CheckoutWalletUi = {
2461
2804
  type CheckoutEmbeddedWalletUi = CheckoutWalletUi & {
2462
2805
  walletAddress: EvmWalletAddress;
2463
2806
  };
2807
+ /**
2808
+ * The external-wallet row of a checkout's wallet step.
2809
+ *
2810
+ * - `hidden`: the host offers no connector and none is connected, so there is
2811
+ * no row at all - a host that only supports embedded wallets.
2812
+ * - `disconnected`: the host offers a connector and nothing is connected yet.
2813
+ * The row is the invitation to connect one.
2814
+ * - `connected`: a wallet like any other. `canDisconnect` is `false` when the
2815
+ * host offers no connector (it handed over a wallet the user cannot change
2816
+ * from here) or while the step is using that wallet.
2817
+ *
2818
+ * A SUM rather than a nullable wallet beside a flag, so a View cannot offer to
2819
+ * connect a wallet the host has no way of connecting.
2820
+ */
2821
+ type CheckoutExternalWalletUi = {
2822
+ type: 'hidden';
2823
+ } | {
2824
+ type: 'disconnected';
2825
+ } | {
2826
+ type: 'connected';
2827
+ wallet: CheckoutWalletUi;
2828
+ canDisconnect: boolean;
2829
+ };
2830
+ declare const CheckoutExternalWalletUi: {
2831
+ /**
2832
+ * The external-wallet row for the host's wallets.
2833
+ *
2834
+ * `locked` is for a step that is using the external wallet right now - mid
2835
+ * signature, say - and must not let it be disconnected underneath itself.
2836
+ */
2837
+ fromDomain: (wallets: WalletSelection, { network, selected, locked, }: {
2838
+ network: string;
2839
+ selected: boolean;
2840
+ locked: boolean;
2841
+ }) => CheckoutExternalWalletUi;
2842
+ };
2464
2843
  /**
2465
2844
  * The wallet the user settled on.
2466
2845
  *
@@ -2513,107 +2892,23 @@ type CheckoutSelectableInputAssetUi = {
2513
2892
  rawBalance: bigint;
2514
2893
  selected: boolean;
2515
2894
  };
2516
-
2517
2895
  /**
2518
- * Step 2 of the Centrifuge checkout: how much of the funding token to deposit.
2519
- *
2520
- * Nothing here touches the chain. Confirming checks the amount in memory and
2521
- * hands it up. The review step approves and places the request together.
2896
+ * Where a placed order can be checked: the wallet it settles to, and the
2897
+ * transaction on a block explorer.
2522
2898
  *
2523
- * @alpha
2899
+ * Every provider's order dialog carries the pair, and builds it the same way
2900
+ * from the same three facts, so it is one model rather than two fields each
2901
+ * dialog re-derives.
2524
2902
  */
2525
- type CentrifugeBuyAmountUiState = {
2526
- type: 'incomplete';
2527
- } | {
2528
- type: 'active';
2529
- /** Exactly what the user has typed. `'1.'` is a legal thing to hold. */
2530
- amountInput: string;
2531
- walletAddress: ShortenedWalletAddress;
2532
- inputAssets: CheckoutSelectableInputAssetUi[];
2533
- confirmCta: CheckoutCtaUi;
2534
- error: string | null;
2535
- } | {
2536
- type: 'complete';
2537
- inputAsset: CheckoutAssetUi;
2538
- amountFormatted: FormattedAmountAssetUi;
2539
- };
2540
- /** @alpha */
2541
- type CentrifugeBuyAmountUiEvent = {
2542
- type: 'ON_AMOUNT_CHANGE';
2543
- value: string;
2544
- } | {
2545
- type: 'ON_MAX_AMOUNT_CLICK';
2546
- } | {
2547
- type: 'ON_SELECT_PAY_WITH';
2548
- value: AssetSymbol;
2549
- } | {
2550
- type: 'ON_CONFIRM_AMOUNT';
2551
- } | {
2552
- type: 'ON_EDIT_AMOUNT';
2553
- };
2554
-
2555
- /**
2556
- * Why a Centrifuge read failed, in the only two flavours a UI acts on
2557
- * differently.
2558
- *
2559
- * `not-authenticated` is split out because no retry helps until the user
2560
- * signs in. Everything else collapses into `generic-error` and is offered a
2561
- * retry.
2562
- *
2563
- * @alpha
2564
- */
2565
- type CentrifugeLoadErrorReason = 'not-authenticated' | 'generic-error';
2566
-
2567
- /**
2568
- * The built deposit request a review step can place.
2569
- *
2570
- * `isRefreshing` rides on `CONTENT` so a rebuild never blanks the numbers on
2571
- * screen. A failed rebuild keeps them and says why.
2572
- *
2573
- * @alpha
2574
- */
2575
- type LoadCentrifugeBuyTransactionState = {
2576
- type: 'LOADING';
2577
- } | {
2578
- type: 'ERROR';
2579
- reason: CentrifugeLoadErrorReason;
2580
- } | {
2581
- type: 'CONTENT';
2582
- transaction: CentrifugeVaultBuyTransaction;
2583
- isRefreshing: boolean;
2584
- refreshError: CentrifugeLoadErrorReason | null;
2585
- };
2586
- /** @alpha */
2587
- interface UseCentrifugeBuyTransactionOptions {
2588
- /**
2589
- * The request to build, or `null` before an amount is confirmed. A `null`
2590
- * request fetches nothing.
2591
- */
2592
- request: BuildCentrifugeVaultBuyParams | null;
2903
+ type CheckoutReceiptUi = {
2904
+ /** The wallet the order settles to. */
2905
+ recipientAddress: ShortenedWalletAddress;
2593
2906
  /**
2594
- * A request the caller already holds, typically the one `prepareBuy`
2595
- * returned. When present the hook adopts it and skips the initial build.
2596
- * `refetch` still builds.
2907
+ * The order's transaction on a block explorer. Always present: a dialog
2908
+ * only exists once there is a transaction to point at.
2597
2909
  */
2598
- data?: CentrifugeVaultBuyTransaction;
2599
- /** When false, the hook does not build. */
2600
- enabled: boolean;
2601
- }
2602
- /** @alpha */
2603
- interface UseCentrifugeBuyTransactionResult {
2604
- state: LoadCentrifugeBuyTransactionState;
2605
- /** Builds a fresh request for the same deposit. */
2606
- refetch: () => void;
2607
- }
2608
- /**
2609
- * Holds the deposit request the review step places, and rebuilds it when
2610
- * asked.
2611
- *
2612
- * **Never polls.** A request is built once, when the user confirms an amount.
2613
- *
2614
- * @alpha
2615
- */
2616
- declare function useCentrifugeBuyTransaction(options: UseCentrifugeBuyTransactionOptions): UseCentrifugeBuyTransactionResult;
2910
+ txExplorerUrl: TxExplorerUrl;
2911
+ };
2617
2912
 
2618
2913
  /**
2619
2914
  * Step 3 of the Centrifuge checkout: confirming the deposit and placing it.
@@ -2648,38 +2943,37 @@ type CentrifugeBuyReviewUiEvent = {
2648
2943
  };
2649
2944
 
2650
2945
  /**
2651
- * Why a Centrifuge checkout cannot run right now, as opposed to a step of it
2652
- * failing.
2946
+ * Why a checkout cannot run right now, as opposed to a step of it failing.
2653
2947
  *
2654
- * @alpha
2655
- */
2656
- type CentrifugeCheckoutErrorReason =
2657
- /**
2658
- * The offer names no vault proxy on the chain the host asked for, so there
2659
- * is no spender to approve and nothing to broadcast to.
2948
+ * Every provider has the same two kinds of answer, and only the second is
2949
+ * named per provider:
2950
+ *
2951
+ * - `unsupported-chain`: the offer names no contract on the chain the host
2952
+ * asked for, so there is no spender to approve and nothing to broadcast to.
2953
+ * Settled at mount, since the offer and the chain are both fixed for its
2954
+ * lifetime, so nothing can clear it.
2955
+ * - `TBlocked`: the provider is known not to take an order right now - a
2956
+ * closed market, a paused vault. Known from a poll, never assumed from one
2957
+ * that is still loading or failed, and it clears on its own once the poll
2958
+ * says so.
2959
+ *
2960
+ * A union rather than a bare flag because the View switches on it for copy.
2660
2961
  */
2661
- 'unsupported-chain'
2962
+ type CheckoutBlockedReason<TBlocked extends string> = 'unsupported-chain' | TBlocked;
2963
+
2662
2964
  /**
2663
- * The vault is known to be unable to take a request: halted, unlinked, or
2664
- * not permissioned. Known from a status whose orderability is blocked.
2665
- * Loading and failed statuses are unknown, and unknown does not block.
2965
+ * Why a Centrifuge checkout cannot run right now, as opposed to a step of it
2966
+ * failing. See {@link CheckoutBlockedReason} for `unsupported-chain`, which
2967
+ * here means the offer names no vault proxy on the chain.
2968
+ *
2969
+ * `not-orderable` is Centrifuge's block: the vault is known to be unable to
2970
+ * take a request - halted, unlinked, or not permissioned. Known from a status
2971
+ * whose orderability is blocked; loading and failed statuses are unknown, and
2972
+ * unknown does not block.
2666
2973
  *
2667
- * Shown only while the user is still choosing a wallet and no request-placed
2668
- * dialog is up. Past that, a pause belongs to the step it interrupts.
2974
+ * @alpha
2669
2975
  */
2670
- | 'not-orderable';
2671
- /** @alpha */
2672
- declare const CentrifugeCheckoutErrorReason: {
2673
- /**
2674
- * Which reason, if any, replaces the whole checkout. `null` means the steps
2675
- * render.
2676
- */
2677
- of: ({ depositableHere, notOrderable, atEntry, }: {
2678
- depositableHere: boolean;
2679
- notOrderable: boolean;
2680
- atEntry: boolean;
2681
- }) => CentrifugeCheckoutErrorReason | null;
2682
- };
2976
+ type CentrifugeCheckoutErrorReason = CheckoutBlockedReason<'not-orderable'>;
2683
2977
 
2684
2978
  /**
2685
2979
  * The asset panel beside the Centrifuge checkout.
@@ -2734,24 +3028,113 @@ type CentrifugeSidebarMinimumUi = {
2734
3028
  };
2735
3029
 
2736
3030
  /**
2737
- * Step 1 of the Centrifuge checkout: which wallet funds the deposit.
3031
+ * The amount step of a checkout whose amount step takes no provider input:
3032
+ * how much to spend, and which stablecoin to spend it in. Centrifuge and
3033
+ * Superstate render it as it stands.
2738
3034
  *
2739
- * There is no `inactive` arm. This step is the first one, so it is either being
2740
- * filled in or already answered — it is never waiting on a step above it.
3035
+ * Shared whole, state machine included, because it is not a provider state
3036
+ * machine: nothing here touches the chain, so confirming checks the amount in
3037
+ * memory and hands it up, and there is nothing for a provider to diverge on.
3038
+ * It forks the moment one provider needs different behaviour - Ondo's already
3039
+ * has, since its confirm approves and builds an order, so it keeps its own
3040
+ * state over the same rules and leaves.
2741
3041
  *
2742
- * Nothing is allow-listed: the user picks a wallet and confirms, and confirming
2743
- * is synchronous. Hence a plain `confirmEnabled`.
3042
+ * The CTA is a `CheckoutCtaUi` all the same, rather than a `confirmEnabled`
3043
+ * flag, so the View renders it through the one CTA every amount step uses. It
3044
+ * is never `loading` here.
3045
+ */
3046
+ type CheckoutAmountUiState = {
3047
+ type: 'incomplete';
3048
+ } | {
3049
+ type: 'active';
3050
+ /**
3051
+ * Exactly what the user has typed, not a parsed number: the field is
3052
+ * mid-edit, and `'1.'` is a legal thing to be holding.
3053
+ */
3054
+ amountInput: string;
3055
+ /**
3056
+ * What the field is denominated in: the selected coin's symbol after the
3057
+ * number, or a `$` before it for a dollar-denominated field.
3058
+ */
3059
+ adornment: CheckoutAmountAdornmentUi;
3060
+ /** The wallet the funds come from, per the wallet step. */
3061
+ walletAddress: ShortenedWalletAddress;
3062
+ /**
3063
+ * Every fundable asset, in display order, whether or not the user holds
3064
+ * any. One entry renders as a plain card, two or more as a picker.
3065
+ */
3066
+ inputAssets: CheckoutSelectableInputAssetUi[];
3067
+ confirmCta: CheckoutCtaUi;
3068
+ /**
3069
+ * Validation copy, e.g. `Insufficient USDC.`, or why no amount can be
3070
+ * confirmed right now, which takes its place.
3071
+ */
3072
+ error: string | null;
3073
+ } | {
3074
+ type: 'complete';
3075
+ inputAsset: CheckoutAssetUi;
3076
+ /**
3077
+ * The confirmed amount as the field asked for it: `1,000.00 USDC`, or
3078
+ * `$1,000.00` for a dollar-denominated field.
3079
+ */
3080
+ amountFormatted: FormattedAmountAssetUi;
3081
+ /**
3082
+ * The same figure in the asset actually being paid, e.g. `1,000.00
3083
+ * USDC`, when the headline names dollars rather than the asset. `null`
3084
+ * when the headline already is in the asset.
3085
+ *
3086
+ * Both are shown for a dollar field because the two are only equal while
3087
+ * the funding asset is a dollar stablecoin - the day a non-dollar one is
3088
+ * fundable, the summary would otherwise silently claim it was.
3089
+ */
3090
+ inputAmountFormatted: FormattedAmountAssetUi | null;
3091
+ };
3092
+ /**
3093
+ * Everything the amount step raises. `ON_CONFIRM_AMOUNT` only moves the flow
3094
+ * to the review step: nothing is placed or paid for here.
3095
+ */
3096
+ type CheckoutAmountUiEvent = {
3097
+ type: 'ON_AMOUNT_CHANGE';
3098
+ value: string;
3099
+ } | {
3100
+ type: 'ON_MAX_AMOUNT_CLICK';
3101
+ } | {
3102
+ type: 'ON_SELECT_PAY_WITH';
3103
+ value: AssetSymbol;
3104
+ } | {
3105
+ type: 'ON_CONFIRM_AMOUNT';
3106
+ } | {
3107
+ type: 'ON_EDIT_AMOUNT';
3108
+ };
3109
+
3110
+ /**
3111
+ * Step 1 of a checkout whose wallet step takes no provider input: which wallet
3112
+ * funds the order and receives the asset. Ondo (buy and sell) and Centrifuge
3113
+ * render it as it stands.
2744
3114
  *
2745
- * @alpha
3115
+ * Shared whole, state machine included, because it is not a provider state
3116
+ * machine: no provider answers anything here, so there is nothing for one to
3117
+ * diverge on. It forks the moment one provider needs different behaviour -
3118
+ * Superstate already has, since its confirm allow-lists the wallet on-chain,
3119
+ * so it keeps its own state over the same rows.
3120
+ *
3121
+ * There is no `inactive` arm. This step is the first one, so it is either
3122
+ * being filled in or already answered - it is never waiting on a step above
3123
+ * it.
3124
+ *
3125
+ * Nothing is allow-listed: the user picks a wallet and confirms, and
3126
+ * confirming is synchronous. Hence a plain `confirmEnabled` rather than a
3127
+ * `CheckoutCtaUi` with loading copy.
2746
3128
  */
2747
- type CentrifugeWalletSelectUiState = {
3129
+ type CheckoutWalletSelectUiState = {
2748
3130
  type: 'active';
2749
3131
  /** The user's CoinList wallets. Empty when they have none. */
2750
3132
  embeddedWallets: CheckoutEmbeddedWalletUi[];
2751
- /** `null` until an external wallet is connected. The row still renders. */
2752
- externalWallet: CheckoutWalletUi | null;
2753
- /** Whether the connected external wallet may be disconnected here. */
2754
- canDisconnect: boolean;
3133
+ /**
3134
+ * The external-wallet row: absent when the host offers no connector,
3135
+ * an invitation to connect one, or the connected wallet.
3136
+ */
3137
+ externalWallet: CheckoutExternalWalletUi;
2755
3138
  confirmEnabled: boolean;
2756
3139
  /** Copy for a failed connect, e.g. the user rejected the wallet prompt. */
2757
3140
  error: string | null;
@@ -2759,8 +3142,7 @@ type CentrifugeWalletSelectUiState = {
2759
3142
  type: 'completed';
2760
3143
  wallet: CheckoutConfirmedWalletUi;
2761
3144
  };
2762
- /** @alpha */
2763
- type CentrifugeWalletSelectUiEvent = {
3145
+ type CheckoutWalletSelectUiEvent = {
2764
3146
  type: 'ON_SELECT_WALLET';
2765
3147
  value: CheckoutWalletTypeUi;
2766
3148
  }
@@ -2787,8 +3169,13 @@ type CentrifugeWalletSelectUiEvent = {
2787
3169
  */
2788
3170
  type CentrifugeBuyCheckoutUiState = {
2789
3171
  type: 'content';
2790
- wallet: CentrifugeWalletSelectUiState;
2791
- amount: CentrifugeBuyAmountUiState;
3172
+ /**
3173
+ * The wallet step, or `null` when the host preselected a wallet and the
3174
+ * flow skipped it. The later steps are numbered from it. Never `null`
3175
+ * today: this flow does not honour a preselection yet.
3176
+ */
3177
+ wallet: CheckoutWalletSelectUiState | null;
3178
+ amount: CheckoutAmountUiState;
2792
3179
  review: CentrifugeBuyReviewUiState;
2793
3180
  sidebar: CentrifugeSidebarUiState;
2794
3181
  orderPlaced: CentrifugeOrderPlacedUiState;
@@ -2797,7 +3184,7 @@ type CentrifugeBuyCheckoutUiState = {
2797
3184
  reason: CentrifugeCheckoutErrorReason;
2798
3185
  };
2799
3186
  /** @alpha */
2800
- type CentrifugeBuyCheckoutUiEvent = CentrifugeWalletSelectUiEvent | CentrifugeBuyAmountUiEvent | CentrifugeBuyReviewUiEvent | CentrifugeOrderPlacedUiEvent;
3187
+ type CentrifugeBuyCheckoutUiEvent = CheckoutWalletSelectUiEvent | CheckoutAmountUiEvent | CentrifugeBuyReviewUiEvent | CentrifugeOrderPlacedUiEvent;
2801
3188
  /**
2802
3189
  * The dialog that closes the checkout once the request has mined.
2803
3190
  *
@@ -2807,13 +3194,11 @@ type CentrifugeBuyCheckoutUiEvent = CentrifugeWalletSelectUiEvent | CentrifugeBu
2807
3194
  */
2808
3195
  type CentrifugeOrderPlacedUiState = {
2809
3196
  type: 'hidden';
2810
- } | {
3197
+ } | ({
2811
3198
  type: 'visible';
2812
3199
  outputAsset: CheckoutAssetUi;
2813
3200
  totalCost: FormattedAmountAssetUi;
2814
- recipientAddress: ShortenedWalletAddress;
2815
- txExplorerUrl: TxExplorerUrl;
2816
- };
3201
+ } & CheckoutReceiptUi);
2817
3202
  /** @alpha */
2818
3203
  type CentrifugeOrderPlacedUiEvent = {
2819
3204
  type: 'ON_CLOSE_ORDER_PLACED';
@@ -2823,6 +3208,15 @@ type CentrifugeOrderPlacedUiEvent = {
2823
3208
  interface UseCentrifugeBuyCheckoutViewModelOptions {
2824
3209
  offer: CentrifugeVaultOfferDetail;
2825
3210
  chain: EthereumChain;
3211
+ /**
3212
+ * The host's wallets, its connector for an external one if any, and
3213
+ * optionally the wallet it has already settled on.
3214
+ *
3215
+ * `wallets.preselected` is read **once**, to seed the step machine: set, the
3216
+ * flow has no wallet step and opens on the amount. A host that changes it
3217
+ * mid-flow is ignored, because the approval the review grants is granted by
3218
+ * one specific wallet.
3219
+ */
2826
3220
  wallets: CheckoutWalletSelection;
2827
3221
  enabled?: boolean;
2828
3222
  /** Fired once the request has mined. The dialog shows either way. */
@@ -2840,15 +3234,22 @@ interface UseCentrifugeBuyCheckoutViewModelResult {
2840
3234
  * review, and sidebar steps. The status poll lives here. The amount step
2841
3235
  * only validates.
2842
3236
  *
2843
- * A vault that is known to be blocked replaces the checkout only at the
2844
- * wallet step. A status that is still loading, or that failed, does not.
3237
+ * A vault that is known to be blocked replaces the checkout only at the step
3238
+ * the flow opened on: the wallet step, or the amount for a wallet the host
3239
+ * preselected. A status that is still loading, or that failed, does not.
2845
3240
  *
2846
3241
  * @alpha
2847
3242
  */
2848
3243
  declare function useCentrifugeBuyCheckoutViewModel({ offer, chain, wallets, enabled, onOrderPlaced, }: UseCentrifugeBuyCheckoutViewModelOptions): UseCentrifugeBuyCheckoutViewModelResult;
2849
3244
 
2850
- type LoadParticipationsReason = 'not-authenticated' | 'generic-error';
3245
+ type LoadParticipationsReason = LoadErrorReason;
3246
+ /**
3247
+ * The state of the participations read. `DISABLED` means the hook was
3248
+ * switched off before an answer arrived, so nothing is in flight.
3249
+ */
2851
3250
  type LoadParticipationsState = {
3251
+ type: 'DISABLED';
3252
+ } | {
2852
3253
  type: 'LOADING';
2853
3254
  } | {
2854
3255
  type: 'ERROR';
@@ -2857,36 +3258,221 @@ type LoadParticipationsState = {
2857
3258
  type: 'CONTENT';
2858
3259
  participations: Participation[];
2859
3260
  };
2860
- interface UseParticipationsOptions {
3261
+ interface UseParticipationsOptions {
3262
+ /**
3263
+ * Participations pre-fetched on the server (e.g. via `CoinListServer#tokenSale.list()`).
3264
+ * When provided, the hook uses this data as-is and skips the initial
3265
+ * client-side fetch; {@link UseParticipationsResult.refetch} still fetches.
3266
+ */
3267
+ data?: Participation[];
3268
+ /**
3269
+ * When `false`, the hook sends no request. A seeded or already-fetched
3270
+ * `CONTENT` survives; otherwise the hook reports `DISABLED`. Defaults to
3271
+ * `true`.
3272
+ */
3273
+ enabled?: boolean;
3274
+ }
3275
+ interface UseParticipationsResult {
3276
+ participationsState: LoadParticipationsState;
3277
+ /**
3278
+ * Fetches again: the recovery path after an `ERROR`, and the way past a
3279
+ * server seed (`data`), which only the first fetch honours. No-op while
3280
+ * disabled.
3281
+ */
3282
+ refetch: () => void;
3283
+ }
3284
+ /**
3285
+ * Loads all CoinList participations for the current user and exposes a UI-friendly state.
3286
+ * Optionally filters by offer when `offerId` is provided.
3287
+ *
3288
+ * Pass `data` (pre-fetched server-side) to open on it and skip the initial
3289
+ * client-side fetch. Pass `enabled: false` to skip the fetch when the hook
3290
+ * must be called but the data is not needed yet.
3291
+ *
3292
+ * Returns `LOADING` while CoinList is initializing or while participations are being fetched.
3293
+ * Returns `CONTENT` with all participations when the read succeeds.
3294
+ * Returns `ERROR` with:
3295
+ * - `not-authenticated` when the user has to sign in first
3296
+ * - `generic-error` for any other failure
3297
+ */
3298
+ declare function useParticipations(offerId?: OfferId, options?: UseParticipationsOptions): UseParticipationsResult;
3299
+
3300
+ /**
3301
+ * The last step of the token-sale checkout: confirming the commitment and
3302
+ * placing it.
3303
+ *
3304
+ * Placing approves the payment to the sale's funding contract and records the
3305
+ * participation. Nothing is spent yet: the sale pulls the payment and
3306
+ * allocates the tokens when it settles, so the quantity shown is an estimate.
3307
+ *
3308
+ * @alpha
3309
+ */
3310
+ type TokenSaleReviewUiState = {
3311
+ type: 'incomplete';
3312
+ } | {
3313
+ type: 'active';
3314
+ /** The token being bought. */
3315
+ outputAsset: CheckoutAssetUi;
3316
+ /** How many tokens the payment buys at the option's price, e.g. `200.00 TKN`. */
3317
+ estimatedTokens: FormattedAmountAssetUi;
3318
+ /** The option's price for one whole token, e.g. `$0.50`. */
3319
+ pricePerToken: FormattedAmountAssetUi;
3320
+ /** What the user commits, e.g. `100.00 USDC`. No fee comes off it. */
3321
+ payAmount: FormattedAmountAssetUi;
3322
+ /** Where the tokens land - the wallet that approves the payment. */
3323
+ recipientAddress: ShortenedWalletAddress;
3324
+ /** The option's sale agreement, which the order is placed under. */
3325
+ saleAgreementUrl: string | null;
3326
+ placeOrderCta: CheckoutCtaUi;
3327
+ error: string | null;
3328
+ };
3329
+ /** @alpha */
3330
+ type TokenSaleReviewUiEvent = {
3331
+ type: 'ON_PLACE_ORDER';
3332
+ };
3333
+
3334
+ /**
3335
+ * Why a token-sale checkout cannot run at all, as opposed to a step of it
3336
+ * failing. Every one of them is a fact about the offer and the host's props,
3337
+ * so none clears on its own:
3338
+ *
3339
+ * - `unsupported-chain`: the sale names no funding contract on the chain.
3340
+ * - `unknown-option`: the host's `optionId` is not one of the offer's options.
3341
+ * - `no-price`: the option has no fixed price - an auction, which the SDK
3342
+ * does not run.
3343
+ * - `no-payable-asset`: the sale accepts no coin the SDK can pay with on the
3344
+ * chain.
3345
+ *
3346
+ * @alpha
3347
+ */
3348
+ type TokenSaleCheckoutErrorReason = CheckoutBlockedReason<'unknown-option' | 'no-price' | 'no-payable-asset'>;
3349
+
3350
+ /**
3351
+ * The reference panel beside the token-sale checkout: which token is being
3352
+ * bought, what one costs, whether the sale is running, and the terms that do
3353
+ * not move while the order is filled in.
3354
+ *
3355
+ * Read-only, so there is no `UiEvent`. Everything is known from the offer the
3356
+ * moment the checkout renders, so the state is a product rather than a union.
3357
+ *
3358
+ * @alpha
3359
+ */
3360
+ type TokenSaleSidebarUiState = {
3361
+ asset: CheckoutAssetUi;
3362
+ /** Whether the sale is running: a live countdown, or why it is not. */
3363
+ sale: CheckoutStatusUi;
3364
+ /** The option's price for one whole token, e.g. `$0.50`. */
3365
+ pricePerToken: FormattedAmountAssetUi;
3366
+ /**
3367
+ * The price times the option's total token supply, e.g. `$500,000,000.00`.
3368
+ * `-` when the option publishes no supply.
3369
+ */
3370
+ fullyDilutedValuation: FormattedAmountAssetUi;
3371
+ /** Display name of the chain the sale is paid on, e.g. `Ethereum`. */
3372
+ networkName: string;
3373
+ /** What the sale can be paid in, e.g. `USDC, USDT`. */
3374
+ purchaseOptionsLabel: string;
3375
+ /** The option's minimum, e.g. `$100.00`. `-` when it publishes none. */
3376
+ minPurchase: FormattedAmountAssetUi;
3377
+ };
3378
+
3379
+ /**
3380
+ * The whole CoinList token-sale checkout: three steps, the sale panel, and the
3381
+ * dialog that says the order was placed.
3382
+ *
3383
+ * @alpha
3384
+ */
3385
+ type CoinListTokenSaleCheckoutUiState = {
3386
+ type: 'content';
3387
+ /**
3388
+ * The wallet step, or `null` when the host preselected a wallet and the
3389
+ * flow skipped it. The later steps are numbered from it.
3390
+ */
3391
+ wallet: CheckoutWalletSelectUiState | null;
3392
+ amount: CheckoutAmountUiState;
3393
+ review: TokenSaleReviewUiState;
3394
+ sidebar: TokenSaleSidebarUiState;
3395
+ orderPlaced: TokenSaleOrderPlacedUiState;
3396
+ } | {
3397
+ type: 'error';
3398
+ reason: TokenSaleCheckoutErrorReason;
3399
+ };
3400
+ /** @alpha */
3401
+ type CoinListTokenSaleCheckoutUiEvent = CheckoutWalletSelectUiEvent | CheckoutAmountUiEvent | TokenSaleReviewUiEvent | TokenSaleOrderPlacedUiEvent;
3402
+ /**
3403
+ * The dialog that closes the checkout once the order is recorded.
3404
+ *
3405
+ * It reports a commitment, not a purchase: the sale allocates the tokens and
3406
+ * pulls the payment when it settles. The explorer link is the approval's,
3407
+ * the one transaction the order sent.
3408
+ *
3409
+ * @alpha
3410
+ */
3411
+ type TokenSaleOrderPlacedUiState = {
3412
+ type: 'hidden';
3413
+ } | ({
3414
+ type: 'visible';
3415
+ outputAsset: CheckoutAssetUi;
3416
+ /** What was committed, e.g. `100.00 USDC`. */
3417
+ payAmount: FormattedAmountAssetUi;
3418
+ /** How many tokens it buys at the option's price, e.g. `200.00 TKN`. */
3419
+ estimatedTokens: FormattedAmountAssetUi;
3420
+ } & CheckoutReceiptUi);
3421
+ /** @alpha */
3422
+ type TokenSaleOrderPlacedUiEvent = {
3423
+ type: 'ON_CLOSE_ORDER_PLACED';
3424
+ };
3425
+
3426
+ /** @alpha */
3427
+ interface UseCoinListTokenSaleCheckoutViewModelOptions {
3428
+ offer: CoinListTokenSaleOfferDetail;
3429
+ /** The chain the order is paid on. The sale must name a funding contract there. */
3430
+ chain: EthereumChain;
2861
3431
  /**
2862
- * Participations pre-fetched on the server (e.g. via `CoinListServer#tokenSale.list()`).
2863
- * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
3432
+ * The option being bought, which sets the price, the minimum and the sale
3433
+ * agreement. Defaults to the offer's first option.
3434
+ *
3435
+ * **Read once, at mount**: the price, minimum and agreement the steps were
3436
+ * filled in against are this option's. A host whose selection can change
3437
+ * remounts with a `key` covering it.
2864
3438
  */
2865
- data?: Participation[];
3439
+ optionId?: OfferOptionId;
2866
3440
  /**
2867
- * When `false`, the hook sends no request. A seeded or already-fetched
2868
- * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
3441
+ * The host's wallets, its connector for an external one if any, and
3442
+ * optionally the wallet it has already settled on.
3443
+ *
3444
+ * `wallets.preselected` is read **once**, to seed the step machine: set, the
3445
+ * flow has no wallet step and opens on the amount. A host that changes it
3446
+ * mid-flow is ignored, because the approval the review grants is granted by
3447
+ * one specific wallet.
2869
3448
  */
3449
+ wallets: CheckoutWalletSelection;
2870
3450
  enabled?: boolean;
3451
+ /** Fired once the participation is recorded. The dialog shows either way. */
3452
+ onOrderPlaced?: (order: TokenSaleOrderPlaced) => void;
2871
3453
  }
2872
- interface UseParticipationsResult {
2873
- participationsState: LoadParticipationsState;
3454
+ /** @alpha */
3455
+ interface UseCoinListTokenSaleCheckoutViewModelResult {
3456
+ state: CoinListTokenSaleCheckoutUiState;
3457
+ onEvent: (event: CoinListTokenSaleCheckoutUiEvent) => void;
2874
3458
  }
2875
3459
  /**
2876
- * Loads all CoinList participations for the current user and exposes a UI-friendly state.
2877
- * Optionally filters by offer when `offerId` is provided.
3460
+ * Drives the CoinList token-sale checkout.
2878
3461
  *
2879
- * Pass `data` (pre-fetched server-side) to use that data as-is and skip
2880
- * the client-side fetch entirely. Pass `enabled: false` to skip the fetch
2881
- * when the hook must be called but the data is not needed yet.
3462
+ * The container mounts this hook only. It composes the shared wallet and
3463
+ * amount steps, the review that places the order, and the sale panel. The
3464
+ * amount step only validates; the review approves the payment to the sale's
3465
+ * funding contract and records the participation.
2882
3466
  *
2883
- * Returns `LOADING` while CoinList is initializing or while participations are being fetched.
2884
- * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.
2885
- * Returns `ERROR` with:
2886
- * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
2887
- * - `generic-error` for any other failure
3467
+ * A sale that cannot take an order on this chain at all - no funding
3468
+ * contract, no such option, no fixed price, no coin the SDK can pay with -
3469
+ * replaces the whole checkout. A sale outside its window blocks the amount
3470
+ * and review steps instead, and the panel says when it opens or that it
3471
+ * ended.
3472
+ *
3473
+ * @alpha
2888
3474
  */
2889
- declare function useParticipations(offerId?: OfferId, options?: UseParticipationsOptions): UseParticipationsResult;
3475
+ declare function useCoinListTokenSaleCheckoutViewModel({ offer, chain, optionId: initialOptionId, wallets, enabled, onOrderPlaced, }: UseCoinListTokenSaleCheckoutViewModelOptions): UseCoinListTokenSaleCheckoutViewModelResult;
2890
3476
 
2891
3477
  /**
2892
3478
  * Step 2 of the Ondo checkout: how much to spend, and which asset to spend.
@@ -2952,28 +3538,43 @@ type OndoBuyAmountUiEvent = {
2952
3538
  * branch in every consumer to distinguish. Split it out if that stops being
2953
3539
  * true.
2954
3540
  */
2955
- type OndoLoadErrorReason = 'not-authenticated' | 'not-tradable' | 'generic-error';
3541
+ type OndoLoadErrorReason = LoadErrorReason | 'not-tradable';
2956
3542
 
2957
3543
  /**
2958
- * The state of the built purchase a review step acts on.
3544
+ * The state of a firm, expiring transaction a review step acts on.
3545
+ *
3546
+ * `DISABLED` means the caller switched the hook off before a transaction was
3547
+ * in hand, so nothing is being built. A transaction already in hand - a seed,
3548
+ * or an earlier build - survives being switched off.
2959
3549
  *
2960
- * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in
2961
- * flight never blanks the numbers the user is reading. A refresh that fails
2962
- * keeps them too, and reports why alongside - the previous purchase may still
2963
- * be good, and a failed refresh is fixed by refreshing again.
3550
+ * `isRefreshing` rides on `CONTENT` rather than replacing it, so a rebuild in
3551
+ * flight never blanks the numbers the user is reading. A rebuild that fails
3552
+ * keeps them too, and reports why alongside - the previous transaction may
3553
+ * still be good, and a failed rebuild is fixed by rebuilding again.
2964
3554
  */
2965
- type LoadOndoBuyTransactionState = {
3555
+ type LoadFirmTransactionState<T, R> = {
3556
+ type: 'DISABLED';
3557
+ } | {
2966
3558
  type: 'LOADING';
2967
3559
  } | {
2968
3560
  type: 'ERROR';
2969
- reason: OndoLoadErrorReason;
3561
+ reason: R;
2970
3562
  } | {
2971
3563
  type: 'CONTENT';
2972
- transaction: OndoBuyTransaction;
3564
+ transaction: T;
2973
3565
  isRefreshing: boolean;
2974
- /** Why the last refresh failed; `null` when the purchase is fresh. */
2975
- refreshError: OndoLoadErrorReason | null;
3566
+ /** Why the last rebuild failed; `null` when the transaction is fresh. */
3567
+ refreshError: R | null;
2976
3568
  };
3569
+
3570
+ /**
3571
+ * The state of the built purchase a review step acts on.
3572
+ *
3573
+ * `DISABLED` while switched off with no purchase in hand. `isRefreshing` rides
3574
+ * on `CONTENT`, so a refresh in flight never blanks the numbers the user is
3575
+ * reading, and a refresh that fails keeps them and says why.
3576
+ */
3577
+ type LoadOndoBuyTransactionState = LoadFirmTransactionState<OndoBuyTransaction, OndoLoadErrorReason>;
2977
3578
  interface UseOndoBuyTransactionOptions {
2978
3579
  /**
2979
3580
  * The order to build, or `null` while there is not one yet - before the
@@ -2997,29 +3598,50 @@ interface UseOndoBuyTransactionResult {
2997
3598
  }
2998
3599
  /**
2999
3600
  * Holds the firm, expiring purchase the buy review step places an order
3000
- * against, and rebuilds it on demand.
3001
- *
3002
- * **Never polls.** Building spends an attestation, so a new one is only ever
3003
- * obtained when the caller asks - on `refetch`, or on the first render if no
3004
- * `data` was supplied. That is also why an expired purchase is left expired
3005
- * here: whether to replace it is the user's call, not a timer's.
3006
- *
3007
- * Disabled it fetches nothing and stays on whatever state it opened with. That
3008
- * is `LOADING` and not an empty `CONTENT` because there is no empty
3009
- * purchase: firm calldata for an order that does not exist is not
3010
- * representable. A caller that switches this hook off should switch its own
3011
- * rendering off with it - which is what the review step does, since a step
3012
- * that is not active is `incomplete` and never reads this state at all.
3601
+ * against, and rebuilds it on demand. **Never polls**: each build spends an
3602
+ * attestation.
3013
3603
  *
3014
3604
  * One of a pair with `useOndoSellTransaction`, and deliberately not one hook
3015
- * over both. The two endpoints answer different shapes - a purchase commits to
3016
- * an exact quantity, a sale to a range - so a shared hook would hand every
3017
- * review step a union to narrow after its own directory had already settled
3018
- * which trade it was. The machinery below is the price of that, and it is the
3019
- * cheaper half: what a screen reads off `CONTENT` is the expensive half.
3605
+ * over both (ADR-10). The two endpoints answer different shapes - a purchase
3606
+ * commits to an exact quantity, a sale to a range - so a shared public hook
3607
+ * would hand every review step a union to narrow after its own directory had
3608
+ * already settled which trade it was. The machinery is shared instead, in
3609
+ * `useFirmTransaction`.
3020
3610
  */
3021
3611
  declare function useOndoBuyTransaction(options: UseOndoBuyTransactionOptions): UseOndoBuyTransactionResult;
3022
3612
 
3613
+ /**
3614
+ * Whether the numbers on an Ondo review step can still be traded on.
3615
+ *
3616
+ * A quote is only good for a few seconds, so this drives the line above the CTA
3617
+ * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
3618
+ * rather than folding into the step's `error`, because the remedy differs: a
3619
+ * failed refresh is fixed by refreshing again, a failed order is not.
3620
+ *
3621
+ * One type for both products, because a buy and a sell quote expire, refresh
3622
+ * and fail to refresh in exactly the same way: `useOndoReviewExecution` derives
3623
+ * it for both from the same firm transaction state.
3624
+ */
3625
+ type OndoQuoteStatusUi =
3626
+ /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
3627
+ {
3628
+ type: 'valid';
3629
+ expiresInLabel: string;
3630
+ }
3631
+ /** A refresh is in flight; the previous numbers are still on screen. */
3632
+ | {
3633
+ type: 'refreshing';
3634
+ }
3635
+ /** Too old to trade on. The user must refresh before placing the order. */
3636
+ | {
3637
+ type: 'expired';
3638
+ }
3639
+ /** The refresh failed. `message` says why. */
3640
+ | {
3641
+ type: 'refresh-failed';
3642
+ message: string;
3643
+ };
3644
+
3023
3645
  /**
3024
3646
  * Step 3 of the Ondo checkout: what the order comes to, and placing it.
3025
3647
  *
@@ -3057,38 +3679,11 @@ type OndoBuyReviewUiState = {
3057
3679
  coinlistFee: FormattedAmountAssetUi | null;
3058
3680
  /** What the user pays in the input asset, e.g. `1,000.00 USDC`. */
3059
3681
  total: FormattedAmountAssetUi;
3060
- quote: OndoBuyQuoteStatusUi;
3682
+ quote: OndoQuoteStatusUi;
3061
3683
  placeOrderCta: CheckoutCtaUi;
3062
3684
  /** A failure from placing the order, distinct from a quote problem. */
3063
3685
  error: string | null;
3064
3686
  };
3065
- /**
3066
- * Whether the shown numbers can still be traded on.
3067
- *
3068
- * A quote is only good for a few seconds, so this drives the line above the CTA
3069
- * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
3070
- * rather than folding into the step's `error`, because the remedy differs: a
3071
- * failed refresh is fixed by refreshing again, a failed order is not.
3072
- */
3073
- type OndoBuyQuoteStatusUi =
3074
- /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
3075
- {
3076
- type: 'valid';
3077
- expiresInLabel: string;
3078
- }
3079
- /** A refresh is in flight; the previous numbers are still on screen. */
3080
- | {
3081
- type: 'refreshing';
3082
- }
3083
- /** Too old to trade on. The user must refresh before placing the order. */
3084
- | {
3085
- type: 'expired';
3086
- }
3087
- /** The refresh failed. `message` says why. */
3088
- | {
3089
- type: 'refresh-failed';
3090
- message: string;
3091
- };
3092
3687
  type OndoBuyReviewUiEvent = {
3093
3688
  type: 'ON_REFRESH_QUOTE';
3094
3689
  }
@@ -3101,9 +3696,14 @@ type OndoBuyReviewUiEvent = {
3101
3696
 
3102
3697
  /**
3103
3698
  * Why an Ondo checkout cannot run right now, as opposed to a step of it
3104
- * failing.
3699
+ * failing. See {@link CheckoutBlockedReason} for `unsupported-chain`, which
3700
+ * here means the offer names no CoinList swap contract on the chain (see
3701
+ * `swapSpender`).
3105
3702
  *
3106
- * A union rather than a bare flag because the View switches on it for copy.
3703
+ * `not-tradable` is Ondo's block: it is not filling orders for this asset on
3704
+ * this side right now, because the market is closed or paused, or the asset is
3705
+ * paused or closed for the session. The trading-status poll keeps running
3706
+ * underneath it, and the checkout comes back once the asset is tradable again.
3107
3707
  *
3108
3708
  * Shared by both products because each reason is a property of the integration
3109
3709
  * or of the market rather than of a direction: buying and selling go through
@@ -3112,47 +3712,7 @@ type OndoBuyReviewUiEvent = {
3112
3712
  * exception the provider-level `shared/` exists for, and it is narrow - the
3113
3713
  * step states stay per-product, since that is where the two genuinely diverge.
3114
3714
  */
3115
- type OndoCheckoutErrorReason =
3116
- /**
3117
- * The offer names no CoinList swap contract on the chain the host asked for,
3118
- * so there is no spender to approve and nothing to broadcast to.
3119
- *
3120
- * Not retryable, and not the host's mistake to correct at runtime: both the
3121
- * offer and the chain are fixed for the lifetime of the mount. See
3122
- * `swapSpender`.
3123
- */
3124
- 'unsupported-chain'
3125
- /**
3126
- * Ondo is not filling orders for this asset on this side right now: the
3127
- * market is closed or paused, or the asset is paused or closed for the
3128
- * session. Known from the trading-status poll, never assumed from a status
3129
- * that is still loading or failed to load.
3130
- *
3131
- * Unlike `unsupported-chain` this one clears on its own. The trading-status
3132
- * poll keeps running underneath it, and the checkout comes back once the
3133
- * asset is tradable again. Only shown while the user is on the step the flow
3134
- * opened on: once they are past it, a pause is a step's to report, so it
3135
- * cannot pull an order out from under the user mid-flow.
3136
- */
3137
- | 'not-tradable';
3138
- declare const OndoCheckoutErrorReason: {
3139
- /**
3140
- * Which reason, if any, replaces the whole checkout. `null` means the steps
3141
- * render.
3142
- *
3143
- * `unsupported-chain` wins because it is settled at mount: no market state
3144
- * can make a chain with no contract tradable. `not-tradable` needs both a
3145
- * market *known* to be closed and a user still at the start of the flow,
3146
- * with no order confirmation on screen. Past the first step a pause belongs
3147
- * to the step it interrupts, and a just-placed order's dialog must not be
3148
- * hidden by a market that closed after it filled.
3149
- */
3150
- of: ({ swappableHere, notTradable, atEntry, }: {
3151
- swappableHere: boolean;
3152
- notTradable: boolean;
3153
- atEntry: boolean;
3154
- }) => OndoCheckoutErrorReason | null;
3155
- };
3715
+ type OndoCheckoutErrorReason = CheckoutBlockedReason<'not-tradable'>;
3156
3716
 
3157
3717
  /**
3158
3718
  * The reference panel beside the Ondo checkout: which asset is being bought,
@@ -3223,54 +3783,6 @@ type OndoSidebarPriceUi =
3223
3783
  type: 'unavailable';
3224
3784
  };
3225
3785
 
3226
- /**
3227
- * Step 1 of the Ondo checkout: which wallet funds the purchase and receives the
3228
- * asset.
3229
- *
3230
- * There is no `inactive` arm. This step is the first one, so it is either being
3231
- * filled in or already answered — it is never waiting on a step above it.
3232
- *
3233
- * Unlike Superstate's equivalent, nothing is allow-listed here: the user picks
3234
- * a wallet and confirms, and confirming is synchronous. Hence a plain
3235
- * `confirmEnabled` rather than the `CheckoutCtaUi` Superstate's step carries.
3236
- * The rows themselves are the shared `Checkout*WalletUi` models — the two
3237
- * providers render the same wallets and disagree only about what confirming
3238
- * does.
3239
- */
3240
- type OndoWalletSelectUiState = {
3241
- type: 'active';
3242
- /** The user's CoinList wallets. Empty when they have none. */
3243
- embeddedWallets: CheckoutEmbeddedWalletUi[];
3244
- /** `null` until an external wallet is connected. The row still renders. */
3245
- externalWallet: CheckoutWalletUi | null;
3246
- /** Whether the connected external wallet may be disconnected here. */
3247
- canDisconnect: boolean;
3248
- confirmEnabled: boolean;
3249
- /** Copy for a failed connect, e.g. the user rejected the wallet prompt. */
3250
- error: string | null;
3251
- } | {
3252
- type: 'completed';
3253
- wallet: CheckoutConfirmedWalletUi;
3254
- };
3255
- type OndoWalletSelectUiEvent = {
3256
- type: 'ON_SELECT_WALLET';
3257
- value: CheckoutWalletTypeUi;
3258
- }
3259
- /**
3260
- * Tapping the external row while nothing is connected. Split from
3261
- * `ON_SELECT_WALLET` because it opens the host's wallet connector rather than
3262
- * changing the selection.
3263
- */
3264
- | {
3265
- type: 'ON_CONNECT_WALLET';
3266
- } | {
3267
- type: 'ON_DISCONNECT_WALLET';
3268
- } | {
3269
- type: 'ON_CONFIRM_WALLET';
3270
- } | {
3271
- type: 'ON_EDIT_WALLET';
3272
- };
3273
-
3274
3786
  /**
3275
3787
  * The whole Ondo buy checkout: three step cards, the reference panel beside
3276
3788
  * them, and the dialog that closes the flow.
@@ -3290,7 +3802,12 @@ type OndoWalletSelectUiEvent = {
3290
3802
  */
3291
3803
  type OndoBuyCheckoutUiState = {
3292
3804
  type: 'content';
3293
- wallet: OndoWalletSelectUiState;
3805
+ /**
3806
+ * The wallet step, or `null` when the host preselected a wallet and the
3807
+ * flow skipped it. The later steps are numbered from it. Never `null`
3808
+ * today: the buy flow does not honour a preselection yet.
3809
+ */
3810
+ wallet: CheckoutWalletSelectUiState | null;
3294
3811
  amount: OndoBuyAmountUiState;
3295
3812
  review: OndoBuyReviewUiState;
3296
3813
  /** The asset panel. Read-only, so it raises no events. */
@@ -3316,7 +3833,7 @@ type OndoBuyCheckoutUiState = {
3316
3833
  * tags must stay globally unique, which is why the edit events are
3317
3834
  * `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared `ON_EDIT`.
3318
3835
  */
3319
- type OndoBuyCheckoutUiEvent = OndoWalletSelectUiEvent | OndoBuyAmountUiEvent | OndoBuyReviewUiEvent | OndoOrderConfirmedUiEvent;
3836
+ type OndoBuyCheckoutUiEvent = CheckoutWalletSelectUiEvent | OndoBuyAmountUiEvent | OndoBuyReviewUiEvent | OndoOrderConfirmedUiEvent;
3320
3837
  /**
3321
3838
  * The dialog that closes the Ondo checkout, once the swap is mined.
3322
3839
  *
@@ -3326,7 +3843,7 @@ type OndoBuyCheckoutUiEvent = OndoWalletSelectUiEvent | OndoBuyAmountUiEvent | O
3326
3843
  */
3327
3844
  type OndoOrderConfirmedUiState = {
3328
3845
  type: 'hidden';
3329
- } | {
3846
+ } | ({
3330
3847
  type: 'visible';
3331
3848
  /**
3332
3849
  * What was bought.
@@ -3342,14 +3859,7 @@ type OndoOrderConfirmedUiState = {
3342
3859
  totalCost: FormattedAmountAssetUi;
3343
3860
  /** Price of one whole token at the time of the fill, e.g. `$378.99`. */
3344
3861
  pricePerShare: FormattedAmountAssetUi;
3345
- /** The wallet the asset was delivered to. */
3346
- recipientAddress: ShortenedWalletAddress;
3347
- /**
3348
- * The settled swap on a block explorer. Always present: the dialog only
3349
- * exists once there is a mined transaction to point at.
3350
- */
3351
- txExplorerUrl: TxExplorerUrl;
3352
- };
3862
+ } & CheckoutReceiptUi);
3353
3863
  /**
3354
3864
  * Closing is the only thing the dialog raises.
3355
3865
  *
@@ -3378,7 +3888,17 @@ interface UseOndoBuyCheckoutViewModelOptions {
3378
3888
  * Fixed for the lifetime of the hook, as `offer` is.
3379
3889
  */
3380
3890
  chain: EthereumChain;
3381
- /** The host's wallets, and the lambdas that connect and disconnect one. */
3891
+ /**
3892
+ * The host's wallets, its connector for an external one if any, and
3893
+ * optionally the wallet it has already settled on.
3894
+ *
3895
+ * `wallets.preselected` is read **once**, to seed the step machine: set, the
3896
+ * flow has no wallet step and opens on the amount. A host that changes it
3897
+ * mid-flow is ignored, because the approval that follows the amount step is
3898
+ * granted by one specific wallet, and moving the flow onto another one under
3899
+ * it would strand that approval and build calldata the new wallet cannot
3900
+ * broadcast.
3901
+ */
3382
3902
  wallets: CheckoutWalletSelection;
3383
3903
  /**
3384
3904
  * Default `true`. When `false` nothing is fetched and no timer runs, for a
@@ -3417,12 +3937,12 @@ interface UseOndoBuyCheckoutViewModelResult {
3417
3937
  * wallet is the same kind of answer for as long as it lasts. See
3418
3938
  * {@link OndoCheckoutErrorReason}.
3419
3939
  *
3420
- * `offer` and `chain` are read as fixed for the lifetime of the hook. The step
3421
- * machine holds a committed quote and an approval granted on one chain for one
3422
- * order, so changing either in place would carry them onto an order they were
3423
- * never priced for. Remount instead: give the component holding this hook a
3424
- * `key` that changes with the offer and the chain, as {@link CheckoutContainer}
3425
- * documents. That discards the flow with its component instance, which is the
3940
+ * `offer` and `chain` are read as fixed for the lifetime of the hook, and so is
3941
+ * the wallet the flow opened on. The step machine holds a committed quote and
3942
+ * an approval granted on one chain by one wallet for one order, so changing any
3943
+ * of them in place would carry them onto an order they were never priced for.
3944
+ * Remount instead: give the component holding this hook a `key` that changes
3945
+ * with the offer and the chain, as {@link CheckoutContainer} documents. That discards the flow with its component instance, which is the
3426
3946
  * only reset that cannot land between an approval and the broadcast it was
3427
3947
  * granted for.
3428
3948
  */
@@ -3506,23 +4026,11 @@ type OndoSellAmountUiEvent = {
3506
4026
  /**
3507
4027
  * The state of the built sale a review step acts on.
3508
4028
  *
3509
- * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in
3510
- * flight never blanks the numbers the user is reading. A refresh that fails
3511
- * keeps them too, and reports why alongside - the previous sale may still
3512
- * be good, and a failed refresh is fixed by refreshing again.
4029
+ * `DISABLED` while switched off with no sale in hand. `isRefreshing` rides on
4030
+ * `CONTENT`, so a refresh in flight never blanks the numbers the user is
4031
+ * reading, and a refresh that fails keeps them and says why.
3513
4032
  */
3514
- type LoadOndoSellTransactionState = {
3515
- type: 'LOADING';
3516
- } | {
3517
- type: 'ERROR';
3518
- reason: OndoLoadErrorReason;
3519
- } | {
3520
- type: 'CONTENT';
3521
- transaction: OndoSellTransaction;
3522
- isRefreshing: boolean;
3523
- /** Why the last refresh failed; `null` when the sale is fresh. */
3524
- refreshError: OndoLoadErrorReason | null;
3525
- };
4033
+ type LoadOndoSellTransactionState = LoadFirmTransactionState<OndoSellTransaction, OndoLoadErrorReason>;
3526
4034
  interface UseOndoSellTransactionOptions {
3527
4035
  /**
3528
4036
  * The order to build, or `null` while there is not one yet - before the
@@ -3545,26 +4053,15 @@ interface UseOndoSellTransactionResult {
3545
4053
  refetch: () => void;
3546
4054
  }
3547
4055
  /**
3548
- * Holds the firm, expiring sale the sell review step places an order
3549
- * against, and rebuilds it on demand.
3550
- *
3551
- * **Never polls.** Building spends an attestation, so a new one is only ever
3552
- * obtained when the caller asks - on `refetch`, or on the first render if no
3553
- * `data` was supplied. That is also why an expired sale is left expired
3554
- * here: whether to replace it is the user's call, not a timer's.
3555
- *
3556
- * Disabled it fetches nothing and stays on whatever state it opened with. That
3557
- * is `LOADING` and not an empty `CONTENT` because there is no empty
3558
- * sale: firm calldata for an order that does not exist is not
3559
- * representable. A caller that switches this hook off should switch its own
3560
- * rendering off with it - which is what the review step does, since a step
3561
- * that is not active is `incomplete` and never reads this state at all.
4056
+ * Holds the firm, expiring sale the sell review step places an order against,
4057
+ * and rebuilds it on demand. **Never polls**: each build spends an
4058
+ * attestation.
3562
4059
  *
3563
4060
  * The sell half of the pair `useOndoBuyTransaction` opens - see there for why
3564
- * the two are not one hook. What differs is entirely in what `CONTENT` carries:
3565
- * an {@link OndoSellTransaction} publishes an expected outcome and a floor
3566
- * beneath it rather than one attested quantity, and the review step renders
3567
- * both.
4061
+ * the two are not one hook. What differs is entirely in what `CONTENT`
4062
+ * carries: an {@link OndoSellTransaction} publishes an expected outcome and a
4063
+ * floor beneath it rather than one attested quantity, and the review step
4064
+ * renders both.
3568
4065
  */
3569
4066
  declare function useOndoSellTransaction(options: UseOndoSellTransactionOptions): UseOndoSellTransactionResult;
3570
4067
 
@@ -3624,7 +4121,7 @@ type OndoSellReviewUiState = {
3624
4121
  * is what the order is expected to fill at.
3625
4122
  */
3626
4123
  pricePerShare: FormattedAmountAssetUi;
3627
- quote: OndoSellQuoteStatusUi;
4124
+ quote: OndoQuoteStatusUi;
3628
4125
  placeOrderCta: CheckoutCtaUi;
3629
4126
  /** A failure from placing the order, distinct from a quote problem. */
3630
4127
  error: string | null;
@@ -3657,33 +4154,6 @@ type OndoSellOutcomeUi = {
3657
4154
  */
3658
4155
  fee: FormattedAmountAssetUi | null;
3659
4156
  };
3660
- /**
3661
- * Whether the shown numbers can still be traded on.
3662
- *
3663
- * A quote is only good for a few seconds, so this drives the line above the CTA
3664
- * and whether the CTA can be pressed at all. `refresh-failed` is its own arm
3665
- * rather than folding into the step's `error`, because the remedy differs: a
3666
- * failed refresh is fixed by refreshing again, a failed order is not.
3667
- */
3668
- type OndoSellQuoteStatusUi =
3669
- /** Still good. `expiresInLabel` is the countdown copy, already formatted. */
3670
- {
3671
- type: 'valid';
3672
- expiresInLabel: string;
3673
- }
3674
- /** A refresh is in flight; the previous numbers are still on screen. */
3675
- | {
3676
- type: 'refreshing';
3677
- }
3678
- /** Too old to trade on. The user must refresh before placing the order. */
3679
- | {
3680
- type: 'expired';
3681
- }
3682
- /** The refresh failed. `message` says why. */
3683
- | {
3684
- type: 'refresh-failed';
3685
- message: string;
3686
- };
3687
4157
  type OndoSellReviewUiEvent = {
3688
4158
  type: 'ON_REFRESH_SELL_QUOTE';
3689
4159
  }
@@ -3719,7 +4189,7 @@ type OndoSellCheckoutUiState = {
3719
4189
  * two-step flow numbered `1, 2` and a three-step flow numbered `1, 2, 3`
3720
4190
  * cannot disagree. A boolean beside a non-null state would have let them.
3721
4191
  */
3722
- wallet: OndoWalletSelectUiState | null;
4192
+ wallet: CheckoutWalletSelectUiState | null;
3723
4193
  amount: OndoSellAmountUiState;
3724
4194
  review: OndoSellReviewUiState;
3725
4195
  /** The asset panel. Read-only, so it raises no events. */
@@ -3747,7 +4217,7 @@ type OndoSellCheckoutUiState = {
3747
4217
  * separate, and a shared tag would make one product's event dispatch into the
3748
4218
  * other's handler in any host that composed both.
3749
4219
  */
3750
- type OndoSellCheckoutUiEvent = OndoWalletSelectUiEvent | OndoSellAmountUiEvent | OndoSellReviewUiEvent | OndoSellOrderConfirmedUiEvent;
4220
+ type OndoSellCheckoutUiEvent = CheckoutWalletSelectUiEvent | OndoSellAmountUiEvent | OndoSellReviewUiEvent | OndoSellOrderConfirmedUiEvent;
3751
4221
  /**
3752
4222
  * The dialog that closes the Ondo sell checkout, once the swap is mined.
3753
4223
  *
@@ -3757,7 +4227,7 @@ type OndoSellCheckoutUiEvent = OndoWalletSelectUiEvent | OndoSellAmountUiEvent |
3757
4227
  */
3758
4228
  type OndoSellOrderConfirmedUiState = {
3759
4229
  type: 'hidden';
3760
- } | {
4230
+ } | ({
3761
4231
  type: 'visible';
3762
4232
  /**
3763
4233
  * What was sold.
@@ -3782,14 +4252,7 @@ type OndoSellOrderConfirmedUiState = {
3782
4252
  proceedsSymbol: AssetSymbol;
3783
4253
  /** Price of one whole token at the time of the fill, e.g. `$378.99`. */
3784
4254
  pricePerShare: FormattedAmountAssetUi;
3785
- /** The wallet the proceeds were delivered to. */
3786
- recipientAddress: ShortenedWalletAddress;
3787
- /**
3788
- * The settled swap on a block explorer. Always present: the dialog only
3789
- * exists once there is a mined transaction to point at.
3790
- */
3791
- txExplorerUrl: TxExplorerUrl;
3792
- };
4255
+ } & CheckoutReceiptUi);
3793
4256
  /**
3794
4257
  * Closing is the only thing the dialog raises.
3795
4258
  *
@@ -3819,7 +4282,7 @@ interface UseOndoSellCheckoutViewModelOptions {
3819
4282
  */
3820
4283
  chain: EthereumChain;
3821
4284
  /**
3822
- * The host's wallets, the lambdas that connect and disconnect one, and
4285
+ * The host's wallets, its connector for an external one if any, and
3823
4286
  * optionally the wallet it has already settled on.
3824
4287
  *
3825
4288
  * `wallets.preselected` is read **once**, to seed the step machine. A host
@@ -3884,6 +4347,7 @@ declare function useOndoSellCheckoutViewModel({ offer, chain, wallets, enabled,
3884
4347
  /**
3885
4348
  * The state of the indicative-price poll.
3886
4349
  *
4350
+ * - `DISABLED`: switched off with no price in hand, so none is coming.
3887
4351
  * - `LOADING`: no price yet (initial, or the provider is still initializing).
3888
4352
  * - `ERROR`: no price could be fetched at all.
3889
4353
  * - `CONTENT`: a price is in hand; `isRefreshing` says whether a newer one is
@@ -3895,6 +4359,8 @@ declare function useOndoSellCheckoutViewModel({ offer, chain, wallets, enabled,
3895
4359
  * when the UI has nothing to show.
3896
4360
  */
3897
4361
  type LoadOndoPriceState = {
4362
+ type: 'DISABLED';
4363
+ } | {
3898
4364
  type: 'LOADING';
3899
4365
  } | {
3900
4366
  type: 'ERROR';
@@ -3941,15 +4407,12 @@ interface UseOndoPriceResult {
3941
4407
  * - committing a fillable quote is `coinlist.ondo.prepareBuy` or
3942
4408
  * `coinlist.ondo.prepareSell`, whichever way the trade runs.
3943
4409
  *
3944
- * Disabled (or before the provider is ready) it neither fetches nor holds a
3945
- * timer, and stays on whatever state it opened with - `LOADING`, or the `data`
3946
- * seed - rather than reporting an error.
3947
- *
3948
- * That is `LOADING` and not an empty `CONTENT` because there is no empty price:
3949
- * a hook whose content is a list can fall back to `[]` the way
3950
- * `useOptionAddresses` does, and one whose content is a number cannot. A caller
3951
- * that switches this hook off should switch its own rendering off with it,
3952
- * rather than read `LOADING` as "a price is coming".
4410
+ * Disabled it neither fetches nor holds a timer. With no price in hand it
4411
+ * reports `DISABLED` - not `LOADING`, since nothing is coming, and not an
4412
+ * empty `CONTENT`, since there is no empty price. A price already in hand (the
4413
+ * `data` seed, or an earlier tick) survives being switched off. Before the
4414
+ * provider is ready it is `LOADING`: the read is coming, it just cannot leave
4415
+ * yet.
3953
4416
  *
3954
4417
  * A `data` price opens the state instead of `LOADING` and is otherwise left to
3955
4418
  * the poll: the first tick fires as it always does, and only replaces the seed
@@ -3969,6 +4432,8 @@ declare function useOndoPrice(options: UseOndoPriceOptions): UseOndoPriceResult;
3969
4432
  * unknown may not.
3970
4433
  */
3971
4434
  type LoadOndoTradingStatusState = {
4435
+ type: 'DISABLED';
4436
+ } | {
3972
4437
  type: 'LOADING';
3973
4438
  } | {
3974
4439
  type: 'ERROR';
@@ -3979,8 +4444,8 @@ type LoadOndoTradingStatusState = {
3979
4444
  };
3980
4445
  /**
3981
4446
  * Whether the market is *known* to be closed for this side: the one reading of
3982
- * the poll a caller may block an order on. `LOADING` and `ERROR` are unknown,
3983
- * and unknown never blocks.
4447
+ * the poll a caller may block an order on. `DISABLED`, `LOADING` and `ERROR`
4448
+ * are unknown, and unknown never blocks.
3984
4449
  */
3985
4450
  declare function isNotTradable(state: LoadOndoTradingStatusState): boolean;
3986
4451
  interface UseOndoTradingStatusOptions {
@@ -4023,94 +4488,30 @@ interface UseOndoTradingStatusResult {
4023
4488
  * the poll: the first tick fires as it always does, and only replaces the seed
4024
4489
  * once it has a status of its own.
4025
4490
  *
4026
- * Disabled it neither fetches nor holds a timer, and stays on whatever state it
4027
- * opened with. That is `LOADING` and not an empty `CONTENT` because there is no
4028
- * empty market status - and an invented one would be worse than none, since
4029
- * `CONTENT` here is what a caller is allowed to block an order on. A caller
4030
- * that switches this hook off should switch its own rendering off with it.
4491
+ * Disabled it neither fetches nor holds a timer. With no status in hand it
4492
+ * reports `DISABLED`, not an empty `CONTENT`: there is no empty market status,
4493
+ * and an invented one would be worse than none, since `CONTENT` here is what a
4494
+ * caller is allowed to block an order on. A status already in hand survives
4495
+ * being switched off.
4031
4496
  */
4032
4497
  declare function useOndoTradingStatus(options: UseOndoTradingStatusOptions): UseOndoTradingStatusResult;
4033
4498
 
4034
4499
  /**
4035
- * Step 2 of the Superstate checkout: how much to spend, and which asset to
4036
- * spend.
4037
- *
4038
- * Nothing here touches the chain. Unlike Ondo's amount step, which approves and
4039
- * commits a quote, this one only validates locally and hands the amount up — a
4040
- * Superstate swap approves and executes together on the review step. Hence a
4041
- * plain `confirmEnabled` rather than a `CheckoutCtaUi` with loading copy: there
4042
- * is no phase to report.
4043
- */
4044
- type SuperstateAmountUiState = {
4045
- type: 'incomplete';
4046
- } | {
4047
- type: 'active';
4048
- /**
4049
- * Exactly what the user has typed, not a parsed number: the field is
4050
- * mid-edit, and `'1.'` is a legal thing to be holding.
4051
- */
4052
- amountInput: string;
4053
- /** The wallet the funds come from, per step 1. */
4054
- walletAddress: ShortenedWalletAddress;
4055
- /**
4056
- * Every supported input asset, in display order, whether or not the user
4057
- * holds any. One entry renders as a plain card, two or more as a picker.
4058
- */
4059
- inputAssets: CheckoutSelectableInputAssetUi[];
4060
- confirmEnabled: boolean;
4061
- /** Validation copy, e.g. `Amount must be greater than 0.` */
4062
- error: string | null;
4063
- } | {
4064
- type: 'complete';
4065
- inputAsset: CheckoutAssetUi;
4066
- /**
4067
- * What the user is spending, as the field asked for it: dollars, e.g.
4068
- * `$1,000.00`. The Superstate field is dollar-denominated, which is why
4069
- * this is prefixed rather than suffixed with a symbol.
4070
- */
4071
- amountFormatted: FormattedAmountAssetUi;
4072
- /**
4073
- * The same figure in the asset actually being paid, e.g. `1,000.00 USDC`.
4074
- *
4075
- * Both are shown because the two are only equal while the funding asset
4076
- * is a dollar stablecoin — the day a non-dollar one is fundable, the
4077
- * summary would otherwise silently claim it was.
4078
- */
4079
- inputAmountFormatted: FormattedAmountAssetUi;
4080
- };
4081
- type SuperstateAmountUiEvent = {
4082
- type: 'ON_AMOUNT_CHANGE';
4083
- value: string;
4084
- } | {
4085
- type: 'ON_MAX_AMOUNT_CLICK';
4086
- } | {
4087
- type: 'ON_SELECT_PAY_WITH';
4088
- value: AssetSymbol;
4089
- }
4090
- /**
4091
- * Named for what it does rather than for the step: confirming here previews
4092
- * the order on step 3, it does not place or pay for anything.
4093
- */
4094
- | {
4095
- type: 'ON_PREVIEW_ORDER';
4096
- } | {
4097
- type: 'ON_EDIT_AMOUNT';
4098
- };
4099
-
4100
- /**
4101
- * The state of the swap's output-token fetch.
4500
+ * The state of the swap's output-token read.
4102
4501
  *
4103
- * - `LOADING`: no result yet (initial, or provider still initializing).
4104
- * - `ERROR`: the fetch failed.
4105
- * - `CONTENT`: the output token was fetched successfully.
4106
- *
4107
- * A stale `CONTENT`/`ERROR` is preserved while a re-fetch (e.g. after a chain
4108
- * change) is in flight, rather than flipping back to `LOADING`.
4502
+ * - `DISABLED`: switched off before an answer arrived.
4503
+ * - `LOADING`: no answer yet (initial, a re-read after the contract or chain
4504
+ * changed, or the provider still initializing).
4505
+ * - `ERROR`: the read failed.
4506
+ * - `CONTENT`: the output token was read.
4109
4507
  */
4110
- type SwapOutputTokenState = {
4508
+ type LoadSwapOutputTokenState = {
4509
+ type: 'DISABLED';
4510
+ } | {
4111
4511
  type: 'LOADING';
4112
4512
  } | {
4113
4513
  type: 'ERROR';
4514
+ reason: LoadErrorReason;
4114
4515
  } | {
4115
4516
  type: 'CONTENT';
4116
4517
  outputToken: Erc20Asset;
@@ -4123,12 +4524,12 @@ interface UseSwapOutputTokenOptions {
4123
4524
  enabled: boolean;
4124
4525
  }
4125
4526
  interface UseSwapOutputTokenResult {
4126
- outputTokenState: SwapOutputTokenState;
4527
+ state: LoadSwapOutputTokenState;
4127
4528
  /**
4128
- * Runs the fetch again after a failure.
4529
+ * Runs the read again after a failure.
4129
4530
  *
4130
4531
  * The output token is read once and never polled, so `ERROR` is otherwise
4131
- * terminal until a dependency changes — and without it there is no quote,
4532
+ * terminal until a dependency changes - and without it there is no quote,
4132
4533
  * no price and no minimum received, which is why the Superstate checkout
4133
4534
  * surfaces it as a whole-flow failure with a retry rather than as one
4134
4535
  * unavailable corner.
@@ -4136,11 +4537,11 @@ interface UseSwapOutputTokenResult {
4136
4537
  refetch: () => void;
4137
4538
  }
4138
4539
  /**
4139
- * Fetches the ERC-20 output token a swap contract pays out. Re-fetches when the
4540
+ * Reads the ERC-20 output token a swap contract pays out. Reads again when the
4140
4541
  * contract or chain changes, and once when `enabled` flips to true.
4141
4542
  *
4142
- * The fetch runs once (no polling); a failure resolves to `ERROR` and is not
4143
- * retried until a dependency changes.
4543
+ * The read runs once (no polling); a failure resolves to `ERROR` and is not
4544
+ * retried until a dependency changes or `refetch` is called.
4144
4545
  */
4145
4546
  declare function useSwapOutputToken(options: UseSwapOutputTokenOptions): UseSwapOutputTokenResult;
4146
4547
 
@@ -4161,21 +4562,45 @@ interface UseSwapQuoteOptions {
4161
4562
  /** When false, the hook neither fetches nor polls. */
4162
4563
  enabled: boolean;
4163
4564
  }
4164
- interface UseSwapQuoteResult {
4165
- /** The latest quote, or `null` until the first successful fetch. */
4166
- quote: SwapQuote | null;
4167
- /** True until the first quote arrives; false while the hook is disabled. */
4168
- isLoading: boolean;
4169
- /** True while a background poll refreshes an existing quote. */
4565
+ /**
4566
+ * The state of the quote poll.
4567
+ *
4568
+ * - `DISABLED`: switched off with no quote in hand, so none is coming.
4569
+ * - `LOADING`: no quote yet - the first read is in flight, the provider is
4570
+ * still initializing, or the output token's decimals are not known yet.
4571
+ * - `ERROR`: no quote could be read at all.
4572
+ * - `CONTENT`: a quote is in hand; `isRefreshing` says whether a newer one is
4573
+ * on the way.
4574
+ *
4575
+ * A tick that fails with a quote already in hand stays `CONTENT`, so `ERROR`
4576
+ * means "never got one". A quote also survives a change of amount until the
4577
+ * new one lands, with `isRefreshing` set: the review step compares the quote
4578
+ * against the amount, and that flag is what tells it the mismatch is a reprice
4579
+ * in flight rather than a quote for the wrong order.
4580
+ */
4581
+ type LoadSwapQuoteState = {
4582
+ type: 'DISABLED';
4583
+ } | {
4584
+ type: 'LOADING';
4585
+ } | {
4586
+ type: 'ERROR';
4587
+ reason: LoadErrorReason;
4588
+ } | {
4589
+ type: 'CONTENT';
4590
+ quote: SwapQuote;
4170
4591
  isRefreshing: boolean;
4592
+ };
4593
+ interface UseSwapQuoteResult {
4594
+ state: LoadSwapQuoteState;
4171
4595
  }
4172
4596
  /**
4173
4597
  * Polls a read-only swap quote for `inputAmount` of `inputTokenAddress` against
4174
4598
  * the given swap contract, refreshing every `pollIntervalMs`.
4175
4599
  *
4176
- * A failed fetch is swallowed: the last quote stays visible and the next poll
4177
- * tick retries. Quoting is skipped while `outputTokenDecimals` is `null` or
4178
- * `enabled` is false, and until the CoinList provider finishes initializing.
4600
+ * A failed tick with a quote in hand keeps it and the next tick retries.
4601
+ * Quoting waits while `outputTokenDecimals` is `null` and until the CoinList
4602
+ * provider finishes initializing. Disabled it neither fetches nor holds a
4603
+ * timer; a quote already in hand survives being switched off.
4179
4604
  */
4180
4605
  declare function useSwapQuote(options: UseSwapQuoteOptions): UseSwapQuoteResult;
4181
4606
 
@@ -4338,10 +4763,11 @@ type SuperstateWalletUiState = {
4338
4763
  type: 'active';
4339
4764
  /** The user's CoinList wallets. Empty when they have none. */
4340
4765
  embeddedWallets: CheckoutEmbeddedWalletUi[];
4341
- /** `null` until an external wallet is connected. The row still renders. */
4342
- externalWallet: CheckoutWalletUi | null;
4343
- /** Whether the connected external wallet may be disconnected here. */
4344
- canDisconnect: boolean;
4766
+ /**
4767
+ * The external-wallet row: absent when the host offers no connector,
4768
+ * an invitation to connect one, or the connected wallet.
4769
+ */
4770
+ externalWallet: CheckoutExternalWalletUi;
4345
4771
  /**
4346
4772
  * Confirming runs the authorization, so this reports its phase as
4347
4773
  * loading copy — `Sign the message in your wallet…` and the rest.
@@ -4385,7 +4811,7 @@ type SuperstateWalletUiEvent = {
4385
4811
  type SuperstateSwapCheckoutUiState = {
4386
4812
  type: 'content';
4387
4813
  wallet: SuperstateWalletUiState;
4388
- amount: SuperstateAmountUiState;
4814
+ amount: CheckoutAmountUiState;
4389
4815
  review: SuperstateReviewUiState;
4390
4816
  /** The sale panel. Read-only, so it raises no events. */
4391
4817
  sidebar: SuperstateSidebarUiState;
@@ -4420,7 +4846,7 @@ type SuperstateSwapLoadErrorReason =
4420
4846
  * edit events are `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared
4421
4847
  * `ON_EDIT`.
4422
4848
  */
4423
- type SuperstateSwapCheckoutUiEvent = SuperstateWalletUiEvent | SuperstateAmountUiEvent | SuperstateReviewUiEvent | SuperstateOrderConfirmedUiEvent | SuperstateSwapCheckoutRetryUiEvent;
4849
+ type SuperstateSwapCheckoutUiEvent = SuperstateWalletUiEvent | CheckoutAmountUiEvent | SuperstateReviewUiEvent | SuperstateOrderConfirmedUiEvent | SuperstateSwapCheckoutRetryUiEvent;
4424
4850
  /**
4425
4851
  * Retrying the load behind the flow-level `error` arm.
4426
4852
  *
@@ -4440,7 +4866,7 @@ type SuperstateSwapCheckoutRetryUiEvent = {
4440
4866
  */
4441
4867
  type SuperstateOrderConfirmedUiState = {
4442
4868
  type: 'hidden';
4443
- } | {
4869
+ } | ({
4444
4870
  type: 'visible';
4445
4871
  /** What was bought. */
4446
4872
  asset: CheckoutAssetUi;
@@ -4464,14 +4890,7 @@ type SuperstateOrderConfirmedUiState = {
4464
4890
  * `outputAmount`, so `outputAmountConfirmed` covers it too.
4465
4891
  */
4466
4892
  pricePerShare: FormattedAmountAssetUi;
4467
- /** The wallet the asset was delivered to. */
4468
- recipientAddress: ShortenedWalletAddress;
4469
- /**
4470
- * The settled swap on a block explorer. Always present: the dialog only
4471
- * exists once there is a mined transaction to point at.
4472
- */
4473
- txExplorerUrl: TxExplorerUrl;
4474
- };
4893
+ } & CheckoutReceiptUi);
4475
4894
  /**
4476
4895
  * Closing is the only thing the dialog raises.
4477
4896
  *
@@ -4499,7 +4918,17 @@ interface UseSuperstateSwapCheckoutViewModelOptions {
4499
4918
  * Fixed for the lifetime of the hook, as `offer` is.
4500
4919
  */
4501
4920
  chain: EthereumChain;
4502
- /** The host's wallets, and the lambdas that connect and disconnect one. */
4921
+ /**
4922
+ * The host's wallets, its connector for an external one if any, and
4923
+ * optionally the wallet it has already settled on.
4924
+ *
4925
+ * `wallets.preselected` never skips the wallet step here: that step
4926
+ * allow-lists the wallet on-chain, which no preselection can stand in for.
4927
+ * It pre-selects the wallet's row instead, so the user confirms and
4928
+ * allow-lists it rather than picking it again. A preselected wallet that
4929
+ * is neither one of `embedded` nor the connected `external` has no row to
4930
+ * select, and the step opens with nothing picked.
4931
+ */
4503
4932
  wallets: CheckoutWalletSelection;
4504
4933
  /**
4505
4934
  * Default `true`. When `false` nothing is fetched and no timer runs, for a
@@ -4598,11 +5027,14 @@ declare function useCentrifugeClaim(): UseCentrifugeClaimResult;
4598
5027
  * failures: a flaky tick must not make a claimable position vanish under the
4599
5028
  * user. A read that has never answered is absent, not zero. `ERROR` is
4600
5029
  * reserved for the case where nothing answered at all, so a screen has
4601
- * nothing to show but a retry.
5030
+ * nothing to show but a retry. `DISABLED` means the hook is switched off and
5031
+ * holds nothing.
4602
5032
  *
4603
5033
  * @alpha
4604
5034
  */
4605
5035
  type LoadCentrifugeClaimPositionsState = {
5036
+ type: 'DISABLED';
5037
+ } | {
4606
5038
  type: 'LOADING';
4607
5039
  } | {
4608
5040
  type: 'ERROR';
@@ -4629,8 +5061,7 @@ interface UseCentrifugeClaimPositionsOptions {
4629
5061
  */
4630
5062
  data?: CentrifugeVaultLeg[];
4631
5063
  /**
4632
- * Default `true`. When `false`: no requests, no timers, and an empty
4633
- * `CONTENT`.
5064
+ * Default `true`. When `false`: no requests, no timers, and `DISABLED`.
4634
5065
  */
4635
5066
  enabled?: boolean;
4636
5067
  }
@@ -4663,86 +5094,6 @@ interface UseCentrifugeClaimPositionsResult {
4663
5094
  */
4664
5095
  declare function useCentrifugeClaimPositions(options: UseCentrifugeClaimPositionsOptions): UseCentrifugeClaimPositionsResult;
4665
5096
 
4666
- type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';
4667
- type LoadOfferDetailsState = {
4668
- type: 'LOADING';
4669
- } | {
4670
- type: 'ERROR';
4671
- reason: LoadOfferDetailsReason;
4672
- } | {
4673
- type: 'CONTENT';
4674
- offerDetail: OfferDetail;
4675
- };
4676
- interface UseOfferDetailsOptions {
4677
- /**
4678
- * Offer detail pre-fetched on the server (e.g. via `CoinListServer#offers.get()`).
4679
- * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
4680
- */
4681
- data?: OfferDetail;
4682
- /**
4683
- * When `false`, the hook sends no request. A seeded or already-fetched
4684
- * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
4685
- */
4686
- enabled?: boolean;
4687
- }
4688
- interface UseOfferDetailsResult {
4689
- offerDetailsState: LoadOfferDetailsState;
4690
- }
4691
- /**
4692
- * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.
4693
- *
4694
- * Pass `data` (pre-fetched server-side) to use that data as-is and skip
4695
- * the client-side fetch entirely. Pass `enabled: false` to skip the fetch
4696
- * when the hook must be called but the data is not needed yet.
4697
- *
4698
- * Returns `LOADING` while CoinList is initializing or while details are being fetched.
4699
- * Returns `CONTENT` with the offer when `offers.get()` succeeds.
4700
- * Returns `ERROR` with:
4701
- * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
4702
- * - `generic-error` for any other failure
4703
- */
4704
- declare function useOfferDetails(offerId: OfferId, options?: UseOfferDetailsOptions): UseOfferDetailsResult;
4705
-
4706
- type LoadOffersReason = 'not-authenticated' | 'generic-error';
4707
- type LoadOffersState = {
4708
- type: 'LOADING';
4709
- } | {
4710
- type: 'ERROR';
4711
- reason: LoadOffersReason;
4712
- } | {
4713
- type: 'CONTENT';
4714
- offers: Offer[];
4715
- };
4716
- interface UseOffersOptions {
4717
- /**
4718
- * Offers pre-fetched on the server (e.g. via `CoinListServer#offers.list()`).
4719
- * When provided, the hook uses this data as-is and skips the client-side fetch entirely.
4720
- */
4721
- data?: Offer[];
4722
- /**
4723
- * When `false`, the hook sends no request. A seeded or already-fetched
4724
- * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.
4725
- */
4726
- enabled?: boolean;
4727
- }
4728
- interface UseOffersResult {
4729
- offersState: LoadOffersState;
4730
- }
4731
- /**
4732
- * Loads all CoinList offers for the current user and exposes a UI-friendly state.
4733
- *
4734
- * Pass `data` (pre-fetched server-side) to use that data as-is and skip
4735
- * the client-side fetch entirely. Pass `enabled: false` to skip the fetch
4736
- * when the hook must be called but the data is not needed yet.
4737
- *
4738
- * Returns `LOADING` while CoinList is initializing or while offers are being fetched.
4739
- * Returns `CONTENT` with all offers when `fetchOffers()` succeeds.
4740
- * Returns `ERROR` with:
4741
- * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
4742
- * - `generic-error` for any other failure
4743
- */
4744
- declare function useOffers(options?: UseOffersOptions): UseOffersResult;
4745
-
4746
5097
  /**
4747
5098
  * A display-ready connect-wallet error: the core flow's machine-readable code
4748
5099
  * and `retryable` flag, plus copy for the UI.
@@ -5032,120 +5383,6 @@ interface UseRequirementsChecklistViewModelResult {
5032
5383
  */
5033
5384
  declare function useRequirementsChecklistViewModel(options: UseRequirementsChecklistViewModelOptions): UseRequirementsChecklistViewModelResult;
5034
5385
 
5035
- /**
5036
- * The state of one vault's status poll.
5037
- *
5038
- * Stale-preserving: a failed tick with a status in hand keeps it, so a flaky
5039
- * read never reads as "vault halted". `ERROR` means the status is unknown -
5040
- * which is not the same as `CONTENT` carrying a blocked orderability, and
5041
- * callers must not conflate them. A vault that is *known* to be unorderable
5042
- * may block a request; one that is merely unknown may not.
5043
- *
5044
- * `below_minimum` never appears here: it needs an amount, which this
5045
- * endpoint is never given.
5046
- *
5047
- * @alpha
5048
- */
5049
- type LoadCentrifugeVaultStatusState = {
5050
- type: 'LOADING';
5051
- } | {
5052
- type: 'ERROR';
5053
- reason: CentrifugeLoadErrorReason;
5054
- } | {
5055
- type: 'CONTENT';
5056
- status: CentrifugeVaultStatus;
5057
- };
5058
- /** @alpha */
5059
- interface UseCentrifugeVaultStatusesOptions {
5060
- /** The vaults to poll, typically one per chain an offer runs on. */
5061
- vaults: CentrifugeVaultRef[];
5062
- /** How often to refresh. Defaults to {@link CENTRIFUGE_POLL_INTERVAL_MS}. */
5063
- pollIntervalMs?: number;
5064
- /**
5065
- * Statuses the caller already holds, typically fetched server-side, each
5066
- * opening the state of the vault it names so a server-rendered panel needs
5067
- * no loading pass.
5068
- *
5069
- * They seed the first render only: the poll still fetches immediately. A
5070
- * vault that was orderable a minute ago can be unlinked now, so a seed
5071
- * that suppressed the first read would be answering "can I act right now"
5072
- * with whenever the page was rendered.
5073
- */
5074
- data?: CentrifugeVaultStatus[];
5075
- /** When false, the hook neither fetches nor polls. */
5076
- enabled: boolean;
5077
- }
5078
- /** @alpha */
5079
- interface UseCentrifugeVaultStatusesResult {
5080
- /** One entry per vault asked for, in the order asked. */
5081
- statuses: {
5082
- vault: CentrifugeVaultRef;
5083
- state: LoadCentrifugeVaultStatusState;
5084
- }[];
5085
- }
5086
- /**
5087
- * Polls whether each of several Centrifuge vaults can be acted on right now,
5088
- * independent of any wallet or amount.
5089
- *
5090
- * Free to poll - it spends no attestation. Centrifuge announces none of the
5091
- * changes this reports, so the poll is the only way a screen notices a vault
5092
- * halting under it. Each vault is read independently on one shared timer, so
5093
- * one failing chain never holds back another.
5094
- *
5095
- * A seeded status opens its vault's state instead of `LOADING` and is
5096
- * otherwise left to the poll: the first tick fires as it always does, and
5097
- * only replaces the seed once it has a status of its own.
5098
- *
5099
- * Disabled it neither fetches nor holds a timer, and each vault stays on
5100
- * whatever state it held. That is `LOADING` and not an empty `CONTENT`
5101
- * because there is no empty vault status - and an invented one would be
5102
- * worse than none, since `CONTENT` here is what a caller is allowed to block
5103
- * on.
5104
- *
5105
- * @alpha
5106
- */
5107
- declare function useCentrifugeVaultStatuses(options: UseCentrifugeVaultStatusesOptions): UseCentrifugeVaultStatusesResult;
5108
-
5109
- /** @alpha */
5110
- interface UseCentrifugeVaultStatusOptions {
5111
- /** Share token symbol of the vault, e.g. `deJTRSY`. */
5112
- symbol: AssetSymbol;
5113
- chain: EthereumChain;
5114
- /** How often to refresh. Defaults to `CENTRIFUGE_POLL_INTERVAL_MS`. */
5115
- pollIntervalMs?: number;
5116
- /**
5117
- * A status the caller already holds, typically fetched server-side, used
5118
- * as the state the hook opens on so a server-rendered panel needs no
5119
- * loading pass.
5120
- *
5121
- * It seeds the first render only: the poll still fetches immediately. A
5122
- * vault that was orderable a minute ago can be unlinked now, so a seed
5123
- * that suppressed the first read would be answering "can I invest right
5124
- * now" with whenever the page was rendered.
5125
- */
5126
- data?: CentrifugeVaultStatus;
5127
- /** When false, the hook neither fetches nor polls. */
5128
- enabled: boolean;
5129
- }
5130
- /** @alpha */
5131
- interface UseCentrifugeVaultStatusResult {
5132
- state: LoadCentrifugeVaultStatusState;
5133
- }
5134
- /**
5135
- * Polls whether a Centrifuge vault can take a request at all right now,
5136
- * independent of any amount.
5137
- *
5138
- * Free to poll - it spends no attestation. Centrifuge announces none of the
5139
- * changes this reports, so the poll is the only way a checkout notices
5140
- * mid-order.
5141
- *
5142
- * The one-vault case of {@link useCentrifugeVaultStatuses}, which carries the
5143
- * seeding, stale-preserving and disabled semantics.
5144
- *
5145
- * @alpha
5146
- */
5147
- declare function useCentrifugeVaultStatus(options: UseCentrifugeVaultStatusOptions): UseCentrifugeVaultStatusResult;
5148
-
5149
5386
  interface UseErc20BalanceOptions {
5150
5387
  /**
5151
5388
  * The token to read, by contract address.
@@ -5156,26 +5393,47 @@ interface UseErc20BalanceOptions {
5156
5393
  * has one.
5157
5394
  */
5158
5395
  tokenAddress: EvmContractAddress | null;
5159
- owner: EvmWalletAddress;
5396
+ /**
5397
+ * The wallet whose balance is read. `null` when there is no wallet yet,
5398
+ * which reads nothing and holds `DISABLED`, exactly as `enabled: false`
5399
+ * does: there is no holding to wait for.
5400
+ */
5401
+ owner: EvmWalletAddress | null;
5160
5402
  chain: EthereumChain;
5161
5403
  /** How often to refresh. Defaults to {@link ERC20_BALANCE_POLL_INTERVAL_MS}. */
5162
5404
  pollIntervalMs?: number;
5163
5405
  /** When false, the hook neither fetches nor polls. */
5164
5406
  enabled: boolean;
5165
5407
  }
5408
+ /**
5409
+ * The state of one balance read.
5410
+ *
5411
+ * Every arm answers for the token, owner and chain currently named by the
5412
+ * options, and nothing else: from the moment any of them changes the state is
5413
+ * `LOADING` until the read for the new one lands. A balance carried across
5414
+ * that change would be a number read for something else, indistinguishable
5415
+ * from a fresh one.
5416
+ *
5417
+ * - `DISABLED`: switched off. No balance is held, for the same reason.
5418
+ * - `LOADING`: no read has settled for this request yet, or `tokenAddress` is
5419
+ * not known yet.
5420
+ * - `ERROR`: the last read failed. A failed read is not a zero balance, and an
5421
+ * order must not be sized against the one before it, so it is dropped.
5422
+ * - `CONTENT`: raw base units of the token.
5423
+ */
5424
+ type LoadErc20BalanceState = {
5425
+ type: 'DISABLED';
5426
+ } | {
5427
+ type: 'LOADING';
5428
+ } | {
5429
+ type: 'ERROR';
5430
+ reason: LoadErrorReason;
5431
+ } | {
5432
+ type: 'CONTENT';
5433
+ balance: bigint;
5434
+ };
5166
5435
  interface UseErc20BalanceResult {
5167
- /**
5168
- * Raw base units of the token currently named by the options, or `null`.
5169
- *
5170
- * `null` covers every state that is not a settled read of *this* request:
5171
- * before the first one settles, after one fails, while disabled, and from
5172
- * the moment the token, owner or chain changes until the read for the new
5173
- * one lands. A caller cannot tell those apart on purpose - none of them is a
5174
- * number to size an order against - and `isLoading` is what says whether to
5175
- * wait.
5176
- */
5177
- balance: bigint | null;
5178
- isLoading: boolean;
5436
+ state: LoadErc20BalanceState;
5179
5437
  }
5180
5438
  /**
5181
5439
  * Polls one wallet's balance of one ERC-20, named by contract address.
@@ -5189,15 +5447,18 @@ interface UseErc20BalanceResult {
5189
5447
  * each independently, which is a different job from following a single token
5190
5448
  * whose address may not be known yet.
5191
5449
  *
5192
- * A poll tick is skipped while the previous read is in flight, so a slow one
5193
- * cannot resolve last and overwrite a fresher balance. `isLoading` is true only
5194
- * until the first read settles; background polls do not toggle it. Disabled, or
5195
- * with no `tokenAddress`, it neither fetches nor holds a timer.
5450
+ * Disabled, with no `owner`, or with no `tokenAddress`, it neither fetches
5451
+ * nor holds a timer.
5196
5452
  */
5197
5453
  declare function useErc20Balance(options: UseErc20BalanceOptions): UseErc20BalanceResult;
5198
5454
 
5199
5455
  interface UseErc20TokenBalancesOptions {
5200
- address: EvmWalletAddress;
5456
+ /**
5457
+ * The wallet whose balances are read. `null` when there is no wallet yet -
5458
+ * a checkout step waiting on the wallet step - which reads nothing and holds
5459
+ * `DISABLED`, exactly as `enabled: false` does.
5460
+ */
5461
+ address: EvmWalletAddress | null;
5201
5462
  chain: EthereumChain;
5202
5463
  /** The assets to read balances for. */
5203
5464
  assets: NonEmptyArray<StablecoinSymbol>;
@@ -5209,29 +5470,47 @@ interface UseErc20TokenBalancesOptions {
5209
5470
  /** When false, the hook neither fetches nor polls. */
5210
5471
  enabled: boolean;
5211
5472
  }
5212
- interface UseErc20TokenBalancesResult {
5213
- /**
5214
- * Raw on-chain balances keyed by the requested assets. Each requested asset
5215
- * with a deployment on the chain has an entry once a fetch settles
5216
- * (`bigint` on success, `null` on a failed read). Assets the chain has no
5217
- * deployment for (e.g. USDT on Base Sepolia) are omitted entirely, so
5218
- * absence and failure stay tellable apart.
5219
- */
5473
+ /**
5474
+ * The state of the balance reads.
5475
+ *
5476
+ * Every arm answers for the address, chain and assets currently named by the
5477
+ * options: from the moment any of them changes the state is `LOADING` until
5478
+ * the reads for the new ones land, so one wallet's balances never stand in
5479
+ * for another's.
5480
+ *
5481
+ * - `DISABLED`: switched off. No balances are held.
5482
+ * - `LOADING`: no poll has settled for this request yet.
5483
+ * - `ERROR`: every read the last poll made failed, so there is no balance at
5484
+ * all to show.
5485
+ * - `CONTENT`: raw on-chain balances keyed by the requested assets. Each
5486
+ * requested asset with a deployment on the chain has an entry (`bigint` on
5487
+ * success, `null` on a failed read). Assets the chain has no deployment for
5488
+ * (e.g. USDT on Base Sepolia) are omitted entirely, so absence and failure
5489
+ * stay tellable apart.
5490
+ */
5491
+ type LoadErc20TokenBalancesState = {
5492
+ type: 'DISABLED';
5493
+ } | {
5494
+ type: 'LOADING';
5495
+ } | {
5496
+ type: 'ERROR';
5497
+ reason: LoadErrorReason;
5498
+ } | {
5499
+ type: 'CONTENT';
5220
5500
  balances: Map<StablecoinSymbol, bigint | null>;
5221
- isLoading: boolean;
5501
+ };
5502
+ interface UseErc20TokenBalancesResult {
5503
+ state: LoadErc20TokenBalancesState;
5222
5504
  }
5223
5505
  /**
5224
5506
  * Polls the raw ERC-20 balances of `assets` for `address`, refreshing every
5225
5507
  * `pollIntervalMs`. Each asset settles independently: a failed read maps to
5226
5508
  * `null` while the others still resolve, and an asset the chain has no
5227
5509
  * deployment for is omitted from the result rather than read at a fake
5228
- * address. A poll tick is skipped while the previous fetch is still in
5229
- * flight. `assets` is compared by contents, so passing an inline array does
5510
+ * address. `assets` is compared by contents, so passing an inline array does
5230
5511
  * not restart the poll.
5231
5512
  *
5232
- * `isLoading` is true only until the first poll settles; background polls do
5233
- * not toggle it. Disabled (or before the provider is ready) the hook does not
5234
- * fetch.
5513
+ * Disabled, or with no `address`, it neither fetches nor holds a timer.
5235
5514
  */
5236
5515
  declare function useErc20TokenBalances(options: UseErc20TokenBalancesOptions): UseErc20TokenBalancesResult;
5237
5516
 
@@ -5367,4 +5646,4 @@ declare class CoinListClientInitializationError extends Error {
5367
5646
  constructor(message?: string);
5368
5647
  }
5369
5648
 
5370
- export { type AuthState, type AuthorizeWalletParams, type BuyCentrifugeParams, type CentrifugeBuyAmountUiEvent, type CentrifugeBuyAmountUiState, type CentrifugeBuyCheckoutUiEvent, type CentrifugeBuyCheckoutUiState, type CentrifugeBuyError, type CentrifugeBuyPhase, type CentrifugeBuyPlacementError, type CentrifugeBuyPlacementPhase, type CentrifugeBuyPlacementResult, type CentrifugeBuyPreparationError, type CentrifugeBuyPreparationPhase, type CentrifugeBuyPreparationResult, type CentrifugeBuyResult, type CentrifugeBuyReviewUiEvent, type CentrifugeBuyReviewUiState, CentrifugeCheckoutErrorReason, type CentrifugeClaimActionUi, type CentrifugeClaimBlockedReasonUi, type CentrifugeClaimDialogUi, type CentrifugeClaimError, type CentrifugeClaimFailureUi, type CentrifugeClaimParams, type CentrifugeClaimPhase, type CentrifugeClaimProgressUi, type CentrifugeClaimResult, type CentrifugeClaimRowUi, type CentrifugeClaimState, type CentrifugeClaimStepUi, type CentrifugeLoadErrorReason, type CentrifugeOrderPlaced, type CentrifugeOrderPlacedUiEvent, type CentrifugeOrderPlacedUiState, type CentrifugeSidebarMinimumUi, type CentrifugeSidebarUiState, type CentrifugeVaultCheckoutConfig, type CentrifugeVaultClaimConfig, type CentrifugeVaultClaimUiEvent, type CentrifugeVaultClaimUiState, type CentrifugeVaultClaimed, type CentrifugeWalletSelectUiEvent, type CentrifugeWalletSelectUiState, 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 ClaimCentrifugeVaultParams, type ClaimConfig, ClaimContainer, type ClaimContainerProps, type ClaimExternalWalletUi, type ClientAuthNamespace, type ClientCentrifugeNamespace, type ClientCoinListTokenSaleNamespace, type ClientConfig, type ClientOndoNamespace, type ClientRequirementsNamespace, type ClientSuperstateSwapNamespace, type ClientSupportNamespace, type ClientWalletsNamespace, type CoinListClient, CoinListClientInitializationError, CoinListProvider, type CoinListProviderProps, CoinListSignInButton, type CoinListSignInButtonProps, CoinListSignInCardContainer, type CoinListSignInCardContainerProps, type CoinListSignInCardUiEvent, type CoinListSignInCardUiState, CoinListStyleScope, type CoinListStyleScopeProps, type CoinListTokenSaleCheckoutConfig, type CompleteOAuthFailureReason, type ConnectWalletError, type ConnectWalletErrorCode, type ConnectWalletFlowError, type ConnectWalletFlowResult, type ConnectWalletParams, type ConnectWalletPhase, type ConnectWalletSignState, type ConnectWalletState, type ConnectedWalletUi, type Erc20AllowanceError, type Erc20AllowancePhase, type Erc20ApprovalError, type ExecuteOndoSwapParams, type ExecuteSwapParams, type ExecuteTokenSaleParams, type ExternalWalletRequestUi, type KycTokenErrorReason, type KycTokenState, type LoadCentrifugeBuyTransactionState, type LoadCentrifugeClaimPositionsState, type LoadCentrifugeVaultStatusState, 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, type LoadTokenRegistryState, type LogoImageUi, type OAuthClientErrorReason, type OAuthClientResult, OfferAssetCard, type OfferAssetCardProps, OfferAssetCardUi, OfferLogoUi, OfferSaleCard, type OfferSaleCardProps, OfferSaleCardUi, OffersGridContainer, type OffersGridContainerProps, type OffersGridData, type OndoBuyAmountUiEvent, type OndoBuyAmountUiState, type OndoBuyCheckoutUiEvent, type OndoBuyCheckoutUiState, type OndoBuyOrderPlaced, type OndoBuyOrderTerms, type OndoBuyPreparationResult, type OndoBuyQuoteStatusUi, type OndoBuyReviewUiEvent, type OndoBuyReviewUiState, type OndoCheckoutConfig, OndoCheckoutErrorReason, type OndoLoadErrorReason, type OndoOrderConfirmedUiEvent, type OndoOrderConfirmedUiState, type OndoOrderPlaced, type OndoOrderPlacedCore, type OndoSellAmountUiEvent, type OndoSellAmountUiState, type OndoSellBalanceUi, type OndoSellCheckoutUiEvent, type OndoSellCheckoutUiState, type OndoSellOrderConfirmedUiEvent, type OndoSellOrderConfirmedUiState, type OndoSellOrderPlaced, type OndoSellOrderTerms, type OndoSellOutcomeUi, type OndoSellPreparationResult, type OndoSellQuoteStatusUi, type OndoSellReviewUiEvent, type OndoSellReviewUiState, type OndoSellSourceWalletUi, type OndoSidebarPriceUi, type OndoSidebarUiState, type OndoSwapExecutionError, type OndoSwapExecutionPhase, type OndoSwapExecutionResult, type OndoSwapPreparationError, type OndoSwapPreparationPhase, type OndoSwapPreparationResult, type OndoWalletSelectUiEvent, type OndoWalletSelectUiState, type PlaceCentrifugeRequestParams, type PrepareCentrifugeBuyParams, type PrepareOndoBuyParams, type PrepareOndoSellParams, type PrepareOndoSwapParamsCore, RequirementItemUi, RequirementStatus, RequirementVariant, RequirementsChecklistContainer, type RequirementsChecklistContainerProps, type RequirementsChecklistItemUi, type RequirementsChecklistUiEvent, type RequirementsChecklistUiState, RequirementsChecklistView, type RequirementsChecklistViewProps, type RequirementsData, type RequirementsVerificationUi, type SignState, type SuperstateAmountUiEvent, type SuperstateAmountUiState, type SuperstateCheckoutConfig, type SuperstateOrderConfirmedUiEvent, type SuperstateOrderConfirmedUiState, type SuperstateOrderPlaced, type SuperstateReviewUiEvent, type SuperstateReviewUiState, type SuperstateSidebarPriceUi, type SuperstateSidebarUiState, type SuperstateSlippageOptionUi, type SuperstateSlippageUi, type SuperstateSwapCheckoutRetryUiEvent, type SuperstateSwapCheckoutUiEvent, type SuperstateSwapCheckoutUiState, type SuperstateSwapLoadErrorReason, type SuperstateWalletUiEvent, type SuperstateWalletUiState, type SwapExecutionError, type SwapExecutionPhase, type SwapExecutionResult, type SwapOutputTokenState, type TaxDocumentAddressParts, type TaxDocumentFields, type TaxDocumentState, type TokenSaleExecutionError, type TokenSaleExecutionPhase, type TokenSaleExecutionResult, type UseCentrifugeBuyCheckoutViewModelOptions, type UseCentrifugeBuyCheckoutViewModelResult, type UseCentrifugeBuyTransactionOptions, type UseCentrifugeBuyTransactionResult, type UseCentrifugeClaimPositionsOptions, type UseCentrifugeClaimPositionsResult, type UseCentrifugeClaimResult, type UseCentrifugeVaultClaimViewModelOptions, type UseCentrifugeVaultClaimViewModelResult, type UseCentrifugeVaultStatusOptions, type UseCentrifugeVaultStatusResult, type UseCentrifugeVaultStatusesOptions, type UseCentrifugeVaultStatusesResult, type UseCoinListResult, type UseCoinListSignInCardViewModelOptions, type UseCoinListSignInCardViewModelResult, type UseCompleteOAuthOptions, type UseConnectWalletOptions, type UseConnectWalletResult, type UseErc20BalanceOptions, type UseErc20BalanceResult, type UseErc20TokenBalancesOptions, type UseErc20TokenBalancesResult, type UseKycTokenResult, type UseOfferDetailsOptions, type UseOfferDetailsResult, type UseOffersOptions, type UseOffersResult, type UseOndoBuyCheckoutViewModelOptions, type UseOndoBuyCheckoutViewModelResult, type UseOndoBuyTransactionOptions, type UseOndoBuyTransactionResult, type UseOndoPriceOptions, type UseOndoPriceResult, type UseOndoSellCheckoutViewModelOptions, type UseOndoSellCheckoutViewModelResult, type UseOndoSellTransactionOptions, type UseOndoSellTransactionResult, type UseOndoTradingStatusOptions, type UseOndoTradingStatusResult, type UseOptionAddressesOptions, type UseOptionAddressesResult, type UseParticipationsOptions, type UseParticipationsResult, type UseRequirementsChecklistViewModelOptions, type UseRequirementsChecklistViewModelResult, type UseRequirementsOptions, type UseRequirementsResult, type UseSuperstateSwapCheckoutViewModelOptions, type UseSuperstateSwapCheckoutViewModelResult, type UseSwapOutputTokenOptions, type UseSwapOutputTokenResult, type UseSwapQuoteOptions, type UseSwapQuoteResult, type UseTaxDocumentOptions, type UseTaxDocumentResult, type UseTokenMetadataOptions, type UseTokenMetadataResult, type UseTokenRegistryOptions, type UseTokenRegistryResult, type WalletAuthorizationError, type WalletAuthorizationPhase, type WalletAuthorizationResult, type WalletsStatus, createCoinListClient, isNotTradable, pinoClientLogger, useCentrifugeBuyCheckoutViewModel, useCentrifugeBuyTransaction, useCentrifugeClaim, useCentrifugeClaimPositions, useCentrifugeVaultClaimViewModel, useCentrifugeVaultStatus, useCentrifugeVaultStatuses, useCoinList, useCoinListSignInCardViewModel, useCompleteOAuth, useConnectWallet, useErc20Balance, useErc20TokenBalances, useKycToken, useOfferDetails, useOffers, useOndoBuyCheckoutViewModel, useOndoBuyTransaction, useOndoPrice, useOndoSellCheckoutViewModel, useOndoSellTransaction, useOndoTradingStatus, useOptionAddresses, useParticipations, useRequirements, useRequirementsChecklistViewModel, useSuperstateSwapCheckoutViewModel, useSwapOutputToken, useSwapQuote, useTaxDocument, useTokenMetadata, useTokenRegistry };
5649
+ export { type ApproveThenBuildError, type ApproveThenBuildPhase, type ApproveThenBuildResult, type AuthState, type AuthorizeWalletParams, type BuyCentrifugeParams, type CentrifugeBuyCheckoutUiEvent, type CentrifugeBuyCheckoutUiState, type CentrifugeBuyError, type CentrifugeBuyPhase, type CentrifugeBuyPlacementError, type CentrifugeBuyPlacementPhase, type CentrifugeBuyPlacementResult, type CentrifugeBuyPreparationError, type CentrifugeBuyPreparationPhase, type CentrifugeBuyPreparationResult, type CentrifugeBuyResult, type CentrifugeBuyReviewUiEvent, type CentrifugeBuyReviewUiState, type CentrifugeCheckoutErrorReason, type CentrifugeClaimActionUi, type CentrifugeClaimBlockedReasonUi, type CentrifugeClaimDialogUi, type CentrifugeClaimError, type CentrifugeClaimFailureUi, type CentrifugeClaimParams, type CentrifugeClaimPhase, type CentrifugeClaimProgressUi, type CentrifugeClaimResult, type CentrifugeClaimRowUi, type CentrifugeClaimState, type CentrifugeClaimStepUi, type CentrifugeLoadErrorReason, type CentrifugeOrderPlaced, type CentrifugeOrderPlacedUiEvent, type CentrifugeOrderPlacedUiState, type CentrifugeSidebarMinimumUi, type CentrifugeSidebarUiState, type CentrifugeVaultCheckoutConfig, type CentrifugeVaultClaimConfig, type CentrifugeVaultClaimUiEvent, type CentrifugeVaultClaimUiState, type CentrifugeVaultClaimed, ChecklistStatus, type CheckoutAmountAdornmentUi, type CheckoutAmountUiEvent, type CheckoutAmountUiState, CheckoutAssetUi, type CheckoutBlockedReason, type CheckoutConfig, type CheckoutConfirmedWalletUi, CheckoutContainer, type CheckoutContainerProps, type CheckoutCtaUi, type CheckoutEmbeddedWalletUi, CheckoutExternalWalletUi, type CheckoutNetworkUi, type CheckoutReceiptUi, type CheckoutSelectableInputAssetUi, type CheckoutStatusUi, type CheckoutWalletSelectUiEvent, type CheckoutWalletSelectUiState, type CheckoutWalletSelection, type CheckoutWalletTypeUi, type CheckoutWalletUi, type ClaimCentrifugeVaultParams, type ClaimConfig, ClaimContainer, type ClaimContainerProps, type ClaimExternalWalletUi, type ClientAuthNamespace, type ClientCentrifugeNamespace, type ClientCoinListTokenSaleNamespace, type ClientConfig, type ClientOndoNamespace, type ClientRequirementsNamespace, type ClientSuperstateSwapNamespace, type ClientSupportNamespace, type ClientWalletsNamespace, type CoinListClient, CoinListClientInitializationError, CoinListProvider, type CoinListProviderProps, CoinListSignInButton, type CoinListSignInButtonProps, CoinListSignInCardContainer, type CoinListSignInCardContainerProps, type CoinListSignInCardUiEvent, type CoinListSignInCardUiState, CoinListStyleScope, type CoinListStyleScopeProps, type CoinListTokenSaleCheckoutConfig, type CoinListTokenSaleCheckoutUiEvent, type CoinListTokenSaleCheckoutUiState, type CompleteOAuthFailureReason, type ConnectWalletError, type ConnectWalletErrorCode, type ConnectWalletFlowError, type ConnectWalletFlowResult, type ConnectWalletParams, type ConnectWalletPhase, type ConnectWalletSignState, type ConnectWalletState, type ConnectedWalletUi, type Erc20AllowanceError, type Erc20AllowancePhase, type Erc20ApprovalError, type ExecuteOndoSwapParams, type ExecuteSwapParams, type ExecuteTokenSaleParams, type ExternalWalletRequestUi, type KycTokenErrorReason, type KycTokenState, type LoadCentrifugeClaimPositionsState, type LoadCentrifugeVaultStatusState, type LoadErc20BalanceState, type LoadErc20TokenBalancesState, type LoadErrorReason, type LoadFirmTransactionState, 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 LoadSwapOutputTokenState, type LoadSwapQuoteState, type LoadTokenMetadataState, type LoadTokenRegistryState, type LogoImageUi, type OAuthClientErrorReason, type OAuthClientResult, OfferAssetCard, type OfferAssetCardProps, OfferAssetCardUi, OfferLogoUi, OfferSaleCard, type OfferSaleCardProps, OfferSaleCardUi, OffersGridContainer, type OffersGridContainerProps, type OffersGridData, type OndoBuyAmountUiEvent, type OndoBuyAmountUiState, type OndoBuyCheckoutUiEvent, type OndoBuyCheckoutUiState, type OndoBuyOrderPlaced, type OndoBuyOrderTerms, type OndoBuyPreparationResult, type OndoBuyReviewUiEvent, type OndoBuyReviewUiState, type OndoCheckoutConfig, type OndoCheckoutErrorReason, type OndoLoadErrorReason, type OndoOrderConfirmedUiEvent, type OndoOrderConfirmedUiState, type OndoOrderPlaced, type OndoOrderPlacedCore, type OndoQuoteStatusUi, type OndoSellAmountUiEvent, type OndoSellAmountUiState, type OndoSellBalanceUi, type OndoSellCheckoutUiEvent, type OndoSellCheckoutUiState, type OndoSellOrderConfirmedUiEvent, type OndoSellOrderConfirmedUiState, type OndoSellOrderPlaced, type OndoSellOrderTerms, type OndoSellOutcomeUi, type OndoSellPreparationResult, type OndoSellReviewUiEvent, type OndoSellReviewUiState, type OndoSellSourceWalletUi, type OndoSidebarPriceUi, type OndoSidebarUiState, type OndoSwapExecutionError, type OndoSwapExecutionPhase, type OndoSwapExecutionResult, type OndoSwapPreparationError, type OndoSwapPreparationPhase, type OndoSwapPreparationResult, type PlaceCentrifugeRequestParams, type PrepareCentrifugeBuyParams, type PrepareOndoBuyParams, type PrepareOndoSellParams, type PrepareOndoSwapParamsCore, RequirementItemUi, RequirementStatus, RequirementVariant, RequirementsChecklistContainer, type RequirementsChecklistContainerProps, type RequirementsChecklistItemUi, type RequirementsChecklistUiEvent, type RequirementsChecklistUiState, RequirementsChecklistView, type RequirementsChecklistViewProps, type RequirementsData, type RequirementsVerificationUi, type ResetThenApprovePhase, type SignState, type SuperstateCheckoutConfig, type SuperstateOrderConfirmedUiEvent, type SuperstateOrderConfirmedUiState, type SuperstateOrderPlaced, type SuperstateReviewUiEvent, type SuperstateReviewUiState, type SuperstateSidebarPriceUi, type SuperstateSidebarUiState, type SuperstateSlippageOptionUi, type SuperstateSlippageUi, type SuperstateSwapCheckoutRetryUiEvent, type SuperstateSwapCheckoutUiEvent, type SuperstateSwapCheckoutUiState, type SuperstateSwapLoadErrorReason, type SuperstateWalletUiEvent, type SuperstateWalletUiState, type SwapExecutionError, type SwapExecutionPhase, type SwapExecutionResult, type TaxDocumentAddressParts, type TaxDocumentFields, type TaxDocumentState, type TokenSaleApproval, type TokenSaleCheckoutErrorReason, type TokenSaleExecutionError, type TokenSaleExecutionPhase, type TokenSaleExecutionResult, type TokenSaleOrderPlaced, type TokenSaleOrderPlacedUiEvent, type TokenSaleOrderPlacedUiState, type TokenSaleReviewUiEvent, type TokenSaleReviewUiState, type TokenSaleSidebarUiState, type UseCentrifugeBuyCheckoutViewModelOptions, type UseCentrifugeBuyCheckoutViewModelResult, type UseCentrifugeClaimPositionsOptions, type UseCentrifugeClaimPositionsResult, type UseCentrifugeClaimResult, type UseCentrifugeVaultClaimViewModelOptions, type UseCentrifugeVaultClaimViewModelResult, type UseCentrifugeVaultStatusOptions, type UseCentrifugeVaultStatusResult, type UseCentrifugeVaultStatusesOptions, type UseCentrifugeVaultStatusesResult, type UseCoinListResult, type UseCoinListSignInCardViewModelOptions, type UseCoinListSignInCardViewModelResult, type UseCoinListTokenSaleCheckoutViewModelOptions, type UseCoinListTokenSaleCheckoutViewModelResult, type UseCompleteOAuthOptions, type UseConnectWalletOptions, type UseConnectWalletResult, type UseErc20BalanceOptions, type UseErc20BalanceResult, type UseErc20TokenBalancesOptions, type UseErc20TokenBalancesResult, type UseKycTokenResult, type UseOfferDetailsOptions, type UseOfferDetailsResult, type UseOffersOptions, type UseOffersResult, type UseOndoBuyCheckoutViewModelOptions, type UseOndoBuyCheckoutViewModelResult, type UseOndoBuyTransactionOptions, type UseOndoBuyTransactionResult, type UseOndoPriceOptions, type UseOndoPriceResult, type UseOndoSellCheckoutViewModelOptions, type UseOndoSellCheckoutViewModelResult, type UseOndoSellTransactionOptions, type UseOndoSellTransactionResult, type UseOndoTradingStatusOptions, type UseOndoTradingStatusResult, type UseOptionAddressesOptions, type UseOptionAddressesResult, type UseParticipationsOptions, type UseParticipationsResult, type UseRequirementsChecklistViewModelOptions, type UseRequirementsChecklistViewModelResult, type UseRequirementsOptions, type UseRequirementsResult, type UseSuperstateSwapCheckoutViewModelOptions, type UseSuperstateSwapCheckoutViewModelResult, type UseSwapOutputTokenOptions, type UseSwapOutputTokenResult, type UseSwapQuoteOptions, type UseSwapQuoteResult, type UseTaxDocumentOptions, type UseTaxDocumentResult, type UseTokenMetadataOptions, type UseTokenMetadataResult, type UseTokenRegistryOptions, type UseTokenRegistryResult, type WalletAuthorizationError, type WalletAuthorizationPhase, type WalletAuthorizationResult, type WalletsStatus, createCoinListClient, isNotTradable, pinoClientLogger, useCentrifugeBuyCheckoutViewModel, useCentrifugeClaim, useCentrifugeClaimPositions, useCentrifugeVaultClaimViewModel, useCentrifugeVaultStatus, useCentrifugeVaultStatuses, useCoinList, useCoinListSignInCardViewModel, useCoinListTokenSaleCheckoutViewModel, useCompleteOAuth, useConnectWallet, useErc20Balance, useErc20TokenBalances, useKycToken, useOfferDetails, useOffers, useOndoBuyCheckoutViewModel, useOndoBuyTransaction, useOndoPrice, useOndoSellCheckoutViewModel, useOndoSellTransaction, useOndoTradingStatus, useOptionAddresses, useParticipations, useRequirements, useRequirementsChecklistViewModel, useSuperstateSwapCheckoutViewModel, useSwapOutputToken, useSwapQuote, useTaxDocument, useTokenMetadata, useTokenRegistry };