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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +10 -0
  2. package/dist/{chunk-45LAPB7U.js → chunk-EKLUJZ7T.js} +10 -10
  3. package/dist/chunk-EKLUJZ7T.js.map +1 -0
  4. package/dist/{chunk-HDJEDOS4.js → chunk-GIE4UWB3.js} +1207 -799
  5. package/dist/chunk-GIE4UWB3.js.map +1 -0
  6. package/dist/chunk-MJ6YXZWH.js +22 -0
  7. package/dist/chunk-MJ6YXZWH.js.map +1 -0
  8. package/dist/{chunk-M7WDZZPX.js → chunk-PIOQA6HW.js} +194 -190
  9. package/dist/chunk-PIOQA6HW.js.map +1 -0
  10. package/dist/client/index.d.ts +2977 -4267
  11. package/dist/client/index.js +8552 -5713
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/server/index.d.ts +7 -33
  14. package/dist/server/index.js +8 -4
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/{tokens-namespace-DrwRi0AQ.d.cts → time-Bbqlt2x7.d.ts} +2081 -2734
  17. package/dist/{token-registry-snapshot-C-Qs3Lgs.d.ts → token-registry-snapshot-DttZXGvY.d.ts} +74 -42
  18. package/dist/universal/index.d.ts +59 -998
  19. package/dist/universal/index.js +38 -36
  20. package/package.json +18 -14
  21. package/dist/chunk-45LAPB7U.js.map +0 -1
  22. package/dist/chunk-HDJEDOS4.js.map +0 -1
  23. package/dist/chunk-M7WDZZPX.js.map +0 -1
  24. package/dist/client/index.cjs +0 -17098
  25. package/dist/client/index.cjs.map +0 -1
  26. package/dist/client/index.d.cts +0 -6660
  27. package/dist/server/index.cjs +0 -4240
  28. package/dist/server/index.cjs.map +0 -1
  29. package/dist/server/index.d.cts +0 -378
  30. package/dist/time-BOCS1TbH.d.cts +0 -50
  31. package/dist/time-C7mhO5_a.d.ts +0 -50
  32. package/dist/token-registry-snapshot-CpzLmsc2.d.cts +0 -179
  33. package/dist/tokens-namespace-DrwRi0AQ.d.ts +0 -3364
  34. package/dist/universal/index.cjs +0 -4135
  35. package/dist/universal/index.cjs.map +0 -1
  36. package/dist/universal/index.d.cts +0 -1314
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/CoinListProvider.tsx","../../src/universal/core/shared/utils/crypto.ts","../../src/client/core/api/middleware/device-id.ts","../../src/universal/api/frontline/config.ts","../../src/universal/api/internal-access-token-source.ts","../../src/universal/api/http-attributes.ts","../../src/client/core/api/middleware/user-agent.ts","../../src/universal/api/http.ts","../../src/universal/core/shared/observability/log-cause.ts","../../src/universal/types/errors.ts","../../src/universal/core/shared/observability/internal-logger.ts","../../src/universal/api/http-client.ts","../../src/universal/api/middleware/attach-session-middleware.ts","../../src/universal/api/middleware/idempotency-key.ts","../../src/universal/api/middleware/request-retry.ts","../../src/universal/api/middleware/session-renewal.ts","../../src/universal/api/authenticated-api-client.ts","../../src/client/core/api/api-client.ts","../../src/universal/core/auth/session-expired.ts","../../src/universal/types/time.ts","../../src/client/core/auth/client-access-token.ts","../../src/universal/types/oauth.ts","../../src/universal/core/auth/pkce.ts","../../src/client/core/auth/client-auth-namespace.ts","../../src/client/core/shared/blockchain/wallet-error.ts","../../src/universal/core/shared/blockchain/erc20/abi.ts","../../src/client/core/shared/blockchain/erc20/approval.ts","../../src/universal/api/pagination.ts","../../src/universal/types/pagination.ts","../../src/universal/types/asset.ts","../../src/universal/core/shared/utils/wire.ts","../../src/universal/types/blockchain/core.ts","../../src/universal/types/offer.ts","../../src/universal/types/trading.ts","../../src/universal/types/offer-detail.ts","../../src/universal/types/providers/coin-list/token-sale.ts","../../src/universal/api/frontline/providers/coin-list/token-sale.ts","../../src/universal/core/checkout/coin-list/token-sale-namespace.ts","../../src/universal/core/shared/blockchain/token-registry.ts","../../src/universal/core/checkout/ondo/constants.ts","../../src/universal/core/checkout/ondo/math.ts","../../src/universal/core/checkout/ondo/not-tradable.ts","../../src/universal/core/shared/blockchain/formatters.ts","../../src/universal/types/blockchain/ui.ts","../../src/universal/core/shared/blockchain/chain.ts","../../src/universal/core/shared/blockchain/math.ts","../../src/universal/types/providers/ondo/ondo.ts","../../src/universal/api/frontline/providers/ondo/ondo.ts","../../src/universal/core/checkout/ondo/ondo-namespace.ts","../../src/universal/core/checkout/superstate/blockchain/abi.ts","../../src/universal/core/shared/blockchain/bps.ts","../../src/universal/core/checkout/superstate/blockchain/math.ts","../../src/universal/core/checkout/superstate/blockchain/quote.ts","../../src/universal/core/checkout/superstate/blockchain/status.ts","../../src/universal/core/checkout/superstate/blockchain/swapped-event.ts","../../src/universal/core/checkout/superstate/constants.ts","../../src/universal/core/checkout/superstate/formatters.ts","../../src/universal/types/providers/superstate/swap.ts","../../src/universal/api/frontline/providers/superstate/swap.ts","../../src/universal/api/rpc/providers/superstate/swap.ts","../../src/universal/core/checkout/superstate/swap-namespace.ts","../../src/universal/api/frontline/offers.ts","../../src/universal/core/offers/offers-namespace.ts","../../src/universal/core/offers/swap-contracts.ts","../../src/universal/types/document-submission.ts","../../src/universal/api/frontline/documents.ts","../../src/universal/types/kyc.ts","../../src/universal/api/frontline/kyc.ts","../../src/universal/types/pii.ts","../../src/universal/api/frontline/pii.ts","../../src/universal/types/requirement.ts","../../src/universal/api/frontline/requirements.ts","../../src/universal/core/requirements/requirements-namespace.ts","../../src/universal/api/rpc/erc20.ts","../../src/universal/core/shared/blockchain/erc20/erc20-namespace.ts","../../src/universal/core/tokens/token-registry-snapshot.ts","../../src/universal/api/nabu/tokens.ts","../../src/universal/types/token-metadata.ts","../../src/universal/core/tokens/tokens-namespace.ts","../../src/universal/types/offer-option-address.ts","../../src/universal/types/wallet-ownership-challenge.ts","../../src/universal/api/frontline/wallet-connect.ts","../../src/universal/core/wallets/wallets-namespace.ts","../../src/universal/types/blockchain/wallet-error.ts","../../src/client/core/checkout/coin-list/token-sale-flows.ts","../../src/client/core/shared/observability/flow-logging.ts","../../src/client/core/checkout/coin-list/client-token-sale-namespace.ts","../../src/client/core/checkout/ondo/ondo-flows.ts","../../src/client/core/checkout/ondo/client-ondo-namespace.ts","../../src/client/core/checkout/superstate/swap-flows.ts","../../src/client/core/checkout/superstate/client-swap-namespace.ts","../../src/client/core/shared/utils/open-in-new-tab.ts","../../src/client/core/requirements/client-requirements-namespace.ts","../../src/client/core/support/client-support-namespace.ts","../../src/universal/api/nabu/config.ts","../../src/universal/api/rpc/public-clients.ts","../../src/universal/api/rpc/frontline-transport.ts","../../src/universal/core/shared/effects.ts","../../src/client/core/coinlist-client.ts","../../src/client/hooks/shared/useLocale.ts","../../src/client/hooks/shared/useLogger.ts","../../src/client/CoinListStyleScope.tsx","../../src/client/generated/sdk-styles.gen.ts","../../src/client/components/design-system/ClButton.tsx","../../src/client/components/design-system/utils.ts","../../src/client/components/design-system/logos/CoinListLogomark.tsx","../../src/client/components/auth/CoinListSignInButton.tsx","../../src/client/components/design-system/AlertBanner.tsx","../../src/client/components/design-system/tokens/typography.ts","../../src/client/components/design-system/CloseButton.tsx","../../src/client/components/auth/CoinListSignInCardView.tsx","../../src/client/hooks/auth/useCoinListSignInCardViewModel.ts","../../src/client/hooks/useCoinList.ts","../../src/client/components/auth/CoinListSignInCardContainer.tsx","../../src/client/components/checkout/CheckoutContainer.tsx","../../src/client/components/checkout/shared/amount/CheckoutAmountInput.tsx","../../src/client/components/checkout/shared/common/AssetIcon.tsx","../../src/client/components/checkout/shared/selection/classes.ts","../../src/client/components/checkout/shared/selection/PayWithAssetCard.tsx","../../src/client/components/checkout/shared/step/CheckoutStepCard.tsx","../../src/client/components/checkout/shared/step/CheckoutStepFooter.tsx","../../src/client/components/checkout/shared/step/CompletedStepSummary.tsx","../../src/client/components/checkout/ondo/buy/amount/OndoBuyAmountView.tsx","../../src/client/components/checkout/ondo/buy/confirmation/OndoBuyOrderConfirmed.tsx","../../src/client/components/checkout/shared/common/DetailRow.tsx","../../src/client/components/checkout/shared/summary/CheckoutDetailList.tsx","../../src/client/components/design-system/Modal.tsx","../../src/client/components/checkout/shared/confirmation/CheckoutConfirmationDialog.tsx","../../src/client/components/checkout/shared/summary/AssetSummaryRow.tsx","../../src/client/components/checkout/ondo/buy/review/OndoBuyReviewView.tsx","../../src/client/components/checkout/ondo/shared/constants.ts","../../src/client/components/checkout/shared/constants.ts","../../src/client/components/design-system/Skeleton.tsx","../../src/client/components/design-system/Tooltip.tsx","../../src/client/components/checkout/ondo/shared/error/OndoCheckoutError.tsx","../../src/client/components/checkout/shared/common/StatusIndicator.tsx","../../src/client/components/checkout/shared/sidebar/CheckoutSidebarCard.tsx","../../src/client/components/checkout/shared/common/CheckoutCard.tsx","../../src/client/components/checkout/ondo/shared/sidebar/OndoSidebarView.tsx","../../src/client/components/checkout/ondo/shared/wallet/OndoWalletSelectView.tsx","../../src/client/components/checkout/shared/selection/SelectableOptionRow.tsx","../../src/client/components/checkout/ondo/buy/OndoBuyCheckoutView.tsx","../../src/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.ts","../../src/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel.ts","../../src/client/ui/format/asset-icon.ts","../../src/client/hooks/checkout/shared/checkout-ui.types.ts","../../src/client/hooks/shared/erc20/useErc20TokenBalances.ts","../../src/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel.ts","../../src/client/hooks/checkout/ondo/buy/data/useOndoBuyTransaction.ts","../../src/client/hooks/checkout/ondo/shared/data/ondo-load-error.ts","../../src/client/ui/hooks/useCountdown.ts","../../src/client/hooks/checkout/ondo/shared/data/useOndoPrice.ts","../../src/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus.ts","../../src/client/hooks/checkout/ondo/shared/ondo-checkout-error.types.ts","../../src/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel.ts","../../src/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel.ts","../../src/client/hooks/shared/useTokenMetadata.ts","../../src/client/hooks/checkout/shared/data/useCheckoutOfferTokenMetadata.ts","../../src/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer.tsx","../../src/client/components/checkout/ondo/sell/amount/OndoSellAmountView.tsx","../../src/client/components/checkout/ondo/sell/confirmation/OndoSellOrderConfirmed.tsx","../../src/client/components/checkout/ondo/sell/review/OndoSellReviewView.tsx","../../src/client/components/checkout/ondo/sell/OndoSellCheckoutView.tsx","../../src/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel.ts","../../src/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel.ts","../../src/client/hooks/shared/erc20/useErc20Balance.ts","../../src/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel.ts","../../src/client/hooks/checkout/ondo/sell/data/useOndoSellTransaction.ts","../../src/client/components/checkout/ondo/sell/OndoSellCheckoutContainer.tsx","../../src/client/components/checkout/superstate/swap/amount/SuperstateAmountView.tsx","../../src/client/components/checkout/superstate/swap/confirmation/SuperstateOrderConfirmed.tsx","../../src/client/components/checkout/superstate/swap/review/SuperstateReviewView.tsx","../../src/client/components/checkout/superstate/shared/constants.ts","../../src/client/components/checkout/superstate/swap/review/SlippagePicker.tsx","../../src/client/components/checkout/superstate/swap/sidebar/SuperstateSidebarView.tsx","../../src/client/components/checkout/superstate/swap/wallet/SuperstateWalletView.tsx","../../src/client/components/checkout/superstate/swap/SuperstateSwapCheckoutView.tsx","../../src/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel.ts","../../src/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel.ts","../../src/client/hooks/checkout/superstate/swap/data/useSwapOutputToken.ts","../../src/client/hooks/checkout/superstate/swap/data/useSwapQuote.ts","../../src/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel.ts","../../src/client/ui/format/duration.ts","../../src/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel.ts","../../src/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel.ts","../../src/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer.tsx","../../src/client/components/design-system/ThemedImage.tsx","../../src/client/components/offers/shared/offer-card-keyboard.ts","../../src/client/components/offers/shared/OfferAssetCard.tsx","../../src/client/components/offers/grid/OffersAssetGrid.tsx","../../src/client/components/offers/shared/OfferSaleCard.tsx","../../src/client/components/offers/shared/sale-card-status.ts","../../src/client/components/offers/grid/OffersGridView.tsx","../../src/client/hooks/offers/grid/useOffersGridViewModel.ts","../../src/client/hooks/offers/data/useOffers.ts","../../src/client/hooks/offers/shared/offer-logo.types.ts","../../src/client/hooks/offers/shared/offer-sale-card.types.ts","../../src/client/hooks/shared/useTokenRegistry.ts","../../src/client/components/offers/grid/OffersGridContainer.tsx","../../src/client/components/requirements/ConnectedWalletList.tsx","../../src/client/components/requirements/identity-verification/IdentityVerificationView.tsx","../../src/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel.ts","../../src/client/hooks/requirements/data/useKycToken.ts","../../src/client/components/requirements/identity-verification/IdentityVerificationContainer.tsx","../../src/client/components/requirements/RequirementItem.tsx","../../src/client/components/design-system/StepStatusIcon.tsx","../../src/client/components/requirements/RequirementsChecklistView.tsx","../../src/client/components/requirements/tax-document/TaxDocumentModalView.tsx","../../src/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel.ts","../../src/client/hooks/requirements/data/useTaxDocument.ts","../../src/client/components/requirements/tax-document/TaxDocumentModalContainer.tsx","../../src/client/components/requirements/VerificationOverlay.tsx","../../src/client/components/requirements/wallet/ConnectWalletModalView.tsx","../../src/client/hooks/requirements/wallet/useConnectWalletModalViewModel.ts","../../src/client/hooks/requirements/data/useConnectWallet.ts","../../src/client/core/wallets/connect-external-wallet.ts","../../src/client/components/requirements/wallet/ConnectWalletModalContainer.tsx","../../src/client/hooks/requirements/useRequirementsChecklistViewModel.ts","../../src/client/hooks/requirements/data/useOptionAddresses.ts","../../src/client/hooks/requirements/data/useRequirements.ts","../../src/client/hooks/requirements/useRequirementsChecklistViewModel.types.ts","../../src/client/components/requirements/RequirementsChecklistContainer.tsx","../../src/client/core/shared/observability/pino-client-logger.ts","../../src/universal/core/shared/observability/pino-logger.ts","../../src/client/hooks/auth/useCompleteOAuth.ts","../../src/client/hooks/checkout/coin-list/token-sale/data/useParticipations.ts","../../src/client/hooks/offers/data/useOfferDetails.ts","../../src/client/hooks/offers/shared/offer-asset-card.types.ts","../../src/client/ui/format/date.ts"],"sourcesContent":["/** biome-ignore-all lint/plugin: one of the three barrels - the only files that may hold export clauses, and the only index files. */\n// Provider\nexport * from '@/client/CoinListProvider';\nexport * from '@/client/CoinListStyleScope';\n// Components: OAuth\nexport * from '@/client/components/auth/CoinListSignInButton';\nexport * from '@/client/components/auth/CoinListSignInCardContainer';\nexport * from '@/client/components/auth/CoinListSignInCardView';\n// Components: checkout - the entry point every host starts from\nexport * from '@/client/components/checkout/CheckoutContainer';\n// Components: checkout - Ondo buy and sell\n// The `checkout/shared/*` components stay internal. Two providers have now\n// exercised their slots, which is what the Superstate port was meant to\n// establish - but publishing them freezes shapes that a third provider\n// (WisdomTree, Centrifuge) is the next real test of, and nothing a partner can\n// do today needs them: `CheckoutContainer` and each provider's View are the\n// supported surfaces. The design-system primitives they lean on (`Skeleton`,\n// `Tooltip`) stay internal for the same reason. Revisit when provider #3 lands.\nexport * from '@/client/components/checkout/ondo/buy/amount/OndoBuyAmountView';\nexport * from '@/client/components/checkout/ondo/buy/confirmation/OndoBuyOrderConfirmed';\nexport * from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer';\nexport * from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutView';\nexport * from '@/client/components/checkout/ondo/buy/review/OndoBuyReviewView';\nexport * from '@/client/components/checkout/ondo/sell/amount/OndoSellAmountView';\nexport * from '@/client/components/checkout/ondo/sell/confirmation/OndoSellOrderConfirmed';\nexport * from '@/client/components/checkout/ondo/sell/OndoSellCheckoutContainer';\nexport * from '@/client/components/checkout/ondo/sell/OndoSellCheckoutView';\nexport * from '@/client/components/checkout/ondo/sell/review/OndoSellReviewView';\nexport * from '@/client/components/checkout/ondo/shared/error/OndoCheckoutError';\nexport * from '@/client/components/checkout/ondo/shared/sidebar/OndoSidebarView';\nexport * from '@/client/components/checkout/ondo/shared/wallet/OndoWalletSelectView';\n// Components: checkout - Superstate swap\nexport * from '@/client/components/checkout/superstate/swap/amount/SuperstateAmountView';\nexport * from '@/client/components/checkout/superstate/swap/confirmation/SuperstateOrderConfirmed';\nexport * from '@/client/components/checkout/superstate/swap/review/SlippagePicker';\nexport * from '@/client/components/checkout/superstate/swap/review/SuperstateReviewView';\nexport * from '@/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer';\nexport * from '@/client/components/checkout/superstate/swap/SuperstateSwapCheckoutView';\nexport * from '@/client/components/checkout/superstate/swap/sidebar/SuperstateSidebarView';\nexport * from '@/client/components/checkout/superstate/swap/wallet/SuperstateWalletView';\n// Components: offers\nexport * from '@/client/components/offers/grid/OffersAssetGrid';\nexport * from '@/client/components/offers/grid/OffersGridContainer';\nexport * from '@/client/components/offers/grid/OffersGridView';\nexport * from '@/client/components/offers/shared/OfferAssetCard';\nexport * from '@/client/components/offers/shared/OfferSaleCard';\n// Components: requirements\nexport * from '@/client/components/requirements/ConnectedWalletList';\nexport * from '@/client/components/requirements/identity-verification/IdentityVerificationContainer';\nexport * from '@/client/components/requirements/identity-verification/IdentityVerificationView';\nexport * from '@/client/components/requirements/RequirementItem';\nexport * from '@/client/components/requirements/RequirementsChecklistContainer';\nexport * from '@/client/components/requirements/RequirementsChecklistView';\nexport * from '@/client/components/requirements/tax-document/TaxDocumentModalContainer';\nexport * from '@/client/components/requirements/tax-document/TaxDocumentModalView';\nexport * from '@/client/components/requirements/VerificationOverlay';\nexport * from '@/client/components/requirements/wallet/ConnectWalletModalContainer';\nexport * from '@/client/components/requirements/wallet/ConnectWalletModalView';\n\n// Core client: the entry point, the feature-agnostic wallet seam, and each\n// provider's namespace next to the on-chain flows it drives.\nexport * from '@/client/core/auth/client-auth-namespace';\nexport * from '@/client/core/auth/types';\nexport * from '@/client/core/checkout/coin-list/client-token-sale-namespace';\nexport * from '@/client/core/checkout/coin-list/token-sale-flows';\nexport * from '@/client/core/checkout/ondo/client-ondo-namespace';\nexport * from '@/client/core/checkout/ondo/ondo-flows';\nexport * from '@/client/core/checkout/superstate/client-swap-namespace';\nexport * from '@/client/core/checkout/superstate/swap-flows';\nexport * from '@/client/core/coinlist-client';\nexport * from '@/client/core/requirements/client-requirements-namespace';\nexport * from '@/client/core/shared/blockchain/erc20/approval';\nexport * from '@/client/core/shared/blockchain/wallet-error';\n// Observability: the `Logger` a host implements and hands to CoinListProvider,\n// plus the console implementation to start from.\nexport * from '@/client/core/shared/observability/pino-client-logger';\nexport * from '@/client/core/support/client-support-namespace';\nexport * from '@/client/core/wallets/connect-external-wallet';\n// Hooks: OAuth\nexport * from '@/client/hooks/auth/useCoinListSignInCardViewModel';\nexport * from '@/client/hooks/auth/useCoinListSignInCardViewModel.types';\nexport * from '@/client/hooks/auth/useCompleteOAuth';\n// Hooks: checkout (CoinList token sale)\nexport * from '@/client/hooks/checkout/coin-list/token-sale/data/useParticipations';\n// Hooks: checkout (Ondo). Each screen exports its viewmodel and the UI\n// contract the View is driven by; the smaller data hooks go out too, so a\n// partner can compose their own viewmodel. Those sit under `ondo/shared/data`\n// where both products share one, and under the product's own `data/` where the\n// endpoint behind it is that product's - `POST /v1/ondo/swap/{buy,sell}`.\nexport * from '@/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/data/useOndoBuyTransaction';\nexport * from '@/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel';\nexport * from '@/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/sell/data/useOndoSellTransaction';\nexport * from '@/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel';\nexport * from '@/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel';\nexport * from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nexport * from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nexport * from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\nexport * from '@/client/hooks/checkout/ondo/shared/ondo-checkout-error.types';\nexport * from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nexport * from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel';\nexport * from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel';\nexport * from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel.types';\nexport * from '@/client/hooks/checkout/shared/checkout-ui.types';\nexport * from '@/client/hooks/checkout/shared/checkout-wallet.types';\n// Hooks: checkout (shared)\nexport * from '@/client/hooks/checkout/shared/data/useCheckoutOfferTokenMetadata';\n// Hooks: checkout (Superstate). Each screen exports its viewmodel and the UI\n// contract the View is driven by; the smaller data hooks go out too, so a\n// partner can compose their own viewmodel.\nexport * from '@/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel';\nexport * from '@/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel.types';\nexport * from '@/client/hooks/checkout/superstate/swap/data/useSwapOutputToken';\nexport * from '@/client/hooks/checkout/superstate/swap/data/useSwapQuote';\nexport * from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel';\nexport * from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel.types';\nexport * from '@/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel';\nexport * from '@/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel.types';\nexport * from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel';\nexport * from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel.types';\nexport * from '@/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel';\nexport * from '@/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel.types';\n// Hooks: offers\nexport * from '@/client/hooks/offers/data/useOfferDetails';\nexport * from '@/client/hooks/offers/data/useOffers';\nexport * from '@/client/hooks/offers/grid/useOffersGridViewModel';\nexport * from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\nexport * from '@/client/hooks/offers/shared/offer-asset-card.types';\nexport * from '@/client/hooks/offers/shared/offer-logo.types';\nexport * from '@/client/hooks/offers/shared/offer-sale-card.types';\nexport * from '@/client/hooks/requirements/data/useConnectWallet';\nexport * from '@/client/hooks/requirements/data/useKycToken';\nexport * from '@/client/hooks/requirements/data/useOptionAddresses';\nexport * from '@/client/hooks/requirements/data/useRequirements';\nexport * from '@/client/hooks/requirements/data/useTaxDocument';\nexport * from '@/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel';\nexport * from '@/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel.types';\nexport * from '@/client/hooks/requirements/shared/tax-document.types';\nexport * from '@/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel';\nexport * from '@/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel.types';\n// Hooks: requirements\nexport * from '@/client/hooks/requirements/useRequirementsChecklistViewModel';\nexport * from '@/client/hooks/requirements/useRequirementsChecklistViewModel.types';\nexport * from '@/client/hooks/requirements/wallet/useConnectWalletModalViewModel';\nexport * from '@/client/hooks/requirements/wallet/useConnectWalletModalViewModel.types';\n// Hooks: shared across features\nexport * from '@/client/hooks/shared/erc20/useErc20Balance';\nexport * from '@/client/hooks/shared/erc20/useErc20TokenBalances';\nexport * from '@/client/hooks/shared/useTokenMetadata';\nexport * from '@/client/hooks/shared/useTokenRegistry';\n// Hooks: ambient\nexport * from '@/client/hooks/useCoinList';\n// UI layer: presentation logic\nexport * from '@/client/ui/format/asset-icon';\nexport * from '@/client/ui/format/date';\nexport * from '@/client/ui/format/duration';\nexport * from '@/client/ui/hooks/useCountdown';\n// Shared types\nexport { HttpError, type HttpResponse } from '@/universal/api/http';\nexport * from '@/universal/types/blockchain/evm-wallet';\nexport * from '@/universal/types/blockchain/wallet-error';\nexport * from '@/universal/types/kyc';\nexport * from '@/universal/types/logger';\n","'use client';\n\n/**\n * CoinList React context + initialization.\n *\n * Both exports provide the client context and nothing visual, so both are safe to mount\n * app-wide. SDK visual components style themselves (each self-scopes via\n * CoinListStyleScope), so neither provider applies styling to the host's own DOM.\n *\n * - CoinListProvider: the provider to mount once at your app root.\n * - CoinListContextProvider: identical; the explicit name for when you want the\n * intent (context only) spelled out.\n *\n * Both also publish the optional `locale` to the tree, so SDK components can format\n * without the host threading it through every component.\n */\n\nimport {\n createContext,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n type ClientConfig,\n type CoinListClient,\n createCoinListClient,\n} from '@/client/core/coinlist-client';\nimport {\n CoinListLocaleContext,\n DEFAULT_LOCALE,\n} from '@/client/hooks/shared/useLocale';\nimport { CoinListLoggerContext } from '@/client/hooks/shared/useLogger';\n\nexport type CoinListContextValue = {\n coinlist: CoinListClient;\n isReady: boolean;\n};\n\nexport const CoinListContext = createContext<CoinListContextValue | null>(null);\n\nexport type CoinListProviderProps = {\n config: ClientConfig;\n /**\n * BCP-47 language tag (e.g. `'fr-FR'`) applied to every SDK component in the\n * tree: number, date and currency formatting, and the language of embedded\n * third-party flows. Set it once here instead of per component. Defaults to\n * `'en-US'`.\n *\n * A plain string, so a Next.js server layout can pass its route locale\n * straight through: `<CoinListProvider config={config} locale={params.locale}>`.\n */\n locale?: string;\n children: ReactNode;\n};\n\n/**\n * Provide CoinList (api + config) to the tree WITHOUT any styling. Renders only the\n * React context: no DOM, no <style>, no .clco-sdk-root. Safe to mount app-wide:\n * it has zero visual impact on the host's own pages.\n *\n * Use this when you need useCoinList() available app-wide. SDK visual components\n * self-scope, so you do not need to wrap them in {@link CoinListStyleScope}.\n * {@link CoinListProvider} is an identical alias with a friendlier name.\n */\nexport function CoinListContextProvider({\n config,\n locale,\n children,\n}: CoinListProviderProps) {\n const [isReady, setIsReady] = useState(false);\n const coinlist = useMemo(() => createCoinListClient(config), [config]);\n\n useEffect(() => {\n let isCancelled = false;\n if (coinlist.auth.getState() === 'unknown') {\n coinlist\n .init()\n .then(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n })\n .catch(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n });\n } else {\n setIsReady(true);\n }\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist]);\n\n const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);\n const logger = config.logger ?? null;\n\n return (\n <CoinListContext.Provider value={value}>\n {/*\n Separate context from the client above: the locale is a plain string, so\n changing it re-renders only the components that read it, never every\n useCoinList() consumer. Keeping it out of `config` also means a locale\n switch does not change the config identity and re-create the client.\n */}\n <CoinListLocaleContext.Provider value={locale ?? DEFAULT_LOCALE}>\n {/*\n Published separately for the same reason, and read by useLogger().\n The client core takes its own copy straight from `config`, so Level 1\n logs with or without a React tree; this is only how the hooks and\n components above it reach the same logger.\n */}\n <CoinListLoggerContext.Provider value={logger}>\n {children}\n </CoinListLoggerContext.Provider>\n </CoinListLocaleContext.Provider>\n </CoinListContext.Provider>\n );\n}\n\n/**\n * The provider to mount once at your app root. Provides the CoinList client context\n * to the whole tree with zero visual impact: it renders no DOM, no `<style>`, and no\n * `.clco-sdk-root`, so it never styles the host's own pages. SDK visual components\n * (CoinListSignInCardContainer, OffersGridContainer, ...) style themselves, so you do not need to wrap\n * them in {@link CoinListStyleScope}.\n *\n * Alias of {@link CoinListContextProvider}: identical behavior, friendlier name for\n * the common \"mount one provider\" case.\n */\nexport const CoinListProvider = CoinListContextProvider;\n","/**\n * Computes SHA-256 digest of the input (UTF-8 string or raw bytes).\n * Uses the Web Crypto API.\n */\nexport async function sha256(data: string | Uint8Array): Promise<ArrayBuffer> {\n const bytes =\n typeof data === 'string' ? new TextEncoder().encode(data) : data;\n const buffer = bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n return crypto.subtle.digest('SHA-256', buffer);\n}\n\n/**\n * Converts an ArrayBuffer to Base64-URL encoding (RFC 4648).\n * @param padding - If false, omits trailing '=' padding (e.g. for PKCE).\n */\nexport function arrayBufferToBase64Url(\n buffer: ArrayBuffer,\n padding: boolean = true\n): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n let base64 = btoa(binary);\n base64 = base64.replace(/\\+/g, '-').replace(/\\//g, '_');\n if (!padding) {\n base64 = base64.replace(/=+$/, '');\n }\n return base64;\n}\n\n/**\n * Securely generates random bytes and returns them as Base64-URL (no padding).\n * Suitable for PKCE code_verifier and OAuth state.\n * @param byteLength - Number of random bytes (e.g. 32 for PKCE).\n */\nexport function generateSecureRandomBase64Url(byteLength: number): string {\n const bytes = new Uint8Array(byteLength);\n crypto.getRandomValues(bytes);\n const buffer = bytes.buffer;\n return arrayBufferToBase64Url(buffer, false);\n}\n\n/**\n * Generate a UUID v4 using the standard Web Crypto API (crypto.randomUUID).\n * Falls back to RFC 4122–compliant generation via crypto.getRandomValues in old browsers.\n */\nexport function getUUIDv4(): string {\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.randomUUID === 'function'\n ) {\n return crypto.randomUUID();\n }\n\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.getRandomValues === 'function'\n ) {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`;\n }\n\n return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;\n}\n\nexport function notBlankStringOrNull(value?: string | null): string | null {\n if (value?.trim()) {\n return value;\n } else {\n return null;\n }\n}\n","'use client';\n\nimport { getUUIDv4 } from '@/universal/core/shared/utils/crypto';\n\nconst DEVICE_ID_KEY = 'coinlist.device_id';\n\n/**\n * Get or create a device ID stored in localStorage.\n * Uses a crypto UUID that persists across sessions.\n */\nexport function getDeviceId(): string {\n let deviceId = localStorage.getItem(DEVICE_ID_KEY);\n\n if (!deviceId) {\n deviceId = getUUIDv4();\n localStorage.setItem(DEVICE_ID_KEY, deviceId);\n }\n\n return deviceId;\n}\n\n/**\n * Clear the stored device ID (useful for testing or logout).\n */\nexport function clearDeviceId(): void {\n localStorage.removeItem(DEVICE_ID_KEY);\n}\n","export const PUBLIC_API_BASE_URL = 'https://api.coinlist.co';\nexport const HEADER_API_VERSION = 'X-API-Version';\nexport const HEADER_USER_AGENT = 'User-Agent';\nexport const HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';\nexport const API_VERSION = '2025-10-17';\n\nexport const COINLIST_BASE_URL = 'https://coinlist.co';\nexport const OAUTH_PAGE_PATH = '/oauth/authorize';\n\nexport const SUPPORT_NEW_TICKET_URL =\n 'https://support.coinlist.co/support/tickets/new';\n\nexport const VERIFY_IDENTITY_PATH = '/verify-identity';\nexport const VERIFY_IDENTITY_ACCREDITATION_PATH =\n '/verify-identity/accreditation_full';\nexport const WALLET_PATH = '/wallet';\n","import type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\n/**\n * Which user access token a request went out with. A refused request that\n * carried none is a different case from one that carried a token, not a\n * missing value: nothing held now can be the token it was refused with.\n */\nexport type SentWith =\n | { type: 'user-token'; token: OAuthAccessToken }\n | { type: 'no-user-token' };\n\nexport const SentWith = {\n userToken: (token: OAuthAccessToken): SentWith => ({\n type: 'user-token',\n token,\n }),\n noUserToken: { type: 'no-user-token' } as const satisfies SentWith,\n};\n\n/**\n * Why the HTTP pipeline is asking for an access token.\n *\n * The two questions have different answers, which is why this is a union and\n * not a `refresh: boolean`:\n *\n * - `before-request` - \"what should this request carry?\" A cached token is\n * the right answer as long as it has not gone stale.\n * - `after-401` - \"the API refused the request sent with `rejected`; is there\n * anything better?\" The token's own expiry no longer matters, because the\n * API has answered for it: a token that still looks valid locally but was\n * revoked elsewhere must be renewed too, or the session sits in a 401 loop\n * until it expires. `rejected` names the token the refused request carried,\n * so a caller that already holds a *different* token can hand that back\n * instead of renewing again.\n */\nexport type TokenTrigger =\n | { type: 'before-request' }\n | { type: 'after-401'; rejected: SentWith };\n\nexport const TokenTrigger = {\n beforeRequest: { type: 'before-request' } as const satisfies TokenTrigger,\n after401: (rejected: SentWith): TokenTrigger => ({\n type: 'after-401',\n rejected,\n }),\n};\n\n/**\n * Where the authenticated pipeline gets its user access token from. Internal:\n * hosts implement `ClientConfig.getAccessToken`, never this.\n *\n * Resolves to `null` when there is no session. **Throws** when it could not\n * find out - a backend outage, a network failure - and that distinction is\n * load-bearing: a throw must never be read as \"logged out\", or every outage\n * signs the user out.\n */\nexport type InternalAccessTokenSource = (\n trigger: TokenTrigger\n) => Promise<OAuthAccessToken | null>;\n\n/** Whether `token` is the one the API just refused. */\nexport function isRejectedToken(\n token: OAuthAccessToken,\n rejected: SentWith\n): boolean {\n switch (rejected.type) {\n case 'user-token':\n return rejected.token.value === token.value;\n case 'no-user-token':\n return false;\n }\n}\n","import { SentWith } from '@/universal/api/internal-access-token-source';\nimport type { RequestId } from '@/universal/types/logger';\nimport type {\n ClientCredentialsOAuth,\n OAuthAccessToken,\n} from '@/universal/types/oauth-session';\n\nexport type HttpRequestAttributes = {\n /**\n * Correlates the log lines of one logical request. Minted by\n * {@link HttpClient} on the first attempt and carried onto every retry and\n * post-renewal re-send by {@link concat}, which is what lets a reader tell\n * three attempts of one request from three separate requests.\n */\n requestId?: RequestId;\n protected?: boolean;\n userAgent?: boolean;\n idempotencyKey?: boolean;\n /** Zero-based attempt index: 0 = first request, 1 = first retry, etc. */\n retryAttempt?: number;\n renewAttempted?: boolean;\n /**\n * `false` opts a request out of `requestRetryMiddleware`. For exchanges\n * that must never be replayed: a refresh token is single-use, so re-sending\n * one whose first attempt reached the server presents a token that has\n * already been rotated away.\n */\n retryable?: boolean;\n /**\n * The user access token `attachSessionMiddleware` put on this request, so\n * that a 401 can say *which* token was refused. Absent when the request\n * went out with no user token.\n */\n sentWith?: OAuthAccessToken;\n clientCredentials?: ClientCredentialsOAuth;\n};\n\nexport type Attributes = Readonly<HttpRequestAttributes>;\n\nconst empty: Attributes = {};\n\nconst concat = (left: Attributes, right: Attributes): Attributes => ({\n ...left,\n ...right,\n});\n\nconst concatAll = (...items: Attributes[]): Attributes => {\n let result = empty;\n for (const item of items) {\n result = concat(result, item);\n }\n return result;\n};\n\nconst protectedRequest = (): Attributes => ({ protected: true });\nconst userAgent = (): Attributes => ({ userAgent: true });\nconst idempotencyKey = (): Attributes => ({\n idempotencyKey: true,\n});\n\nconst clientCredentials = (\n credentials: ClientCredentialsOAuth | undefined\n): Attributes => ({\n clientCredentials: credentials,\n});\n/** Returns attributes with the given retry attempt (zero-based). */\nconst retryAttempt = (attempt: number): Attributes => ({\n retryAttempt: attempt,\n});\nconst renewAttempted = (value: boolean): Attributes => ({\n renewAttempted: value,\n});\n\nconst notRetryable = (): Attributes => ({ retryable: false });\nconst sentWith = (token: OAuthAccessToken): Attributes => ({\n sentWith: token,\n});\n\nconst requestId = (id: RequestId): Attributes => ({ requestId: id });\n\nconst getRequestId = (attrs?: HttpRequestAttributes): RequestId | null =>\n attrs?.requestId ?? null;\n\nconst isProtected = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.protected === true;\nconst needUserAgent = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.userAgent === true;\nconst isIdempotent = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.idempotencyKey === true;\nconst getRetryAttempt = (attrs?: HttpRequestAttributes): number =>\n attrs?.retryAttempt ?? 0;\nconst wasRenewAttempted = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.renewAttempted === true;\nconst isRetryable = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.retryable !== false;\nconst getSentWith = (attrs?: HttpRequestAttributes): SentWith =>\n attrs?.sentWith === undefined\n ? SentWith.noUserToken\n : SentWith.userToken(attrs.sentWith);\nconst getClientCredentials = (\n attrs?: HttpRequestAttributes\n): ClientCredentialsOAuth | undefined => attrs?.clientCredentials;\n\nexport const Attributes = {\n empty,\n concat,\n concatAll,\n protected: protectedRequest,\n isProtected,\n userAgent,\n needUserAgent,\n idempotencyKey,\n isIdempotent,\n retryAttempt,\n getRetryAttempt,\n renewAttempted,\n wasRenewAttempted,\n notRetryable,\n isRetryable,\n sentWith,\n getSentWith,\n clientCredentials,\n getClientCredentials,\n requestId,\n getRequestId,\n} as const;\n","'use client';\n\nimport { getDeviceId } from '@/client/core/api/middleware/device-id';\nimport { HEADER_USER_AGENT } from '@/universal/api/frontline/config';\nimport type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\n\nexport const userAgentMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.needUserAgent(request.attributes)) {\n return request;\n }\n\n const userAgent = generateUserAgent();\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n [HEADER_USER_AGENT]: userAgent,\n },\n };\n};\n\n// Generate User-Agent in the required format for Frontline API\n// Format: <app-info> (<device-info>; DevicePlatform <device-platform>; DeviceAppID <device-app-id>; DeviceID <device-id>)\nfunction generateUserAgent(): string {\n const appInfo = `CoinList/1.0`;\n const deviceInfo = 'Web Browser';\n const devicePlatform = 'DevicePlatform web'; // Must be 'web' for validation\n\n const deviceAppId = 'DeviceAppID co.coinlist.sdk'; // SDK app ID\n\n const deviceId = getDeviceId();\n const finalDeviceId = `DeviceID ${deviceId}`;\n\n return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;\n}\n","import {\n Attributes,\n type HttpRequestAttributes,\n} from '@/universal/api/http-attributes';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport type { RequestId } from '@/universal/types/logger';\n\nexport type HttpClientConfig = {\n baseUrl: string;\n /**\n * The frontline `X-API-Version` header. Omit for clients against other\n * backends (e.g. the token registry): a version header they don't know\n * would also force a CORS preflight the CDN cannot answer.\n */\n xApiVersion?: string;\n};\n\nexport type HttpRequest<TBody = unknown> =\n | {\n method: 'GET';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'POST';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n body: TBody;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'DELETE';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n };\nexport type HttpResponse<TBody = unknown> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody | null;\n /**\n * The id of the request that produced this response, stamped by\n * {@link HttpClient} so that whoever turns a non-2xx into an\n * {@link HttpError} can carry it without threading the request alongside.\n * Absent when the response did not come from an `HttpClient`.\n */\n requestId?: RequestId;\n};\n\nexport class HttpError<TBody = unknown> extends Error {\n readonly response: HttpResponse<TBody>;\n\n constructor(response: HttpResponse<TBody>) {\n super(`Request failed with ${response.status} status`);\n this.name = 'HttpError';\n this.response = response;\n }\n\n /**\n * Correlates this failure with the `[HTTP]` log lines for the same request,\n * which carry the method, the URL, the duration and every retry. `null` when\n * the response did not come from an {@link HttpClient}.\n *\n * Worth quoting in a bug report: it is what makes a log excerpt readable.\n */\n get requestId(): RequestId | null {\n return this.response.requestId ?? null;\n }\n}\n\n/**\n * The machine-readable `code` frontline attaches to an error, or `null` for\n * anything else - a non-HTTP failure, or an error body that carries only a\n * message.\n *\n * Frontline answers a failure with `{ type, message, code?, errors?,\n * event_id? }`, and `code` is the only part of it meant to be branched on:\n * `message` is prose that may be reworded, and `type` distinguishes\n * `invalid_request_error` from `api_error` without saying which one.\n *\n * Reach for this only where a code has a distinct remedy the user can act on.\n * Mapping the whole vocabulary would couple the SDK to strings frontline does\n * not version; falling back to a generic failure is the right default.\n */\nexport function apiErrorCode(error: unknown): string | null {\n if (!(error instanceof HttpError)) return null;\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const code: unknown = (body as { code?: unknown }).code;\n return typeof code === 'string' ? code : null;\n}\n\nexport async function makeRequest<TResponse = unknown>(\n request: HttpRequest\n): Promise<HttpResponse<TResponse>> {\n const headers: Record<string, string> = {\n Accept: 'application/json',\n ...(request.method === 'POST' && request.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(request.headers ?? {}),\n };\n\n const init: RequestInit = {\n method: request.method,\n headers,\n ...(request.redirect !== undefined ? { redirect: request.redirect } : {}),\n };\n\n if (request.method === 'POST' && request.body !== undefined) {\n init.body = JSON.stringify(request.body);\n }\n\n const response = await fetch(\n buildUrlWithQueryParams(request.url, request.queryParams),\n init\n );\n const responseHeaders = headersToRecord(response.headers);\n\n if (response.status === 204 || response.status === 205) {\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n await response.text();\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n const text = await response.text();\n let body: TResponse | null;\n try {\n body = text ? (JSON.parse(text) as TResponse) : null;\n } catch (_) {\n // A non-JSON body (an HTML error page from a CDN, proxy, or load\n // balancer) would otherwise surface as a bare SyntaxError with the status\n // lost. Throw the full response instead, so callers can classify the\n // failure by status and still see what the server actually sent.\n throw new HttpError({\n status: response.status,\n headers: responseHeaders,\n body: text,\n });\n }\n\n return {\n status: response.status,\n body,\n headers: responseHeaders,\n };\n}\n\n/**\n * The URL as `fetch` will see it, query string included.\n *\n * Exported for {@link HttpClient}'s `debug` request line, which renders the\n * request exactly as sent. Every other log line carries {@link HttpRequest.url}\n * alone - the query holds wallet addresses, chains and amounts, and `debug` is\n * the only level allowed to see them.\n */\nexport function buildUrlWithQueryParams(\n url: string,\n queryParams?: Record<string, QueryParamValues>\n): string {\n if (!queryParams) {\n return url;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) {\n continue;\n }\n searchParams.append(key, String(item));\n }\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const queryString = searchParams.toString();\n if (!queryString) {\n return url;\n }\n\n return url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`;\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key.toLowerCase()] = value;\n });\n return record;\n}\n\nfunction concatAttributes(\n request: HttpRequest,\n attrs: Attributes\n): HttpRequest {\n const nextAttributes = Attributes.concat(\n request.attributes ?? Attributes.empty,\n attrs\n );\n const nextRequest: typeof request = {\n ...request,\n attributes: nextAttributes,\n };\n return nextRequest;\n}\n\nexport const Request = {\n concatAttributes,\n};\n","import {\n BaseError,\n ContractFunctionExecutionError,\n ContractFunctionRevertedError,\n HttpRequestError,\n RpcError,\n SocketClosedError,\n TimeoutError,\n WebSocketRequestError,\n} from 'viem';\nimport { apiErrorCode, HttpError } from '@/universal/api/http';\nimport {\n InvariantError,\n MathError,\n NotAuthenticatedError,\n NotImplementedError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type {\n FrontlineEventId,\n LogCause,\n RpcFailureReason,\n} from '@/universal/types/logger';\n\n/**\n * Classifies anything thrown inside the SDK into a {@link LogCause}.\n *\n * The SDK's **only** structured classification of a thrown error. It reaches\n * `warn` as well as `error`, since a recoverable failure is no less worth\n * naming than a fatal one.\n *\n * An `instanceof` chain rather than a pattern match, for the same reason\n * `classifyWalletError` is one: these are classes, not an ADT, so there is no\n * tag to match on. The chain is ordered most specific first and ends in\n * `generic-error`, which is total - a host-supplied lambda may throw anything\n * at all, a string included.\n *\n * Everything it returns is safe above `'debug'`, and the chain itself is the\n * opt-in list: only the five SDK-authored error classes named below reach an\n * arm carrying a `message`, because only those messages were written by the\n * SDK. Everything else contributes its class name and nothing more, since its\n * message and its fields are host-authored. {@link describeErrorUnredacted} is\n * where those go. A new error type has to be added here deliberately, which is\n * the moment to ask whether its message is SDK-authored all the way down;\n * defaulting to \"safe\" is how the leak ADR-8 replaced happened.\n *\n * Lives at Level 1 rather than beside {@link LogCause} because classifying an\n * {@link HttpError} means importing `@/universal/api`, which `@/universal/types` may\n * not do (`data.yaml#domain-models-dont-reach-the-api-layer`).\n */\nexport function classifyLogCause(error: unknown): LogCause {\n if (error instanceof HttpError) {\n return httpCause(error);\n }\n if (error instanceof ValidationError) {\n return { type: 'validation', message: error.message };\n }\n if (error instanceof InvariantError) {\n return { type: 'invariant', message: error.message };\n }\n if (error instanceof MathError) {\n return { type: 'math', message: error.message };\n }\n if (error instanceof NotAuthenticatedError) {\n return { type: 'not-authenticated' };\n }\n if (error instanceof NotImplementedError) {\n return { type: 'not-implemented' };\n }\n if (error instanceof BaseError) {\n // viem wraps whatever a `Transport` threw, so an `HttpError` the SDK's own\n // proxy transport raised arrives inside a chain failure. It is an HTTP\n // failure, not a bad decode, and its `requestId` is what leads to the rest.\n const http = error.walk((e) => e instanceof HttpError);\n if (http instanceof HttpError) {\n return httpCause(http);\n }\n return { type: 'rpc', reason: rpcFailureReason(error) };\n }\n return { type: 'generic-error', name: errorName(error) };\n}\n\n/**\n * Classifies a viem error by what a caller would do about it.\n *\n * `instanceof` against viem's exported classes and nothing else. Reading\n * `error.name` would be simpler and is unsafe twice over: it is a writable\n * property, so a host-supplied `Transport` throwing a doctored error would put\n * its own string on an `'error'` line, and a class name is a fact about viem's\n * hierarchy rather than a remedy. `walk` is viem's own accessor for the cause\n * chain - a revert arrives wrapped in a `ContractFunctionExecutionError`, so\n * the specific arm is never the outermost one.\n *\n * `malformed-response` is decided **structurally, by elimination**, rather than\n * from a list of viem's decoding classes. The wrapper says only that the\n * failure came out of a contract call: `getContractError` builds a\n * `ContractFunctionExecutionError` on every throw out of `call`, a transport\n * that never reached the node included. So the elimination is sound only\n * because **every transport class viem can raise is named in the arm above** -\n * that list is load-bearing, and a transport error class viem grows later\n * belongs in it rather than here. Given it, an error carrying the wrapper that\n * is not a revert, not an `RpcError` and not a transport failure can only be\n * the returned bytes failing to fit the ABI - a wrong address or a stale\n * constant. An allowlist cannot express that:\n * a return type the ABI no longer matches surfaces as `IntegerOutOfRangeError`,\n * which is not an `Abi*` class at all, and is the same class viem raises when\n * *encoding* an out-of-range argument. Only the wrapper separates the two.\n *\n * Which is also why the encode side falls through to `'unknown'`. An argument\n * the SDK got wrong, or a `functionName` absent from its own ABI constant, is\n * raised before the call and arrives unwrapped: an SDK bug rather than anything\n * the chain answered, and not something `malformed-response` should claim.\n *\n * `'unknown'` discloses nothing. The full message, the revert reason and the\n * calldata are on the paired `'debug'` line, via\n * {@link describeErrorUnredacted}.\n */\nfunction rpcFailureReason(error: BaseError): RpcFailureReason {\n if (error.walk((e) => e instanceof ContractFunctionRevertedError)) {\n return 'reverted';\n }\n if (error.walk((e) => e instanceof RpcError)) {\n return 'node-rejected';\n }\n if (\n error.walk(\n (e) =>\n e instanceof HttpRequestError ||\n e instanceof WebSocketRequestError ||\n e instanceof SocketClosedError ||\n e instanceof TimeoutError\n )\n ) {\n return 'transport';\n }\n if (error instanceof ContractFunctionExecutionError) {\n return 'malformed-response';\n }\n return 'unknown';\n}\n\n/**\n * A one-line rendering of a thrown error **verbatim**, message included.\n *\n * Unredacted, and therefore `'debug'` only: every caller puts the result in a\n * {@link DebugEvent} field, which the level check has already admitted. Always\n * called inside an event lambda, so it never runs below the level.\n *\n * The difference from {@link classifyLogCause} is one word - `message` - and\n * it is the whole safety boundary. A viem `BaseError.message` embeds the\n * transaction's `from`, `to`, `value` and calldata; a host's `getAccessToken`\n * may throw `new Error('token abc123 rejected')`. Neither is something the SDK\n * can vouch for.\n *\n * A rendered string rather than the error object, because an `Error`'s `name`,\n * `message` and `stack` are all non-enumerable: handed to a structured sink as\n * an object it serialises to `{}`.\n */\nexport function describeErrorUnredacted(error: unknown): string {\n if (error instanceof HttpError) {\n return describeHttpErrorRedacted(error);\n }\n if (error instanceof Error) {\n return `${error.name}: ${error.message}`;\n }\n return `thrown non-error: ${stringifyUnredacted(error)}`;\n}\n\n/**\n * Renders a value for a log field without ever throwing. A DTO holding a\n * `bigint`, or a params object the host made circular, must not turn a log\n * line into a second failure.\n *\n * Unredacted by construction - it stringifies whatever it is handed - so every\n * call site must be a `'debug'` one.\n */\nexport function stringifyUnredacted(value: unknown): string {\n if (value === undefined) return '';\n try {\n // `JSON.stringify` answers `undefined` for a function or a symbol, which\n // a params object can legitimately hold - an `onProgress` callback, say.\n return (\n JSON.stringify(value, (_key, item: unknown) =>\n typeof item === 'bigint' ? `${item}` : item\n ) ?? String(value)\n );\n } catch (_) {\n return '<unserializable>';\n }\n}\n\n/**\n * The status and frontline's code. Server-authored, so it is the same string\n * at every level rather than two renderings of one failure.\n */\nfunction describeHttpErrorRedacted(error: HttpError): string {\n const code = apiErrorCode(error);\n const status = error.response.status;\n return code === null\n ? `HttpError ${status}`\n : `HttpError ${status} (${code})`;\n}\n\n/**\n * The class name of an unrecognised throw, which is all of it that the SDK may\n * repeat above `'debug'`. A thrown non-error has no class worth naming, so its\n * `typeof` stands in.\n */\nfunction errorName(error: unknown): string {\n return error instanceof Error ? error.name : `non-error ${typeof error}`;\n}\n\n/**\n * The status and the two identifiers, and nothing else. The body stays out:\n * this value reaches `Logger.error`, which runs at every level a host would\n * enable in production, and a response body is a `'debug'`-only disclosure.\n * `requestId` is what leads back to it.\n */\nfunction httpCause(error: HttpError): LogCause {\n return {\n type: 'http',\n requestId: error.requestId,\n status: error.response.status,\n code: apiErrorCode(error),\n eventId: apiErrorEventId(error),\n };\n}\n\n/**\n * Frontline stamps a failure with `event_id`, the id its own logs are keyed\n * by. It is the single most useful thing to quote when raising a ticket, which\n * is why it is pulled out of the body rather than left for a reader to find.\n *\n * Private, unlike `apiErrorCode`: nothing branches on it, so it is a logging\n * detail rather than public API.\n */\nfunction apiErrorEventId(error: HttpError): FrontlineEventId | null {\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const eventId: unknown = (body as { event_id?: unknown }).event_id;\n return typeof eventId === 'string' ? (eventId as FrontlineEventId) : null;\n}\n","/**\n * Error thrown when a feature or code path is not yet implemented.\n */\nexport class NotImplementedError extends Error {\n constructor(message = 'Not implemented yet') {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\n/**\n * Error thrown when accessing a feature that requires authentication\n * without being authenticated.\n */\nexport class NotAuthenticatedError extends Error {\n constructor(\n message = 'The user is not authenticated. Go through the OAuth flow first!'\n ) {\n super(message);\n this.name = 'NotAuthenticatedError';\n }\n}\n\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Error thrown when the SDK computes something impossible: a value outside\n * uint256 after its own arithmetic, a symbol missing from a registry the SDK\n * itself ships. Distinct from {@link ValidationError}, which means the backend\n * sent a shape the SDK does not understand.\n *\n * The two have different remedies, which is the whole reason they are separate\n * types: a {@link ValidationError} is worth reporting to CoinList, an\n * `InvariantError` is an SDK bug worth reporting against the SDK.\n */\nexport class InvariantError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvariantError';\n }\n}\n\n/**\n * Error thrown when an arithmetic operation has no answer to give: a division\n * by zero, or a result that falls outside the range its type can represent.\n *\n * Distinct from {@link ValidationError}, which says a value arrived malformed.\n * A `MathError` says every operand was well-formed and the operation on them\n * still has no result, so the two are worth catching apart: one points at the\n * response, the other at the arithmetic we asked for.\n */\nexport class MathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MathError';\n }\n}\n","import {\n classifyLogCause,\n describeErrorUnredacted,\n} from '@/universal/core/shared/observability/log-cause';\nimport type {\n DebugEvent,\n LogBinding,\n LogBindings,\n LogCause,\n Logger,\n LogLevel,\n LogScope,\n SafeEvent,\n SafeFields,\n UnredactedFields,\n} from '@/universal/types/logger';\n\n/**\n * Wraps the host's {@link Logger}, or its absence, into the thing SDK code\n * actually calls.\n *\n * Three jobs, the first two of which exist so that no call site anywhere in\n * the SDK ever branches on whether logging is on:\n *\n * 1. **Absence is normalised away.** No logger yields {@link noopInternalLogger},\n * whose methods do nothing and whose `wrap` still runs the wrapped work.\n * 2. **The level is checked here, once per call.** Below the level, the\n * event lambda is never invoked and no {@link LogCause} is built. That is\n * the whole reason events are lambdas: expensive debug detail costs nothing\n * in production.\n * 3. **The safety boundary is enforced here.** `'debug'` is the unredacted\n * level; `info`, `warn` and `error` carry only what the SDK authored and\n * what the server minted. {@link InternalLogger.failure} and\n * {@link InternalLogger.warning} render an error twice - verbatim onto a\n * `debug` line, classified onto theirs - rather than once, so that a host\n * running at `'debug'` may still forward `error` to a tracker unchanged.\n *\n * The scope and the accumulated {@link LogBindings} are stamped here, so a\n * call site names only what happened. That is also why call sites hand over an\n * {@link InternalSafeEvent} rather than a finished {@link SafeEvent}: nothing\n * should have to know its own scope twice.\n *\n * ```ts\n * const log = internalLogger(ctx.logger, 'ONDO');\n * log.child({ flow: 'review' }).failure(\n * () => ({ msg: 'quote refresh failed' }),\n * error\n * );\n * // { scope: 'ONDO', flow: 'review', cause: { type: 'http', status: 410, ... },\n * // msg: 'quote refresh failed' }\n * ```\n */\nexport function internalLogger(\n logger: Logger | null | undefined,\n scope: LogScope\n): InternalLogger {\n return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;\n}\n\n/**\n * The logging surface SDK code uses. Never exported to hosts: they implement\n * {@link Logger}, which is deliberately smaller.\n */\nexport type InternalLogger = {\n /**\n * A logger narrowed by one more {@link LogBinding}, which every line it\n * emits carries as its own field.\n */\n child(binding: LogBinding): InternalLogger;\n\n /**\n * The unredacted level. Request and response bodies, full URLs, headers,\n * operation params and raw thrown errors belong here and **only** here.\n */\n debug(event: () => InternalDebugEvent): void;\n\n info(event: () => InternalSafeEvent): void;\n warn(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a failure whose cause is already known, or has none. Prefer\n * {@link failure}, which classifies a thrown error for you.\n */\n error(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a thrown error, classifying it into a {@link LogCause}. Prefer\n * this over `error` at a `catch`: classification only happens when the level\n * admits it.\n *\n * The `error` line names the error's class but never its message, since an\n * error the SDK did not author may say anything at all. The verbatim\n * rendering goes onto a paired `debug` line instead.\n *\n * For a failure the SDK recovers from, use {@link warning} instead. An\n * `error` line a host cannot act on is worse than no line at all: it trains\n * them to ignore the ones that matter.\n */\n failure(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * {@link failure} for trouble that did not break anything: a poll tick that\n * failed while the last value still stands, a retried request.\n *\n * Carries the classified {@link LogCause} exactly as `failure` does. The two\n * differ in level and in nothing else, because what separates them is\n * whether anything actually broke - not how much is known about it.\n */\n warning(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * Runs one namespace operation with logging around it: the call and its\n * params at `debug`, and any throw at `error` with the cause classified.\n * Every line carries `op` as a binding.\n *\n * **The params never reach the `error` line.** They routinely hold the\n * things this SDK must not put in front of a production error tracker - an\n * app bearer token, a document's signing fields, a wallet signature - and\n * the `debug` line plus the request id is how you get them back. The type\n * says so: `params` is `unknown`, which is not a {@link SafeFields} value.\n *\n * Always rethrows. Logging observes behaviour, it never changes it.\n */\n wrap<T>(op: string, params: unknown, run: () => Promise<T>): Promise<T>;\n};\n\n/**\n * What a call site hands to `info`, `warn`, `error`, `failure` or `warning` -\n * a {@link SafeEvent} minus the scope and bindings the logger stamps itself.\n */\nexport type InternalSafeEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: SafeFields;\n readonly cause?: LogCause;\n};\n\n/** What a call site hands to `debug`. Its fields accept anything. */\nexport type InternalDebugEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: UnredactedFields;\n};\n\n/** Each level admits itself and everything above it in this table. */\nconst LEVEL_RANK: Record<LogLevel, number> = {\n none: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction scopedLogger(\n logger: Logger,\n scope: LogScope,\n bindings: LogBindings\n): InternalLogger {\n const admits = (level: LogLevel): boolean =>\n LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];\n\n const safe = (event: InternalSafeEvent): SafeEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n ...(event.cause === undefined ? {} : { cause: event.cause }),\n });\n\n const unredacted = (event: InternalDebugEvent): DebugEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n });\n\n const self: InternalLogger = {\n child: (binding) =>\n scopedLogger(logger, scope, { ...bindings, ...binding }),\n\n debug: (event) => {\n if (admits('debug')) logger.debug(() => unredacted(event()));\n },\n\n info: (event) => {\n if (admits('info')) logger.info(() => safe(event()));\n },\n\n warn: (event) => {\n if (admits('warn')) logger.warn(() => safe(event()));\n },\n\n error: (event) => {\n if (admits('error')) logger.error(() => safe(event()));\n },\n\n failure: (event, error) => {\n // Two lines rather than one, and deliberately in this order: the `error`\n // line stays safe at every level, so a host running `'debug'` in beta\n // can still pipe `error` to Sentry without leaking what `debug` shows.\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('error')) logger.error(() => safe(classified(event(), error)));\n },\n\n warning: (event, error) => {\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('warn')) logger.warn(() => safe(classified(event(), error)));\n },\n\n wrap: async (op, params, run) => {\n const opLog = self.child({ op });\n opLog.debug(() => ({ msg: 'call', fields: { params } }));\n try {\n return await run();\n } catch (error) {\n opLog.failure(() => ({ msg: 'call failed' }), error);\n throw error;\n }\n },\n };\n\n return self;\n}\n\n/**\n * The same event with the thrown error rendered **verbatim** - for the\n * `'debug'` line, and nowhere else.\n */\nfunction verbatim(\n event: InternalSafeEvent,\n error: unknown\n): InternalDebugEvent {\n return {\n msg: event.msg,\n fields: { ...event.fields, error: describeErrorUnredacted(error) },\n };\n}\n\n/**\n * The same event with the thrown error classified into a {@link LogCause}\n * - safe at `'warn'` and `'error'`.\n *\n * An explicit `cause` on the event wins: a call site that already knows what\n * went wrong knows better than the classifier.\n */\nfunction classified(\n event: InternalSafeEvent,\n error: unknown\n): InternalSafeEvent {\n return { ...event, cause: event.cause ?? classifyLogCause(error) };\n}\n\n/**\n * What every SDK codepath gets when the host supplied no logger. `wrap` still\n * runs the work it is given; everything else is inert.\n *\n * There is no `console` fallback here or anywhere else in the SDK: a host who\n * supplied no logger gets silence, not a default destination they did not\n * choose.\n */\nexport const noopInternalLogger: InternalLogger = {\n child: () => noopInternalLogger,\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n failure: () => undefined,\n warning: () => undefined,\n wrap: (_op, _params, run) => run(),\n};\n","import { HEADER_API_VERSION } from '@/universal/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/universal/api/http';\nimport { buildUrlWithQueryParams, makeRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n Logger,\n RequestId,\n UnredactedFields,\n} from '@/universal/types/logger';\n\nexport type BeforeRequestMiddleware = (\n request: HttpRequest\n) => Promise<HttpRequest>;\n\nexport type AfterRequestMiddleware = (args: {\n request: HttpRequest;\n response: HttpResponse<unknown>;\n retry: (request?: HttpRequest) => Promise<HttpResponse<unknown>>;\n}) => Promise<HttpResponse<unknown>>;\n\nexport type HttpClientMiddleware = {\n beforeRequest?: BeforeRequestMiddleware[];\n afterRequest?: AfterRequestMiddleware[];\n};\n\nexport type HttpClientOptions = {\n /**\n * Mints the id that correlates one request's log lines. Injected so specs\n * can assert on log output, the same reason\n * {@link createRequestRetryMiddleware} takes a `delayFn`; defaults to a\n * short random string.\n */\n makeRequestId?: () => RequestId;\n};\n\n/**\n * Logging lives here rather than in a middleware pair so that every client\n * built on `HttpClient` reports by construction - the frontline client, the\n * token registry client, and whatever comes next. A middleware would have to\n * be remembered per client, and could not time a request or see one that threw\n * before producing a response.\n */\nexport class HttpClient {\n private readonly log: InternalLogger;\n private readonly makeRequestId: () => RequestId;\n\n constructor(\n readonly config: HttpClientConfig,\n readonly middleware: HttpClientMiddleware = {},\n logger: Logger | null = null,\n options: HttpClientOptions = {}\n ) {\n this.log = internalLogger(logger, 'HTTP');\n this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;\n }\n\n async send<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n return this.runRequestWithAfterMiddleware<TResponse>(request);\n }\n\n /**\n * Runs beforeRequest, executeRequest, then the full afterRequest middleware\n * chain. Used by send() and by the retry() callback so that when a\n * middleware calls retry(), the retried response also goes through all\n * afterRequest middleware (e.g. session renewal, retry). Middleware\n * must use request.attributes.retryAttempt (or similar) to avoid infinite\n * recursion when they trigger retries.\n */\n private async runRequestWithAfterMiddleware<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const preparedRequest = await this.runBeforeRequestMiddleware(\n this.withClientDefaults(request)\n );\n let response = await this.executeRequest<TResponse>(preparedRequest);\n\n for (const middleware of this.middleware.afterRequest ?? []) {\n let retried = false;\n response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) => {\n retried = true;\n return this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >;\n },\n })) as HttpResponse<TResponse>;\n // A retried response has already been through the whole chain, the\n // middleware after this one included. Running those again here would\n // hand them the outer request's attributes - a fresh retry budget - so\n // a 401 renewed into a persistent 5xx would be retried twice over.\n if (retried) {\n return response;\n }\n }\n\n return response;\n }\n\n private withClientDefaults(request: HttpRequest): HttpRequest {\n const url = this.resolveUrl(request.url);\n const headers = {\n ...(request.headers ?? {}),\n ...(this.config.xApiVersion !== undefined\n ? { [HEADER_API_VERSION]: this.config.xApiVersion }\n : {}),\n };\n\n return {\n ...request,\n url,\n headers,\n // Only when absent: a retry or a post-renewal re-send arrives with the\n // first attempt's id already on it, and keeping it is the whole point.\n attributes:\n Attributes.getRequestId(request.attributes) === null\n ? Attributes.concat(\n request.attributes ?? Attributes.empty,\n Attributes.requestId(this.makeRequestId())\n )\n : request.attributes,\n };\n }\n\n /**\n * Resolves a request URL against the client's baseUrl.\n *\n * @internal Public only for testing. Do not use in application code; use\n * {@link HttpClient.send} with a path and the client will resolve the URL.\n */\n resolveUrl(url: string): string {\n // If already absolute, use as-is.\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n // Otherwise append path to baseUrl so base path (e.g. /api) is preserved.\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const path = url.startsWith('/') ? url : `/${url}`;\n return base + path;\n }\n\n private async runBeforeRequestMiddleware(\n initialRequest: HttpRequest\n ): Promise<HttpRequest> {\n let request = initialRequest;\n for (const middleware of this.middleware.beforeRequest ?? []) {\n request = await middleware(request);\n }\n\n return request;\n }\n\n /**\n * One physical attempt, logged as one line.\n *\n * A non-2xx is a `warn` rather than an `error` because the wire does not\n * know whether it is a failure: the retry middleware may turn a 503 into a\n * success, and the token registry reads a 404 as \"not listed\". The namespace\n * above decides, and logs the `error` when it does.\n */\n private async executeRequest<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const requestId = Attributes.getRequestId(request.attributes);\n const log = requestId === null ? this.log : this.log.child({ requestId });\n const attempt = Attributes.getRetryAttempt(request.attributes) + 1;\n const startedAt = Date.now();\n\n log.debug(() => ({\n msg: 'request sent',\n fields: describeRequestUnredacted(request),\n }));\n\n try {\n const response = await makeRequest<TResponse>(request);\n const elapsed = Date.now() - startedAt;\n const outcome = () => ({\n msg: 'request completed',\n fields: {\n ...identifyRequest(request),\n 'http.response.status_code': response.status,\n duration_ms: elapsed,\n attempt,\n },\n });\n\n if (response.status >= 200 && response.status < 300) {\n log.info(outcome);\n } else {\n log.warn(outcome);\n }\n log.debug(() => ({\n msg: 'response received',\n fields: { body: response.body },\n }));\n\n return requestId === null ? response : { ...response, requestId };\n } catch (error) {\n const elapsed = Date.now() - startedAt;\n // `warning`, not two hand-written lines: it renders the error verbatim\n // at `'debug'` and classified at `'warn'`, which is the pairing this\n // used to spell out by hand.\n log.warning(\n () => ({\n msg: 'request threw',\n fields: {\n ...identifyRequest(request),\n duration_ms: elapsed,\n attempt,\n },\n }),\n error\n );\n throw error;\n }\n }\n}\n\n/**\n * How a request is named on every line above `'debug'`.\n *\n * `server.address` and `url.path` rather than OpenTelemetry's `url.full`, and\n * that is a deliberate deviation from the convention the rest of these keys\n * follow. `url.full` is defined to carry the query string, and frontline reads\n * take `chain`, `wallet_address` and `amount` as query parameters - so the\n * standard key would put host data on the levels this SDK keeps redacted.\n * The full URL appears at `'debug'` and nowhere else.\n *\n * `HttpRequest.url` carries no query to begin with - {@link makeRequest}\n * appends it on the way to `fetch` - so the split is about naming rather than\n * about stripping anything.\n */\nfunction identifyRequest(request: HttpRequest): {\n 'http.request.method': string;\n 'server.address': string | null;\n 'url.path': string;\n} {\n const { host, path } = splitUrl(request.url);\n return {\n 'http.request.method': request.method,\n 'server.address': host,\n 'url.path': path,\n };\n}\n\n/**\n * The host and the path of an absolute URL, separately, because OpenTelemetry\n * names them separately and because only the path is worth grouping on.\n *\n * Never throws: it runs inside an event lambda, and the {@link Logger}\n * contract says nothing the SDK hands over may turn a log line into a second\n * failure. A URL `URL` refuses is reported as it stands, which is safe either\n * way - `HttpRequest.url` never carries a query string.\n */\nfunction splitUrl(url: string): { host: string | null; path: string } {\n try {\n const parsed = new URL(url);\n return { host: parsed.host, path: parsed.pathname };\n } catch (_) {\n return { host: null, path: url };\n }\n}\n\n/**\n * Eight base36 characters. Short enough to read at the head of every line and\n * wide enough that two concurrent requests in one session will not collide.\n * Deliberately not a counter: a module-level counter would be global mutable\n * state shared by every client in the process.\n */\nfunction defaultMakeRequestId(): RequestId {\n return Math.random().toString(36).slice(2, 10).padEnd(8, '0') as RequestId;\n}\n\n/**\n * The request as sent - full URL, headers and body verbatim. `debug` is\n * documented as unredacted: it exists to reproduce a bug, and a redacted\n * `Authorization` is exactly what you need when the bug is that the wrong\n * token went out.\n *\n * The query string appears here and nowhere else, under `url.full`. Every\n * other line names the request through {@link identifyRequest}, whose\n * `url.path` has none - which is why those lines are safe above `debug`.\n * Rendering the sent URL here is what makes a `wallet_address`, a `chain` or\n * an `amount` reproducible at all.\n *\n * The values are handed over as they stand rather than stringified: a\n * {@link DebugEvent} accepts anything, and the logger implementation is what\n * guarantees a `bigint` or a cycle cannot fail to render.\n */\nfunction describeRequestUnredacted(request: HttpRequest): UnredactedFields {\n return {\n 'http.request.method': request.method,\n 'url.full': buildUrlWithQueryParams(request.url, request.queryParams),\n headers: request.headers,\n ...(request.method === 'POST' ? { body: request.body } : {}),\n };\n}\n\n/**\n * Structural interface satisfied by both {@link AuthenticatedApiClient} and\n * {@link ApiClient}. Used by the shared frontline API functions so they can\n * be called from either the client or server without any browser dependencies.\n */\nexport interface Sender {\n send<T>(request: HttpRequest): Promise<T>;\n}\n","import type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport {\n type InternalAccessTokenSource,\n TokenTrigger,\n} from '@/universal/api/internal-access-token-source';\n\nexport function attachSessionMiddleware(\n fetchAccessToken: InternalAccessTokenSource\n): BeforeRequestMiddleware {\n return async (request: HttpRequest): Promise<HttpRequest> => {\n if (!Attributes.isProtected(request.attributes)) {\n return request;\n }\n\n const userToken = await fetchAccessToken(TokenTrigger.beforeRequest);\n if (userToken !== null) {\n // Recorded so a 401 can name the token it refused: see `TokenTrigger`.\n return withBearer(\n {\n ...request,\n attributes: Attributes.concat(\n request.attributes ?? Attributes.empty,\n Attributes.sentWith(userToken)\n ),\n },\n userToken.value\n );\n }\n\n const clientCreds = Attributes.getClientCredentials(request.attributes);\n if (clientCreds) {\n return withBearer(request, clientCreds.value);\n }\n return request;\n };\n}\n\nfunction withBearer(request: HttpRequest, token: string): HttpRequest {\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n Authorization: `Bearer ${token}`,\n },\n };\n}\n","import { HEADER_IDEMPOTENCY_KEY } from '@/universal/api/frontline/config';\nimport type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { getUUIDv4 } from '@/universal/core/shared/utils/crypto';\n\nexport const idempotencyKeyMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.isIdempotent(request.attributes)) {\n return request;\n }\n\n const existingHeaders = request.headers ?? {};\n if (existingHeaders[HEADER_IDEMPOTENCY_KEY]) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...existingHeaders,\n [HEADER_IDEMPOTENCY_KEY]: getUUIDv4(),\n },\n };\n};\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\n\nconst MAX_ATTEMPTS = 3;\nconst INITIAL_DELAY_MS = 300;\nconst MAX_DELAY_MS = 2000;\n\nconst RETRYABLE_4XX = new Set([408, 409, 429]);\n\nexport function isRetryableStatus(status: number): boolean {\n return (status >= 500 && status < 600) || RETRYABLE_4XX.has(status);\n}\n\nfunction getRetryDelayMs(attempt: number): number {\n return Math.min(INITIAL_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n}\n\nexport type RequestRetryMiddlewareOptions = {\n /**\n * Optional delay function. Defaults to real setTimeout-based delay.\n * Use a no-op (e.g. () => Promise.resolve()) in tests to avoid slow tests.\n */\n delayFn?: (ms: number) => Promise<void>;\n};\n\n/**\n * Creates the request retry after-request middleware. Inject a no-op delayFn\n * in tests to avoid real delays (unit testing best practice).\n */\nexport function createRequestRetryMiddleware(\n options: RequestRetryMiddlewareOptions = {}\n): AfterRequestMiddleware {\n const delayFn = options.delayFn ?? defaultDelay;\n\n return async ({ request, response, retry }) => {\n if (\n !isRetryableStatus(response.status) ||\n !Attributes.isRetryable(request.attributes)\n ) {\n return response;\n }\n\n const currentAttempt = Attributes.getRetryAttempt(request.attributes);\n if (currentAttempt >= MAX_ATTEMPTS - 1) {\n return response;\n }\n\n const nextAttempt = currentAttempt + 1;\n await delayFn(getRetryDelayMs(nextAttempt));\n\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.retryAttempt(nextAttempt)\n );\n return retry(nextRequest);\n };\n}\n\nfunction defaultDelay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retries the request up to 3 times with exponential backoff when the response\n * has a retryable status (5xx server errors). Uses request.attributes.retryAttempt\n * to decide delay and whether to retry, so the middleware does not loop when\n * retry() runs the full HTTP middleware chain again.\n */\nexport const requestRetryMiddleware: AfterRequestMiddleware =\n createRequestRetryMiddleware();\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\nimport {\n type InternalAccessTokenSource,\n TokenTrigger,\n} from '@/universal/api/internal-access-token-source';\n\n/**\n * On a 401 to a protected request, asks for a better token than the one the\n * request was sent with and replays the request once with it.\n *\n * Deduplication is the token source's job, not this middleware's: a burst of\n * N requests that all 401 calls it N times, and the source answers all of\n * them from one renewal.\n */\nexport function renewSessionMiddleware(\n fetchAccessToken: InternalAccessTokenSource\n): AfterRequestMiddleware {\n return async ({ request, response, retry }) => {\n if (response.status !== 401) {\n return response;\n }\n if (!Attributes.isProtected(request.attributes)) {\n return response;\n }\n if (Attributes.wasRenewAttempted(request.attributes)) {\n return response;\n }\n\n const newToken = await fetchAccessToken(\n TokenTrigger.after401(Attributes.getSentWith(request.attributes))\n );\n if (newToken) {\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.renewAttempted(true)\n );\n return retry(nextRequest);\n } else {\n return response;\n }\n };\n}\n","import type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport { HttpError } from '@/universal/api/http';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { HttpClient } from '@/universal/api/http-client';\nimport type { InternalAccessTokenSource } from '@/universal/api/internal-access-token-source';\nimport { attachSessionMiddleware } from '@/universal/api/middleware/attach-session-middleware';\nimport { idempotencyKeyMiddleware } from '@/universal/api/middleware/idempotency-key';\nimport { requestRetryMiddleware } from '@/universal/api/middleware/request-retry';\nimport { renewSessionMiddleware } from '@/universal/api/middleware/session-renewal';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * Isomorphic HTTP client with session attachment, session renewal on 401,\n * idempotency key injection, and request retry. Works in both browser and\n * Node/server environments. Pass `additionalBeforeRequest` to inject\n * environment-specific middleware (e.g. `userAgentMiddleware` on the client).\n *\n * Pass `logger` through to have every request reported; the client logs\n * nothing without one.\n */\nexport class AuthenticatedApiClient {\n private readonly httpClient: HttpClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: InternalAccessTokenSource,\n additionalBeforeRequest: BeforeRequestMiddleware[] = [],\n logger: Logger | null = null\n ) {\n this.httpClient = new HttpClient(\n config,\n {\n beforeRequest: [\n attachSessionMiddleware(fetchAccessToken),\n ...additionalBeforeRequest,\n idempotencyKeyMiddleware,\n ],\n afterRequest: [\n renewSessionMiddleware(fetchAccessToken),\n requestRetryMiddleware,\n ],\n },\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n const response = await this.httpClient.send<TResponse>(request);\n if (response.status >= 200 && response.status < 300) {\n return response.body as TResponse;\n } else {\n throw new HttpError(response);\n }\n }\n}\n","'use client';\n\nimport { userAgentMiddleware } from '@/client/core/api/middleware/user-agent';\nimport { AuthenticatedApiClient } from '@/universal/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport type { InternalAccessTokenSource } from '@/universal/api/internal-access-token-source';\nimport type { Logger } from '@/universal/types/logger';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: InternalAccessTokenSource,\n logger: Logger | null = null\n ) {\n this.client = new AuthenticatedApiClient(\n config,\n fetchAccessToken,\n [userAgentMiddleware],\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","import type { InternalLogger } from '@/universal/core/shared/observability/internal-logger';\n\n/**\n * Calls the host's `Config.onSessionExpired`, without awaiting it and without\n * letting it fail the request that found out.\n *\n * Total: the handler runs on the next microtask, so a sync throw from untyped\n * JavaScript and an async rejection land on the same `catch`, and both are\n * logged and dropped.\n */\nexport function notifySessionExpired(\n onSessionExpired: (() => Promise<void>) | undefined,\n log: InternalLogger\n): void {\n if (onSessionExpired === undefined) {\n return;\n }\n Promise.resolve()\n .then(onSessionExpired)\n .catch((error: unknown) =>\n log.failure(() => ({ msg: 'onSessionExpired threw' }), error)\n );\n}\n","import { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * An instant: milliseconds since the Unix epoch, as `Date.now()` reads it.\n * Distinct from {@link Millis}, a duration, so an instant cannot be passed\n * where a timeout is expected or the other way round.\n */\nexport type EpochMillis = Newtype<number, 'EpochMillis'>;\n\n/**\n * A duration in milliseconds. May be negative: the gap between two instants\n * read off a wall clock that stepped back in between.\n */\nexport type Millis = Newtype<number, 'Millis'>;\n\n/** A duration in whole, non-negative seconds. */\nexport type Seconds = Newtype<number, 'Seconds'>;\n\n/** The furthest a `Date` reaches either side of the epoch (ECMA-262 §21.4.1.1). */\nconst MAX_EPOCH_MILLIS = 8_640_000_000_000_000;\n\nexport const EpochMillis = {\n /**\n * @throws {@link ValidationError} unless `value` is an integer a `Date` can\n * represent: at most {@link MAX_EPOCH_MILLIS} either side of the epoch.\n */\n of: (value: number): EpochMillis => {\n if (!Number.isInteger(value) || Math.abs(value) > MAX_EPOCH_MILLIS) {\n throw new ValidationError(\n `EpochMillis must be an integer within ±${MAX_EPOCH_MILLIS}, got ${value}`\n );\n }\n return value as EpochMillis;\n },\n /** The wall clock. Code that needs the time takes a `TimeEff` instead. */\n now: (): EpochMillis => EpochMillis.of(Date.now()),\n /** @throws {@link ValidationError} for an invalid `Date`. */\n fromDate: (date: Date): EpochMillis => EpochMillis.of(date.getTime()),\n /** How long after `from` the instant `to` is; negative if it is before. */\n elapsed: (from: EpochMillis, to: EpochMillis): Millis => Millis.of(to - from),\n plus: (at: EpochMillis, duration: Millis): EpochMillis =>\n EpochMillis.of(at + duration),\n};\n\nexport const Millis = {\n of: (value: number): Millis => value as Millis,\n};\n\nexport const Seconds = {\n /**\n * @throws {@link ValidationError} unless `value` is a non-negative integer.\n */\n of: (value: number): Seconds => {\n if (!Number.isInteger(value) || value < 0) {\n throw new ValidationError(\n `Seconds must be a non-negative integer, got ${value}`\n );\n }\n return value as Seconds;\n },\n toMillis: (value: Seconds): Millis => Millis.of(value * 1000),\n};\n\n/**\n * Whether `expiresAt` has passed at `now`, counting it as passed `buffer`\n * early. The boundary instant itself counts as expired.\n */\nexport function isExpired({\n expiresAt,\n now,\n buffer = Millis.of(0),\n}: {\n expiresAt: EpochMillis;\n now: EpochMillis;\n buffer?: Millis;\n}): boolean {\n return now >= expiresAt - buffer;\n}\n","import type { AuthState } from '@/client/core/auth/types';\nimport {\n isRejectedToken,\n SentWith,\n type TokenTrigger,\n} from '@/universal/api/internal-access-token-source';\nimport { notifySessionExpired } from '@/universal/core/auth/session-expired';\nimport type { DelayEff } from '@/universal/core/shared/effects';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Logger } from '@/universal/types/logger';\nimport type { Newtype } from '@/universal/types/newtype';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\nimport { Millis } from '@/universal/types/time';\n\n/**\n * How long the browser waits before asking the host a second time, when the\n * first answer suggested the session is gone. Long enough for the winning\n * refresh's cookie to have landed, so the second request carries it.\n */\nexport const CONFIRM_DELAY: Millis = Millis.of(1_000);\n\n/** What the browser knows about the user's session. */\nexport type TokenState =\n | { type: 'unknown' }\n | { type: 'logged-out' }\n | { type: 'logged-in'; token: OAuthAccessToken };\n\n/**\n * What {@link ClientAccessToken.get} does for a trigger: answer from memory,\n * or ask the host. `rejected` is what the refused request carried, if any,\n * and decides whether the host's answer must be confirmed.\n */\nexport type TokenDecision =\n | { type: 'serve'; token: OAuthAccessToken | null }\n | { type: 'ask'; rejected: SentWith };\n\nexport type ClientAccessTokenEnv = DelayEff & {\n /** The host's `ClientConfig.getAccessToken`. */\n getAccessToken: () => Promise<OAuthAccessToken | null>;\n onSessionExpired?: () => Promise<void>;\n logger: Logger | null;\n};\n\n/**\n * Counts logouts. A host call that started under an older generation must\n * not write when it lands.\n */\ntype Generation = Newtype<number, 'Generation'>;\n\nconst Generation = {\n initial: 0 as Generation,\n next: (generation: Generation): Generation => (generation + 1) as Generation,\n};\n\n/**\n * The browser's in-memory access token, and the only thing that asks the\n * host for a new one.\n *\n * **One host call per burst.** Every caller that needs the host while a call\n * is already running joins it, so N requests that 401 together make one\n * `getAccessToken()` call rather than N - each of which would make the host's\n * backend refresh the same single-use refresh token. Only the call is shared:\n * each caller judges its answer by what its own request carried, so a 401\n * that joins a `load()` still refuses the token it was refused.\n *\n * **Confirm before believing.** When the host answers `null`, or hands back\n * the very token the API just refused, that is only a suspicion: the\n * backend answers a refresh that lost a race exactly as it answers a dead\n * session. The client waits {@link CONFIRM_DELAY} and asks once more. Only\n * a second such answer is the verdict: `'logged-out'`, and\n * `onSessionExpired` if the user had been logged in.\n *\n * **A throw is not an answer.** When the host's `getAccessToken` throws, the\n * state is left as it was and the error reaches the caller: an outage must\n * never read as a logout.\n */\nexport class ClientAccessToken {\n private state: TokenState = { type: 'unknown' };\n private hostCall: Promise<OAuthAccessToken | null> | null = null;\n /**\n * Bumped by {@link clear}. A host call that started before a logout must not\n * log the user back in when it lands, so every write checks it first. A 401\n * that arrives after the logout never starts one: `'logged-out'` refuses it.\n */\n private generation: Generation = Generation.initial;\n private readonly log: InternalLogger;\n\n constructor(private readonly env: ClientAccessTokenEnv) {\n this.log = internalLogger(env.logger, 'AUTH').child({\n op: 'getAccessToken',\n });\n }\n\n authState(): AuthState {\n return this.state.type;\n }\n\n /**\n * Asks the host for the current token, whatever is cached.\n *\n * Never answers from a host call already in flight: one started before a\n * login (the mount's `init()`, racing the OAuth callback's) would hand back\n * the answer from before the session cookie existed. It waits for that call\n * to settle instead, so that call's verdict still lands, then asks afresh.\n * A logout while it waits still wins.\n *\n * @throws whatever the host's `getAccessToken` throws.\n */\n async load(): Promise<AuthState> {\n const generation = this.generation;\n if (this.hostCall !== null) {\n await this.hostCall.catch(() => null);\n }\n await this.ask(SentWith.noUserToken, generation);\n return this.authState();\n }\n\n /**\n * The HTTP pipeline's token source: see {@link TokenTrigger}.\n *\n * @throws whatever the host's `getAccessToken` throws.\n */\n async get(trigger: TokenTrigger): Promise<OAuthAccessToken | null> {\n const decision = decideToken(this.state, trigger);\n switch (decision.type) {\n case 'serve':\n return decision.token;\n case 'ask':\n return this.ask(decision.rejected, this.generation);\n }\n }\n\n /** Forgets the token: `auth.logout()`. Never an expiry, so never notifies. */\n clear(): void {\n this.generation = Generation.next(this.generation);\n this.hostCall = null;\n this.state = { type: 'logged-out' };\n }\n\n /**\n * A request that carried no user token was not refused for a token, so the\n * host's first answer stands. One that was is confirmed before it is\n * believed.\n */\n private async ask(\n rejected: SentWith,\n generation: Generation\n ): Promise<OAuthAccessToken | null> {\n // Asked before a logout: nothing to ask, as nothing it learnt may land.\n if (generation !== this.generation) {\n return currentToken(this.state);\n }\n const first = await this.callHost();\n switch (rejected.type) {\n case 'no-user-token':\n return this.commit(first, generation);\n case 'user-token':\n return isFresh(first, rejected)\n ? this.commit(first, generation)\n : this.confirm(rejected, generation);\n }\n }\n\n private async confirm(\n rejected: SentWith,\n generation: Generation\n ): Promise<OAuthAccessToken | null> {\n this.log.warn(() => ({\n msg: 'host returned no fresh token; asking again before signing out',\n }));\n await this.env.delay(CONFIRM_DELAY);\n const second = await this.callHost();\n return isFresh(second, rejected)\n ? this.commit(second, generation)\n : this.expire(generation);\n }\n\n /** The host's `getAccessToken`, joining a call already in flight. */\n private callHost(): Promise<OAuthAccessToken | null> {\n if (this.hostCall !== null) {\n this.log.debug(() => ({ msg: 'joined a host call already in flight' }));\n return this.hostCall;\n }\n // Async, so a host that throws synchronously rejects the call instead.\n const call = (async () => this.env.getAccessToken())().finally(() => {\n if (this.hostCall === call) {\n this.hostCall = null;\n }\n });\n this.hostCall = call;\n return call;\n }\n\n private commit(\n token: OAuthAccessToken | null,\n generation: Generation\n ): OAuthAccessToken | null {\n if (generation !== this.generation) {\n return currentToken(this.state);\n }\n this.state =\n token === null ? { type: 'logged-out' } : { type: 'logged-in', token };\n return token;\n }\n\n private expire(generation: Generation): null {\n if (generation !== this.generation) {\n return null;\n }\n const wasLoggedIn = this.state.type === 'logged-in';\n this.state = { type: 'logged-out' };\n if (wasLoggedIn) {\n this.log.info(() => ({ msg: 'session expired' }));\n notifySessionExpired(this.env.onSessionExpired, this.log);\n }\n return null;\n }\n}\n\n/**\n * Whether a token can be answered from memory. Pure, so every pairing of\n * state and trigger is a plain table.\n */\nexport function decideToken(\n state: TokenState,\n trigger: TokenTrigger\n): TokenDecision {\n switch (trigger.type) {\n case 'before-request':\n return state.type === 'unknown'\n ? { type: 'ask', rejected: SentWith.noUserToken }\n : { type: 'serve', token: currentToken(state) };\n case 'after-401':\n switch (state.type) {\n // A logout or an expiry verdict: only `load()` may log back in, so a\n // 401 to a request sent before it must not ask the host again.\n case 'logged-out':\n return { type: 'serve', token: null };\n // Another request may already have renewed since this one was sent.\n case 'logged-in':\n return isRejectedToken(state.token, trigger.rejected)\n ? { type: 'ask', rejected: trigger.rejected }\n : { type: 'serve', token: state.token };\n case 'unknown':\n return { type: 'ask', rejected: trigger.rejected };\n }\n }\n}\n\nfunction currentToken(state: TokenState): OAuthAccessToken | null {\n switch (state.type) {\n case 'logged-in':\n return state.token;\n case 'unknown':\n case 'logged-out':\n return null;\n }\n}\n\n/** A token, and not the one the API just refused. */\nfunction isFresh(\n token: OAuthAccessToken | null,\n rejected: SentWith\n): token is OAuthAccessToken {\n return token !== null && !isRejectedToken(token, rejected);\n}\n","import type { Newtype } from '@/universal/types/newtype';\n\nexport type AuthorizationCode = Newtype<string, 'AuthorizationCode'>;\nexport const AuthorizationCode = (value: string): AuthorizationCode =>\n value as AuthorizationCode;\n\nexport type CodeVerifier = Newtype<string, 'CodeVerifier'>;\nexport const CodeVerifier = (value: string): CodeVerifier =>\n value as CodeVerifier;\n\nexport type CodeChallenge = Newtype<string, 'CodeChallenge'>;\nexport const CodeChallenge = (value: string): CodeChallenge =>\n value as CodeChallenge;\n\nexport type PKCEState = Newtype<string, 'PKCEState'>;\nexport const PKCEState = (value: string) => value as PKCEState;\n\nexport type RedirectUri = Newtype<string, 'RedirectUri'>;\nexport const RedirectUri = (value: string): RedirectUri => value as RedirectUri;\n\nexport type ClientId = Newtype<string, 'ClientId'>;\nexport const ClientId = (value: string): ClientId => value as ClientId;\n\nexport type ClientSecret = Newtype<string, 'ClientSecret'>;\nexport const ClientSecret = (value: string): ClientSecret =>\n value as ClientSecret;\n","import {\n arrayBufferToBase64Url,\n generateSecureRandomBase64Url,\n sha256,\n} from '@/universal/core/shared/utils/crypto';\nimport type {\n CodeChallenge as CodeChallengeType,\n CodeVerifier as CodeVerifierType,\n PKCEState as PKCEStateType,\n} from '@/universal/types/oauth';\nimport {\n type ClientId,\n CodeChallenge,\n CodeVerifier,\n PKCEState,\n type RedirectUri,\n} from '@/universal/types/oauth';\n\nexport type PKCEParams = {\n clientId: ClientId;\n responseType: 'code';\n redirectUri: RedirectUri;\n codeChallenge: CodeChallengeType;\n codeChallengeMethod: 'S256';\n state: PKCEStateType;\n codeVerifier: CodeVerifierType;\n};\n\nexport type PKCEConfig = {\n clientId: ClientId;\n redirectUri: RedirectUri;\n};\n\n/**\n * Generates PKCE parameters for an OAuth2 authorization code flow.\n * Pure crypto — no React, no DOM beyond Web Crypto API. Safe to use\n * in server-side code and Next.js middleware.\n */\nexport async function generatePKCEParams(\n config: PKCEConfig\n): Promise<PKCEParams> {\n const state = generateSecureRandomBase64Url(32);\n const codeVerifier = generateSecureRandomBase64Url(32);\n const codeChallengeRaw = await sha256(codeVerifier);\n const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);\n\n return {\n clientId: config.clientId,\n responseType: 'code',\n redirectUri: config.redirectUri,\n codeChallenge: CodeChallenge(codeChallenge),\n codeChallengeMethod: 'S256',\n state: PKCEState(state),\n codeVerifier: CodeVerifier(codeVerifier),\n };\n}\n","import type { AuthState, OauthClientResult } from '@/client/core/auth/types';\nimport {\n COINLIST_BASE_URL,\n OAUTH_PAGE_PATH,\n} from '@/universal/api/frontline/config';\nimport {\n generatePKCEParams,\n type PKCEConfig,\n} from '@/universal/core/auth/pkce';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Logger } from '@/universal/types/logger';\nimport { AuthorizationCode, CodeVerifier } from '@/universal/types/oauth';\n\n/** Session storage keys for OAuth PKCE (used by startOAuth and completeOAuth). */\nexport const OAUTH_STATE_KEY = 'coinlist.oauth_state';\nexport const OAUTH_CODE_VERIFIER_KEY = 'coinlist.oauth_code_verifier';\n\n/**\n * Everything the browser half of the SDK knows about the current user's\n * session, and the OAuth 2.0 + PKCE flow that establishes one.\n *\n * The SDK never holds a client secret in the browser: {@link startOAuth}\n * redirects the user to CoinList, and {@link completeOAuth} only parses and\n * validates the redirect. Exchanging the returned code for a session is your\n * backend's job — see `CoinListServer#auth.completeOAuth`.\n *\n * This namespace is client-only: every operation here needs `window` or\n * `sessionStorage`, so it shares no interface with `CoinListServer#auth`.\n * That namespace is called `auth` too and owns the other half of the same\n * flow, but its shape is entirely server-side - see `ServerAuthNamespace`.\n */\nexport interface ClientAuthNamespace {\n /**\n * Returns the current auth state: `'logged-in'`, `'logged-out'`, or\n * `'unknown'`.\n *\n * Returns `'unknown'` until {@link CoinListClient.init} has completed.\n * Prefer `const { isReady, coinlist } = useCoinList()` to know when the SDK\n * has initialized, or await {@link CoinListClient.init} before relying on\n * this value.\n */\n getState(): AuthState;\n\n /**\n * Starts the OAuth flow with PKCE. Generates a random `state` and\n * `code_verifier`, stores them in `sessionStorage` for {@link completeOAuth}\n * to validate, then redirects the browser to the CoinList authorization\n * page. The user is sent back to your application's redirect URI; call\n * {@link completeOAuth} on that page to finish the flow.\n */\n startOAuth(): Promise<void>;\n\n /**\n * Completes the OAuth flow on the frontend, with PKCE and `state`\n * validation. Parses `state` and `code` out of the redirect URL and\n * validates them against `sessionStorage`; the `state` check protects\n * against CSRF (cross-site request forgery).\n *\n * On `ok`: call your backend to exchange the short-lived `code` (and the\n * returned `codeVerifier`) for a long-lived session. If your backend is in\n * TypeScript, use `CoinListServer#auth.completeOAuth` from\n * `@/server/core/coinlist-server` to perform that exchange.\n *\n * On `error`: `reason` is an {@link OauthClientErrorReason} (e.g.\n * `'missing_state'`, `'invalid_state'`) so you can switch on it and surface\n * a message to the user.\n */\n completeOAuth(): OauthClientResult;\n\n /**\n * Clears the in-memory access token. This does **not** clear your backend's\n * session — also call `CoinListServer#auth.logout` to revoke the token and\n * drop the session cookie.\n */\n logout(): void;\n}\n\n/**\n * The session state {@link ClientAuthNamespaceImpl} reads and mutates. Owned\n * by `CoinListClient`, which caches the token and hands this seam to the\n * namespace so both agree on a single source of truth.\n */\nexport type ClientAuthSession = {\n getState(): AuthState;\n clearAccessToken(): void;\n};\n\n/**\n * What the auth namespace needs from {@link ClientConfig}: the OAuth\n * credentials, plus the CoinList web app to redirect to.\n */\nexport type ClientAuthConfig = PKCEConfig & {\n readonly coinlistBaseUrl?: string;\n readonly logger?: Logger;\n};\n\nexport class ClientAuthNamespaceImpl implements ClientAuthNamespace {\n private readonly log: InternalLogger;\n\n constructor(\n private readonly config: ClientAuthConfig,\n private readonly session: ClientAuthSession\n ) {\n this.log = internalLogger(config.logger ?? null, 'AUTH');\n }\n\n getState(): AuthState {\n return this.session.getState();\n }\n\n async startOAuth(): Promise<void> {\n // Wrapped for the same reason `completeOAuth` logs its reasons: the ways\n // this fails - `sessionStorage` blocked, no `crypto.subtle` off a secure\n // origin - are invisible from the host's side and end in the same\n // \"nothing happened when I clicked sign in\".\n return this.log.wrap('startOAuth', undefined, () => this.redirectToOAuth());\n }\n\n private async redirectToOAuth(): Promise<void> {\n const pkceParams = await generatePKCEParams(this.config);\n\n sessionStorage.setItem(OAUTH_STATE_KEY, pkceParams.state);\n sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, pkceParams.codeVerifier);\n\n const params = new URLSearchParams({\n client_id: pkceParams.clientId,\n response_type: pkceParams.responseType,\n redirect_uri: pkceParams.redirectUri,\n code_challenge: pkceParams.codeChallenge,\n code_challenge_method: pkceParams.codeChallengeMethod,\n state: pkceParams.state,\n });\n const baseUrl = this.config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n this.log\n .child({ op: 'startOAuth' })\n .info(() => ({ msg: 'redirecting to CoinList', fields: { baseUrl } }));\n window.location.href = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;\n }\n\n /**\n * Every failure here is silent from the browser's side - a state mismatch\n * and a missing verifier both just leave the user logged out - so the\n * reason is logged rather than left for the host to infer from a callback.\n */\n completeOAuth(): OauthClientResult {\n const result = this.readOauthCallback();\n switch (result.type) {\n case 'error':\n this.log.child({ op: 'completeOAuth' }).error(() => ({\n msg: 'oauth callback rejected',\n fields: { reason: result.reason },\n }));\n return result;\n case 'ok':\n this.log\n .child({ op: 'completeOAuth' })\n .info(() => ({ msg: 'authorization code received' }));\n return result;\n default: {\n const _exhaustive: never = result;\n return result;\n }\n }\n }\n\n logout(): void {\n this.log\n .child({ op: 'logout' })\n .info(() => ({ msg: 'access token cleared' }));\n this.session.clearAccessToken();\n }\n\n private readOauthCallback(): OauthClientResult {\n const params = new URLSearchParams(window.location.search);\n\n const coinlistError = params.get('error');\n if (coinlistError) {\n return { type: 'error', reason: 'user_canceled' };\n }\n\n const stateParam = params.get('state');\n if (!stateParam) {\n return { type: 'error', reason: 'missing_state' };\n }\n const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);\n if (storedState === null || storedState !== stateParam) {\n return { type: 'error', reason: 'invalid_state' };\n }\n\n const codeParam = params.get('code');\n if (!codeParam) {\n return { type: 'error', reason: 'missing_code' };\n }\n\n const codeVerifierValue = sessionStorage.getItem(OAUTH_CODE_VERIFIER_KEY);\n if (!codeVerifierValue) {\n return { type: 'error', reason: 'missing_code_verifier' };\n }\n\n return {\n type: 'ok',\n code: AuthorizationCode(codeParam),\n codeVerifier: CodeVerifier(codeVerifierValue),\n };\n }\n}\n","import {\n BaseError,\n ContractFunctionRevertedError,\n type Hash,\n InsufficientFundsError,\n UserRejectedRequestError,\n WaitForTransactionReceiptTimeoutError,\n} from 'viem';\nimport type { WalletError } from '@/universal/types/blockchain/wallet-error';\n\n/**\n * Classifies an error thrown by an {@link EvmWallet} into a typed\n * {@link WalletError}. Pass the transaction `hash` when awaiting a receipt so a\n * timeout can be reported against it.\n *\n * **Every check walks the cause chain rather than testing the thrown object.**\n * viem never throws the error that says what happened: `sendTransaction` wraps\n * it in a `TransactionExecutionError` and `writeContract` wraps that again in a\n * `ContractFunctionExecutionError`, so a MetaMask 4001 arrives as a\n * `UserRejectedRequestError` two levels down. Testing the top level - which is\n * what this did until it was caught in a partner demo - classified every real\n * refusal and every real revert as `unknown`, and that is public API: a host\n * branching on `user_rejected` to stay quiet when a user simply cancels never\n * saw one.\n */\nexport function classifyWalletError(\n error: unknown,\n ctx?: { hash?: Hash }\n): WalletError {\n if (causeOf(error, UserRejectedRequestError)) {\n return { type: 'user_rejected' };\n }\n if (causeOf(error, InsufficientFundsError)) {\n return { type: 'insufficient_funds' };\n }\n const reverted = causeOf(error, ContractFunctionRevertedError);\n if (reverted) {\n return { type: 'contract_reverted', reason: revertReason(reverted) };\n }\n if (causeOf(error, WaitForTransactionReceiptTimeoutError) && ctx?.hash) {\n return { type: 'timeout', hash: ctx.hash };\n }\n return { type: 'unknown', cause: error };\n}\n\n/**\n * The first error of this class in the chain, or `null`.\n *\n * `BaseError.walk` is viem's own answer to its own wrapping, so this defers to\n * it rather than following `cause` by hand. The `instanceof` first is what\n * keeps a bare throw working - a host's `EvmWallet` may raise a viem error it\n * constructed itself, and a plain `TypeError` is not a `BaseError` at all.\n *\n * Reads nothing off what it finds: which arm to return is the only question,\n * and the redaction rules for each arm are unchanged.\n */\nfunction causeOf<T>(\n error: unknown,\n errorClass: abstract new (...args: never[]) => T\n): T | null {\n if (error instanceof errorClass) return error;\n if (!(error instanceof BaseError)) return null;\n const found = error.walk((cause) => cause instanceof errorClass);\n return found instanceof errorClass ? found : null;\n}\n\n/**\n * What the contract is, never what it was called with, and never what the node\n * said about it.\n *\n * A {@link WalletError} is forwarded at `'error'`, so everything read here has\n * to be a compile-time constant out of the ABI: a `require` string is a\n * Solidity literal, a panic description comes from viem's own table, and an\n * error name and a selector are identifiers. A custom error's *arguments* are\n * deliberately not read - they are runtime values such as a wallet address or\n * a balance, and they belong on the `'debug'` line with the rest of the error.\n *\n * `raw` is the gate rather than `reason`, because `reason` has two sources and\n * only one is the contract's. With revert data, viem decodes it. With none, it\n * assigns the RPC node's `details` string to `reason` instead - provider text\n * that has been seen to embed the caller's address, its balance and the\n * transaction's value. `error.message` renders that same string as a\n * `Details:` line on every path, which is why it is never read at all.\n */\nfunction revertReason(error: ContractFunctionRevertedError): string | null {\n if (!error.raw || error.raw === '0x') return null;\n return error.reason ?? error.data?.errorName ?? error.signature ?? null;\n}\n","/**\n * Minimal ERC-20 ABI the SDK writes against (mirrors viem's `erc20Abi`). The\n * swap flow uses `approve`; `allowance`/`balanceOf`/`decimals`/`symbol`/`name`\n * are included so reads share a single SDK-owned ABI.\n */\nexport const ERC20_ABI = [\n {\n type: 'function',\n name: 'allowance',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'approve',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'decimals',\n inputs: [],\n outputs: [{ name: '', type: 'uint8' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'name',\n inputs: [],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'symbol',\n inputs: [],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalSupply',\n inputs: [],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'recipient', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transferFrom',\n inputs: [\n { name: 'sender', type: 'address' },\n { name: 'recipient', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'event',\n name: 'Approval',\n inputs: [\n { name: 'owner', type: 'address', indexed: true },\n { name: 'spender', type: 'address', indexed: true },\n { name: 'value', type: 'uint256', indexed: false },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Transfer',\n inputs: [\n { name: 'from', type: 'address', indexed: true },\n { name: 'to', type: 'address', indexed: true },\n { name: 'value', type: 'uint256', indexed: false },\n ],\n anonymous: false,\n },\n] as const;\n","import type { Hash, TransactionReceipt } from 'viem';\nimport { classifyWalletError } from '@/client/core/shared/blockchain/wallet-error';\nimport { ERC20_ABI } from '@/universal/core/shared/blockchain/erc20/abi';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type {\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n Uint256,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/universal/types/blockchain/wallet-error';\n\nexport type Erc20AllowancePhase =\n | 'checking-allowance'\n | 'resetting-allowance'\n | 'confirming-allowance-reset'\n | 'approving'\n | 'confirming-approval';\n\nexport type Erc20AllowanceResult =\n | {\n type: 'success';\n }\n | {\n type: 'error';\n error: Erc20AllowanceError;\n };\n\nexport type Erc20AllowanceError =\n | { step: 'allowance-check' }\n | Erc20ApprovalError;\n\nexport async function ensureErc20Allowance({\n erc20,\n chain,\n tokenAddress,\n amount,\n wallet,\n spender,\n onProgress,\n}: {\n erc20: Erc20Namespace;\n chain: EthereumChain;\n tokenAddress: EvmContractAddress;\n amount: BlockchainAmount;\n wallet: EvmWallet;\n spender: EvmContractAddress;\n onProgress?: (phase: Erc20AllowancePhase) => void;\n}): Promise<Erc20AllowanceResult> {\n const emit = (phase: Erc20AllowancePhase) => onProgress?.(phase);\n // Step 1: Read the current ERC-20 allowance\n emit('checking-allowance');\n let allowance: Uint256;\n try {\n allowance = await erc20.getAllowance({\n tokenAddress,\n owner: wallet.address,\n spender,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'allowance-check' } };\n }\n\n // Step 2: Approve only when the current allowance is insufficient.\n if (allowance < amount.raw) {\n // Some ERC-20s (e.g. USDT) reject a non-zero -> non-zero approve(); the\n // existing allowance must first be reset to 0.\n if (allowance > 0n) {\n const reset = await submitErc20Approval({\n wallet,\n tokenAddress,\n spender,\n chain,\n value: 0n,\n pending: 'resetting-allowance',\n confirming: 'confirming-allowance-reset',\n emit,\n });\n if (reset.type === 'error') return { type: 'error', error: reset.error };\n }\n\n const approve = await submitErc20Approval({\n wallet,\n tokenAddress,\n spender,\n chain,\n value: amount.raw,\n pending: 'approving',\n confirming: 'confirming-approval',\n emit,\n });\n if (approve.type === 'error') {\n return { type: 'error', error: approve.error };\n }\n }\n\n return {\n type: 'success',\n };\n}\n\n/** A step-tagged reason {@link submitErc20Approval} failed. */\nexport type Erc20ApprovalError =\n | { step: 'approval'; cause: WalletError }\n | { step: 'approval-reverted' };\n\nexport type SubmitErc20ApprovalResult =\n | { type: 'ok'; txHash: Hash }\n | { type: 'error'; error: Erc20ApprovalError };\n\n/**\n * Submits an ERC-20 `approve()` and waits for it to mine successfully. The\n * `pending`/`confirming` phases are generic so each flow can report progress\n * with its own phase vocabulary (e.g. `approving` vs `resetting-allowance`).\n * Returns the mined transaction hash so callers can forward it (e.g. to record\n * a participation).\n */\nexport async function submitErc20Approval<Phase extends string>(args: {\n wallet: EvmWallet;\n tokenAddress: EvmContractAddress;\n spender: EvmContractAddress;\n chain: EthereumChain;\n value: bigint;\n pending: Phase;\n confirming: Phase;\n emit: (phase: Phase) => void;\n}): Promise<SubmitErc20ApprovalResult> {\n const {\n wallet,\n tokenAddress,\n spender,\n chain,\n value,\n pending,\n confirming,\n emit,\n } = args;\n\n emit(pending);\n let hash: Hash;\n try {\n hash = await wallet.writeContract({\n abi: ERC20_ABI,\n address: tokenAddress,\n functionName: 'approve',\n args: [spender, value],\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'approval', cause: classifyWalletError(error) },\n };\n }\n\n emit(confirming);\n let receipt: TransactionReceipt;\n try {\n receipt = await wallet.awaitTx(hash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'approval', cause: classifyWalletError(error, { hash }) },\n };\n }\n if (receipt.status !== 'success') {\n return { type: 'error', error: { step: 'approval-reverted' } };\n }\n return { type: 'ok', txHash: hash };\n}\n","import type {\n Cursor,\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * Walks every page of a cursor-paginated endpoint and returns the flattened\n * result.\n *\n * Lives in the API layer rather than beside `PaginationParams` because it\n * drives requests: it is the auto-paginating half that `list()` is built on,\n * while the params and the response envelope are domain models the client and\n * the server both name.\n */\nexport async function fetchAllPages<\n A,\n P extends PaginationParams = PaginationParams,\n>(\n fetchPage: (params: P) => Promise<PaginatedResponse<A>>,\n baseParams?: Omit<P, keyof PaginationParams>\n): Promise<A[]> {\n const items: A[] = [];\n let cursor: Cursor | null = null;\n\n do {\n const params = {\n ...(baseParams ?? {}),\n after: cursor ?? undefined,\n } as P;\n const page = await fetchPage(params);\n items.push(...page.data);\n cursor = page.startingAfter;\n } while (cursor);\n\n return items;\n}\n","import type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type Cursor = Newtype<string, 'Cursor'>;\nexport const Cursor = (value: string) => value as Cursor;\n\n/**\n * Cursor-based pagination input used when requesting paginated API resources.\n * Set `after` or `before` to navigate relative to a known cursor, and `limit`\n * to control the maximum number of returned items.\n */\nexport interface PaginationParams {\n before?: Cursor;\n after?: Cursor;\n limit?: number;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n startingAfter: Cursor | null;\n startingBefore: Cursor | null;\n}\n\nexport const PaginatedResponse = {\n fromDto: <A, B>(\n dto: PaginatedResponseDto<A>,\n itemMapper: (item: A) => B\n ): PaginatedResponse<B> =>\n PaginatedResponse.fromDtoPage(dto, (items) => items.map(itemMapper)),\n\n /**\n * For a mapper that decides the page as a whole - one that drops items it\n * cannot map, such as `Offer.listFromDto` - rather than item by item. The\n * cursors are the wire's either way: dropping an item changes what the\n * page holds, not where the next page starts.\n */\n fromDtoPage: <A, B>(\n dto: PaginatedResponseDto<A>,\n pageMapper: (items: A[]) => B[]\n ): PaginatedResponse<B> => ({\n data: pageMapper(dto.data),\n startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,\n startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null,\n }),\n};\n\nexport const PaginationParams = {\n toQueryParams: (\n params: PaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams: Record<string, QueryParamValue> = {};\n if (params.after) {\n queryParams.starting_after = params.after;\n }\n if (params.before) {\n queryParams.starting_before = params.before;\n }\n if (params.limit) {\n queryParams.limit = params.limit;\n }\n return queryParams;\n },\n};\n","import type { AssetDto } from '@/universal/types/dto/asset';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type AssetId = Newtype<string, 'AssetId'>;\nexport const AssetId = (value: string) => value as AssetId;\n\nexport type AssetCode = Newtype<string, 'AssetCode'>;\nexport const AssetCode = (value: string) => value as AssetCode;\n\nexport type Asset = {\n id: AssetId;\n code: AssetCode;\n name: string;\n fractionalDigits: number;\n};\n\nexport const Asset = {\n fromDto: (dto: AssetDto): Asset => ({\n id: AssetId(dto.id),\n code: AssetCode(dto.code),\n name: dto.name,\n fractionalDigits: dto.fractional_digits,\n }),\n};\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { ValidationError } from '@/universal/types/errors';\n\n/**\n * Guards for a `fromDto` reading a field its payload is required to carry.\n * Each takes the field's wire name and throws a `ValidationError` naming it,\n * which `classifyLogCause` maps to the `validation` remedy. Kept out of\n * `@/universal/types` so the barrel does not publish them.\n */\n\n/**\n * A `type` this SDK does not name, on a payload discriminated by it. Takes\n * `never`, so a new variant fails to compile at every `switch` that has not\n * handled it, and throws a `ValidationError` naming the field when a backend\n * running ahead of this build sends one anyway. Returns `never`, so a\n * `default: return unknownTypeError(...)` type-checks in any `switch`.\n */\nexport function unknownTypeError(dto: never, model: string): never {\n const type = (dto as { type?: unknown }).type;\n throw new ValidationError(\n `${model}.type: unknown type ${JSON.stringify(type)}`\n );\n}\n\n/**\n * A string its variant requires. Blank counts as missing: a form can post\n * `''`, and a card titled with it is no better than one titled with nothing.\n */\nexport function requiredString(\n value: string | null | undefined,\n field: string\n): string {\n const text = notBlankStringOrNull(value);\n if (text === null) {\n throw new ValidationError(\n `${field}: expected a non-blank string, got ${\n typeof value === 'string' ? 'a blank string' : String(value)\n }`\n );\n }\n return text;\n}\n\n/**\n * `new Date` never throws: a missing or malformed value becomes an Invalid\n * Date, or 1970 for `null`, and a countdown reads either as \"already started\".\n * Fail here, naming the field, instead.\n */\nexport function requiredDate(\n value: string | null | undefined,\n field: string\n): Date {\n const date = typeof value === 'string' ? new Date(value) : null;\n if (date === null || Number.isNaN(date.getTime())) {\n throw new ValidationError(\n `${field}: expected a date, got ${JSON.stringify(value)}`\n );\n }\n return date;\n}\n\n/**\n * An array its payload is required to carry. A backend sending anything else\n * would otherwise surface from `.map` as a bare `TypeError` classified\n * `generic-error`, naming neither the field nor whose fault it was.\n */\nexport function requiredArray<T>(\n value: T[] | null | undefined,\n field: string\n): T[] {\n if (!Array.isArray(value)) {\n throw new ValidationError(\n `${field}: expected an array, got ${typeof value}`\n );\n }\n return value;\n}\n","import {\n InvariantError,\n MathError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type EthereumChain =\n | 'ethereum_mainnet'\n | 'ethereum_sepolia'\n | 'base_mainnet'\n | 'base_sepolia';\n\n/**\n * The exhaustive chain set: a new {@link EthereumChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const ETHEREUM_CHAINS: Record<EthereumChain, true> = {\n ethereum_mainnet: true,\n ethereum_sepolia: true,\n base_mainnet: true,\n base_sepolia: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const EthereumChain = (value: string): EthereumChain => {\n if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Ethereum chain: \"${value}\"`);\n }\n return value as EthereumChain;\n};\n\nexport type SolanaChain = 'solana_mainnet' | 'solana_devnet';\n\n/**\n * The exhaustive chain set: a new {@link SolanaChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const SOLANA_CHAINS: Record<SolanaChain, true> = {\n solana_mainnet: true,\n solana_devnet: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const SolanaChain = (value: string): SolanaChain => {\n if (!Object.keys(SOLANA_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Solana chain: \"${value}\"`);\n }\n return value as SolanaChain;\n};\n\nexport type Chain = EthereumChain | SolanaChain;\n\n/**\n * {@link Chain}'s check without the throw, for a mapper over a list that drops\n * the entries it cannot name rather than rejecting the whole list. Frontline's\n * chain registry may carry chains this SDK does not model yet.\n */\nexport const isChain = (value: string): value is Chain =>\n Object.keys(ETHEREUM_CHAINS).includes(value) ||\n Object.keys(SOLANA_CHAINS).includes(value);\n\nexport const Chain = (value: string): Chain => {\n if (!isChain(value)) {\n throw new ValidationError(`Unsupported chain: \"${value}\"`);\n }\n return value;\n};\n\n/**\n * Protocol a wallet binding is scoped to. EVM-only for now: an EVM address\n * binds once per option regardless of which EVM chain proved ownership.\n * Frontline's enum also has `:solana`, but we don't handle Solana bindings yet,\n * so this stays `'ethereum'` until Solana support lands.\n */\nexport type WalletProtocol = 'ethereum';\n\n/**\n * EVM addresses keep a `0x${string}` base so they stay assignable to the\n * `0x${string}` shapes that on-chain libraries (viem/wagmi) expect. We only\n * drop the runtime `0x` narrowing: values are trusted at the boundary and\n * branded via the constructor.\n */\nexport type EvmWalletAddress = Newtype<`0x${string}`, 'EvmWalletAddress'>;\nexport const EvmWalletAddress = (value: string): EvmWalletAddress =>\n value as EvmWalletAddress;\n\nexport type EvmContractAddress = Newtype<`0x${string}`, 'EvmContractAddress'>;\nexport const EvmContractAddress = (value: string): EvmContractAddress =>\n value as EvmContractAddress;\n\n/**\n * What uniquely identifies a token: the chain it is deployed on plus its\n * contract address. Never a symbol, which can collide across issuers.\n */\nexport type TokenIdentifier = {\n /** The chain the token contract is deployed on. */\n chain: EthereumChain;\n /**\n * The token's contract address, in any casing — consumers that need the\n * EIP-55 form (e.g. the token registry routes) checksum it themselves.\n */\n address: EvmContractAddress;\n};\n\nexport type HexEncodedTransactionData = Newtype<\n `0x${string}`,\n 'HexEncodedTransactionData'\n>;\nexport const HexEncodedTransactionData = (\n value: string\n): HexEncodedTransactionData => value as HexEncodedTransactionData;\n\n/**\n * A transaction the backend has already encoded for us — the caller only\n * broadcasts it. Used by the flows that hand a wallet a ready-made `to`/`data`\n * pair (allow-listing a wallet, an Ondo swap) rather than encoding a contract\n * call themselves.\n */\nexport type Tx = {\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n};\n\n/**\n * The largest exponent whose power of ten still fits a uint256: 10^77 fits,\n * 10^78 does not.\n *\n * The bound is arithmetic rather than a token standard's. ERC-20 reports\n * `decimals()` as a `uint8`, so 255 is what a contract *can* say, but every\n * {@link AssetDecimals} in this codebase is paired with a {@link Uint256} raw\n * by construction, and scaling by anything past this leaves that pairing\n * unrepresentable. A value between 78 and 255 would therefore pass a\n * standard-faithful check and then break the first multiplication it reached.\n */\nexport const MAX_ASSET_DECIMALS = 77;\n\n/**\n * How many decimal places one whole token divides into.\n *\n * Validated, unlike its neighbours here — {@link Uint256} is a bare `bigint`\n * with a separate {@link assertUint256} guard, and {@link DecimalString} casts\n * unchecked. The asymmetry is deliberate and follows the value's provenance:\n * an `AssetDecimals` used to come only from literals and the token registry,\n * but backends now publish exponents of their own (`asset_decimals` on an Ondo\n * quote, both scales on a built swap), and those feed `10n ** BigInt(d)`\n * during render. Guarding at construction is what keeps a fractional or\n * unbounded exponent from surfacing as a `RangeError` mid-render — or, at\n * 10^200, as a hung tab — instead of as the failed state the screen has.\n *\n * See docs/ADR-7-VALIDATED-NEWTYPES.md.\n *\n * @throws ValidationError on a non-integer, a negative, or anything above\n * {@link MAX_ASSET_DECIMALS}.\n */\nexport type AssetDecimals = Newtype<number, 'AssetDecimals'>;\nexport const AssetDecimals = (value: number): AssetDecimals => {\n if (!Number.isInteger(value)) {\n throw new ValidationError(`Asset decimals must be an integer: ${value}`);\n }\n if (value < 0 || value > MAX_ASSET_DECIMALS) {\n throw new ValidationError(\n `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`\n );\n }\n return value as AssetDecimals;\n};\n\nexport const STABLE_DECIMALS = AssetDecimals(6);\n\n/**\n * A non-negative decimal number the backend sent as a string, kept unscaled.\n *\n * Reach for it when a response gives you a number but not the decimals to\n * scale it by, or gives you one it has already applied. Inventing an exponent\n * for either is how a display ends up orders of magnitude out.\n *\n * Contrast {@link BlockchainAmount}, which pairs a raw uint256 with the\n * decimals it is denominated in and so is only constructible when you know\n * both. Arithmetic on a `DecimalString` needs a decimal library we\n * deliberately do not ship.\n */\nexport type DecimalString = Newtype<string, 'DecimalString'>;\nexport const DecimalString = (value: string): DecimalString =>\n value as DecimalString;\n\nexport const MAX_UINT_256 = 2n ** 256n - 1n;\n\n/**\n * A non-negative integer within uint256 bounds. Kept unbranded (a plain\n * `bigint`) so raw on-chain amounts flow in without ceremony; bounds are\n * enforced where it matters (see {@link combineAmounts}).\n */\nexport type Uint256 = bigint;\n\n/**\n * Asserts a computed bigint falls within uint256 bounds. Use at on-chain\n * arithmetic boundaries (bps math, price computation) where the SDK's own\n * arithmetic could underflow below zero or overflow above 2^256-1.\n *\n * Throws {@link InvariantError}, because reaching it means the SDK computed\n * something no chain could represent. **For a value that came off the wire,\n * use {@link parseUint256} instead**: the backend sending an unrepresentable\n * number is a {@link ValidationError}, and the two have different remedies.\n */\nexport const assertUint256 = (value: bigint): Uint256 => {\n if (isUint256(value)) return value;\n throw new InvariantError(`Value out of uint256 bounds: ${value}`);\n};\n\n/**\n * {@link assertUint256} at a wire boundary: the same bounds check, reported as\n * a {@link ValidationError} against the named field, because a value out of\n * range here is the backend's, not the SDK's.\n *\n * `label` names the field the way a DTO mapper's other failures do, so a log\n * line says which one - `SwapPreview.pay_input_amount`, not `a number`.\n */\nexport const parseUint256 = (value: bigint, label: string): Uint256 => {\n if (isUint256(value)) return value;\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n};\n\nconst isUint256 = (value: bigint): boolean =>\n value >= 0n && value <= MAX_UINT_256;\n\nexport type BlockchainAmount = Newtype<\n { raw: Uint256; decimals: AssetDecimals },\n 'BlockchainAmount'\n>;\n\n/**\n * Constructs a {@link BlockchainAmount} and exposes arithmetic helpers.\n * TypeScript has no operator overloading, so use `BlockchainAmount.add(a, b)`\n * instead of `+`/`-`/`*`/`/` on the objects directly.\n */\nexport const BlockchainAmount = Object.assign(\n (value: { raw: Uint256; decimals: AssetDecimals }): BlockchainAmount =>\n value as BlockchainAmount,\n {\n add: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x + y),\n sub: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x - y),\n mul: multiplyAmounts,\n div: divideAmounts,\n }\n);\n\n/**\n * `a * b`, denominated in `a`'s decimals - a price times a quantity, an amount\n * times a rate.\n *\n * The exact inverse of {@link divideAmounts}, and it reads the same way round:\n * the answer stays in `a`'s scale and `b`'s divides back out, so the two\n * compose - `mul(div(a, b), b)` is `a` again, short only what truncation took.\n * That is what makes `price x quantity` land in the currency the price was\n * quoted in rather than at some product of two exponents no token uses.\n *\n * The multiplication happens *before* the division by `10^b.decimals`, so the\n * full precision of both operands survives into the one rounding at the end.\n * Like `div` it truncates towards zero on both signs, which is the safe\n * direction for money: a total is never inflated past what the parts hold.\n *\n * Total - unlike `div`, there is nothing here to reject. The scale it divides\n * by is a power of ten, never zero, and a product is not bounds-checked for\n * the same reason a quotient is not: whether one past uint256 is a corrupt\n * response or an expected magnitude belongs to the caller.\n */\nfunction multiplyAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n const product = a.raw * b.raw;\n return BlockchainAmount({\n raw: product / 10n ** BigInt(b.decimals),\n decimals: a.decimals,\n });\n}\n\n/**\n * `a / b`, denominated in `a`'s decimals - a price, a ratio, a rate.\n *\n * Unlike {@link combineAmounts}, the two operands may be at different scales,\n * and usually are: dividing dollars by shares is the point of the operation,\n * and the two tokens rarely share an exponent. `b`'s scale divides back out -\n * the numerator is scaled by `10^b.decimals` *before* the division, so nothing\n * is lost to integer truncation early and the quotient lands in `a`'s scale,\n * which is the one the amounts it is rendered beside are in.\n *\n * Truncates towards zero on both signs, which is what BigInt division already\n * does and the safe direction for money: the total a price implies never\n * exceeds, in magnitude, the amount that actually moved.\n *\n * A zero divisor is the only rejection. The quotient is deliberately *not*\n * bounds-checked the way {@link combineAmounts} checks a sum: scaling the\n * numerator carries even legal pairs past uint256 (a maximal amount over a\n * single base unit), and whether that reads as a corrupt response or an\n * expected magnitude is the caller's to judge - see `computeOndoBuyPrice` and\n * `computeOndoSellPrice`, which bounds-check the price they build out of this.\n *\n * @throws MathError when `b` is zero. `add` and `sub` throw a bare `Error`\n * because a scale mismatch is a programming error caught in review; a zero\n * divisor arrives from a server response and is divided by during render, so\n * it is a named failure a screen can catch and map to a failed state.\n */\nfunction divideAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n if (b.raw === 0n) {\n throw new MathError('Cannot divide a BlockchainAmount by zero');\n }\n\n const scaled = a.raw * 10n ** BigInt(b.decimals);\n return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });\n}\n\n/**\n * Combine two amounts with a raw-bigint `op`. Both operands must share the\n * same `decimals` — adding/subtracting differently-scaled amounts is a\n * programming error, so we throw rather than silently producing garbage.\n * The result is bounds-checked, so an underflow (negative `raw`) or uint256\n * overflow is rejected.\n */\nfunction combineAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount,\n op: (x: bigint, y: bigint) => bigint\n): BlockchainAmount {\n if (a.decimals !== b.decimals) {\n throw new InvariantError(\n 'Cannot combine BlockchainAmounts with different decimals: ' +\n `${a.decimals} vs ${b.decimals}`\n );\n }\n const raw = op(a.raw, b.raw);\n if (raw < 0n || raw > MAX_UINT_256) {\n throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);\n }\n return BlockchainAmount({ raw, decimals: a.decimals });\n}\n\nexport type AssetSymbol = Newtype<string, 'AssetSymbol'>;\nexport const AssetSymbol = (value: string): AssetSymbol => value as AssetSymbol;\n\n/**\n * A stablecoin symbol is an {@link AssetSymbol} narrowed to the coins we\n * support. It shares the `AssetSymbol` brand so it stays assignable to it.\n */\nexport type StablecoinSymbol = Newtype<'USDC' | 'USDT', 'AssetSymbol'>;\nexport const StablecoinSymbol = (value: 'USDC' | 'USDT'): StablecoinSymbol =>\n value as StablecoinSymbol;\n\nexport type KnownAssetSymbol = StablecoinSymbol;\nexport const KnownAssetSymbol = StablecoinSymbol;\n\nexport type Erc20Asset = {\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n};\n\nexport type Bps = Newtype<bigint, 'Bps'>;\nexport const Bps = (value: bigint): Bps => value as Bps;\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport {\n requiredArray,\n requiredDate,\n requiredString,\n unknownTypeError,\n} from '@/universal/core/shared/utils/wire';\nimport {\n Chain,\n EvmContractAddress,\n isChain,\n} from '@/universal/types/blockchain/core';\nimport type {\n OfferDto,\n OfferEditorialDto,\n OfferTokenDto,\n OfferTypeDto,\n} from '@/universal/types/dto/offer';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type OfferId = Newtype<string, 'OfferId'>;\nexport const OfferId = (value: string) => value as OfferId;\n\nexport type OfferSlug = Newtype<string, 'OfferSlug'>;\nexport const OfferSlug = (value: string) => value as OfferSlug;\n\nexport type OfferType = OfferTypeDto;\n\n// A record rather than an array, so a fourth `OfferTypeDto` fails to compile\n// here until it is listed - the same way `CheckoutConfig` is keyed.\nconst OFFER_TYPES: Record<OfferType, true> = {\n 'coinlist::token_sale': true,\n 'superstate::swap': true,\n 'ondo::swap': true,\n};\n\nexport const isOfferType = (value: string): value is OfferType =>\n Object.keys(OFFER_TYPES).includes(value);\n\n/**\n * An offer as `GET /v1/offers` lists it: a union on {@link OfferType}, each\n * variant carrying only the fields that mean something for it. Narrow on\n * `type` before reading anything beyond {@link OfferBase} - an Ondo swap has\n * no `startsAt` to read, and the compiler says so.\n */\nexport type Offer =\n | CoinListTokenSaleOffer\n | SuperstateSwapOffer\n | OndoSwapOffer;\n\nexport type OfferBase = {\n id: OfferId;\n slug: OfferSlug;\n endsAt: Date | null;\n tokens: OfferToken[];\n};\n\n/**\n * A curated sale window and the hand-authored copy that goes with it. Every\n * variant that runs such a campaign carries all three, validated; an Ondo swap\n * trades continuously, runs none, and carries none.\n */\nexport type OfferEditorial = {\n tagline: string;\n bannerUrl: string;\n startsAt: Date;\n};\n\nexport type CoinListTokenSaleOffer = OfferBase &\n OfferEditorial & {\n type: 'coinlist::token_sale';\n logoUrl: string;\n };\n\nexport type SuperstateSwapOffer = OfferBase &\n OfferEditorial & {\n type: 'superstate::swap';\n /** Null when nobody has uploaded artwork: a swap publishes without it. */\n logoUrl: string | null;\n };\n\nexport type OndoSwapOffer = OfferBase & {\n type: 'ondo::swap';\n /** Null when nobody has uploaded artwork: a swap publishes without it. */\n logoUrl: string | null;\n};\n\nexport const OfferEditorial = {\n /**\n * `model` prefixes the field in the error (`'Offer'`, `'OfferDetail'`), so\n * the same three checks name the payload that failed them.\n */\n fromDto: (dto: OfferEditorialDto, model: string): OfferEditorial => ({\n tagline: requiredString(dto.tagline, `${model}.tagline`),\n bannerUrl: requiredString(dto.banner_url, `${model}.banner_url`),\n startsAt: requiredDate(dto.starts_at, `${model}.starts_at`),\n }),\n};\n\nexport const Offer = {\n fromDto: (dto: OfferDto): Offer => {\n const tokens = requiredArray(dto.tokens, 'Offer.tokens');\n\n const base: OfferBase = {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n tokens: OfferToken.listFromDto(tokens),\n };\n\n switch (dto.type) {\n case 'coinlist::token_sale':\n return {\n ...base,\n ...OfferEditorial.fromDto(dto, 'Offer'),\n type: dto.type,\n logoUrl: requiredString(dto.logo_url, 'Offer.logo_url'),\n };\n case 'superstate::swap':\n return {\n ...base,\n ...OfferEditorial.fromDto(dto, 'Offer'),\n type: dto.type,\n logoUrl: notBlankStringOrNull(dto.logo_url),\n };\n // `tagline`, `banner_url` and `starts_at` arrive as `null` and are left\n // on the wire: copying them would hand every consumer a `startsAt` that\n // is 1970 for one variant and a date for the others.\n case 'ondo::swap':\n return {\n ...base,\n type: dto.type,\n logoUrl: notBlankStringOrNull(dto.logo_url),\n };\n default:\n return unknownTypeError(dto, 'Offer');\n }\n },\n\n /**\n * Maps a page of offers, dropping every offer whose `type` this SDK does not\n * name. The same reasoning as {@link OfferToken.listFromDto}: a plain `.map`\n * would throw out of `fromDto` and, through `PaginatedResponse.fromDto`,\n * reject the whole page, so one offer of an unknown type would blank the\n * grid for every offer beside it. A single offer fetched by id still\n * throws, because there is nothing beside it to keep.\n */\n listFromDto: (dtos: OfferDto[]): Offer[] =>\n dtos.filter((dto) => isOfferType(dto.type)).map(Offer.fromDto),\n};\n\nexport type TokenRole = 'funding' | 'distribution' | 'swap';\n\nexport type OfferToken = {\n role: TokenRole;\n chain: Chain;\n address: EvmContractAddress;\n};\n\nexport const OfferToken = {\n fromDto: (dto: OfferTokenDto): OfferToken => ({\n role: dto.role,\n chain: Chain(dto.chain),\n address: EvmContractAddress(dto.address),\n }),\n\n /**\n * Maps an offer's token list, dropping every token on a chain this SDK does\n * not name. Frontline's chain registry runs ahead of {@link Chain}, and a\n * plain `.map` would throw out of `Offer.fromDto` and, through\n * `PaginatedResponse.fromDto`, reject the whole offers page - which is how\n * one Base token blanked production's offers list. Dropping costs that\n * token's metadata alone: `coinlist.tokens.get` takes an `EthereumChain`,\n * so nobody could have looked it up anyway.\n *\n * Same shape as `TokenMetadata.fromRegistryDto`.\n */\n listFromDto: (dtos: OfferTokenDto[]): OfferToken[] =>\n dtos.filter((dto) => isChain(dto.chain)).map(OfferToken.fromDto),\n};\n","import type { Newtype } from '@/universal/types/newtype';\n\nexport type Ticker = Newtype<string, 'Ticker'>;\nexport const Ticker = (value: string): Ticker => value as Ticker;\n\n/**\n * An ISO 6166 International Securities Identification Number, e.g.\n * `US0378331005`. Identifies the security itself, which is what makes it the\n * stable key across venues where a {@link Ticker} is not: the same security\n * trades under different tickers in different places, and the same ticker\n * means different securities in different places.\n *\n * Not validated on construction — the value comes from a supplier that has\n * already checked it, and a client-side check-digit test could only reject\n * data the SDK still has to display.\n */\nexport type Isin = Newtype<string, 'Isin'>;\nexport const Isin = (value: string): Isin => value as Isin;\n\nexport type OrderBookSide = 'buy' | 'sell';\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport {\n requiredArray,\n requiredString,\n unknownTypeError,\n} from '@/universal/core/shared/utils/wire';\nimport { Asset } from '@/universal/types/asset';\nimport { Chain, EvmContractAddress } from '@/universal/types/blockchain/core';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailSwapContractDto,\n OfferDetailTermDto,\n} from '@/universal/types/dto/offer-detail';\nimport type { Newtype } from '@/universal/types/newtype';\nimport {\n OfferEditorial,\n OfferId,\n OfferSlug,\n OfferToken,\n} from '@/universal/types/offer';\nimport { Isin, Ticker } from '@/universal/types/trading';\n\n/**\n * An offer as `GET /v1/offers/:id` serves it: the same union on `type` as\n * {@link Offer}, each variant carrying only the fields that mean something\n * for it. Narrow on `type` before reading anything beyond\n * {@link OfferDetailBase}.\n */\nexport type OfferDetail =\n | CoinListTokenSaleOfferDetail\n | SuperstateSwapOfferDetail\n | OndoSwapOfferDetail;\n\nexport type CoinListTokenSaleOfferDetail = OfferDetailBase &\n OfferEditorial & {\n type: 'coinlist::token_sale';\n logoUrl: string;\n };\n\nexport type SuperstateSwapOfferDetail = OfferDetailBase &\n OfferEditorial & {\n type: 'superstate::swap';\n /** Null when nobody has uploaded artwork: a swap publishes without it. */\n logoUrl: string | null;\n };\n\nexport type OndoSwapOfferDetail = OfferDetailBase & {\n type: 'ondo::swap';\n /** Null when nobody has uploaded artwork: a swap publishes without it. */\n logoUrl: string | null;\n /**\n * Every chain this offer can be swapped on, with the CoinList contract each\n * settles through. Empty means it cannot be swapped anywhere.\n */\n swapContracts: OfferSwapContract[];\n};\n\nexport type OfferDetailBase = {\n id: OfferId;\n slug: OfferSlug;\n name: string;\n\n asset: Asset;\n fundingAssets: Asset[];\n tokens: OfferToken[];\n\n about: string | null;\n category: string;\n\n /**\n * The legal issuer of the *token*, e.g. `'Ondo Global Markets'`. The issuer\n * of the security it tracks is {@link OfferDetail.name} (`'Apple Inc.'`).\n * Null on offers with no single named issuer.\n */\n issuer: string | null;\n\n /**\n * ISO 6166 identifier of the underlying security, e.g. `'US0378331005'`.\n * Null both on offers that tokenize no security and on the few that do but\n * whose supplier publishes no ISIN, so absence does not imply \"not a\n * security\".\n */\n isin: Isin | null;\n\n /**\n * The underlying security's symbol on its listing venue, e.g. `'QQQ'`. This\n * is *not* the token's symbol — that is `asset.code` (`'QQQon'`). Null on\n * offers that tokenize no listed security.\n */\n ticker: Ticker | null;\n\n /**\n * What kind of instrument the underlying is, as the supplier classifies it:\n * `'Stock'`, `'ETF'`. Distinct from {@link OfferDetail.category}, which is\n * the broader class the offer is grouped under (`'Equities'`) — this field\n * describes the single instrument, `category` describes the shelf it sits\n * on.\n *\n * An open set: the vocabulary belongs to the supplier and may grow without\n * notice, so render an unrecognized value rather than branching on it. Note\n * the supplier's spelling is its own — a common stock arrives as `'Stock'`.\n */\n instrumentType: string | null;\n\n /**\n * The exchange the underlying security lists on, e.g. `'NASDAQ'`. Not\n * derivable from {@link OfferDetail.isin}, whose country prefix is the\n * country of issuance rather than the venue.\n *\n * Unlike the fields above, this one is recorded by hand rather than served\n * by the supplier, so it is null until someone records it — on a newly\n * listed offer that is the normal state, and it says nothing about whether\n * the offer tokenizes a security.\n */\n listingVenue: string | null;\n\n endsAt: Date | null;\n\n faqs: FaqItem[];\n links: Link[];\n milestones: Milestone[];\n options: OfferOption[];\n terms: TermItem[];\n};\n\nexport type OfferOptionId = Newtype<string, 'OfferOptionId'>;\nexport const OfferOptionId = (value: string) => value as OfferOptionId;\n\nexport type OfferOptionSlug = Newtype<string, 'OfferOptionSlug'>;\nexport const OfferOptionSlug = (value: string) => value as OfferOptionSlug;\n\nexport type OfferOption = {\n id: OfferOptionId;\n slug: OfferOptionSlug;\n bidIncrement: number | null;\n floorPriceUsd: number | null;\n minimumPurchaseUsd: number | null;\n priceUsd: string | null;\n saleAgreementUrl: string | null;\n totalTokenSupply: number | null;\n};\n\nexport type FaqItem = {\n question: string | null;\n answer: string | null;\n};\n\nexport type TermItem = {\n key: string | null;\n value: string | null;\n};\n\nexport type Milestone = {\n name: string | null;\n schedule: string | null;\n status: 'completed' | 'active' | 'upcoming';\n};\n\nexport type Link = {\n label: string | null;\n url: string | null;\n};\n\n/**\n * A chain an offer can be swapped on, with the CoinList contract the swap\n * settles through - the spender to approve before any quote exists.\n *\n * Carries no role, unlike {@link OfferToken}: there is one swap contract per\n * chain and it serves every Ondo asset on it, so which token is being traded\n * does not change the answer.\n */\nexport type OfferSwapContract = {\n chain: Chain;\n address: EvmContractAddress;\n};\n\nexport const OfferSwapContract = {\n fromDto: (dto: OfferDetailSwapContractDto): OfferSwapContract => ({\n chain: Chain(dto.chain),\n address: EvmContractAddress(dto.address),\n }),\n};\n\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n // Arrays first: a body that is not this shape at all fails here, naming\n // the field, before any nested mapper can trip over it.\n const fundingAssets = requiredArray(\n dto.funding_assets,\n 'OfferDetail.funding_assets'\n );\n const options = requiredArray(dto.options, 'OfferDetail.options');\n const terms = requiredArray(dto.terms, 'OfferDetail.terms');\n const links = requiredArray(dto.links, 'OfferDetail.links');\n const faqs = requiredArray(dto.faqs, 'OfferDetail.faqs');\n const milestones = requiredArray(dto.milestones, 'OfferDetail.milestones');\n const tokens = requiredArray(dto.tokens, 'OfferDetail.tokens');\n\n const isin = notBlankStringOrNull(dto.isin);\n const ticker = notBlankStringOrNull(dto.ticker);\n\n const base: OfferDetailBase = {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n name: dto.name,\n\n asset: Asset.fromDto(dto.asset),\n fundingAssets: fundingAssets.map(Asset.fromDto),\n tokens: OfferToken.listFromDto(tokens),\n\n about: notBlankStringOrNull(dto.about),\n category: dto.category,\n\n issuer: notBlankStringOrNull(dto.issuer),\n isin: isin === null ? null : Isin(isin),\n ticker: ticker === null ? null : Ticker(ticker),\n instrumentType: notBlankStringOrNull(dto.instrument_type),\n listingVenue: notBlankStringOrNull(dto.listing_venue),\n\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: faqs.map(FaqItem.fromDto),\n links: links.map(Link.fromDto),\n milestones: milestones.map(Milestone.fromDto),\n options: options.map(OfferOption.fromDto),\n terms: terms.map(TermItem.fromDto),\n };\n\n switch (dto.type) {\n case 'coinlist::token_sale':\n return {\n ...base,\n ...OfferEditorial.fromDto(dto, 'OfferDetail'),\n type: dto.type,\n logoUrl: requiredString(dto.logo_url, 'OfferDetail.logo_url'),\n };\n case 'superstate::swap':\n return {\n ...base,\n ...OfferEditorial.fromDto(dto, 'OfferDetail'),\n type: dto.type,\n logoUrl: notBlankStringOrNull(dto.logo_url),\n };\n // `tagline`, `banner_url` and `starts_at` arrive as `null` and are left\n // on the wire, as in `Offer.fromDto`.\n case 'ondo::swap':\n // `[]` means \"swaps nowhere\" and is fine. A missing key is not: this\n // is the spender a user approves, and defaulting it would report a\n // broken payload as an offer nobody can trade.\n return {\n ...base,\n type: dto.type,\n logoUrl: notBlankStringOrNull(dto.logo_url),\n swapContracts: requiredArray(\n dto.swap_contracts,\n 'OfferDetail.swap_contracts'\n ).map(OfferSwapContract.fromDto),\n };\n default:\n return unknownTypeError(dto, 'OfferDetail');\n }\n },\n};\n\nexport const OfferOption = {\n fromDto: (dto: OfferDetailOptionDto): OfferOption => ({\n id: OfferOptionId(dto.id),\n slug: OfferOptionSlug(dto.slug),\n bidIncrement: dto.bid_increment,\n floorPriceUsd: dto.floor_price_usd,\n minimumPurchaseUsd: dto.minimum_purchase_usd,\n priceUsd: dto.price_usd,\n saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),\n totalTokenSupply: dto.total_token_supply,\n }),\n};\n\nexport const FaqItem = {\n fromDto: (dto: OfferDetailFaqDto): FaqItem => ({\n question: notBlankStringOrNull(dto.question),\n answer: notBlankStringOrNull(dto.answer),\n }),\n};\n\nexport const Link = {\n fromDto: (dto: OfferDetailLinkDto): Link => ({\n label: notBlankStringOrNull(dto.label),\n url: notBlankStringOrNull(dto.url),\n }),\n};\n\nexport const TermItem = {\n fromDto: (dto: OfferDetailTermDto): TermItem => ({\n key: notBlankStringOrNull(dto.key),\n value: notBlankStringOrNull(dto.value),\n }),\n};\n\nexport const Milestone = {\n fromDto: (dto: OfferDetailMilestoneDto): Milestone => ({\n name: notBlankStringOrNull(dto.name),\n schedule: notBlankStringOrNull(dto.schedule),\n status: dto.status,\n }),\n};\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { Asset, type AssetId } from '@/universal/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/universal/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/universal/types/offer-detail';\nimport { PaginationParams } from '@/universal/types/pagination';\n\n/** Unique identifier for a participation. */\nexport type ParticipationId = Newtype<string, 'ParticipationId'>;\n/** Casts a string into a typed {@link ParticipationId}. */\nexport const ParticipationId = (value: string) => value as ParticipationId;\n\n/** Blockchain identifier for where a participation is funded. */\nexport type Blockchain = Newtype<string, 'Blockchain'>;\n/** Casts a string into a typed {@link Blockchain}. */\nexport const Blockchain = (value: string) => value as Blockchain;\n\n/** Wallet address used for a participation. */\nexport type WalletAddress = Newtype<`0x${string}`, 'WalletAddress'>;\n/** Casts a `0x`-prefixed string into a typed {@link WalletAddress}. */\nexport const WalletAddress = (value: `0x${string}`) => value as WalletAddress;\n\n/** Possible participation lifecycle states returned by the API. */\nexport type ParticipationStatus = ParticipationStatusDto;\n\n/** Domain model for a participation returned by CoinList APIs. */\nexport type Participation = {\n /** Unique participation id. */\n id: ParticipationId;\n /** Parent offer id. */\n offerId: OfferIdType;\n /** Selected offer option id. */\n offerOptionId: OfferOptionIdType;\n /** Current processing status. */\n status: ParticipationStatus;\n /** Raw participation amount from API. */\n amount: string;\n /** Human-readable formatted amount from API. */\n displayAmount: string;\n /** Asset metadata for the participation amount. */\n asset: Asset;\n /** Funding chain identifier. */\n chain: Blockchain;\n /** Creation timestamp, if returned by API. */\n insertedAt: Date | null;\n /** Last update timestamp, if returned by API. */\n updatedAt: Date | null;\n /** Wallet used for participation, blank values normalized to null. */\n walletAddress: WalletAddress | null;\n};\n\n/** Parameters required to create a new participation. */\nexport type CreateParticipationParams = {\n /** Offer to participate in. */\n offerId: OfferIdType;\n /** Offer option selected for participation. */\n offerOptionId: OfferOptionIdType;\n /** Blockchain for funding. */\n chain: Blockchain;\n /** Wallet address that funds the participation. */\n walletAddress: WalletAddress;\n /**\n * Decimal token amount to participate with (e.g. `\"100\"` for 100 USDC), NOT\n * raw base units. The backend rescales this by the asset's decimals to verify\n * it against the on-chain approval allowance.\n */\n amount: string;\n /** Funding asset id. */\n assetId: AssetId;\n /**\n * Hash of the ERC-20 `approve()` transaction covering this participation.\n * Required: the backend verifies it on-chain (sender, token, spender, and\n * approved amount) before confirming the participation.\n */\n approvalTransactionHash: string;\n};\n\n/** Pagination params for listing participations, with an optional offer filter. */\nexport interface ParticipationsPaginationParams extends PaginationParams {\n offerId?: OfferIdType;\n}\n\nexport const ParticipationsPaginationParams = {\n toQueryParams: (\n params: ParticipationsPaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams = PaginationParams.toQueryParams(params);\n if (params.offerId) {\n queryParams['filters[0][field]'] = 'offer_id';\n queryParams['filters[0][op]'] = '==';\n queryParams['filters[0][value]'] = params.offerId;\n }\n return queryParams;\n },\n};\n\nexport const Participation = {\n /** Maps API DTO shape into the SDK participation domain model. */\n fromDto: (dto: ParticipationDto): Participation => {\n const walletAddress = notBlankStringOrNull(dto.wallet_address);\n return {\n id: ParticipationId(dto.id),\n offerId: OfferId(dto.offer_id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n status: dto.status,\n amount: dto.amount,\n displayAmount: dto.amount_string,\n asset: Asset.fromDto(dto.asset),\n chain: Blockchain(dto.chain),\n insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,\n updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,\n walletAddress: walletAddress\n ? WalletAddress(walletAddress as `0x${string}`)\n : null,\n };\n },\n};\n\nexport const CreateParticipationParams = {\n /** Maps participation creation params into API DTO payload. */\n toDto: (params: CreateParticipationParams): CreateParticipationDto => ({\n offer_id: params.offerId,\n offer_option_id: params.offerOptionId,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount,\n asset_id: params.assetId,\n approval_transaction_hash: params.approvalTransactionHash,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ParticipationDto } from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { OfferId } from '@/universal/types/offer';\nimport { PaginatedResponse } from '@/universal/types/pagination';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\nexport async function fetchParticipations(\n api: Sender,\n offerId?: OfferId\n): Promise<Participation[]> {\n return fetchAllPages<Participation, ParticipationsPaginationParams>(\n (params) => fetchParticipationsPage(api, params),\n { offerId }\n );\n}\n\nexport async function fetchParticipationsPage(\n api: Sender,\n params: ParticipationsPaginationParams\n): Promise<PaginatedResponse<Participation>> {\n const pageDto = await api.send<PaginatedResponseDto<ParticipationDto>>({\n method: 'GET',\n url: '/v1/participations',\n queryParams: ParticipationsPaginationParams.toQueryParams(params),\n attributes: Attributes.protected(),\n });\n return PaginatedResponse.fromDto(pageDto, Participation.fromDto);\n}\n\nexport async function fetchParticipation(\n api: Sender,\n id: ParticipationId\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'GET',\n url: `/v1/participations/${id}`,\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n\nexport async function createParticipation(\n api: Sender,\n params: CreateParticipationParams\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'POST',\n url: '/v1/participations',\n body: CreateParticipationParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n","import * as participationsApi from '@/universal/api/frontline/providers/coin-list/token-sale';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { PaginatedResponse } from '@/universal/types/pagination';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\n/**\n * Read/write operations for token sales: listing and reading the current user's\n * participations, and recording a new one. The on-chain execution flow\n * (`executeTokenSale`) is layered on top of this in the client-side namespace.\n */\nexport interface CoinListTokenSaleNamespace {\n /**\n * Fetches all participations by iterating through every paginated response,\n * optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n list(offerId?: OfferId): Promise<Participation[]>;\n\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n\n /**\n * Fetches a participation by id.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n get(id: ParticipationId): Promise<Participation>;\n\n /**\n * Records a participation with CoinList.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n}\n\nexport class CoinListTokenSaleNamespaceImpl\n implements CoinListTokenSaleNamespace\n{\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'TOKEN_SALE');\n }\n\n async list(offerId?: OfferId): Promise<Participation[]> {\n return this.log.wrap('list', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipations(this.ctx.api, offerId);\n });\n }\n\n async listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipationsPage(this.ctx.api, params);\n });\n }\n\n async get(id: ParticipationId): Promise<Participation> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipation(this.ctx.api, id);\n });\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n return this.log.wrap('createParticipation', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.createParticipation(this.ctx.api, params);\n });\n }\n}\n","import {\n AssetDecimals,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type KnownAssetSymbol,\n StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport { InvariantError } from '@/universal/types/errors';\n\nexport const USDC_SYMBOL: StablecoinSymbol = StablecoinSymbol('USDC');\nexport const USDC: Erc20Asset = {\n name: 'USD Coin',\n symbol: USDC_SYMBOL,\n decimals: AssetDecimals(6),\n};\n\nexport const USDT_SYMBOL: StablecoinSymbol = StablecoinSymbol('USDT');\nexport const USDT: Erc20Asset = {\n name: 'Tether USD',\n symbol: USDT_SYMBOL,\n decimals: AssetDecimals(6),\n};\n\n/** ERC-20 contract addresses for a supported stablecoin, keyed by chain. */\ntype TokenAddresses = Record<EthereumChain, EvmContractAddress>;\n\nconst USDC_ADDRESSES: TokenAddresses = {\n ethereum_mainnet: EvmContractAddress(\n '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'\n ),\n base_mainnet: EvmContractAddress(\n '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'\n ),\n base_sepolia: EvmContractAddress(\n '0x036CbD53842c5426634e7929541eC2318f3dCF7e'\n ),\n};\n\n/**\n * USDT is not deployed on every chain the SDK models: Tether publishes no\n * Base Sepolia token. The table stays total, with that one absence an\n * explicit `null`, so a new {@link EthereumChain} is still a compile error\n * here until the author decides whether USDT exists on it — the same\n * exhaustiveness the rest of the chain model relies on. A lookup then\n * answers the honest `null` rather than calling a fake address.\n */\nconst USDT_ADDRESSES: Record<EthereumChain, EvmContractAddress | null> = {\n ethereum_mainnet: EvmContractAddress(\n '0xdac17f958d2ee523a2206206994597c13d831ec7'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x7169D38820dfd117C3FA1f22a697dBA58d90BA06'\n ),\n base_mainnet: EvmContractAddress(\n '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2'\n ),\n base_sepolia: null,\n};\n\n/** Lookups for the stablecoins the SDK's swap flows support out of the box. */\nexport const TOKEN_REGISTRY = {\n erc20: (symbol: KnownAssetSymbol): Erc20Asset => {\n switch (symbol) {\n case 'USDC':\n return USDC;\n case 'USDT':\n return USDT;\n default:\n throw new InvariantError(`Unknown asset symbol: ${symbol}`);\n }\n },\n /**\n * USDC's contract on `chain`. USDC is deployed on every chain the SDK\n * models, so the table is total and the answer is never `null`.\n */\n usdcAddress: (chain: EthereumChain): EvmContractAddress =>\n USDC_ADDRESSES[chain],\n /**\n * USDT's contract on `chain`, or `null` where Tether publishes none —\n * Base Sepolia today. The honest answer, never a fake address a balance\n * read would call.\n */\n usdtAddress: (chain: EthereumChain): EvmContractAddress | null =>\n USDT_ADDRESSES[chain],\n};\n","import { USDC_SYMBOL } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n DecimalString,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { NonEmptyArray } from '@/universal/types/collections';\n\n/**\n * How often the Ondo checkout refreshes what it is allowed to poll: the market\n * status and the indicative price. Both are free - neither spends an\n * attestation - so this is paced for a price the user can trust rather than\n * for cost.\n *\n * A built transaction is deliberately not on this timer. Building spends an\n * attestation, so it happens once per order and once per refresh the user\n * asks for.\n */\nexport const ONDO_POLL_INTERVAL_MS = 15_000;\n\n/** Max time the review step offers a built quote. */\nexport const ONDO_QUOTE_MAX_TTL_MS = 15_000;\n\n/**\n * The order size the sidebar prices against before the user names one.\n *\n * Ondo prices by size, so some amount has to be sent. $1,000 is a plausible\n * order rather than a token one: a size so small that Ondo's minimum rejects\n * it would leave the panel permanently blank.\n *\n * Named distinctly from `DEFAULT_AMOUNT_TO_COMPUTE_PRICE` in the swap\n * constants, which is a raw `bigint` of USDC base units for a different\n * endpoint. Both barrels are flat, so two constants of the same name could not\n * coexist - and they mean different things anyway.\n */\nexport const DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString('1000');\n\n/**\n * The coin an Ondo sell settles into, for display only.\n *\n * The scale of every amount on a built transaction comes off the response, so\n * this names the token and never sizes it - `receive_output_decimals` is the\n * only authority on how many decimals the proceeds are counted in, and the two\n * are allowed to disagree.\n *\n * Named apart from {@link ONDO_SUPPORTED_INPUT_ASSETS} rather than read out of\n * it, though both are USDC today. On a buy USDC is what the user funds with\n * and one of a list that may grow; on a sell it is what they settle into and\n * there is one of it. Reading `ONDO_SUPPORTED_INPUT_ASSETS[0]` here would make\n * the sell screen quietly follow whichever funding coin happened to be listed\n * first.\n */\nexport const ONDO_SETTLEMENT_ASSET: StablecoinSymbol = USDC_SYMBOL;\n\n/**\n * The order size the sidebar prices a sell against before the user names one.\n *\n * Sells are quoted by token amount rather than by notional: the fee comes out\n * of dollars, and Ondo's price is size-aware, so a buy's quantity depends on\n * the quote being asked for while a sell is sized by what the user already\n * holds. One whole share is a size Ondo will price - small enough to be\n * plausible for any asset, large enough that Ondo's minimum does not reject it\n * and leave the panel permanently blank.\n *\n * The buy counterpart is {@link DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE}, which\n * is a dollar figure for the same reason in reverse.\n */\nexport const DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE = 1;\n\n/**\n * The coins an Ondo buy can be funded with, in display order, with the first\n * preselected.\n *\n * USDC alone today: it is what the Sepolia integration contract accepts. The\n * amount step renders a single entry as a plain card and two or more as a\n * picker, so adding one here is all it takes.\n */\nexport const ONDO_SUPPORTED_INPUT_ASSETS: NonEmptyArray<StablecoinSymbol> = [\n USDC_SYMBOL,\n];\n","import { ONDO_QUOTE_MAX_TTL_MS } from '@/universal/core/checkout/ondo/constants';\nimport {\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n type Uint256,\n} from '@/universal/types/blockchain/core';\nimport { MathError } from '@/universal/types/errors';\nimport type {\n OndoBuyTransaction,\n OndoSellOutcome,\n OndoSellTransaction,\n} from '@/universal/types/providers/ondo/ondo';\n\n/**\n * The price of one whole asset token in a built Ondo purchase, in the funding\n * token's units - USD per share.\n *\n * Neither builder publishes a price. Frontline drops Ninshubur's deliberately,\n * because `GET /v1/ondo/swap/quote` already serves one under that name at a\n * different scale, and echoing both would leave a caller to guess which was\n * which.\n *\n * Dividing the two amounts the response *does* carry is better than reading\n * the indicative one anyway: it is the price this transaction fills at, rather\n * than a poll that has since moved and was struck against a different size.\n *\n * **Fee-exclusive.** `notionalValue` is the deposit after CoinList's fee comes\n * off, so this is the price Ondo filled at, not the buyer's all-in cost per\n * token - that would be `spendInputAmount / receiveOutputAmount`, and it is\n * higher. Fee-exclusive is what the review screen wants, because it renders\n * the fee on its own line: price x quantity, plus fee, comes to the total.\n * Making this all-in would double-count the fee against that breakdown.\n *\n * The two are equal until ENG-1718 turns a fee on, which frontline rejects\n * today. They diverge the moment it does, so the choice is load-bearing rather\n * than academic.\n */\nexport function computeOndoBuyPrice(\n transaction: OndoBuyTransaction\n): BlockchainAmount {\n const { notionalValue, receiveOutputAmount } = transaction;\n return pricePerShare({\n usd: notionalValue,\n shares: receiveOutputAmount,\n });\n}\n\n/**\n * The price of one whole asset token in a built Ondo sale, in the settlement\n * token's units - USD per share, the same thing\n * {@link computeOndoBuyPrice} answers with the ratio inverted.\n *\n * **Fee-exclusive, and it takes arithmetic to be so.** `expected.quantity` is\n * published already net of `expected.fee`, so the proceeds are added back\n * before dividing: what comes out is the price Ondo filled at, which is the\n * buy arm's meaning rather than a second one. That is what lets one review row\n * render on either screen, and what keeps the sell breakdown honest - the fee\n * sits on its own line beside this, and a net price would count it twice.\n *\n * Read against {@link OndoSellTransaction.expected} alone. The `minimum` arm\n * describes the same trade at a different outcome, and pricing that one would\n * answer \"the worst price this could fill at\", which no screen asks for.\n *\n * The two readings coincide while frontline forces the fee to zero, which it\n * does today. They diverge the day ENG-1718 lands.\n */\nexport function computeOndoSellPrice(\n transaction: OndoSellTransaction\n): BlockchainAmount {\n const { expected, spendInputAmount } = transaction;\n return pricePerShare({\n usd: grossProceeds(expected),\n shares: spendInputAmount,\n });\n}\n\n/** The sooner of Ondo's deadline and now + {@link ONDO_QUOTE_MAX_TTL_MS}. */\nexport function ondoQuoteOfferDeadline(\n expiresAt: Date,\n nowMs: number = Date.now()\n): Date {\n return new Date(Math.min(expiresAt.getTime(), nowMs + ONDO_QUOTE_MAX_TTL_MS));\n}\n\n/**\n * What Ondo returned before CoinList took its cut: the published quantity with\n * the fee charged on it added back.\n *\n * Bounded before the addition rather than after. The two amounts are parsed\n * independently, each a uint256 in its own right, so nothing in the mapper\n * stops their sum leaving the range - and `BlockchainAmount.add` answers an\n * out-of-range sum with an `InvariantError`, which says the SDK's own\n * arithmetic went wrong. It did not: a gross that no uint256 can hold is a\n * corrupt response, the same kind of thing {@link assertPriceFits} reports, and\n * it has to say so here rather than take the checkout down mid-render.\n *\n * The addition itself is still `BlockchainAmount.add`, so the two amounts\n * disagreeing about their scale stays an `InvariantError`. That one really is\n * internal: `OndoSellTransaction.fromDto` reads both off\n * `receive_output_decimals`.\n */\nfunction grossProceeds(expected: OndoSellOutcome): BlockchainAmount {\n const raw = expected.quantity.raw + expected.fee.raw;\n if (raw > MAX_UINT_256) {\n throw new MathError(`Ondo sell proceeds: out of uint256 bounds (${raw})`);\n }\n return BlockchainAmount.add(expected.quantity, expected.fee);\n}\n\n/**\n * USD per whole share, in the USD amount's decimals.\n *\n * Both prices bottom out here so the scaling, the rounding and the bound are\n * written once: whichever side the amounts came off, a price is one dollar\n * amount divided by one asset amount.\n *\n * {@link BlockchainAmount.div} owns the arithmetic - it scales the numerator\n * by the asset's exponent so the quotient lands back in the funding token's,\n * truncates towards zero so the total a price implies never overstates what\n * was paid, and refuses a zero share quantity rather than dividing by it.\n * That last guard is unreachable through either `fromDto`, which rejects a\n * non-positive amount on both sides of the trade at the boundary - both of\n * them, because which one lands in the denominator here flips with the\n * direction. It matters because this runs during render, where a bare BigInt\n * division would take the checkout down with a RangeError instead of failing\n * one step.\n *\n * What is Ondo's rather than every amount's is the uint256 bound: `div`\n * deliberately does not check one, because scaling can carry a legal pair out\n * of range, and here that can only mean a corrupt response.\n */\nfunction pricePerShare({\n usd,\n shares,\n}: {\n usd: BlockchainAmount;\n shares: BlockchainAmount;\n}): BlockchainAmount {\n const price = BlockchainAmount.div(usd, shares);\n return BlockchainAmount({\n raw: assertPriceFits(price.raw),\n decimals: price.decimals,\n });\n}\n\n/**\n * A price past uint256 needs an output amount of a few base units against a\n * notional no real balance holds. It cannot come off the wire, so it is a\n * corrupt response rather than an expensive order.\n */\nfunction assertPriceFits(raw: bigint): Uint256 {\n try {\n return assertUint256(raw);\n } catch {\n throw new MathError(`Ondo price: out of uint256 bounds (${raw})`);\n }\n}\n","import { apiErrorCode, type HttpError } from '@/universal/api/http';\n\n/**\n * The CoinList API's error code for an Ondo quote refused because the asset\n * cannot be traded right now: the market is closed or paused, or the asset is\n * paused or closed for the session. It arrives on a 409.\n *\n * One code for all four of Ondo's reasons, because the remedy is the same:\n * wait for the market to open. Ondo pauses for a moment at every US session\n * change (04:00 and 16:00 ET), so a poll can land on one even while\n * `getTradingStatus` reported the asset tradable a second earlier.\n */\nexport const ONDO_NOT_TRADABLE_CODE = 'not_tradable';\n\n/**\n * Whether `error` is the CoinList API refusing an Ondo quote because the\n * market is not open, as opposed to a request that failed.\n *\n * Total: anything that is not an `HttpError` carrying\n * {@link ONDO_NOT_TRADABLE_CODE} is `false`.\n */\nexport function isOndoNotTradableError(error: unknown): error is HttpError {\n return apiErrorCode(error) === ONDO_NOT_TRADABLE_CODE;\n}\n","import { formatUnits } from 'viem';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport { AssetDecimals } from '@/universal/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/universal/types/blockchain/ui';\n\nexport function shortenAddress(\n address: EvmWalletAddress\n): ShortenedWalletAddress {\n const short =\n address.length > 10\n ? `${address.slice(0, 6)}…${address.slice(-4)}`\n : address;\n return ShortenedWalletAddress(short);\n}\n\nexport type FormatAmountOptions = {\n maxFractionDigits?: AssetDecimals;\n /**\n * Trailing zeros are kept down to this many places. Defaults to\n * `maxFractionDigits` when that is set, otherwise 2 (or the token's own\n * decimals, when fewer). A figure that wants a cap and a shorter floor —\n * a share headline — passes both.\n */\n minFractionDigits?: AssetDecimals;\n};\n\nexport function formatAmount(\n amount: BlockchainAmount,\n locale: string,\n options?: FormatAmountOptions\n): FormattedAmountUi {\n const decimal = formatRawAmount(amount);\n let [integerPart, fractionPart = ''] = decimal.split('.');\n\n const maxFractionDigits = options?.maxFractionDigits;\n const minFractionDigits = Math.min(\n options?.minFractionDigits ??\n (maxFractionDigits !== undefined ? maxFractionDigits : 2),\n maxFractionDigits ?? amount.decimals,\n amount.decimals\n );\n\n if (\n maxFractionDigits !== undefined &&\n fractionPart.length > maxFractionDigits\n ) {\n ({ integerPart, fractionPart } = roundFractionHalfUp(\n integerPart,\n fractionPart,\n maxFractionDigits\n ));\n }\n\n // Zeros past the floor carry no information: `1.500000` at a floor of 2 is\n // `1.50`, and a cap that rounded `…383` down to `…000` must not pad back\n // out to the cap.\n const trimmed = fractionPart.replace(/0+$/, '');\n const fraction = trimmed.padEnd(minFractionDigits, '0');\n\n const integerFormatted = BigInt(integerPart).toLocaleString(locale);\n if (minFractionDigits === 0 && fraction === '') {\n return FormattedAmountUi(integerFormatted);\n }\n\n const decimalSeparator =\n new Intl.NumberFormat(locale)\n .formatToParts(1.1)\n .find((p) => p.type === 'decimal')?.value ?? '.';\n\n return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);\n}\n\n/**\n * Rounds a decimal split into `integerPart`/`fractionPart` strings half-up to\n * `maxFractionDigits`, carrying into the integer part when needed (via BigInt,\n * so precision is preserved beyond `Number.MAX_SAFE_INTEGER`).\n *\n * Precondition: `integerPart` must be non-negative (guaranteed here because\n * `BlockchainAmount.raw` is a `Uint256`). A negative integer part would carry\n * in the wrong direction (toward +∞ instead of away from zero).\n */\nfunction roundFractionHalfUp(\n integerPart: string,\n fractionPart: string,\n maxFractionDigits: number\n): { integerPart: string; fractionPart: string } {\n if (fractionPart.length <= maxFractionDigits) {\n return { integerPart, fractionPart };\n }\n\n if (maxFractionDigits === 0) {\n const roundUp = fractionPart[0] >= '5';\n const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);\n return { integerPart: integer.toString(), fractionPart: '' };\n }\n\n const trimmed = fractionPart.slice(0, maxFractionDigits);\n if (fractionPart[maxFractionDigits] < '5') {\n return { integerPart, fractionPart: trimmed };\n }\n\n const digits = trimmed.split('').map((digit) => Number.parseInt(digit, 10));\n let carry = 1;\n for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {\n const sum = digits[i] + carry;\n if (sum === 10) {\n digits[i] = 0;\n carry = 1;\n } else {\n digits[i] = sum;\n carry = 0;\n }\n }\n\n return {\n integerPart:\n carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,\n fractionPart: digits.join(''),\n };\n}\n\nexport function formatRawAmount(amount: BlockchainAmount): string {\n return formatUnits(amount.raw, amount.decimals);\n}\n\n/**\n * Formats a {@link BlockchainAmount} using compact notation (e.g. `1.37B`,\n * `5M`). Compact notation only surfaces a couple of significant decimals, so\n * the bigint → number narrowing here is intentional and safe: full precision\n * is deliberately dropped in favour of a human-readable summary value.\n */\nexport function formatCompactAmount(\n amount: BlockchainAmount,\n locale: string\n): FormattedAmountUi {\n const value = Number(formatRawAmount(amount));\n const formatted = new Intl.NumberFormat(locale, {\n notation: 'compact',\n maximumFractionDigits: 2,\n }).format(value);\n return FormattedAmountUi(formatted);\n}\n\nexport function formatBpsAsPercent(\n bps: Bps,\n locale: string\n): FormattedPercentUi {\n const whole = bps / 100n;\n const fraction = bps % 100n;\n const wholeFormatted = whole.toLocaleString(locale);\n const decimalSeparator =\n new Intl.NumberFormat(locale)\n .formatToParts(1.1)\n .find((p) => p.type === 'decimal')?.value ?? '.';\n\n if (fraction === 0n) {\n return FormattedPercentUi(`${wholeFormatted}%`);\n }\n\n const fractionFormatted = fraction\n .toString()\n .padStart(2, '0')\n .replace(/0+$/, '');\n\n return FormattedPercentUi(\n `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`\n );\n}\n\nexport function usdAmount(amount: FormattedAmountUi): FormattedAmountAssetUi {\n return FormattedAmountAssetUi(`$${amount}`);\n}\n\nexport function assetAmount(\n amount: FormattedAmountUi,\n symbol: AssetSymbol\n): FormattedAmountAssetUi {\n return FormattedAmountAssetUi(`${amount} ${symbol}`);\n}\n\n/** Placeholder shown when an amount is unavailable (e.g. a loading quote). */\nexport const NA_AMOUNT_ASSET_UI: FormattedAmountAssetUi =\n FormattedAmountAssetUi('-');\n\nconst SHARE_MAX_FRACTION_DIGITS = AssetDecimals(6);\nconst SHARE_MIN_FRACTION_DIGITS = AssetDecimals(2);\n\n/**\n * A share quantity for a headline: at most 6 decimal places, at least 2, with\n * the zeros between those dropped.\n *\n * An 18-decimal fill (`0.002689383776381483`) otherwise takes the whole\n * confirmation row and the fund name collapses to an ellipsis. Places past 6\n * are dust at share scale. The chain amount is unchanged, and the transaction\n * link still carries the exact figure.\n */\nexport function formatShareAmount(\n amount: BlockchainAmount,\n locale: string\n): FormattedAmountUi {\n return formatAmount(amount, locale, {\n maxFractionDigits: SHARE_MAX_FRACTION_DIGITS,\n minFractionDigits: SHARE_MIN_FRACTION_DIGITS,\n });\n}\n\nconst USD_FRACTION_DIGITS = AssetDecimals(2);\n\n/**\n * Formats a USD amount capped at 2 fractional digits, falling back to the\n * {@link NA_AMOUNT_ASSET_UI} placeholder when the amount is absent.\n */\nexport function formattedUsdPrice(\n amount: BlockchainAmount | null,\n locale: string\n): FormattedAmountAssetUi {\n if (!amount) return NA_AMOUNT_ASSET_UI;\n return usdAmount(\n formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })\n );\n}\n","import type { Newtype } from '@/universal/types/newtype';\n\nexport type FormattedAmountUi = Newtype<string, 'FormattedAmountUi'>;\nexport const FormattedAmountUi = (value: string): FormattedAmountUi =>\n value as FormattedAmountUi;\n\nexport type FormattedPercentUi = Newtype<string, 'FormattedPercentUi'>;\nexport const FormattedPercentUi = (value: string): FormattedPercentUi =>\n value as FormattedPercentUi;\n\nexport type TxExplorerUrl = Newtype<string, 'TxExplorerUrl'>;\nexport const TxExplorerUrl = (value: string): TxExplorerUrl =>\n value as TxExplorerUrl;\n\n/**\n * A wallet address shortened for display (e.g. `0x1234…5678`). Keeps a\n * `0x${string}` base but drops the runtime `0x` narrowing.\n */\nexport type ShortenedWalletAddress = Newtype<\n `0x${string}`,\n 'ShortenedWalletAddress'\n>;\nexport const ShortenedWalletAddress = (value: string): ShortenedWalletAddress =>\n value as ShortenedWalletAddress;\n\nexport type FormattedAmountAssetUi = Newtype<string, 'FormattedAmountAssetUi'>;\nexport const FormattedAmountAssetUi = (value: string): FormattedAmountAssetUi =>\n value as FormattedAmountAssetUi;\n\nexport type AssetIconUrl = Newtype<string, 'AssetIconUrl'>;\nexport const AssetIconUrl = (value: string): AssetIconUrl =>\n value as AssetIconUrl;\n","import type { Chain, Hash } from 'viem';\nimport { base, baseSepolia, mainnet, sepolia } from 'viem/chains';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport { TxExplorerUrl } from '@/universal/types/blockchain/ui';\nimport { ValidationError } from '@/universal/types/errors';\n\n/**\n * The one chain table. `satisfies` makes a new {@link EthereumChain} a compile\n * error here until its definition is added, which is what keeps every lookup\n * below total.\n *\n * viem's own definitions rather than a hand-written `{ id }` map: they carry\n * the EIP-155 id *and* the deployed Multicall3 address, which is what lets\n * `publicClients` batch concurrent reads into one `eth_call`. A hand-rolled\n * definition would silently lose that.\n */\nconst VIEM_CHAINS = {\n ethereum_mainnet: mainnet,\n ethereum_sepolia: sepolia,\n base_mainnet: base,\n base_sepolia: baseSepolia,\n} as const satisfies Record<EthereumChain, Chain>;\n\n/** The viem chain definition the SDK reads and writes this chain through. */\nexport function viemChain(chain: EthereumChain): Chain {\n return VIEM_CHAINS[chain];\n}\n\nexport function getChainId(chain: EthereumChain): number {\n return VIEM_CHAINS[chain].id;\n}\n\n/**\n * Resolves an EIP-155 chain id to the chain the SDK names it by — the inverse\n * of {@link getChainId}, for backends that report a bare `chain_id`.\n *\n * @throws ValidationError on an unrecognised id. Defaulting to mainnet would\n * let a testnet response read as a live one.\n */\nexport function chainFromId(chainId: string): EthereumChain {\n const chains = Object.keys(VIEM_CHAINS) as EthereumChain[];\n const chain = chains.find((c) => String(VIEM_CHAINS[c].id) === chainId);\n if (!chain) {\n throw new ValidationError(`Unsupported EIP-155 chain id: \"${chainId}\"`);\n }\n return chain;\n}\n\nexport function getNetworkName(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'Ethereum';\n case 'ethereum_sepolia':\n return 'Ethereum Sepolia';\n case 'base_mainnet':\n return 'Base';\n case 'base_sepolia':\n return 'Base Sepolia';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n\nexport function txExplorerUrl(\n chain: EthereumChain,\n txHash: Hash\n): TxExplorerUrl {\n return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);\n}\n\nfunction explorerBaseUrl(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'https://etherscan.io';\n case 'ethereum_sepolia':\n return 'https://sepolia.etherscan.io';\n case 'base_mainnet':\n return 'https://basescan.org';\n case 'base_sepolia':\n return 'https://sepolia-explorer.base.org';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n","import { parseUnits } from 'viem';\nimport {\n type AssetDecimals,\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/universal/types/blockchain/core';\nimport { ValidationError } from '@/universal/types/errors';\n\n/** A typed, i18n-agnostic reason a raw amount string failed to parse. */\nexport type AmountParseErrorReason =\n | { type: 'empty' }\n | { type: 'negative' }\n | { type: 'invalid-format' }\n | { type: 'too-many-decimals'; maxDecimals: AssetDecimals }\n /** Scaled up by `decimals`, the amount no longer fits a uint256. */\n | { type: 'overflow' };\n\nexport type AmountParseResult =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; reason: AmountParseErrorReason };\n\n/**\n * Wraps a raw uint256 base-unit string — what Ondo and the on-chain reads\n * return (\"100000000\" is 100 USDC, not 100 wei-of-nothing) — in a\n * {@link BlockchainAmount} at the given decimals. The value is already scaled,\n * so `decimals` is only the unit tag that travels with it.\n *\n * Distinct from {@link parseBlockchainAmount}, which takes a *human decimal*\n * string and scales it up. Feeding a raw amount to that one silently\n * multiplies it by 10^decimals — pick by what the backend sends, not by which\n * one is closer at hand.\n *\n * @throws ValidationError when the string is not a non-negative uint256\n * integer. A backend that regresses to decimal strings fails loudly here\n * rather than truncating.\n */\nexport function blockchainAmountFromRawOrThrow({\n label,\n raw,\n decimals,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n}): BlockchainAmount {\n const trimmed = raw.trim();\n // BigInt('') is 0n, not an error — an absent amount must not read as zero.\n if (trimmed === '') {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n let value: bigint;\n try {\n // BigInt() rejects \"0.5\", \"abc\" and \"1e18\" by throwing SyntaxError.\n value = BigInt(trimmed);\n } catch {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n try {\n return BlockchainAmount({ raw: assertUint256(value), decimals });\n } catch {\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n }\n}\n\n/**\n * Parses a user-entered decimal string into a {@link BlockchainAmount} at the\n * given token decimals. Rejects scientific notation, negatives, malformed\n * input, more fractional digits than the token supports, and amounts that\n * scale past uint256 — surfacing a typed {@link AmountParseErrorReason} so\n * callers own the display copy.\n */\nexport function parseBlockchainAmount(\n amount: string,\n decimals: AssetDecimals\n): AmountParseResult {\n const trimmed = amount.trim();\n if (trimmed === '') return { valid: false, reason: { type: 'empty' } };\n if (trimmed.startsWith('-')) {\n return { valid: false, reason: { type: 'negative' } };\n }\n // viem accepts \"1e18\" as scientific notation — reject it explicitly\n if (/[eE]/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // reject bare decimal point\n if (trimmed === '.') {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // normalize a leading or trailing decimal\n // replace(/^./, '0.') -> Turns \".25\" to \"0.25\"\n // replace(/.$/, '') -> Turns \"25.\" to \"25\"\n const normalised = trimmed.replace(/^\\./, '0.').replace(/\\.$/, '');\n if (!/^\\d+(\\.\\d+)?$/.test(normalised)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n const [, fraction = ''] = normalised.split('.');\n if (fraction.length > decimals) {\n return {\n valid: false,\n reason: { type: 'too-many-decimals', maxDecimals: decimals },\n };\n }\n try {\n // parseUnits is unbounded: a long enough input scales past uint256, which\n // no on-chain amount can hold. Reporting it as valid would send a\n // truncated or reverting value to a contract.\n const raw = parseUnits(normalised, decimals);\n if (raw > MAX_UINT_256) {\n return { valid: false, reason: { type: 'overflow' } };\n }\n return {\n valid: true,\n amount: BlockchainAmount({ raw, decimals }),\n };\n } catch {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n}\n","import { chainFromId } from '@/universal/core/shared/blockchain/chain';\nimport { blockchainAmountFromRawOrThrow } from '@/universal/core/shared/blockchain/math';\nimport {\n AssetDecimals,\n AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n HexEncodedTransactionData,\n type Tx,\n} from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoSwapDtoCore,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport { type OrderBookSide, Ticker } from '@/universal/types/trading';\n\n/**\n * Whether an Ondo asset can be traded right now.\n *\n * The caps only mean anything while trading is open, so they live on the\n * `tradable` branch. They stay {@link DecimalString} rather than\n * {@link BlockchainAmount} because the response carries no `asset_decimals`:\n * there is no honest exponent to attach, and the USD caps arrive with more\n * fractional digits than a stablecoin has decimals.\n *\n * Each cap is independently nullable even when tradable — Ondo may open an\n * asset for trading without publishing every limit.\n *\n * `side` is carried through from the response rather than dropped: the whole\n * status describes one side, so a buy and a sell status are otherwise\n * indistinguishable once a caller holds both.\n */\nexport type OndoTradingStatus =\n | {\n type: 'tradable';\n side: OrderBookSide;\n /** Largest order in whole tokens. */\n grossMaxTokens: DecimalString | null;\n /** Largest order in USD. */\n grossMaxNotionalValue: DecimalString | null;\n /** USD cap for the session the market is currently in. */\n grossMaxActiveNotionalValue: DecimalString | null;\n }\n | {\n type: 'not-tradable';\n side: OrderBookSide;\n };\n\nexport const OndoTradingStatus = {\n fromDto: (dto: OndoTradingStatusDto): OndoTradingStatus => {\n if (!dto.tradable) return { type: 'not-tradable', side: dto.side };\n return {\n type: 'tradable',\n side: dto.side,\n grossMaxTokens: decimalOrNull(dto.gross_max_tokens),\n grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),\n grossMaxActiveNotionalValue: decimalOrNull(\n dto.gross_max_active_notional_value\n ),\n };\n },\n};\n\nconst decimalOrNull = (value: string | null): DecimalString | null =>\n value === null ? null : DecimalString(value);\n\n/**\n * An indicative price for an Ondo asset, free to poll while the user edits an\n * order.\n *\n * **No CoinList fee is applied to the quantity or the price.** Ondo prices\n * exactly the amount asked for. A CoinList approval is fee-inclusive, so\n * sizing a quote against one without netting the fee first overstates what the\n * user receives. Showing a gross/net breakdown needs a CoinList swap\n * contract's `preview`, and no such contract exists for Ondo yet.\n *\n * The quote carries no transaction to broadcast and no expiry. Building one is\n * a separate endpoint per side that spends an attestation - see\n * {@link OndoBuyTransaction} and {@link OndoSellTransaction}.\n */\nexport type OndoQuote = {\n /** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */\n chain: EthereumChain;\n ticker: Ticker;\n /**\n * Needed to approve or transfer the asset; the quote is the only source.\n *\n * **Resolved on Ethereum mainnet**, like everything else on this quote, and\n * therefore not necessarily the contract the swap pulls from on the chain\n * the order executes on. Frontline resolves that one per chain and publishes\n * it nowhere, so on a testnet these are two different tokens. Tracked\n * against the frontline stack that follows ENG-1756.\n */\n assetAddress: EvmContractAddress;\n /**\n * The asset as the quote resolves it, from frontline's own catalogue.\n *\n * Its `decimals` scale {@link tokenBaseUnits} and nothing else. They are\n * **not** the scale of a built transaction's spend or output: those are\n * reported by whatever priced them, the sources are allowed to disagree, and\n * only the one that produced a number answers for it.\n */\n asset: Erc20Asset;\n side: OrderBookSide;\n tokenBaseUnits: BlockchainAmount;\n /**\n * USD price of one whole token. Unscaled because Ondo has already scaled it,\n * and by USDon's 18 decimals rather than the stablecoin's 6 — re-scaling it\n * by either would be wrong.\n */\n price: DecimalString;\n};\n\nexport const OndoQuote = {\n fromDto: (dto: OndoQuoteDto): OndoQuote => {\n const assetDecimals = AssetDecimals(dto.asset_decimals);\n return {\n chain: chainFromId(dto.chain_id),\n ticker: Ticker(dto.ticker),\n assetAddress: EvmContractAddress(dto.asset_address),\n asset: {\n name: dto.ticker,\n symbol: AssetSymbol(dto.symbol),\n decimals: assetDecimals,\n },\n side: dto.side,\n tokenBaseUnits: blockchainAmountFromRawOrThrow({\n label: 'tokenBaseUnits',\n raw: dto.token_base_units,\n decimals: assetDecimals,\n }),\n price: DecimalString(dto.price),\n };\n },\n};\n\n/**\n * The half of a built swap that both sides share: the calldata, its deadline,\n * and what the wallet parts with.\n *\n * There is deliberately **no union over the two sides**. Each is built by its\n * own endpoint and its own namespace method, so a caller never holds one\n * without knowing which it is, and a union would only re-pose a question the\n * call site had already answered. What is genuinely common lives here, and\n * {@link executeOndoSwap} takes this rather than either arm - broadcasting\n * knows nothing about the direction of the trade.\n *\n * `side` is not on this type but on each arm, as a literal the SDK authors\n * from the method that was called. The wire stopped echoing one when the\n * endpoint split, and it is still worth carrying: `OndoOrderPlaced` is a union\n * the SDK builds from both, and that union needs a tag.\n */\nexport type OndoSwapTransactionCore = {\n /**\n * Broadcast as-is. The `to` is the swap contract, which is also the ERC-20\n * spender the user must have approved.\n */\n tx: Tx;\n /**\n * When the calldata stops being accepted. A transaction broadcast after this\n * reverts, so callers must compare against it before signing.\n */\n expiresAt: Date;\n /**\n * Gross amount the wallet spends, in the decimals of the token this side\n * spends: the funding token on a buy, the asset on a sell.\n *\n * The same field at two scales, which is the whole reason the two sides are\n * two types. It is also what the approval has to cover.\n */\n spendInputAmount: BlockchainAmount;\n};\n\n/**\n * A signed, expiring purchase: a funding token in, an exact quantity of the\n * asset out.\n *\n * Distinct from {@link OndoQuote} in three ways that matter: it costs an\n * attestation to obtain, it expires, and it carries a {@link Tx} the wallet\n * broadcasts verbatim. Treat it as single-use - once broadcast (or once\n * `expiresAt` passes) it is spent, and a new one must be built.\n *\n * **The quantity is attested and exact, with no floor beneath it.** That is\n * what separates it from an {@link OndoSellTransaction}, which commits to a\n * range: nothing here is an estimate.\n *\n * **It carries no other identity.** No chain, ticker or asset: the endpoint\n * publishes none of them, and inventing them from the request would assert\n * what the server resolved rather than report it. What it does publish is the\n * scale of every amount on it, so a caller needs nothing alongside it to read\n * the numbers - only to name the assets, which the offer already does.\n *\n * It carries no price either. See `computeOndoBuyPrice`, which derives it from\n * the amounts the response does carry - the price this transaction fills at,\n * rather than an indicative one that has since moved.\n */\nexport type OndoBuyTransaction = OndoSwapTransactionCore & {\n side: 'buy';\n /**\n * CoinList's cut, in `spendInputAmount`'s decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Taken at execution rather than added on top, so the approval never has to\n * cover more than `spendInputAmount`.\n */\n fee: BlockchainAmount;\n /**\n * `spendInputAmount` less `fee`, in the same decimals: what Ondo priced, and\n * the numerator of the fill price.\n *\n * Read from the response rather than subtracted here. Whether the fee comes\n * off the deposit or goes on top of it is the server's definition to change,\n * and a client that derives this cannot notice when it does.\n */\n notionalValue: BlockchainAmount;\n /**\n * Quantity of the asset the wallet receives, at the scale whatever priced it\n * reported - not at the {@link OndoQuote}'s `asset.decimals`.\n */\n receiveOutputAmount: BlockchainAmount;\n};\n\nexport const OndoBuyTransaction = {\n fromDto: (dto: OndoBuyDto): OndoBuyTransaction => {\n // Read once each, so a mapper that reached for the wrong exponent on one\n // of the amounts is a visible mistake rather than a plausible one.\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'buy',\n fee: blockchainAmountFromRawOrThrow({\n label: 'fee',\n raw: dto.fee,\n decimals: spendDecimals,\n }),\n notionalValue: blockchainAmountFromRawOrThrow({\n label: 'notional_value',\n raw: dto.notional_value,\n decimals: spendDecimals,\n }),\n receiveOutputAmount: parsePositiveAmount({\n label: 'receive_output_amount',\n raw: dto.receive_output_amount,\n decimals: outputDecimals,\n // A transaction that yields nothing is not one to sign - the user\n // would pay the deposit and receive no asset - and frontline refuses\n // to emit one. A zero here is a changed encoding, not a small order.\n // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`\n // divide by it without a fallible result: the failure surfaces as the\n // data hook's ERROR state rather than as a division during render.\n reason: 'a buy that yields nothing is not fillable',\n }),\n };\n },\n};\n\n/**\n * One end of the range a sale commits to: what arrives, and what CoinList took\n * to get it there.\n *\n * The two travel together because they are charged against each other -\n * `quantity` is already **net** of `fee` - and because the pair a caller wants\n * is always both halves of the same outcome. Grouping them is what makes\n * \"the expected quantity, less the fee at the floor\" unrepresentable rather\n * than merely wrong.\n */\nexport type OndoSellOutcome = {\n /** What the wallet receives at this outcome, net of {@link fee}. */\n quantity: BlockchainAmount;\n /**\n * CoinList's cut at this outcome, in the same decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Already deducted from {@link quantity} rather than charged on top of it.\n */\n fee: BlockchainAmount;\n};\n\n/**\n * A signed, expiring sale: the asset in, a settlement coin out, somewhere\n * between two published outcomes.\n *\n * Single-use and expiring for the same reasons as an {@link OndoBuyTransaction},\n * and obtained the same way - one endpoint, one attestation.\n *\n * **A sale commits to a range, not a quantity.** Ondo settles through USDon\n * before converting to the settlement token, so {@link expected} is what to\n * expect and {@link minimum} is what the calldata enforces. A screen that\n * shows only the first presents a firm-looking number the contract may\n * legitimately fill below.\n *\n * There is deliberately no counterpart to a buy's `notionalValue`. A sale\n * commits on the output side, so frontline reports no fee-exclusive input and\n * refuses to relate numbers Ninshubur did not relate. What it does relate is\n * each quantity to the fee beside it, which is why {@link OndoSellOutcome}\n * pairs them.\n *\n * One thing this type cannot see: the floor signed into `tx.data` is gross of\n * the fee, so a caller decoding the calldata finds a larger number than\n * `minimum.quantity`. Both are correct; `minimum.quantity` is what the wallet\n * actually receives.\n */\nexport type OndoSellTransaction = OndoSwapTransactionCore & {\n side: 'sell';\n /** What the sale is expected to return. An expectation, not a guarantee. */\n expected: OndoSellOutcome;\n /**\n * The floor the calldata enforces. A fill below it reverts on chain, so this\n * - not {@link expected} - is what a seller is actually guaranteed.\n */\n minimum: OndoSellOutcome;\n};\n\nexport const OndoSellTransaction = {\n fromDto: (dto: OndoSellDto): OndoSellTransaction => {\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n // One exponent for all four amounts below, unlike a buy where the fee\n // follows the spend. A sale takes its cut from the coin it settles in.\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n const expectedQuantity = parsePositiveAmount({\n label: 'expected_quantity',\n raw: dto.expected_quantity,\n decimals: outputDecimals,\n reason: 'a sale that yields nothing is not fillable',\n });\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'sell',\n expected: {\n quantity: expectedQuantity,\n fee: blockchainAmountFromRawOrThrow({\n label: 'expected_fee',\n raw: dto.expected_fee,\n decimals: outputDecimals,\n }),\n },\n minimum: {\n quantity: parseMinimumQuantity(\n dto.minimum_quantity,\n outputDecimals,\n expectedQuantity\n ),\n fee: blockchainAmountFromRawOrThrow({\n label: 'minimum_fee',\n raw: dto.minimum_fee,\n decimals: outputDecimals,\n }),\n },\n };\n },\n};\n\n/**\n * The three fields both responses carry, mapped once.\n *\n * `spendDecimals` is passed in rather than read here because a buy also\n * denominates its `fee` and `notionalValue` in it, so reading it twice would\n * leave two places to get wrong.\n */\nfunction parseSwapCore(\n dto: OndoSwapDtoCore,\n spendDecimals: AssetDecimals\n): OndoSwapTransactionCore {\n return {\n tx: {\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n },\n expiresAt: parseExpiresAt(dto.expires_at),\n spendInputAmount: parsePositiveAmount({\n label: 'spend_input_amount',\n raw: dto.spend_input_amount,\n decimals: spendDecimals,\n // A transaction that takes nothing from the wallet is not one to sign:\n // it would settle one leg of a trade and skip the other. Frontline\n // refuses an `amount` of zero whichever way the trade runs, so this is a\n // changed encoding rather than a small order.\n //\n // Guarded on both sides rather than on the sale alone, because which\n // amount becomes the divisor in the price flips with the direction: a\n // guard placed by that would be a rule about the arithmetic rather than\n // about the trade.\n reason: 'a swap that spends nothing is not fillable',\n }),\n };\n}\n\n/**\n * The floor under a sale's proceeds, refused when it cannot be one.\n *\n * A floor above the amount it is a floor on cannot be filled: the calldata\n * would revert on every outcome. Frontline validates both bounds\n * (`minimum <= expected`, and `> 0`), so either is a changed encoding rather\n * than a tight quote.\n *\n * Rejecting them at the boundary is what lets the review screen render the\n * pair without deciding what to do when they contradict each other - the\n * failure surfaces as the data hook's ERROR state instead.\n */\nfunction parseMinimumQuantity(\n raw: string,\n decimals: AssetDecimals,\n expectedQuantity: BlockchainAmount\n): BlockchainAmount {\n const amount = parsePositiveAmount({\n label: 'minimum_quantity',\n raw,\n decimals,\n reason: 'a floor of zero guarantees nothing',\n });\n if (amount.raw > expectedQuantity.raw) {\n throw new ValidationError(\n `minimum_quantity: must not exceed expected_quantity (\"${raw}\" > \"${expectedQuantity.raw}\")`\n );\n }\n return amount;\n}\n\n/**\n * An amount the trade cannot proceed without, refused at zero.\n *\n * `reason` says what the zero would have meant, so the message names the trade\n * rather than the field alone - the same field is a deposit on one side and a\n * quantity of shares on the other.\n */\nfunction parsePositiveAmount({\n label,\n raw,\n decimals,\n reason,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n reason: string;\n}): BlockchainAmount {\n const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });\n if (amount.raw <= 0n) {\n throw new ValidationError(\n `${label}: must be greater than zero (\"${raw}\") - ${reason}`\n );\n }\n return amount;\n}\n\n/**\n * A transaction whose expiry cannot be read is not safely fillable - the\n * deadline is encoded in the calldata either way, so broadcasting against an\n * unknown one only spends gas on a revert. Fail here instead.\n */\nfunction parseExpiresAt(value: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n throw new ValidationError(`expires_at: not a date (\"${value}\")`);\n }\n return date;\n}\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport { formatRawAmount } from '@/universal/core/shared/blockchain/formatters';\nimport type { BlockchainAmount } from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\nexport async function getOndoTradingStatus(\n api: Sender,\n params: GetOndoTradingStatusParams\n): Promise<OndoTradingStatus> {\n const dto = await api.send<OndoTradingStatusDto>({\n method: 'GET',\n url: '/v1/ondo/swap/trading-status',\n queryParams: { symbol: params.symbol, side: params.side },\n attributes: Attributes.protected(),\n });\n return OndoTradingStatus.fromDto(dto);\n}\n\nexport async function getOndoQuote(\n api: Sender,\n params: GetOndoQuoteParams\n): Promise<OndoQuote> {\n const dto = await api.send<OndoQuoteDto>({\n method: 'GET',\n url: '/v1/ondo/swap/quote',\n queryParams: {\n symbol: params.symbol,\n side: params.side,\n duration: params.duration,\n ...sizeParam(params),\n },\n attributes: Attributes.protected(),\n });\n return OndoQuote.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a purchase: spends an attestation and\n * returns signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the funding token**, unlike\n * `getOndoQuote`'s `token_amount` which is in whole tokens: this number\n * becomes the ERC-20 pull encoded into the calldata, so it is the on-chain\n * integer, not a human figure. Frontline refuses zero, and refuses a wallet\n * whose allowance on that token does not cover it with a 422 carrying\n * `code: \"insufficient_allowance\"`.\n *\n * The body carries no `side`. It used to, optional on the wire and defaulting\n * to `buy`, which is exactly the silent default the endpoint split removed:\n * the path is now what says which trade to sign and which token's allowance to\n * read, and a request cannot lose it.\n */\nexport async function buildOndoBuy(\n api: Sender,\n params: BuildOndoBuyParams\n): Promise<OndoBuyTransaction> {\n const dto = await api.send<OndoBuyDto>({\n method: 'POST',\n url: '/v1/ondo/swap/buy',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'purchase',\n });\n return OndoBuyTransaction.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a sale: spends an attestation and returns\n * signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the asset**, which is the one thing\n * that makes this materially different from {@link buildOndoBuy} rather than a\n * mirror of it. The same integer means something 1e12 different on the two\n * sides, so an order sized in the funding token's units and posted here is not\n * a rejected request but a wrong one.\n *\n * Frontline reads the allowance on the **asset** before asking Ninshubur for\n * anything - a sale delivers it, so the swap contract pulls it with\n * `transferFrom` - and refuses a short one with a 422 carrying\n * `code: \"insufficient_allowance\"` and a message naming that address.\n */\nexport async function buildOndoSell(\n api: Sender,\n params: BuildOndoSellParams\n): Promise<OndoSellTransaction> {\n const dto = await api.send<OndoSellDto>({\n method: 'POST',\n url: '/v1/ondo/swap/sell',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'sale',\n // The two answers come from two chains, so on a testnet they can disagree\n // for a reason that is neither the caller's nor a corrupt response. Say so,\n // or a QA run reads as a puzzle rather than a diagnosis.\n note:\n 'the quote resolves the asset on Ethereum mainnet while the swap ' +\n 'executes on the chain requested, so these disagree until frontline ' +\n 'serves a chain-scoped quote',\n });\n return OndoSellTransaction.fromDto(dto);\n}\n\n/**\n * The four fields both endpoints take, spelled the same way for both.\n *\n * `amount` is the only one whose meaning forks, and it forks in the *token*\n * rather than in the encoding - a uint256 decimal string either way.\n */\nfunction swapBody(\n params: BuildOndoBuyParams | BuildOndoSellParams\n): Record<string, string> {\n return {\n symbol: params.symbol,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount.raw.toString(),\n };\n}\n\n/**\n * Refuses a response denominated in a different scale than the request was.\n *\n * The two are independent resolutions of the same token: the caller sized\n * `amount` in the coin it chose and approved, while frontline reads\n * `decimals()` on-chain from the token the side spends, which it resolves from\n * the offer. On a purchase they should never differ - an approval on some\n * other token reads as a zero allowance, which frontline refuses before it\n * signs anything - so a disagreement is a changed encoding rather than a user\n * error, the same reasoning the mapper rejects a zero amount under.\n *\n * Worth the check because of where the value lands: `spend_input_amount` at\n * the wrong exponent renders the review screen's committed amount orders of\n * magnitude out, on the screen where the user commits money.\n */\nfunction assertSpendScaleAgrees({\n published,\n sized,\n trade,\n note,\n}: {\n published: number;\n sized: BlockchainAmount;\n trade: 'purchase' | 'sale';\n note?: string;\n}): void {\n if (published === sized.decimals) return;\n const because = note === undefined ? '' : ` - ${note}`;\n throw new ValidationError(\n `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`\n );\n}\n\n/**\n * `token_amount` is in **whole tokens**, unlike the response's\n * `token_base_units` — Ondo names both `tokenAmount`, 1e18 apart. Hence the\n * unscale on the way out.\n *\n * The size is checked at runtime because the types do not cover it: TypeScript\n * rejects an object carrying *neither*, but against a union of object types it\n * accepts one carrying *both*, and a JavaScript caller gets no check at all.\n */\nfunction sizeParam(\n params: GetOndoQuoteParams\n): Record<string, QueryParamValues> {\n const tokenAmount = 'tokenAmount' in params ? params.tokenAmount : undefined;\n const notionalValue =\n 'notionalValue' in params ? params.notionalValue : undefined;\n\n if (tokenAmount !== undefined) {\n if (notionalValue !== undefined) {\n throw new ValidationError(\n 'An Ondo quote takes tokenAmount or notionalValue, not both'\n );\n }\n return { token_amount: formatRawAmount(tokenAmount) };\n }\n if (notionalValue === undefined) {\n throw new ValidationError(\n 'An Ondo quote must be sized by tokenAmount or notionalValue'\n );\n }\n return { notional_value: notionalValue };\n}\n","import {\n buildOndoBuy,\n buildOndoSell,\n getOndoQuote,\n getOndoTradingStatus,\n} from '@/universal/api/frontline/providers/ondo/ondo';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\n/**\n * Ondo swap reads, plus the write that turns one into a fillable transaction.\n *\n * The two reads are free to poll - neither spends an attestation, so a client\n * may call them while the user edits an order. The two builders are not:\n * budget one call per order placed, plus one per refresh the user asks for.\n *\n * **One builder per side, mirroring the endpoints.** A purchase and a sale\n * agree on how to broadcast and on nothing else: a purchase commits to an\n * exact quantity, a sale to a range with a floor beneath it, and `amount` is\n * the funding token on one and the asset on the other. A single method taking\n * a `side` would have to return a union the caller then re-narrows, having\n * already decided which trade it was placing.\n *\n * **No CoinList fee is applied to a read quote, and no read discloses one.**\n * Ondo prices exactly the amount passed. A CoinList approval is fee-inclusive,\n * so sizing a quote against a user's approval without subtracting the fee\n * first overstates what they receive. A built transaction carries the fee\n * explicitly, and it is zero until one lands (ENG-1718).\n *\n * Every method requires `AuthState === 'logged-in'` and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface OndoNamespace {\n getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus>;\n /**\n * An indicative price for `params`' size, from Ondo's live market.\n *\n * Ondo refuses to quote while the market is closed or paused, or the asset\n * is paused or closed for the session - including for about a minute at\n * every US session change, when `getTradingStatus` may still have reported\n * the asset tradable. The request then rejects with a 409 carrying\n * `code: \"not_tradable\"`; tell it apart from a failure with\n * {@link isOndoNotTradableError}. Retrying before the market opens fails the\n * same way.\n */\n getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;\n /**\n * Builds a purchase for a specific wallet and deposit: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoBuyTransaction.expiresAt}.\n *\n * The wallet must have approved the swap contract to spend `amount` of the\n * offer's **funding token** first. Frontline reads that allowance before\n * asking Ninshubur for anything, and rejects a short one with a 422 carrying\n * `code: \"insufficient_allowance\"`. See `prepareBuy` on the client\n * namespace, which approves and then builds, in that order.\n *\n * The tokens themselves are the offer's rather than the caller's to name.\n */\n buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;\n /**\n * Builds a sale for a specific wallet and quantity: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoSellTransaction.expiresAt}.\n *\n * The approval this one needs is on the **asset**, not on a stablecoin - a\n * sale delivers the asset, so the swap contract pulls it with `transferFrom`\n * exactly as it pulls the deposit on a purchase. Same 422 when it is short,\n * with a message naming that address. See `prepareSell` on the client\n * namespace.\n *\n * Returns a range rather than a quantity: Ondo settles through USDon before\n * converting to the settlement token, so disclose\n * {@link OndoSellTransaction.minimum} and not only `expected`.\n */\n buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction>;\n}\n\nexport class OndoNamespaceImpl implements OndoNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ONDO');\n }\n\n async getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus> {\n return this.log.wrap('getTradingStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoTradingStatus(this.ctx.api, params);\n });\n }\n\n async getQuote(params: GetOndoQuoteParams): Promise<OndoQuote> {\n return this.log.wrap('getQuote', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoQuote(this.ctx.api, params);\n });\n }\n\n async buildBuyTransaction(\n params: BuildOndoBuyParams\n ): Promise<OndoBuyTransaction> {\n return this.log.wrap('buildBuyTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoBuy(this.ctx.api, params);\n });\n }\n\n async buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction> {\n return this.log.wrap('buildSellTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoSell(this.ctx.api, params);\n });\n }\n}\n","/**\n * The Superstate swap contract's ABI, generated verbatim from the shared\n * `TokenSwap` base contract:\n *\n * ```\n * cd ../solidity && forge inspect TokenSwap abi --json --use 0.8.34\n * ```\n *\n * Generated rather than hand-trimmed to the four methods the SDK calls, so\n * regenerating after a contract change is one command and a paste. The custom\n * errors carry their weight in particular: viem decodes a revert against them,\n * so a `preview()` on a stopped contract surfaces as `IsStopped` rather than\n * as an opaque `0x`-prefixed blob.\n *\n * `status()` returns `Status { uint32 flags; State state }` where `State` is\n * `0 = Active | 1 = Paused | 2 = Stopped`. It replaced the older\n * `stopped() -> uint256` bitmask, which this contract still exposes but as a\n * `bool`; {@link SwapStatus} reads `status()` and nothing else.\n */\nexport const SUPERSTATE_SWAP_ABI = [\n {\n type: 'function',\n name: 'KIND',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint16',\n internalType: 'uint16',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'ONE_HUNDRED_P',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'SWAP_LEVEL',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'VERSION',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint16',\n internalType: 'uint16',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'authorized',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'bpp',\n inputs: [\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'bps',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'cancelOwnershipHandover',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'completeOwnershipHandover',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'fee',\n inputs: [\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'id',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bytes32',\n internalType: 'bytes32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'inputTokens',\n inputs: [\n {\n name: '',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputToken',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'address',\n internalType: 'address',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputTokenBalance',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'owner',\n inputs: [],\n outputs: [\n {\n name: 'result',\n type: 'address',\n internalType: 'address',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'ownershipHandoverExpiresAt',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: 'result',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'pause',\n inputs: [\n {\n name: 'level',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'paused',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'preview',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Preview',\n components: [\n {\n name: 'input',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'fee',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'output',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'renounceOwnership',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'requestOwnershipHandover',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'setBps',\n inputs: [\n {\n name: 'points',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'setInputToken',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'val',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'status',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Status',\n components: [\n {\n name: 'flags',\n type: 'uint32',\n internalType: 'uint32',\n },\n {\n name: 'state',\n type: 'uint8',\n internalType: 'enum State',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'stop',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'stopped',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'swap',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'slip',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'tokenBalance',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n {\n name: 'inputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'feeSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'outputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'count',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n {\n name: 'inputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'feeSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'outputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'count',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n {\n name: 'to',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n {\n name: 'to',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transferOwnership',\n inputs: [\n {\n name: 'newOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'event',\n name: 'BpsUpdated',\n inputs: [\n {\n name: 'prev',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'next',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'InputTokenUpdated',\n inputs: [\n {\n name: 'token',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'prev',\n type: 'bool',\n indexed: false,\n internalType: 'bool',\n },\n {\n name: 'next',\n type: 'bool',\n indexed: false,\n internalType: 'bool',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipHandoverCanceled',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipHandoverRequested',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipTransferred',\n inputs: [\n {\n name: 'oldOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'newOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Paused',\n inputs: [\n {\n name: 'previous',\n type: 'uint32',\n indexed: false,\n internalType: 'uint32',\n },\n {\n name: 'next',\n type: 'uint32',\n indexed: false,\n internalType: 'uint32',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Stopped',\n inputs: [],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Swapped',\n inputs: [\n {\n name: 'user',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'inputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'outputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'inputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'fee',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'outputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Transferred',\n inputs: [\n {\n name: 'to',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'error',\n name: 'AlreadyInitialized',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InsufficientAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'IsPaused',\n inputs: [\n {\n name: 'level',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n },\n {\n type: 'error',\n name: 'IsStopped',\n inputs: [],\n },\n {\n type: 'error',\n name: 'NewOwnerIsZeroAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'NoHandoverRequest',\n inputs: [],\n },\n {\n type: 'error',\n name: 'SwapFailed',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n },\n {\n type: 'error',\n name: 'Unauthorized',\n inputs: [],\n },\n] as const;\n","import {\n assertUint256,\n Bps,\n type Uint256,\n} from '@/universal/types/blockchain/core';\n\n/** Basis-point denominator: 10_000 bps = 100%. */\nexport const BPS_DENOM: Bps = Bps(10_000n);\n\n/**\n * Applies a basis-point fraction to an amount, flooring the result.\n * `floor((amount × bps) / BPS_DENOM)`. The result is bounds-checked, so an\n * overflow (bps far above BPS_DENOM) or a negative product is rejected.\n */\nexport function applyBps(amount: Uint256, bps: Bps): Uint256 {\n return assertUint256((amount * bps) / BPS_DENOM);\n}\n","import type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport { applyBps, BPS_DENOM } from '@/universal/core/shared/blockchain/bps';\nimport {\n assertUint256,\n BlockchainAmount,\n Bps,\n} from '@/universal/types/blockchain/core';\n\n/**\n * Price of 1 output token in USD, assuming the input token is a $1 stablecoin.\n *\n * `raw_price = inputTokenAmount.raw × 10^outputDecimals ÷ outputTokenAmount.raw`\n *\n * The multiplication happens before the division so we never lose precision to\n * integer truncation early. This mirrors standard fixed-point practice on-chain.\n * Returned decimals match the input token decimals (always the stablecoin's 6).\n */\nexport function computePrice({\n inputTokenAmount,\n outputTokenAmount,\n}: SwapQuote): BlockchainAmount | null {\n if (outputTokenAmount.raw === 0n) return null;\n\n const scale = 10n ** BigInt(outputTokenAmount.decimals);\n const raw = assertUint256(\n (inputTokenAmount.raw * scale) / outputTokenAmount.raw\n );\n\n return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });\n}\n\n/**\n * Applies slippage to an amount, returning the minimum acceptable amount:\n * `amount × (BPS_DENOM − slippage) / BPS_DENOM`. Throws when `slippage` exceeds\n * `BPS_DENOM` (the retained fraction would be negative).\n */\nexport function computeSlip(\n amount: BlockchainAmount,\n slippage: Bps\n): BlockchainAmount {\n const retained = Bps(assertUint256(BPS_DENOM - slippage));\n const slipRaw = applyBps(amount.raw, retained);\n return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });\n}\n","import {\n type AssetDecimals,\n BlockchainAmount,\n} from '@/universal/types/blockchain/core';\nimport type { SwapPreview } from '@/universal/types/providers/superstate/swap';\n\n/**\n * A read-only quote for a swap as domain amounts: how much goes in, the\n * protocol fee, and how much would come out. Derived from the raw\n * {@link SwapPreview} the swap contract returns.\n */\nexport type SwapQuote = {\n inputTokenAmount: BlockchainAmount;\n fee: BlockchainAmount;\n outputTokenAmount: BlockchainAmount;\n};\n\nexport const SwapQuote = {\n /**\n * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The\n * input and fee are denominated in the input token; the output in the output\n * token.\n */\n fromPreview: (\n preview: SwapPreview,\n inputDecimals: AssetDecimals,\n outputDecimals: AssetDecimals\n ): SwapQuote => ({\n inputTokenAmount: BlockchainAmount({\n raw: preview.inputAmount,\n decimals: inputDecimals,\n }),\n fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),\n outputTokenAmount: BlockchainAmount({\n raw: preview.outputAmount,\n decimals: outputDecimals,\n }),\n }),\n};\n","import type { SwapStatus } from '@/universal/types/providers/superstate/swap';\n\n/**\n * The bit `Operable.paused` sets for the swap operation, mirroring the\n * contract's `SWAP_LEVEL` constant.\n *\n * A constant rather than a `SWAP_LEVEL()` read: it is `constant` in the\n * contract, so reading it would spend a round-trip to be told the same number\n * every time.\n */\nexport const SWAP_LEVEL = 2;\n\n/**\n * Whether the contract will actually accept a swap right now.\n *\n * Not the same question as \"is it active\". `paused` is a bitmask over\n * *operations*, so a contract can suspend something unrelated and go on\n * swapping; only the {@link SWAP_LEVEL} bit stops it. Reading `state ===\n * 'active'` instead would refuse swaps the contract is perfectly willing to\n * make.\n */\nexport function isSwapAvailable(status: SwapStatus): boolean {\n switch (status.state) {\n case 'active':\n return true;\n case 'stopped':\n return false;\n case 'paused':\n return (status.pausedLevels & SWAP_LEVEL) === 0;\n default: {\n const _exhaustive: never = status;\n return _exhaustive;\n }\n }\n}\n","import { parseEventLogs, type TransactionReceipt } from 'viem';\nimport { SUPERSTATE_SWAP_ABI } from '@/universal/core/checkout/superstate/blockchain/abi';\nimport {\n type AssetDecimals,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/universal/types/blockchain/core';\n\n/**\n * Decodes the confirmed output amount from the `Swapped` event in a swap\n * transaction receipt.\n *\n * Returns `null` when the event is absent or the amount is not a valid uint256\n * so callers can fall back to the quote's expected output — the swap already\n * confirmed on-chain, so a missing/undecodable event should not fail the flow.\n */\nexport function decodeSwappedOutputAmount(\n receipt: TransactionReceipt,\n outputDecimals: AssetDecimals\n): BlockchainAmount | null {\n try {\n const [swapped] = parseEventLogs({\n abi: SUPERSTATE_SWAP_ABI,\n eventName: 'Swapped',\n logs: receipt.logs,\n });\n if (!swapped) return null;\n\n const raw = swapped.args.outputAmount;\n if (raw < 0n || raw > MAX_UINT_256) return null;\n return BlockchainAmount({ raw, decimals: outputDecimals });\n } catch {\n // Undecodable log (ABI mismatch / malformed) — fall back to the\n // quote. The swap already confirmed on-chain, so never fail here.\n return null;\n }\n}\n","import { USDC_SYMBOL } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n Bps,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { NonEmptyArray } from '@/universal/types/collections';\n\n/**\n * Who issues the asset a Superstate swap pays out.\n *\n * A constant rather than a field off the offer: no frontline endpoint carries\n * an issuer, and every offer this checkout serves is Superstate's by\n * definition — `CheckoutContainer` routes here on `superstate::swap` alone.\n */\nexport const SUPERSTATE_ISSUER_NAME = 'Superstate';\n\n/**\n * The coins a Superstate swap can be funded with, in display order, with the\n * first preselected.\n *\n * USDC alone today: it is what the deployed swap contract accepts. The amount\n * step renders a single entry as a plain card and two or more as a picker, so\n * adding one here is all it takes.\n */\nexport const SUPERSTATE_SUPPORTED_INPUT_ASSETS: NonEmptyArray<StablecoinSymbol> =\n [USDC_SYMBOL];\n\n/** Poll interval for refreshing on-chain swap quotes and balances. */\nexport const SWAP_POLL_INTERVAL_MS = 15_000;\n\n/**\n * Notional input used to derive a display price-per-share when the user has\n * not yet entered an amount (1 USDC at 6 decimals).\n */\nexport const DEFAULT_AMOUNT_TO_COMPUTE_PRICE = 1_000_000n;\n\n/** Slippage tolerances offered in the review step, in basis points. */\nexport const SLIPPAGE_OPTIONS_BPS: Bps[] = [25n, 50n, 100n, 200n, 500n].map(\n (n) => Bps(n)\n);\n\n/** Default slippage tolerance (0.5%). */\nexport const DEFAULT_SLIPPAGE_BPS: Bps = Bps(50n);\n\n/**\n * The deployed Superstate swap contract on Ethereum Sepolia, and therefore the\n * ERC-20 spender the user approves there.\n *\n * Exported in its own right for a partner driving `coinlist.superstate.execute`\n * at Level 1, where the contract is an explicit parameter.\n */\nexport const SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA: EvmContractAddress =\n EvmContractAddress('0x27E8CE9Ca1A1E98Bc4009F08Dc596bFcf88aCED1');\n\n/**\n * The Superstate swap contract per chain.\n *\n * Mainnet is absent, not zeroed: the production address is not finalized\n * upstream, and a zero address would be approved happily and revert only later.\n * A chain with no entry has no checkout — `useSuperstateSwapCheckoutViewModel`\n * reports it as the flow-level error rather than quoting against nothing.\n */\nconst SUPERSTATE_SWAP_CONTRACT_ADDRESSES: Partial<\n Record<EthereumChain, EvmContractAddress>\n> = {\n ethereum_sepolia: SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA,\n};\n\n/**\n * The Superstate swap contract on `chain`, or `null` where none is deployed.\n *\n * TODO(ENG-1734): Ondo now reads its spender off the offer's `swap_contracts`\n * via `swapSpender`, which is why that helper sits in `shared/core/offers/`\n * rather than under a provider. Superstate still resolves from this table, so\n * two mechanisms answer one question. Migrate once frontline serves\n * `swap_contracts` on Superstate offers too.\n */\nexport function superstateSwapContractAddress(\n chain: EthereumChain\n): EvmContractAddress | null {\n return SUPERSTATE_SWAP_CONTRACT_ADDRESSES[chain] ?? null;\n}\n","import { computePrice } from '@/universal/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport {\n formattedUsdPrice,\n NA_AMOUNT_ASSET_UI,\n} from '@/universal/core/shared/blockchain/formatters';\nimport type { FormattedAmountAssetUi } from '@/universal/types/blockchain/ui';\n\n/**\n * Formats a quote's implied price per output token as a USD amount.\n *\n * Lives with the provider rather than in `@/universal/core/shared/blockchain/formatters`\n * because {@link SwapQuote} and {@link computePrice} are Superstate's: the\n * shared formatters stay provider-agnostic.\n */\nexport function formattedPricePerShare(\n quote: SwapQuote | null,\n locale: string\n): FormattedAmountAssetUi {\n if (!quote) return NA_AMOUNT_ASSET_UI;\n return formattedUsdPrice(computePrice(quote), locale);\n}\n","import {\n EvmContractAddress,\n HexEncodedTransactionData,\n parseUint256,\n type Uint256,\n} from '@/universal/types/blockchain/core';\nimport type { AllowWalletResponseDto } from '@/universal/types/dto/providers/superstate/swap';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * A read-only quote for a swap: how much goes in, the protocol fee, and how\n * much would come out. All amounts are raw on-chain integers (uint256).\n */\nexport type SwapPreview = {\n inputAmount: Uint256;\n fee: Uint256;\n outputAmount: Uint256;\n};\n\nexport const SwapPreview = {\n /** Maps the contract's `Preview { input, fee, output }` struct. */\n fromContract: (preview: {\n input: bigint;\n fee: bigint;\n output: bigint;\n }): SwapPreview => ({\n inputAmount: parseUint256(preview.input, 'SwapPreview.input'),\n fee: parseUint256(preview.fee, 'SwapPreview.fee'),\n outputAmount: parseUint256(preview.output, 'SwapPreview.output'),\n }),\n};\n\n/**\n * The bitmask of operations a swap contract has paused, as `Operable.paused`\n * reports it. Each bit is one operation level; swapping is\n * {@link SWAP_LEVEL}.\n *\n * Meaningful only while the contract is paused, which is why it lives on that\n * arm of {@link SwapStatus} alone: an active contract has nothing paused, and\n * a stopped one is past caring which level was.\n */\nexport type PauseFlags = Newtype<number, 'PauseFlags'>;\nexport const PauseFlags = (value: number): PauseFlags => value as PauseFlags;\n\n/**\n * The on-chain state of a swap contract, as `status()` reports it.\n *\n * - `active` - operating normally.\n * - `paused` - one or more operations are suspended, and may be resumed.\n * `pausedLevels` says which. **This does not by itself mean swapping is\n * down**: a contract can pause an unrelated operation and keep swapping.\n * Ask `isSwapAvailable` rather than reading the state.\n * - `stopped` - permanently halted, and cannot be reactivated.\n */\nexport type SwapStatus =\n | { state: 'active' }\n | { state: 'paused'; pausedLevels: PauseFlags }\n | { state: 'stopped' };\n\nexport const SwapStatus = {\n /**\n * Maps the contract's `Status { uint32 flags; State state }` struct, where\n * `State` is `0 = Active | 1 = Paused | 2 = Stopped`.\n *\n * `flags` is carried onto the `paused` arm only. On the other two the\n * contract sets it to a self-identifying marker rather than to information -\n * so repeating it would invite a caller to read meaning into a constant.\n *\n * @throws ValidationError on a `state` outside the enum. A contract that has\n * grown a fourth state is one the SDK does not model, and guessing `active`\n * would let a halted swap read as a live one.\n */\n fromContract: (status: { flags: number; state: number }): SwapStatus => {\n switch (status.state) {\n case 0:\n return { state: 'active' };\n case 1:\n return { state: 'paused', pausedLevels: PauseFlags(status.flags) };\n case 2:\n return { state: 'stopped' };\n default:\n throw new ValidationError(\n `SwapStatus.state: unknown contract state (${status.state})`\n );\n }\n },\n};\n\n/**\n * The backend's response to an allow-wallet request. Either the caller must\n * broadcast an on-chain transaction to complete allow-listing, or nothing is\n * required because the wallet is already allowed.\n */\nexport type AllowWalletResponse =\n | {\n action: 'broadcast_transaction';\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n }\n | {\n action: 'none';\n alreadyAllowed: boolean;\n };\n\nexport const AllowWalletResponse = {\n fromDto: (dto: AllowWalletResponseDto): AllowWalletResponse => {\n switch (dto.action) {\n case 'broadcast_transaction':\n return {\n action: 'broadcast_transaction',\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n };\n case 'none':\n return {\n action: 'none',\n alreadyAllowed: dto.already_allowed,\n };\n default: {\n const _exhaustive: never = dto;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { AllowWalletParams } from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type { AllowWalletResponseDto } from '@/universal/types/dto/providers/superstate/swap';\nimport { AllowWalletResponse } from '@/universal/types/providers/superstate/swap';\n\n/**\n * What is left of the Superstate swap's backend surface once the contract\n * reads moved on-chain (ADR-11): allow-listing is a backend write, decided by\n * frontline against the offer, so it stays an endpoint.\n */\nexport async function allowWallet(\n api: Sender,\n params: AllowWalletParams\n): Promise<AllowWalletResponse> {\n const dto = await api.send<AllowWalletResponseDto>({\n method: 'POST',\n url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,\n body: {\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n },\n attributes: Attributes.protected(),\n });\n return AllowWalletResponse.fromDto(dto);\n}\n","import type { PublicClients } from '@/universal/api/rpc/public-clients';\nimport { SUPERSTATE_SWAP_ABI } from '@/universal/core/checkout/superstate/blockchain/abi';\nimport type {\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport { ERC20_ABI } from '@/universal/core/shared/blockchain/erc20/abi';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport {\n SwapPreview,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\n\n/**\n * The Superstate swap contract's views, read straight from the chain.\n *\n * Each of these was a bespoke frontline endpoint until the SDK gained a\n * generic JSON-RPC transport (ADR-11). They take their subject as an argument\n * rather than reading `msg.sender`, which is what makes them safe to batch -\n * see `publicClients`.\n */\nexport async function getSwapAuthorization(\n clients: PublicClients,\n params: GetSwapAuthorizationParams\n): Promise<boolean> {\n return clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'authorized',\n args: [params.walletAddress],\n });\n}\n\nexport async function getSwapPreview(\n clients: PublicClients,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const preview = await clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'preview',\n args: [params.inputToken, params.amount],\n });\n return SwapPreview.fromContract(preview);\n}\n\nexport async function getSwapStatus(\n clients: PublicClients,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const status = await clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'status',\n });\n return SwapStatus.fromContract(status);\n}\n\n/**\n * The ERC-20 the swap pays out, with the metadata a UI needs to render an\n * amount of it.\n *\n * Two round-trips, and it cannot be one: `outputToken()` has to answer before\n * there is an address to ask for `name`/`symbol`/`decimals`. The second is an\n * explicit `multicall` rather than three awaited reads - the client would\n * batch them anyway, but writing it out says the three belong together and\n * survives someone turning auto-batching off.\n */\nexport async function getSwapOutputToken(\n clients: PublicClients,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const client = clients(params.chain);\n\n const tokenAddress = await client.readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'outputToken',\n });\n\n const token = { address: EvmContractAddress(tokenAddress), abi: ERC20_ABI };\n const [name, symbol, decimals] = await client.multicall({\n contracts: [\n { ...token, functionName: 'name' },\n { ...token, functionName: 'symbol' },\n { ...token, functionName: 'decimals' },\n ],\n allowFailure: false,\n });\n\n return {\n name,\n symbol: AssetSymbol(symbol),\n decimals: AssetDecimals(decimals),\n };\n}\n","import { allowWallet } from '@/universal/api/frontline/providers/superstate/swap';\nimport {\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/universal/api/rpc/providers/superstate/swap';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Erc20Asset } from '@/universal/types/blockchain/core';\nimport type {\n AllowWalletResponse,\n SwapPreview,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, and proving/allow-listing wallet ownership.\n *\n * Every read here is a contract call the SDK makes itself. By default those go\n * through CoinList's authenticated JSON-RPC proxy, so a logged-out caller gets\n * the proxy's `401` - surfaced as a viem error wrapping the SDK's `HttpError`,\n * not as `NotAuthenticatedError`, since viem re-wraps whatever a `Transport`\n * throws. Point `Config.rpc` at your own node for this chain and no CoinList\n * session is involved at all. `allowWallet` is the exception: it is a backend\n * write and always needs one, and throws `NotAuthenticatedError` without.\n */\nexport interface SuperstateSwapNamespace {\n /**\n * Checks whether a wallet is authorized to swap against the given contract.\n */\n getAuthorization(params: GetSwapAuthorizationParams): Promise<boolean>;\n\n /**\n * Fetches a read-only quote for swapping `amount` of `inputToken`.\n *\n * The contract reverts rather than quoting when it is stopped, or when\n * `inputToken` is not one it accepts, so this surfaces a viem\n * `ContractFunctionRevertedError` naming the contract's own error. Check\n * {@link getStatus} first if you would rather not provoke one.\n */\n getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;\n\n /**\n * Reads the current on-chain state of a swap contract. See\n * {@link isSwapAvailable} before concluding that a `paused` contract cannot\n * swap - the two are not the same question.\n */\n getStatus(params: SwapContractRef): Promise<SwapStatus>;\n\n /**\n * Reads the ERC-20 output token a swap contract pays out, with its metadata.\n */\n getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;\n\n /**\n * Submits a signed wallet-ownership challenge to allow-list the wallet for\n * an offer, identified by its offer id. Obtain the challenge from\n * `WalletsNamespace.createOwnershipChallenge`.\n *\n * @throws NotAuthenticatedError without a logged-in user.\n */\n allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;\n}\n\nexport class SuperstateSwapNamespaceImpl implements SuperstateSwapNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'SUPERSTATE');\n }\n\n async getAuthorization(params: GetSwapAuthorizationParams): Promise<boolean> {\n return this.log.wrap('getAuthorization', params, async () =>\n getSwapAuthorization(this.ctx.rpc, params)\n );\n }\n\n async getPreview(params: GetSwapPreviewParams): Promise<SwapPreview> {\n return this.log.wrap('getPreview', params, async () =>\n getSwapPreview(this.ctx.rpc, params)\n );\n }\n\n async getStatus(params: SwapContractRef): Promise<SwapStatus> {\n return this.log.wrap('getStatus', params, async () =>\n getSwapStatus(this.ctx.rpc, params)\n );\n }\n\n async getOutputToken(params: SwapContractRef): Promise<Erc20Asset> {\n return this.log.wrap('getOutputToken', params, async () =>\n getSwapOutputToken(this.ctx.rpc, params)\n );\n }\n\n async allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse> {\n return this.log.wrap('allowWallet', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return allowWallet(this.ctx.api, params);\n });\n }\n}\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { OfferDto } from '@/universal/types/dto/offer';\nimport type { OfferDetailDto } from '@/universal/types/dto/offer-detail';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport { Offer, type OfferId } from '@/universal/types/offer';\nimport { OfferDetail } from '@/universal/types/offer-detail';\nimport {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\nexport async function fetchOffers(\n api: Sender,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Offer[]> {\n return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));\n}\n\nexport async function fetchOffersPage(\n api: Sender,\n params: PaginationParams,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<PaginatedResponse<Offer>> {\n const queryParams = PaginationParams.toQueryParams(params);\n const pageDto = await api.send<PaginatedResponseDto<OfferDto>>({\n method: 'GET',\n url: '/v1/offers',\n queryParams,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return PaginatedResponse.fromDtoPage(pageDto, Offer.listFromDto);\n}\n\nexport async function fetchOfferDetails(\n api: Sender,\n id: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<OfferDetail> {\n const dto = await api.send<OfferDetailDto>({\n method: 'GET',\n url: `/v1/offers/${id}`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return OfferDetail.fromDto(dto);\n}\n","import * as offersApi from '@/universal/api/frontline/offers';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Offer, OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * Reads over CoinList's offers: the catalogue a user can browse, and the full\n * detail of a single offer.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise. On the server, the same reads are\n * additionally available with an app-level token — see\n * `ServerOffersNamespace`.\n */\nexport interface OffersNamespace {\n /**\n * Fetches every offer, iterating through all pages. Prefer {@link listPage}\n * when you render a paginated list yourself.\n */\n list(): Promise<Offer[]>;\n\n /**\n * Fetches a single page of offers. Pass the previous response's\n * `startingAfter` as `after` to advance.\n */\n listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n\n /**\n * Fetches the full detail of one offer, including its options. Note this\n * returns {@link OfferDetail} — a richer model than the {@link Offer}\n * summaries {@link list} returns.\n */\n get(id: OfferId): Promise<OfferDetail>;\n}\n\nexport class OffersNamespaceImpl implements OffersNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'OFFERS');\n }\n\n async list(): Promise<Offer[]> {\n return this.log.wrap('list', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOffers(this.ctx.api, undefined);\n });\n }\n\n async listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOffersPage(this.ctx.api, params, undefined);\n });\n }\n\n async get(id: OfferId): Promise<OfferDetail> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOfferDetails(this.ctx.api, id, undefined);\n });\n }\n}\n","import type {\n EthereumChain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport type { OfferSwapContract } from '@/universal/types/offer-detail';\n\n/**\n * The CoinList contract a swap on `chain` settles through, and therefore the\n * ERC-20 spender the user approves - or `null` where this offer cannot be\n * swapped on that chain.\n *\n * Read off the offer rather than held as a constant because the address varies\n * by environment, not only by chain: beta and production both run\n * `ethereum_sepolia` and deploy a different contract on each, and one constant\n * cannot name both. Frontline resolves it per environment and serves the\n * answer on the offer.\n *\n * The array varies per *offer* as well as per chain - frontline drops a chain\n * whose funding and swap tokens do not both resolve for this asset - so an\n * array read for one symbol must not be reused for another. An empty array\n * means \"cannot swap here\", which is an answer rather than an error.\n *\n * A capability rather than a provider slice, and named for the data it reads\n * rather than for its first caller: `swap_contracts` is an offer field, and\n * `universal-core-isolation-and-sharing` would stop Superstate reusing this if\n * it lived under `checkout/ondo/`. Superstate has not migrated yet - it still\n * reads `superstateSwapContractAddress` - so Ondo is the only caller today.\n */\nexport function swapSpender(\n swapContracts: OfferSwapContract[],\n chain: EthereumChain\n): EvmContractAddress | null {\n return (\n swapContracts.find((contract) => contract.chain === chain)?.address ?? null\n );\n}\n","import type {\n DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/universal/types/dto/document-submission';\n\n/** Document types that can be signed via {@link CoinListClient.submitDocument}. */\nexport type DocumentType = 'tax_certification';\n\n/** Signing-state machine status for a document submission. */\nexport type DocumentSubmissionStatus = DocumentSubmissionStatusDto;\n\n/** The tax form derived from the entity's kind (individual vs company/trust). */\nexport type DocumentFormType = DocumentFormTypeDto;\n\n/** Result of starting (or resuming) a document signing submission. */\nexport type DocumentSubmission = {\n status: DocumentSubmissionStatus;\n formType: DocumentFormType;\n};\n\nexport const DocumentSubmission = {\n fromDto: (dto: DocumentSubmissionDto): DocumentSubmission => ({\n status: dto.status,\n formType: dto.form_type,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/universal/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/universal/types/dto/document-submission';\n\n/**\n * Starts (or resumes) a document signing submission for the given type.\n *\n * `fields` are signing-form values keyed by the document's DocuSeal field\n * names (e.g. `\"Full Name\"`, `\"Permanent Address\"`) and are forwarded\n * verbatim to Passport to pre-fill the document. They are not validated or\n * persisted by Frontline.\n */\nexport async function submitDocument(\n api: Sender,\n documentType: DocumentType,\n fields: Record<string, string>\n): Promise<DocumentSubmission> {\n const dto = await api.send<DocumentSubmissionDto>({\n method: 'POST',\n url: `/v1/documents/${documentType}/submission`,\n body: fields,\n attributes: Attributes.protected(),\n });\n return DocumentSubmission.fromDto(dto);\n}\n","import type { KycTokenDto } from '@/universal/types/dto/kyc';\n\n/**\n * Sumsub verification level name. Determines which screens the Sumsub WebSDK\n * shows (levels are configured in the Sumsub dashboard). The backend\n * prescribes the level (and whether the applicant must be reset first) in the\n * requirement statuses response — clients never compute levels themselves.\n */\nexport type KycLevelName = string;\n\n/** Short-lived Sumsub WebSDK access token scoped to the current user. */\nexport type KycToken = {\n token: string;\n};\n\nexport const KycToken = {\n fromDto: (dto: KycTokenDto): KycToken => ({\n token: dto.token,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { KycTokenDto } from '@/universal/types/dto/kyc';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport { KycToken } from '@/universal/types/kyc';\n\nexport async function createKycToken(\n api: Sender,\n levelName?: KycLevelName,\n reset?: boolean\n): Promise<KycToken> {\n const dto = await api.send<KycTokenDto>({\n method: 'POST',\n url: '/v1/kyc-token',\n body: {\n ...(levelName === undefined ? {} : { level_name: levelName }),\n ...(reset === undefined ? {} : { reset }),\n },\n attributes: Attributes.protected(),\n });\n return KycToken.fromDto(dto);\n}\n","import type {\n PiiAddressDto,\n PiiDto,\n PiiJurisdictionDto,\n PiiKindDto,\n} from '@/universal/types/dto/pii';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/** Whether the PII belongs to an individual or a company/trust entity. */\nexport type PiiKind = PiiKindDto;\n\n/** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */\nexport type Iso2CountryCode = Newtype<string, 'Iso2CountryCode'>;\nexport const Iso2CountryCode = (value: string) => value as Iso2CountryCode;\n\n/** Jurisdiction derived from the entity's address country. */\nexport type PiiJurisdiction = {\n iso2: Iso2CountryCode;\n name: string | null;\n};\n\nexport const PiiJurisdiction = {\n fromDto: (dto: PiiJurisdictionDto): PiiJurisdiction => ({\n iso2: Iso2CountryCode(dto.iso_2),\n name: dto.name,\n }),\n};\n\n/** Permanent address on file for the entity. */\nexport type PiiAddress = {\n street: string | null;\n city: string | null;\n state: string | null;\n postalCode: string | null;\n country: string | null;\n};\n\nexport const PiiAddress = {\n fromDto: (dto: PiiAddressDto): PiiAddress => ({\n street: dto.street,\n city: dto.city,\n state: dto.state,\n postalCode: dto.postal_code,\n country: dto.country,\n }),\n};\n\n/**\n * The current user's PII, used to pre-fill tax forms such as the W-8BEN.\n * Fields the entity hasn't provided are `null`.\n */\nexport type Pii = {\n kind: PiiKind;\n fullLegalName: string | null;\n dateOfBirth: string | null;\n jurisdiction: PiiJurisdiction | null;\n taxId: string | null;\n permanentAddress: PiiAddress;\n};\n\nexport const Pii = {\n fromDto: (dto: PiiDto): Pii => ({\n kind: dto.kind,\n fullLegalName: dto.full_legal_name,\n dateOfBirth: dto.date_of_birth,\n jurisdiction: dto.jurisdiction\n ? PiiJurisdiction.fromDto(dto.jurisdiction)\n : null,\n taxId: dto.tax_id,\n permanentAddress: PiiAddress.fromDto(dto.permanent_address),\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { PiiDto } from '@/universal/types/dto/pii';\nimport { Pii } from '@/universal/types/pii';\n\nexport async function fetchPii(api: Sender): Promise<Pii> {\n const dto = await api.send<PiiDto>({\n method: 'GET',\n url: '/v1/pii',\n attributes: Attributes.protected(),\n });\n return Pii.fromDto(dto);\n}\n","import type {\n RequirementActionNeededReasonDto,\n RequirementDto,\n RequirementStatusesDto,\n RequirementStatusValueDto,\n RequirementTypeDto,\n} from '@/universal/types/dto/requirement';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type RequirementId = Newtype<string, 'RequirementId'>;\nexport const RequirementId = (value: string) => value as RequirementId;\n\nexport type RequirementType = RequirementTypeDto;\nexport type RequirementStatusValue = RequirementStatusValueDto;\nexport type RequirementActionNeededReason = RequirementActionNeededReasonDto;\n\nexport type Requirement = {\n id: RequirementId;\n type: RequirementType;\n details: Record<string, unknown> | null;\n};\n\nexport const Requirement = {\n fromDto: (dto: RequirementDto): Requirement => ({\n id: RequirementId(dto.id),\n type: dto.type,\n details: dto.details,\n }),\n};\n\nexport type RequirementStatusInfo = {\n id: RequirementId;\n status: RequirementStatusValue;\n /** Why the requirement needs action (KYC-backed requirements only). */\n action: RequirementActionNeededReason | null;\n /**\n * The Sumsub verification level that resolves this requirement, prescribed\n * by the backend. Present exactly when an inline Sumsub flow can be started.\n */\n kycLevel?: KycLevelName;\n /**\n * Whether the Sumsub applicant must be reset before starting the flow\n * (redoing an already-approved level, e.g. to update stale PII). Forward to\n * the kyc-token request as-is.\n */\n kycReset?: boolean;\n};\n\nexport const RequirementStatusInfo = {\n fromStatusesDto: (dto: RequirementStatusesDto): RequirementStatusInfo[] =>\n Object.entries(dto.statuses).map(([id, value]) =>\n typeof value === 'string'\n ? { id: RequirementId(id), status: value, action: null }\n : {\n id: RequirementId(id),\n status: value.status,\n action: value.action ?? null,\n kycLevel: value.kyc_level,\n kycReset: value.kyc_reset,\n }\n ),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/universal/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport async function fetchOfferRequirements(\n api: Sender,\n offerId: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Record<OfferOptionId, Requirement[]>> {\n const response = await api.send<OfferRequirementsDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return Object.fromEntries(\n Object.entries(response.options).map(([optionId, list]) => [\n optionId,\n list.data.map(Requirement.fromDto),\n ])\n );\n}\n\nexport async function fetchRequirementStatuses(\n api: Sender,\n offerId: OfferId\n): Promise<RequirementStatusInfo[]> {\n const response = await api.send<RequirementStatusesDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements/statuses`,\n attributes: Attributes.protected(),\n });\n return RequirementStatusInfo.fromStatusesDto(response);\n}\n","import * as documentsApi from '@/universal/api/frontline/documents';\nimport * as kycApi from '@/universal/api/frontline/kyc';\nimport * as piiApi from '@/universal/api/frontline/pii';\nimport * as requirementsApi from '@/universal/api/frontline/requirements';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/universal/types/document-submission';\nimport type { KycLevelName, KycToken } from '@/universal/types/kyc';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Pii } from '@/universal/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport type CreateKycTokenParams = {\n /**\n * Sumsub verification level to run. Defaults to the backend's standard\n * level.\n */\n levelName?: KycLevelName;\n /**\n * Resets the Sumsub applicant first, so an already-approved level can be\n * executed again (e.g. to update stale PII). Pass the `kycReset` value from\n * the requirement status, and never on mid-flow token refreshes.\n */\n reset?: boolean;\n};\n\nexport type SubmitDocumentParams = {\n /** Currently only `tax_certification` (W-8BEN / W-8BEN-E). */\n documentType: DocumentType;\n /**\n * Signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to pre-fill the document.\n */\n fields: Record<string, string>;\n};\n\n/**\n * Everything a user must satisfy before they can participate in an offer:\n * reading the checklist and its live statuses, and the operations that satisfy\n * individual requirements — identity verification (KYC) and tax-document\n * signing.\n *\n * Wallet requirements (`external_wallet`, `whitelisted_wallet`) are satisfied\n * through `WalletsNamespace` instead, since wallet proofs are also used\n * outside the requirements flow.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface RequirementsNamespace {\n /**\n * Fetches the requirements for every option of an offer, grouped by option\n * id. This is the definition of the checklist; {@link statuses} tells you\n * where the user stands against it.\n */\n forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;\n\n /**\n * Fetches the current user's status for each requirement of an offer.\n */\n statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n\n /**\n * Creates a short-lived Sumsub WebSDK access token so an identity\n * verification (KYC) flow can be started, e.g. by the `IdentityVerification`\n * component.\n */\n createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;\n\n /**\n * Fetches the current user's PII, used to pre-fill tax forms such as the\n * W-8BEN. Fields the entity hasn't provided are `null`.\n */\n getPii(): Promise<Pii>;\n\n /**\n * Starts (or resumes) a document signing submission.\n */\n submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;\n}\n\nexport class RequirementsNamespaceImpl implements RequirementsNamespace {\n protected readonly log: InternalLogger;\n\n constructor(protected readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'REQUIREMENTS');\n }\n\n async forOffer(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchOfferRequirements(\n this.ctx.api,\n offerId,\n undefined\n );\n });\n }\n\n async statuses(offerId: OfferId): Promise<RequirementStatusInfo[]> {\n return this.log.wrap('statuses', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.ctx.api, offerId);\n });\n }\n\n async createKycToken(params?: CreateKycTokenParams): Promise<KycToken> {\n return this.log.wrap('createKycToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return kycApi.createKycToken(\n this.ctx.api,\n params?.levelName,\n params?.reset\n );\n });\n }\n\n async getPii(): Promise<Pii> {\n return this.log.wrap('getPii', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return piiApi.fetchPii(this.ctx.api);\n });\n }\n\n async submitDocument(\n params: SubmitDocumentParams\n ): Promise<DocumentSubmission> {\n return this.log.wrap('submitDocument', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return documentsApi.submitDocument(\n this.ctx.api,\n params.documentType,\n params.fields\n );\n });\n }\n}\n","import type { PublicClients } from '@/universal/api/rpc/public-clients';\nimport { ERC20_ABI } from '@/universal/core/shared/blockchain/erc20/abi';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport { parseUint256, type Uint256 } from '@/universal/types/blockchain/core';\n\n/**\n * Generic ERC-20 reads, straight from the chain.\n *\n * Both take their subject as an argument rather than reading `msg.sender`,\n * which is what makes them safe to batch - see `publicClients`.\n */\nexport async function getTokenAllowance(\n clients: PublicClients,\n params: GetTokenAllowanceParams\n): Promise<Uint256> {\n const allowance = await clients(params.chain).readContract({\n address: params.tokenAddress,\n abi: ERC20_ABI,\n functionName: 'allowance',\n args: [params.owner, params.spender],\n });\n return parseUint256(allowance, 'allowance');\n}\n\nexport async function getTokenBalance(\n clients: PublicClients,\n params: GetTokenBalanceParams\n): Promise<Uint256> {\n const balance = await clients(params.chain).readContract({\n address: params.tokenAddress,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [params.owner],\n });\n return parseUint256(balance, 'balanceOf');\n}\n","import { getTokenAllowance, getTokenBalance } from '@/universal/api/rpc/erc20';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Uint256 } from '@/universal/types/blockchain/core';\n\n/**\n * Generic ERC-20 reads shared across on-chain flows (swap, token sale): the\n * allowance an owner has granted a spender, and the raw token balance an owner\n * holds. These are plain token reads, not tied to any single product flow.\n *\n * Read from the chain rather than from a CoinList endpoint. By default that\n * goes through CoinList's authenticated JSON-RPC proxy, so a logged-out caller\n * gets the proxy's `401` - surfaced as a viem error wrapping the SDK's\n * `HttpError`, not as `NotAuthenticatedError`, since viem re-wraps whatever a\n * `Transport` throws. Point `Config.rpc` at your own node for this chain and no\n * CoinList session is involved at all. See {@link RpcConfig}.\n */\nexport interface Erc20Namespace {\n /**\n * Reads the ERC-20 allowance an `owner` has granted a `spender`, as a raw\n * on-chain integer.\n */\n getAllowance(params: GetTokenAllowanceParams): Promise<Uint256>;\n\n /**\n * Reads the raw ERC-20 balance an `owner` holds of a token.\n */\n getBalance(params: GetTokenBalanceParams): Promise<Uint256>;\n}\n\nexport class Erc20NamespaceImpl implements Erc20Namespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ERC20');\n }\n\n async getAllowance(params: GetTokenAllowanceParams): Promise<Uint256> {\n return this.log.wrap('getAllowance', params, async () =>\n getTokenAllowance(this.ctx.rpc, params)\n );\n }\n\n async getBalance(params: GetTokenBalanceParams): Promise<Uint256> {\n return this.log.wrap('getBalance', params, async () =>\n getTokenBalance(this.ctx.rpc, params)\n );\n }\n}\n","import type {\n Chain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport type { OfferToken } from '@/universal/types/offer';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * One `coinlist.tokens.list()` answer, indexed for the lookups a catalogue\n * makes: by the `(chain, address)` pairs `Offer.tokens` carries.\n *\n * The registry is fetched whole - a few hundred tokens across every chain in\n * one request - and then asked one question per offer. Building the index\n * once is what keeps that a map lookup per card rather than a scan of the\n * snapshot per card. The same rule frontline-web and every other host wrote\n * for themselves, kept here so that none of them has to.\n */\nexport type TokenRegistrySnapshot = {\n /** Every token the snapshot lists, in registry order. */\n readonly tokens: readonly TokenMetadata[];\n /** `chain:address` (address lowercased) to its metadata. */\n readonly byKey: ReadonlyMap<string, TokenMetadata>;\n};\n\n/**\n * A token as a lookup names it. `Chain` rather than `EthereumChain` because\n * `OfferToken.chain` is the wider type; a Solana entry simply never matches,\n * since the snapshot models EVM chains only.\n */\ntype TokenKey = { chain: Chain; address: EvmContractAddress };\n\nexport const TokenRegistrySnapshot = {\n /** Indexes a `tokens.list()` result. `[]` is a valid, empty snapshot. */\n fromTokens: (tokens: readonly TokenMetadata[]): TokenRegistrySnapshot => ({\n tokens,\n byKey: new Map(\n tokens.map((token) => [registryKey(token.identifier), token])\n ),\n }),\n\n /**\n * The registry's entry for one token, or `null` when it lists none. The\n * registry is curated, so `null` is an ordinary answer rather than an\n * error, and callers fall back to their own display defaults.\n */\n get: (\n snapshot: TokenRegistrySnapshot,\n token: TokenKey\n ): TokenMetadata | null => snapshot.byKey.get(registryKey(token)) ?? null,\n\n /**\n * The registry's entry for the token an offer is *about*, or `null` when\n * it lists none of them.\n *\n * Resolution follows {@link offerDisplayTokens}: the token a sale\n * distributes or a swap hands over, never the funding token the user pays\n * with. An offer deployed on several chains carries one such token per\n * chain, and the first the registry knows wins - they are the same asset,\n * so any listed one answers for the offer.\n */\n forOffer: (\n snapshot: TokenRegistrySnapshot,\n offer: { tokens: readonly OfferToken[] }\n ): TokenMetadata | null => {\n for (const token of offerDisplayTokens(offer)) {\n const metadata = TokenRegistrySnapshot.get(snapshot, token);\n if (metadata !== null) {\n return metadata;\n }\n }\n return null;\n },\n};\n\n/**\n * The tokens an offer is *about*, most specific first: every `swap` entry,\n * then every `distribution` entry. `funding` entries name what a swap is paid\n * with (USDC, USDT) and never the asset on offer, so they are left out.\n *\n * `swap` outranks `distribution` because a swap product names the asset it\n * hands over precisely, while a sale's distribution entry names the same\n * token for a sale product and is accepted as the fallback. The checkout's\n * per-chain lookup and the catalogue's any-chain lookup both read this\n * ordering, which is why it is stated once, here.\n */\nexport function offerDisplayTokens(offer: {\n tokens: readonly OfferToken[];\n}): OfferToken[] {\n const swaps = offer.tokens.filter((token) => token.role === 'swap');\n const distributions = offer.tokens.filter(\n (token) => token.role === 'distribution'\n );\n return [...swaps, ...distributions];\n}\n\n/**\n * The registry serves EIP-55 checksummed addresses while an offer may carry\n * any casing, so an EVM address compares case-insensitively. Every chain the\n * registry snapshot models is an EVM chain (`TokenMetadata.identifier.chain`\n * is an `EthereumChain`), so lowercasing is safe for every entry it holds.\n */\nfunction registryKey(token: TokenKey): string {\n return `${token.chain}:${token.address.toLowerCase()}`;\n}\n","import { getAddress } from 'viem';\nimport { HttpError, type HttpResponse } from '@/universal/api/http';\nimport { HttpClient } from '@/universal/api/http-client';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Logger } from '@/universal/types/logger';\nimport { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * An {@link HttpClient} against the token registry rather than frontline: no\n * `X-API-Version` (the registry doesn't know it, and the extra header would\n * force a CORS preflight the static CDN cannot answer) and no session\n * middleware (the registry is public).\n */\nexport function createNabuApiClient(\n baseUrl: string,\n logger: Logger | null = null\n): HttpClient {\n return new HttpClient({ baseUrl }, {}, logger);\n}\n\n/**\n * Fetches one token's display metadata from the registry.\n *\n * Returns `null` when the registry does not list the token: the registry is\n * curated, so \"not listed\" is a domain answer, not a failure. The deployment\n * signals it as either a 404 or — Cloudflare Pages' fallback for unknown\n * routes — a 2xx serving its HTML inspection page, so both map to `null`.\n * Everything else throws: a non-2xx status is an {@link HttpError} carrying\n * the registry's response, including a 5xx whose body is an HTML error page.\n */\nexport async function fetchTokenMetadata(\n client: HttpClient,\n token: TokenIdentifier\n): Promise<TokenMetadata | null> {\n // The registry's canonical route uses the EIP-55 checksummed address:\n // lowercase costs a redirect round-trip and wrong mixed casing 404s.\n const address = checksummed(token.address);\n let response: HttpResponse<NabuTokenDto>;\n try {\n response = await client.send<NabuTokenDto>({\n method: 'GET',\n url: `/${token.chain}/token/${address}`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n return null;\n }\n throw error;\n }\n\n if (response.status === 404) {\n return null;\n }\n assertOk(response);\n if (response.body === null) {\n // Not a \"not listed\" signal — those are the 404 and the HTML fallback. A\n // 2xx with a zero-length body is a broken deploy or a mangling\n // intermediary, and mapping it to null would hide a listed token.\n throw new ValidationError(\n `Token registry returned an empty body for token \"${address}\" on \"${token.chain}\"`\n );\n }\n return TokenMetadata.fromDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches all available tokens the registry lists for `chain`, in a single\n * request against the chain snapshot — fetching N tokens one by one would\n * cost N round-trips for a catalogue that arrives whole anyway.\n *\n * Unlike {@link fetchTokenMetadata}, a missing snapshot throws rather than\n * mapping to an empty answer: the registry publishes a snapshot for every\n * chain it knows, so its absence is a deployment problem — and an invented\n * `[]` would render as \"no metadata\" without anyone noticing.\n */\nexport async function fetchTokensMetadata(\n client: HttpClient,\n chain: EthereumChain\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuChainAssetsDto>;\n try {\n response = await client.send<NabuChainAssetsDto>({\n method: 'GET',\n url: `/${chain}/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n `Token registry returned non-JSON for the \"${chain}\" snapshot`\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n `Token registry returned an empty \"${chain}\" snapshot`\n );\n }\n return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches every token the registry lists, across all chains, in a single\n * request against the complete snapshot — the cheapest way to resolve a\n * multi-chain catalogue: one download regardless of how many assets or\n * chains it spans.\n *\n * Chains outside the SDK's type surface (e.g. Solana) are skipped rather\n * than failing the whole snapshot. As with the per-chain snapshot, a missing\n * or empty response throws: the registry always publishes `/assets.json`, so\n * its absence is a deployment problem, not an empty catalogue.\n */\nexport async function fetchAllTokensMetadata(\n client: HttpClient\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuRegistryDto>;\n try {\n response = await client.send<NabuRegistryDto>({\n method: 'GET',\n url: `/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n 'Token registry returned non-JSON for the complete snapshot'\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n 'Token registry returned an empty complete snapshot'\n );\n }\n return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);\n}\n\n/**\n * The registry's deployment answers routes that have no static file with its\n * HTML inspection page and a 2xx status. `makeRequest` surfaces any non-JSON\n * body as an {@link HttpError} carrying the status, so \"2xx but not JSON\" is\n * precisely the registry's \"no such file\" signal — while a non-2xx with an\n * HTML body (a CDN 502/503 page, a proxy block page) keeps its status and\n * stays an outage for the caller to see, never a domain answer.\n */\nfunction isRegistryHtmlFallback(error: unknown): boolean {\n return (\n error instanceof HttpError &&\n error.response.status >= 200 &&\n error.response.status < 300\n );\n}\n\nfunction assertOk(response: HttpResponse<unknown>): void {\n if (response.status < 200 || response.status >= 300) {\n // The full response, never a stripped one: HttpError is public API and\n // callers classify failures off `response.body` (e.g. a 429 vs a 502).\n throw new HttpError(response);\n }\n}\n\nfunction checksummed(address: string): string {\n try {\n return getAddress(address);\n } catch (_) {\n throw new ValidationError(`Invalid EVM contract address: \"${address}\"`);\n }\n}\n","import {\n AssetDecimals,\n AssetSymbol,\n EthereumChain,\n EvmContractAddress,\n type TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuLogoDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * An absolute URL to a logo image in the token registry. Registry image URLs\n * are content-fingerprinted and served immutable, so a value is safe to cache\n * for as long as you hold it.\n */\nexport type TokenLogoUrl = Newtype<string, 'TokenLogoUrl'>;\nexport const TokenLogoUrl = (value: string): TokenLogoUrl =>\n value as TokenLogoUrl;\n\nexport type TokenLogoImage = {\n url: TokenLogoUrl;\n width: number;\n height: number;\n};\n\n/**\n * `VECTOR` is a single SVG. `RASTER` has webp variants at 32/64/128/256/512px\n * widths (never wider than the original): use the smallest one that covers\n * your render size, or `original` if none does.\n */\nexport type TokenLogo =\n | { kind: 'VECTOR'; url: TokenLogoUrl }\n | { kind: 'RASTER'; original: TokenLogoImage; variants: TokenLogoImage[] };\n\nexport const TokenLogo = {\n /** `baseUrl` is the registry origin; registry URLs are root-relative. */\n fromDto: (dto: NabuLogoDto, baseUrl: string): TokenLogo =>\n dto.kind === 'VECTOR'\n ? { kind: 'VECTOR', url: resolveLogoUrl(dto.url, baseUrl) }\n : {\n kind: 'RASTER',\n original: logoImageFromDto(dto.original, baseUrl),\n variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl)),\n },\n};\n\n/**\n * Display metadata for one token, from CoinList's public token registry.\n *\n * Keyed by `(chain, address)` — never by symbol, which can collide. The\n * registry is curated: a token missing from it is an expected answer, not an\n * error, so lookups return `null` rather than throwing.\n */\nexport type TokenMetadata = {\n identifier: TokenIdentifier;\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n logo: TokenLogo;\n /** Dark-theme logo; `null` when the registry configures none. */\n logoDark: TokenLogo | null;\n};\n\nexport const TokenMetadata = {\n /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */\n fromDto: (dto: NabuTokenDto, baseUrl: string): TokenMetadata => {\n assertSupportedSchemaVersion(dto.schema_version);\n return {\n identifier: {\n chain: EthereumChain(dto.chain),\n address: EvmContractAddress(dto.address),\n },\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n logo: TokenLogo.fromDto(dto.logo, baseUrl),\n logoDark:\n dto.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(dto.logo_dark, baseUrl),\n };\n },\n\n /**\n * Maps the complete registry snapshot to every token it lists across the\n * chains this SDK models, skipping native coins and chains outside\n * {@link EthereumChain} (e.g. Solana) rather than failing on them — the\n * registry may serve chains ahead of the SDK's type surface.\n */\n fromRegistryDto: (dto: NabuRegistryDto, baseUrl: string): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return dto.chains.flatMap((chainDto) => {\n let chain: EthereumChain;\n try {\n chain = EthereumChain(chainDto.chain);\n } catch {\n return [];\n }\n return tokensOfChain(chain, chainDto.assets, baseUrl);\n });\n },\n\n /**\n * Maps a chain snapshot to the tokens it lists, skipping the chain's native\n * coin (`kind: 'COIN'`, no contract address).\n */\n fromChainAssetsDto: (\n dto: NabuChainAssetsDto,\n baseUrl: string\n ): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);\n },\n};\n\n/** The token rows of one chain's asset list, skipping the native coin. */\nfunction tokensOfChain(\n chain: EthereumChain,\n assets: NabuChainAssetsDto['assets'],\n baseUrl: string\n): TokenMetadata[] {\n return assets\n .filter((asset) => asset.kind === 'TOKEN' && asset.address !== undefined)\n .map((asset) => ({\n identifier: {\n chain,\n // The filter above cannot narrow `address` for the type checker.\n address: EvmContractAddress(asset.address as string),\n },\n name: asset.name,\n symbol: AssetSymbol(asset.symbol),\n decimals: AssetDecimals(asset.decimals),\n logo: TokenLogo.fromDto(asset.logo, baseUrl),\n logoDark:\n asset.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(asset.logo_dark, baseUrl),\n }));\n}\n\n/**\n * The registry bumps schema_version only on breaking changes, so mapping a\n * newer schema with this code would produce silent garbage — fail instead.\n */\nfunction assertSupportedSchemaVersion(version: number): void {\n if (version !== 1) {\n throw new ValidationError(\n `Unsupported token registry schema_version: ${version}`\n );\n }\n}\n\nconst logoImageFromDto = (\n dto: { url: string; width: number; height: number },\n baseUrl: string\n): TokenLogoImage => ({\n url: resolveLogoUrl(dto.url, baseUrl),\n width: dto.width,\n height: dto.height,\n});\n\nconst resolveLogoUrl = (url: string, baseUrl: string): TokenLogoUrl =>\n TokenLogoUrl(\n url.startsWith('http') ? url : `${baseUrl.replace(/\\/$/, '')}${url}`\n );\n","import type { HttpClient } from '@/universal/api/http-client';\nimport {\n createNabuApiClient,\n fetchAllTokensMetadata,\n fetchTokenMetadata,\n fetchTokensMetadata,\n} from '@/universal/api/nabu/tokens';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type { Logger } from '@/universal/types/logger';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Token display metadata — name, symbol, decimals, and logos — from\n * CoinList's public token registry, keyed by {@link TokenIdentifier} (the\n * same chain + address pairs `Offer.tokens` carries).\n *\n * Unlike the other namespaces, this one is public: no method requires an\n * authenticated user, and nothing here touches the CoinList API — reads go to\n * the registry's CDN.\n */\nexport interface TokensNamespace {\n /**\n * Fetches metadata for one token. Returns `null` when the registry does not\n * list the token — the registry is curated, so callers must fall back to\n * their own display defaults rather than treat this as an error.\n */\n get(token: TokenIdentifier): Promise<TokenMetadata | null>;\n\n /**\n * Fetches every token the registry lists, in one request: the complete\n * snapshot with no `chain`, or one chain's snapshot with it. Prefer this\n * over calling {@link get} in a loop when displaying a catalogue — two\n * hundred tokens across three chains is still a single download.\n *\n * The complete snapshot spans every chain the registry knows; tokens on\n * chains this SDK does not model (e.g. Solana) are left out of the result.\n *\n * Unlike {@link get}, a missing snapshot throws rather than returning `[]`:\n * the registry always publishes the complete snapshot and one per chain it\n * knows, so an absence is a deployment problem, not an empty catalogue.\n */\n list(chain?: EthereumChain): Promise<TokenMetadata[]>;\n}\n\nexport class TokensNamespaceImpl implements TokensNamespace {\n private readonly api: HttpClient;\n private readonly log: InternalLogger;\n\n /**\n * Takes the registry origin rather than a `UniversalNamespaceContext`: the\n * registry is unauthenticated and on its own host, so the frontline sender\n * and the auth check would both be dead weight here.\n */\n constructor(baseUrl: string, logger: Logger | null = null) {\n this.api = createNabuApiClient(baseUrl, logger);\n this.log = internalLogger(logger, 'TOKENS');\n }\n\n get(token: TokenIdentifier): Promise<TokenMetadata | null> {\n return this.log.wrap('get', token, () =>\n fetchTokenMetadata(this.api, token)\n );\n }\n\n list(chain?: EthereumChain): Promise<TokenMetadata[]> {\n return this.log.wrap('list', chain, () =>\n chain === undefined\n ? fetchAllTokensMetadata(this.api)\n : fetchTokensMetadata(this.api, chain)\n );\n }\n}\n","import type { Hex } from 'viem';\nimport {\n type EthereumChain,\n EvmWalletAddress,\n type WalletProtocol,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/universal/types/dto/offer-option-address';\nimport type { Newtype } from '@/universal/types/newtype';\nimport type { OfferId } from '@/universal/types/offer';\nimport { OfferOptionId } from '@/universal/types/offer-detail';\n\n/** Unique identifier for a proven wallet binding on an offer option. */\nexport type OfferOptionAddressId = Newtype<string, 'OfferOptionAddressId'>;\n/** Casts a string into a typed {@link OfferOptionAddressId}. */\nexport const OfferOptionAddressId = (value: string) =>\n value as OfferOptionAddressId;\n\n/**\n * A user's external wallet, proven via a wallet-ownership challenge and bound\n * to an offer option. Returned by the `/v1/offers/:offer_id/addresses` resource.\n */\nexport type OfferOptionAddress = {\n /** Unique binding id. */\n id: OfferOptionAddressId;\n /** Offer option the wallet is bound to. */\n offerOptionId: OfferOptionId;\n /** The connected external wallet address. */\n address: EvmWalletAddress;\n /**\n * Protocol the binding is scoped to. An EVM address binds once per option\n * regardless of which EVM chain proved ownership.\n */\n protocol: WalletProtocol;\n /** When the binding was created. */\n createdAt: Date;\n};\n\n/** Parameters required to connect a proven external wallet to an offer option. */\nexport type ConnectExternalWalletParams = {\n /** Offer the option belongs to. */\n offerId: OfferId;\n /** Offer option to bind the wallet to. */\n offerOptionId: OfferOptionId;\n /** External wallet address that was proven. */\n walletAddress: EvmWalletAddress;\n /** Chain the ownership was proven on. */\n chain: EthereumChain;\n /** Signature of the wallet-ownership challenge message. */\n signature: Hex;\n};\n\nexport const OfferOptionAddress = {\n /** Maps the API DTO into the SDK offer-option-address domain model. */\n fromDto: (dto: OfferOptionAddressDto): OfferOptionAddress => ({\n id: OfferOptionAddressId(dto.id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n address: EvmWalletAddress(dto.address),\n protocol: dto.protocol,\n createdAt: new Date(dto.created_at),\n }),\n};\n\nexport const ConnectExternalWalletParams = {\n /** Maps connect-wallet params into the API DTO payload. */\n toDto: (\n params: ConnectExternalWalletParams\n ): CreateOfferOptionAddressDto => ({\n offer_option_id: params.offerOptionId,\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n }),\n};\n","import type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/universal/types/dto/wallet-ownership-challenge';\n\n/**\n * A single-use ownership challenge returned by `POST /v1/wallet-ownership`.\n * The consumer signs {@link message} with their wallet, then submits the\n * signature to connect the wallet to an offer option.\n */\nexport type WalletOwnershipChallenge = {\n /** The message the wallet must sign. */\n message: string;\n /** When the challenge expires and can no longer be consumed. */\n expiresAt: Date;\n};\n\n/** Fields common to every wallet-ownership challenge request. */\ntype WalletOwnershipChallengeParamsBase = {\n /** Wallet address to prove ownership of. */\n walletAddress: EvmWalletAddress;\n /** Chain the wallet belongs to. */\n chain: EthereumChain;\n};\n\n/**\n * Parameters for requesting a wallet-ownership challenge. Modeled as a\n * discriminated union on `challengeType` so a `siwe` challenge must carry\n * `domain`/`uri`/`statement`, matching the backend contract at compile time.\n */\nexport type CreateWalletOwnershipChallengeParams =\n | (WalletOwnershipChallengeParamsBase & {\n /** A bare message the wallet signs. */\n challengeType: 'plain';\n })\n | (WalletOwnershipChallengeParamsBase & {\n /** Marks this as a Sign-In With Ethereum challenge. */\n challengeType: 'siwe';\n /** The requesting site's hostname (e.g. `example.com`). */\n domain: string;\n /** The requesting site's URI. */\n uri: string;\n /** Human-readable statement shown in the signing prompt. */\n statement: string;\n });\n\n/**\n * How the ownership challenge is framed: a plain message or a Sign-In With\n * Ethereum challenge. Extracted as its own type so SDK consumers can pass it as\n * a standalone param without reaching into the {@link CreateWalletOwnershipChallengeParams}\n * union.\n */\nexport type WalletChallengeType =\n CreateWalletOwnershipChallengeParams['challengeType'];\n\nexport const WalletOwnershipChallenge = {\n /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */\n fromDto: (dto: WalletOwnershipChallengeDto): WalletOwnershipChallenge => ({\n message: dto.message,\n expiresAt: new Date(dto.expires_at),\n }),\n};\n\nexport const CreateWalletOwnershipChallengeParams = {\n /**\n * Maps challenge-request params into the API DTO payload. The discriminated\n * union guarantees SIWE fields are present exactly when `challengeType` is\n * `siwe`, so the mapping narrows on the discriminant.\n */\n toDto: (\n params: CreateWalletOwnershipChallengeParams\n ): CreateWalletOwnershipChallengeDto => {\n switch (params.challengeType) {\n case 'plain':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'plain',\n };\n case 'siwe':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'siwe',\n domain: params.domain,\n uri: params.uri,\n statement: params.statement,\n };\n default: {\n const _exhaustive: never = params;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { OfferOptionAddressDto } from '@/universal/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/universal/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/universal/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\n/**\n * Creates a single-use wallet-ownership challenge. The consumer signs the\n * returned message with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 when params are invalid — an unparseable\n * address, or SIWE fields (`domain`/`uri`/`statement`) that are missing on a\n * `siwe` challenge or present on a `plain` one. The `ApiErrorDto` body\n * carries the validation detail.\n */\nexport async function createWalletOwnershipChallenge(\n api: Sender,\n params: CreateWalletOwnershipChallengeParams\n): Promise<WalletOwnershipChallenge> {\n const dto = await api.send<WalletOwnershipChallengeDto>({\n method: 'POST',\n url: '/v1/wallet-ownership',\n body: CreateWalletOwnershipChallengeParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return WalletOwnershipChallenge.fromDto(dto);\n}\n\n/**\n * Connects a proven external wallet to an offer option. Requires a signature\n * of a previously created, unconsumed wallet-ownership challenge for the same\n * wallet and chain.\n *\n * Single-slot (`external_wallet`) options replace the existing binding in place\n * on re-submit — the binding `id` is stable across a \"change wallet\" — so\n * `max_wallets_reached` only fires for `whitelisted_wallet` options at their cap.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 for every binding failure; discriminate via the\n * `ApiErrorDto` body. Failures with a machine-readable `code`:\n * `wallet_not_whitelisted`, `max_wallets_reached`. Every other binding failure\n * (protocol mismatch, concurrent-connect lock, etc.) is rendered as an opaque\n * generic 422 with no `code`, by backend design. Challenge-state failures\n * surface by message only: no unconsumed challenge, wallet/chain not matching\n * the challenge, expired, or already used. Expired and already-used are not\n * retry-safe — request a fresh challenge first.\n */\nexport async function connectExternalWallet(\n api: Sender,\n params: ConnectExternalWalletParams\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'POST',\n url: `/v1/offers/${params.offerId}/addresses`,\n body: ConnectExternalWalletParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n\n/**\n * Lists the user's proven wallet bindings for a single offer option. Single-slot\n * (`external_wallet`) options return at most one binding; `whitelisted_wallet`\n * options return up to the requirement's `max_wallets`. Works after the offer\n * ends, so partners can read the final bindings.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n */\nexport async function listOptionAddresses(\n api: Sender,\n offerId: OfferId,\n offerOptionId: OfferOptionId\n): Promise<OfferOptionAddress[]> {\n const { data } = await api.send<ListResponseDto<OfferOptionAddressDto>>({\n method: 'GET',\n url: `/v1/offers/${offerId}/addresses`,\n queryParams: { offer_option_id: offerOptionId },\n attributes: Attributes.protected(),\n });\n return data.map(OfferOptionAddress.fromDto);\n}\n\n/**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 with `code` `offer_ended` once the offer has\n * ended (bindings on an offer that has not yet started stay removable), or a\n * 404 when the binding does not exist or is not the caller's.\n */\nexport async function removeOptionAddress(\n api: Sender,\n offerId: OfferId,\n addressId: OfferOptionAddressId\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'DELETE',\n url: `/v1/offers/${offerId}/addresses/${addressId}`,\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n","import * as walletConnectApi from '@/universal/api/frontline/wallet-connect';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\nexport type ListOptionAddressesParams = {\n offerId: OfferId;\n /** Offer option whose bindings to list. */\n offerOptionId: OfferOptionId;\n};\n\nexport type RemoveOptionAddressParams = {\n offerId: OfferId;\n /** Binding to remove, as returned by {@link WalletsNamespace.list}. */\n addressId: OfferOptionAddressId;\n};\n\n/**\n * The user's external wallets: proving ownership of one, binding it to an\n * offer option, and managing those bindings.\n *\n * Ownership proof is a provider-agnostic primitive — the swap flow uses the\n * same challenge to allow-list a wallet — so it lives here rather than being\n * duplicated per product namespace.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface WalletsNamespace {\n /**\n * Creates a single-use challenge the user signs to prove they control a\n * wallet. Supports both `plain` and `siwe` challenges. Pass the signature of\n * the returned {@link WalletOwnershipChallenge.message} to\n * {@link connectExternal}.\n */\n createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n\n /**\n * Binds a proven external wallet to an offer option, using a signature of a\n * challenge from {@link createOwnershipChallenge}.\n */\n connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n\n /**\n * Lists the user's proven wallet bindings for one offer option — the single\n * bound address for an `external_wallet` option, or every allow-listed\n * wallet for a `whitelisted_wallet` option.\n */\n list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;\n\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n */\n remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;\n}\n\nexport class WalletsNamespaceImpl implements WalletsNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'WALLETS');\n }\n\n async createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n return this.log.wrap('createOwnershipChallenge', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(\n this.ctx.api,\n params\n );\n });\n }\n\n async connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n return this.log.wrap('connectExternal', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.connectExternalWallet(this.ctx.api, params);\n });\n }\n\n async list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]> {\n return this.log.wrap('list', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.ctx.api,\n params.offerId,\n params.offerOptionId\n );\n });\n }\n\n async remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress> {\n return this.log.wrap('remove', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.removeOptionAddress(\n this.ctx.api,\n params.offerId,\n params.addressId\n );\n });\n }\n}\n","import type { Hash } from 'viem';\n\n/**\n * A classified wallet or transaction failure. The SDK derives this from\n * whatever the {@link EvmWallet} throws, so hosts get a stable, typed error\n * shape regardless of the wallet library underneath.\n *\n * Lives here rather than beside its classifier because it is the failure half\n * of the {@link EvmWallet} contract, and because both `@/universal` and\n * `@/client` name it: {@link LogCause} carries one, and classifying a thrown\n * error into one needs viem's error classes, which are browser-side.\n */\nexport type WalletError =\n | { type: 'user_rejected' }\n | { type: 'insufficient_funds' }\n | {\n type: 'contract_reverted';\n /**\n * What the contract said, when it said anything: a `require` string, a\n * panic description, a custom error's name, or the four-byte selector of\n * an error the ABI could not decode.\n *\n * `null` when a revert carried no data, since the string the RPC node\n * offers in its place is not the contract's - see `classifyWalletError`.\n * Nullable rather than optional so that every arm has to answer the\n * question: \"it reverted and said nothing\" is a fact about the revert,\n * and a caller should have to read it rather than miss it.\n *\n * Never the custom error's arguments. A name is a compile-time\n * identifier; its operands are runtime values - an address, a balance -\n * and those are `'debug'` material.\n */\n reason: string | null;\n }\n | { type: 'timeout'; hash: Hash }\n | { type: 'unknown'; cause: unknown };\n\n/**\n * A {@link WalletError} as it may be reported above `'debug'`: the\n * classification, never the throw.\n *\n * Only the `unknown` arm differs, and it differs because it is the one arm\n * carrying a value the SDK did not author - the raw error the wallet library\n * threw, whose message and metadata hold the transaction's `from`, `to`,\n * `value` and calldata. The other four carry compile-time constants or a\n * server-minted identifier already, so they pass through as they stand.\n *\n * This exists as a type rather than as a scrub some function remembers to\n * apply: `LogCause` names it, so an arm that grew a raw field would fail the\n * build instead of quietly reaching {@link Logger.error}.\n */\nexport type RedactedWalletError =\n | Exclude<WalletError, { type: 'unknown' }>\n | { type: 'unknown' };\n\nexport const RedactedWalletError = {\n fromWalletError: (error: WalletError): RedactedWalletError =>\n error.type === 'unknown' ? { type: 'unknown' } : error,\n};\n","import type { Hash } from 'viem';\nimport {\n type Erc20ApprovalError,\n submitErc20Approval,\n} from '@/client/core/shared/blockchain/erc20/approval';\nimport { formatRawAmount } from '@/universal';\nimport type { CoinListTokenSaleNamespace } from '@/universal/core/checkout/coin-list/token-sale-namespace';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { AssetId } from '@/universal/types/asset';\nimport type {\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/universal/types/blockchain/wallet-error';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n Blockchain,\n type Participation,\n WalletAddress,\n} from '@/universal/types/providers/coin-list/token-sale';\n\n/**\n * Progress phases emitted by {@link executeTokenSale}, in the order they occur.\n * The `resetting-allowance`/`confirming-allowance-reset` phases only occur when\n * the wallet holds a non-zero allowance that must be reset to 0 first\n * (USDT-style tokens reject non-zero -> non-zero `approve()`).\n */\nexport type TokenSaleExecutionPhase =\n | 'checking-allowance'\n | 'resetting-allowance'\n | 'confirming-allowance-reset'\n | 'approving'\n | 'confirming-approval'\n | 'recording-participation';\n\n/**\n * A step-tagged reason {@link executeTokenSale} failed.\n *\n * The reset-to-zero step (`allowance-reset` / `allowance-reset-reverted`) is\n * reported distinctly from the main approval (`approval` /\n * `approval-reverted`, reused from {@link Erc20ApprovalError}) so consumers can\n * tell which of the two wallet prompts the user rejected or which approval\n * reverted on-chain.\n */\nexport type TokenSaleExecutionError =\n | { step: 'allowance-check' }\n | { step: 'allowance-reset'; cause: WalletError }\n | { step: 'allowance-reset-reverted' }\n | Erc20ApprovalError\n | { step: 'participation'; approvalTxHash: Hash };\n\nexport type TokenSaleExecutionResult =\n | {\n type: 'success';\n participation: Participation;\n approvalTxHash: Hash;\n }\n | { type: 'error'; error: TokenSaleExecutionError };\n\nexport type ExecuteTokenSaleParams = {\n erc20: Erc20Namespace;\n tokenSale: CoinListTokenSaleNamespace;\n wallet: EvmWallet;\n offerId: OfferId;\n offerOptionId: OfferOptionId;\n assetId: AssetId;\n /** ERC-20 the user pays with (e.g. USDC/USDT). */\n paymentTokenAddress: EvmContractAddress;\n /** Contract that pulls the payment — the `approve()` spender. */\n fundingContractAddress: EvmContractAddress;\n chain: EthereumChain;\n amount: BlockchainAmount;\n onProgress?: (phase: TokenSaleExecutionPhase) => void;\n};\n\n/**\n * Executes a token sale end-to-end: submits an ERC-20 `approve()` for the sale\n * amount to the funding contract (resetting a stale non-zero allowance to 0\n * first for USDT-style tokens), waits for it to mine, and records the\n * participation with CoinList. An approval is submitted even when the existing\n * allowance already covers the amount — the backend requires a fresh approval\n * transaction hash for every participation and verifies it on-chain before\n * confirming.\n *\n * Wallet selection/connection and chain switching are the app's responsibility —\n * this operates on an already-connected {@link EvmWallet}. Progress is reported\n * via `onProgress` for consumers rendering loading states.\n */\nexport async function executeTokenSale(\n params: ExecuteTokenSaleParams\n): Promise<TokenSaleExecutionResult> {\n const {\n erc20,\n tokenSale,\n wallet,\n offerId,\n offerOptionId,\n assetId,\n paymentTokenAddress,\n fundingContractAddress,\n chain,\n amount,\n onProgress,\n } = params;\n const emit = (phase: TokenSaleExecutionPhase) => onProgress?.(phase);\n\n // Step 1: Read the current ERC-20 allowance for the funding contract, to\n // decide whether a reset-to-zero is needed before approving. The backend\n // performs the on-chain read, so this needs an authenticated user.\n emit('checking-allowance');\n let currentAllowance: bigint;\n try {\n currentAllowance = await erc20.getAllowance({\n tokenAddress: paymentTokenAddress,\n owner: wallet.address,\n spender: fundingContractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'allowance-check' } };\n }\n\n // Step 2: Approve the sale amount. The backend requires an approval tx hash\n // for every participation, so this happens even when the current allowance\n // already covers the amount. Some ERC-20s (e.g. USDT) reject a non-zero ->\n // non-zero approve(); an existing allowance must first be reset to 0.\n if (currentAllowance > 0n) {\n const reset = await submitErc20Approval({\n wallet,\n tokenAddress: paymentTokenAddress,\n spender: fundingContractAddress,\n chain,\n value: 0n,\n pending: 'resetting-allowance',\n confirming: 'confirming-allowance-reset',\n emit,\n });\n // Re-tag the shared approval error so a reset failure is distinguishable\n // from the main-approval failure that follows (both are ERC-20 approves).\n if (reset.type === 'error') {\n return {\n type: 'error',\n error:\n reset.error.step === 'approval-reverted'\n ? { step: 'allowance-reset-reverted' }\n : { step: 'allowance-reset', cause: reset.error.cause },\n };\n }\n }\n\n const approve = await submitErc20Approval({\n wallet,\n tokenAddress: paymentTokenAddress,\n spender: fundingContractAddress,\n chain,\n value: amount.raw,\n pending: 'approving',\n confirming: 'confirming-approval',\n emit,\n });\n if (approve.type === 'error') {\n return { type: 'error', error: approve.error };\n }\n const approvalTxHash = approve.txHash;\n\n // Step 3: Record the participation with CoinList. The backend verifies the\n // approval transaction on-chain, so this runs only after it has mined.\n // The participations API expects the amount as a decimal token amount (e.g.\n // \"25\" for 25 USDC), NOT raw base units — it rescales by the asset's decimals\n // to check against the on-chain allowance, so passing base units here makes\n // the required allowance overflow and the backend rejects the participation.\n emit('recording-participation');\n let participation: Participation;\n try {\n participation = await tokenSale.createParticipation({\n offerId,\n offerOptionId,\n chain: Blockchain(chain),\n walletAddress: WalletAddress(wallet.address),\n amount: formatRawAmount(amount),\n assetId,\n approvalTransactionHash: approvalTxHash,\n });\n } catch {\n return { type: 'error', error: { step: 'participation', approvalTxHash } };\n }\n\n return { type: 'success', participation, approvalTxHash };\n}\n","import type { InternalLogger } from '@/universal/core/shared/observability/internal-logger';\nimport { describeErrorUnredacted } from '@/universal/core/shared/observability/log-cause';\nimport {\n RedactedWalletError,\n type WalletError,\n} from '@/universal/types/blockchain/wallet-error';\nimport type { LogCause, SafeFields } from '@/universal/types/logger';\n\n/**\n * Runs an on-chain flow with logging around it: every phase at `info`, and the\n * step it stopped at at `error`.\n *\n * On-chain flows are *total* - they return a step-tagged result rather than\n * throwing - so nothing catches them and the `wrap` a namespace method uses\n * would see only a fulfilled promise. This is the flow-shaped equivalent:\n * it pattern-matches the outcome instead of catching.\n *\n * The host's own `onProgress` is called after the log line, so wrapping a flow\n * never changes what the host observes.\n *\n * Every line carries `flow` as a binding and the phase or step as a field, so\n * a host filters on `flow: 'prepareSell'` rather than matching a prefix.\n *\n * `fields` is stamped on every line the flow emits, for what identifies *this*\n * run of it. A flow name alone is not always enough to tell two runs apart:\n * `executeSwap` broadcasts an Ondo buy and an Ondo sell under one name, and a\n * host reading a tracker needs to know which one it is looking at. `SafeFields`\n * rather than a\n * {@link LogBinding} because the set of bindings is closed on purpose - they\n * are the SDK's own correlation keys - and because it is the type that already\n * says a value here is redacted. So it takes an SDK-authored classification\n * (`side`, `chain`) and never an address, an amount or anything else off a\n * param.\n *\n * ```ts\n * withFlowLogging(this.log, 'prepareSell', { side: 'sell' },\n * params.onProgress, (onProgress) =>\n * prepareOndoSell({ ...params, onProgress, ondo: this, erc20: this.erc20 })\n * );\n * // INFO { scope: 'ONDO', flow: 'prepareSell', side: 'sell',\n * // msg: 'flow started' }\n * // INFO { scope: 'ONDO', flow: 'prepareSell', side: 'sell',\n * // phase: 'approving', msg: 'flow advanced' }\n * // ERROR { scope: 'ONDO', flow: 'prepareSell', side: 'sell',\n * // step: 'insufficient-allowance', msg: 'flow failed' }\n * ```\n */\nexport async function withFlowLogging<\n TPhase extends string,\n TResult extends FlowOutcome,\n>(\n log: InternalLogger,\n flow: string,\n fields: SafeFields | undefined,\n onProgress: ((phase: TPhase) => void) | undefined,\n run: (onProgress: (phase: TPhase) => void) => Promise<TResult>\n): Promise<TResult> {\n const flowLog = log.child({ flow });\n flowLog.info(() => ({ msg: 'flow started', fields }));\n\n try {\n const result = await run((phase) => {\n flowLog.info(() => ({\n msg: 'flow advanced',\n fields: { ...fields, phase },\n }));\n onProgress?.(phase);\n });\n logOutcome(flowLog, fields, result);\n return result;\n } catch (error) {\n // A flow that throws is an SDK bug: they are meant to be total. Worth an\n // `error` line of its own, since no step tag describes what happened.\n flowLog.failure(\n () => ({ msg: 'flow threw instead of returning a step', fields }),\n error\n );\n throw error;\n }\n}\n\n/**\n * The shape every on-chain flow result shares. A flow's own result type is\n * richer - a success carries a transaction hash, an error arm carries the\n * chain it could not use - and stays assignable to this.\n */\nexport type FlowOutcome =\n | { readonly type: 'success' }\n | { readonly type: 'error'; readonly error: FlowStep };\n\n/**\n * The step a flow stopped at, and whatever refused, when something did.\n *\n * **`step` is a field on an `error` line, so it must be an SDK-authored\n * literal** - `'insufficient-allowance'`, `'quote-expired'` - and never a\n * value computed from a response, a param or a thrown error. `string` rather\n * than a closed union because the union belongs to each flow: collecting every\n * flow's step tags here would couple this module to all of them and break on\n * each new step. The same holds for `TPhase` in {@link withFlowLogging}, whose\n * phases are logged at `info`.\n *\n * `cause` is rendered verbatim into the `'debug'` line's fields and nowhere\n * else. Above that it reaches {@link LogCause} through `walletCause`, which\n * forwards the classification only.\n */\nexport type FlowStep = {\n readonly step: string;\n readonly cause?: unknown;\n};\n\nfunction logOutcome(\n log: InternalLogger,\n fields: SafeFields | undefined,\n outcome: FlowOutcome\n): void {\n switch (outcome.type) {\n case 'success':\n log.info(() => ({ msg: 'flow succeeded', fields }));\n return;\n case 'error':\n // Two lines, the same pair `failure` emits: verbatim at `'debug'`,\n // classified at `'error'`. This seam cannot call `failure` itself - a\n // total flow returns its cause rather than throwing it - but the\n // guarantee is the same, and it is what makes the classified line\n // affordable: everything dropped from it is one level down.\n log.debug(() => ({\n msg: 'flow failed',\n fields: {\n ...fields,\n step: outcome.error.step,\n error: describeErrorUnredacted(outcome.error.cause),\n },\n }));\n log.error(() => ({\n msg: 'flow failed',\n fields: { ...fields, step: outcome.error.step },\n ...walletCause(outcome.error.cause),\n }));\n return;\n default: {\n // A new outcome arm without a case here is a compile error.\n const _exhaustive: never = outcome;\n return;\n }\n }\n}\n\n/**\n * A flow's error arm often carries the {@link WalletError} that caused it, and\n * that is worth handing to the host classified rather than buried in a step\n * tag. Anything else has no cause worth reporting: the step tag already is one.\n *\n * The `unknown` arm arrives here still holding the raw error the wallet threw,\n * and {@link RedactedWalletError} is what drops it. A viem error outside the\n * four recognised classes carries the transaction's `from`, `to`, `value` and\n * calldata in its message and `metaMessages`, and a {@link LogCause} reaches\n * {@link Logger.error} - the level a host pipes to a tracker. The flow's own\n * returned result still carries it, and so does the paired `debug` line above.\n */\nfunction walletCause(cause: unknown): { cause?: LogCause } {\n if (!isWalletError(cause)) return {};\n return {\n cause: {\n type: 'wallet',\n error: RedactedWalletError.fromWalletError(cause),\n },\n };\n}\n\nconst WALLET_ERROR_TYPES: ReadonlySet<string> = new Set<WalletError['type']>([\n 'user_rejected',\n 'insufficient_funds',\n 'contract_reverted',\n 'timeout',\n 'unknown',\n]);\n\nfunction isWalletError(value: unknown): value is WalletError {\n if (typeof value !== 'object' || value === null) return false;\n const type: unknown = (value as { type?: unknown }).type;\n return typeof type === 'string' && WALLET_ERROR_TYPES.has(type);\n}\n","import {\n type ExecuteTokenSaleParams,\n executeTokenSale,\n type TokenSaleExecutionResult,\n} from '@/client/core/checkout/coin-list/token-sale-flows';\nimport { withFlowLogging } from '@/client/core/shared/observability/flow-logging';\nimport {\n type CoinListTokenSaleNamespace,\n CoinListTokenSaleNamespaceImpl,\n} from '@/universal/core/checkout/coin-list/token-sale-namespace';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\n\n/**\n * The client-side token-sale namespace: everything the shared\n * {@link CoinListTokenSaleNamespace} reads/writes over the API, plus the\n * on-chain flow that drives a wallet (`execute`). The flow takes the wallet\n * and addresses per call; the namespace supplies the participation writes and\n * (via the ERC-20 namespace) the allowance read it depends on.\n */\nexport interface ClientCoinListTokenSaleNamespace\n extends CoinListTokenSaleNamespace {\n /**\n * Runs a token sale end-to-end against the given wallet: ERC-20\n * allowance/approval (resetting a stale non-zero allowance first for\n * USDT-style tokens), approval confirmation, and participation recording.\n *\n * Total: returns a step-tagged {@link TokenSaleExecutionResult} rather than\n * throwing, so each failure can be mapped to UI copy.\n */\n execute(\n params: Omit<ExecuteTokenSaleParams, 'erc20' | 'tokenSale'>\n ): Promise<TokenSaleExecutionResult>;\n}\n\nexport class ClientCoinListTokenSaleNamespaceImpl\n extends CoinListTokenSaleNamespaceImpl\n implements ClientCoinListTokenSaleNamespace\n{\n constructor(\n ctx: UniversalNamespaceContext,\n private readonly erc20: Erc20Namespace\n ) {\n super(ctx);\n }\n\n execute(\n params: Omit<ExecuteTokenSaleParams, 'erc20' | 'tokenSale'>\n ): Promise<TokenSaleExecutionResult> {\n return withFlowLogging(\n this.log,\n 'execute',\n undefined,\n params.onProgress,\n (onProgress) =>\n executeTokenSale({\n ...params,\n onProgress,\n erc20: this.erc20,\n tokenSale: this,\n })\n );\n }\n}\n","import type { Hash, TransactionReceipt } from 'viem';\nimport {\n type Erc20AllowanceError,\n type Erc20AllowancePhase,\n ensureErc20Allowance,\n} from '@/client/core/shared/blockchain/erc20/approval';\nimport { classifyWalletError } from '@/client/core/shared/blockchain/wallet-error';\nimport { apiErrorCode } from '@/universal/api/http';\nimport type { OndoNamespace } from '@/universal/core/checkout/ondo/ondo-namespace';\nimport { swapSpender } from '@/universal/core/offers/swap-contracts';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/universal/types/blockchain/wallet-error';\nimport type { OfferSwapContract } from '@/universal/types/offer-detail';\nimport type {\n OndoBuyTransaction,\n OndoSellTransaction,\n OndoSwapTransactionCore,\n} from '@/universal/types/providers/ondo/ondo';\n\n// ---------------------------------------------------------------------------\n// prepareOndoBuy / prepareOndoSell\n// ---------------------------------------------------------------------------\n\n/**\n * Progress phases emitted while an order is being prepared, in the order they\n * occur. An allowance that already covers the order skips the approval phases.\n */\nexport type OndoSwapPreparationPhase =\n | Erc20AllowancePhase\n | 'building-transaction';\n\n/**\n * A step-tagged reason a preparation failed.\n *\n * Shared by both directions because every arm names a *remedy* rather than a\n * trade: an unsupported chain, a refused approval and a build that would not\n * complete are fixed the same way whichever token was being approved.\n *\n * `insufficient-allowance` is separated from the generic build failure because\n * it is the one with a remedy: frontline reads the allowance before asking\n * Ninshubur for anything, so reaching it means the approval this flow just\n * mined is not the one frontline sees. That is usually its RPC node lagging a\n * block behind, which retrying fixes - so it is a retry, not a re-approval.\n */\nexport type OndoSwapPreparationError =\n | { step: 'unsupported-chain'; chain: EthereumChain }\n | Erc20AllowanceError\n | { step: 'insufficient-allowance' }\n | { step: 'build-transaction' };\n\n/**\n * A prepared order of whichever kind was asked for, or the step that stopped\n * it.\n *\n * Generic in the transaction rather than a union over the two, so a caller\n * that asked for a sale cannot be handed a purchase to narrow.\n */\nexport type OndoSwapPreparationResult<T> =\n | { type: 'success'; transaction: T }\n | { type: 'error'; error: OndoSwapPreparationError };\n\nexport type OndoBuyPreparationResult =\n OndoSwapPreparationResult<OndoBuyTransaction>;\n\nexport type OndoSellPreparationResult =\n OndoSwapPreparationResult<OndoSellTransaction>;\n\n/** What both preparations take, before the two fields whose meaning forks. */\nexport type PrepareOndoSwapParamsCore = {\n ondo: OndoNamespace;\n erc20: Erc20Namespace;\n wallet: EvmWallet;\n /** Ondo's API symbol, e.g. `AAPLon` - not the on-chain `symbol()`. */\n symbol: AssetSymbol;\n /** The chain the swap executes on, which the swap contract lives on. */\n chain: EthereumChain;\n /**\n * The offer's `swap_contracts` - every chain it can be swapped on, with the\n * contract each settles through.\n *\n * Passed in rather than fetched here because it belongs to the offer the\n * caller already holds, and it varies per offer. An array with no entry for\n * `chain` yields `unsupported-chain`, as does an empty one.\n */\n swapContracts: OfferSwapContract[];\n onProgress?: (phase: OndoSwapPreparationPhase) => void;\n};\n\nexport type PrepareOndoBuyParams = PrepareOndoSwapParamsCore & {\n /**\n * The funding token being spent - USDC on `chain`.\n *\n * Approval only - it is not sent to frontline, which resolves both tokens\n * from the offer. The two agreeing is what the allowance check on the far\n * side is confirming.\n */\n tokenAddress: EvmContractAddress;\n /** How much of the funding token to spend, in its base units. */\n amount: BlockchainAmount;\n};\n\nexport type PrepareOndoSellParams = PrepareOndoSwapParamsCore & {\n /**\n * The **asset** being sold, on `chain` - not a stablecoin. A sale delivers\n * the asset, so this is what the swap contract must be approved to pull.\n *\n * Approval only, as on a purchase. Unlike a purchase, the SDK has no\n * registry entry to fall back on: the address comes off the sell quote and\n * nowhere else.\n */\n tokenAddress: EvmContractAddress;\n /** How much of the asset to sell, in the asset's base units. */\n amount: BlockchainAmount;\n};\n\n/**\n * Gets a purchase ready to place: ensures the swap contract may pull `amount`\n * of the funding token, then builds the transaction that spends it.\n *\n * The approval comes first deliberately. Built calldata is only good for about\n * a minute and an approval takes most of one to mine, so building first would\n * hand the user a transaction that had already expired by the time they could\n * act on it - and each build spends an attestation. That ordering is why the\n * spender comes off the offer rather than from the `tx.to` the response\n * returns: `tx.to` arrives too late to approve against.\n *\n * Total: every failure is returned step-tagged rather than thrown, so a caller\n * can map each one to its own copy.\n */\nexport async function prepareOndoBuy(\n params: PrepareOndoBuyParams\n): Promise<OndoBuyPreparationResult> {\n const { ondo, symbol, chain, wallet, amount } = params;\n return prepare(params, () =>\n ondo.buildBuyTransaction({\n symbol,\n chain,\n walletAddress: wallet.address,\n amount,\n })\n );\n}\n\n/**\n * Gets a sale ready to place: ensures the swap contract may pull `amount` of\n * the **asset**, then builds the transaction that spends it.\n *\n * Identical in shape to {@link prepareOndoBuy} and different in what it\n * approves, which is the only thing about a sale that is not the purchase\n * inverted. Same ordering, and for the same reason.\n */\nexport async function prepareOndoSell(\n params: PrepareOndoSellParams\n): Promise<OndoSellPreparationResult> {\n const { ondo, symbol, chain, wallet, amount } = params;\n return prepare(params, () =>\n ondo.buildSellTransaction({\n symbol,\n chain,\n walletAddress: wallet.address,\n amount,\n })\n );\n}\n\n/**\n * Approve, then build - the half both directions share.\n *\n * `build` is a lambda rather than a `side` flag because that is the whole of\n * the difference: everything before it reads the same token the caller named\n * and nothing here has to know which one that was. Not exported, so the only\n * ways in are the two functions above, each of which has already picked its\n * endpoint.\n */\nasync function prepare<T>(\n params: PrepareOndoBuyParams | PrepareOndoSellParams,\n build: () => Promise<T>\n): Promise<OndoSwapPreparationResult<T>> {\n const {\n erc20,\n wallet,\n chain,\n swapContracts,\n tokenAddress,\n amount,\n onProgress,\n } = params;\n const emit = (phase: OndoSwapPreparationPhase) => onProgress?.(phase);\n\n // Step 0: Refuse a chain the offer cannot be swapped on. Approving a zero\n // address would succeed and only revert later, at the user's expense.\n const spender = swapSpender(swapContracts, chain);\n if (spender === null) {\n return { type: 'error', error: { step: 'unsupported-chain', chain } };\n }\n\n // Steps 1-2: Ensure the contract may pull the input (resetting a stale\n // non-zero allowance first, for USDT-style tokens).\n const allowance = await ensureErc20Allowance({\n erc20,\n chain,\n tokenAddress,\n amount,\n wallet,\n spender,\n onProgress: emit,\n });\n if (allowance.type === 'error') return allowance;\n\n // Step 3: Build the transaction. Spends an attestation, so it happens once,\n // last, and only after the allowance is known to cover the order.\n emit('building-transaction');\n try {\n return { type: 'success', transaction: await build() };\n } catch (error) {\n // Frontline checked the allowance itself and disagreed with step 1-2. The\n // approval is mined either way, so the order is not lost - see the type.\n if (apiErrorCode(error) === INSUFFICIENT_ALLOWANCE_CODE) {\n return { type: 'error', error: { step: 'insufficient-allowance' } };\n }\n return { type: 'error', error: { step: 'build-transaction' } };\n }\n}\n\n/** Frontline's error code for a wallet whose allowance is short of `amount`. */\nconst INSUFFICIENT_ALLOWANCE_CODE = 'insufficient_allowance';\n\n// ---------------------------------------------------------------------------\n// executeOndoSwap\n// ---------------------------------------------------------------------------\n\n/** Progress phases emitted by {@link executeOndoSwap}, in order. */\nexport type OndoSwapExecutionPhase = 'broadcasting-swap' | 'confirming-swap';\n\n/**\n * A step-tagged reason {@link executeOndoSwap} failed.\n *\n * `quote-expired` is a refusal to broadcast rather than a failure of a\n * broadcast: it would revert on chain and cost the user gas, and it is fixed\n * by building a fresh transaction.\n */\nexport type OndoSwapExecutionError =\n | { step: 'quote-expired' }\n | { step: 'swap'; cause: WalletError }\n | { step: 'swap-reverted' };\n\nexport type OndoSwapExecutionResult<T> =\n | { type: 'success'; txHash: Hash; transaction: T }\n | { type: 'error'; error: OndoSwapExecutionError };\n\nexport type OndoBuyExecutionResult =\n OndoSwapExecutionResult<OndoBuyTransaction>;\n\nexport type OndoSellExecutionResult =\n OndoSwapExecutionResult<OndoSellTransaction>;\n\nexport type ExecuteOndoSwapParams<T> = {\n wallet: EvmWallet;\n /**\n * The transaction to fill, from {@link prepareOndoBuy},\n * {@link prepareOndoSell}, or either namespace builder.\n *\n * Typed by what it carries rather than by which direction built it:\n * broadcasting reads the calldata, the deadline and nothing else, so a\n * purchase and a sale are the same job here. The concrete type travels\n * through to the result so a caller gets back what it handed in.\n */\n transaction: T;\n /**\n * The chain it was built for.\n *\n * A parameter because the response does not say: it carries calldata and\n * amounts and no identity at all. Pass the same `chain` the transaction was\n * built with - broadcasting to another puts the user's approval on one chain\n * and their transaction on a different one.\n */\n chain: EthereumChain;\n /**\n * Now, as the caller sees it. Taken as a parameter rather than read from the\n * clock so the expiry check is deterministic and testable.\n */\n now?: Date;\n onProgress?: (phase: OndoSwapExecutionPhase) => void;\n};\n\n/**\n * Fills a built transaction, whichever direction built it: broadcasts the\n * calldata Ondo encoded and waits for it to mine.\n *\n * The one function both directions share, because it is the one step that does\n * not depend on which token moves - {@link OndoSwapTransactionCore} is exactly\n * what it reads.\n *\n * The calldata is broadcast verbatim - the SDK never re-encodes it, because\n * the contract verifies a signature over the exact arguments inside it.\n *\n * One check runs first, which would otherwise surface as a reverted\n * transaction the user paid for: the transaction must not have expired, its\n * deadline being encoded in the calldata.\n *\n * Where `tx.to` points is deliberately not checked. Frontline compares it to\n * its own configured contract in `addressed_to_our_contract/2`, and the\n * spender this SDK approved came off the same offer frontline served, so a\n * check here would compare two values derived from one source (ENG-1734).\n */\nexport async function executeOndoSwap<T extends OndoSwapTransactionCore>(\n params: ExecuteOndoSwapParams<T>\n): Promise<OndoSwapExecutionResult<T>> {\n const { wallet, transaction, chain, now = new Date(), onProgress } = params;\n const emit = (phase: OndoSwapExecutionPhase) => onProgress?.(phase);\n\n // Step 0a: Refuse an expired transaction. The deadline is signed into the\n // calldata, so the contract would reject it after the user paid for gas.\n if (now.getTime() >= transaction.expiresAt.getTime()) {\n return { type: 'error', error: { step: 'quote-expired' } };\n }\n\n // Step 1: Broadcast Ondo's transaction as-is.\n emit('broadcasting-swap');\n let txHash: Hash;\n try {\n txHash = await wallet.broadcastRawTx({\n to: transaction.tx.to,\n data: transaction.tx.data,\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'swap', cause: classifyWalletError(error) },\n };\n }\n\n // Step 2: Await the receipt, so the caller only reports a filled order once\n // it actually mined.\n emit('confirming-swap');\n let receipt: TransactionReceipt;\n try {\n receipt = await wallet.awaitTx(txHash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: {\n step: 'swap',\n cause: classifyWalletError(error, { hash: txHash }),\n },\n };\n }\n if (receipt.status !== 'success') {\n return { type: 'error', error: { step: 'swap-reverted' } };\n }\n\n return { type: 'success', txHash, transaction };\n}\n","import {\n type ExecuteOndoSwapParams,\n executeOndoSwap,\n type OndoBuyPreparationResult,\n type OndoSellPreparationResult,\n type OndoSwapExecutionResult,\n type PrepareOndoBuyParams,\n type PrepareOndoSellParams,\n prepareOndoBuy,\n prepareOndoSell,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport { withFlowLogging } from '@/client/core/shared/observability/flow-logging';\nimport {\n type OndoNamespace,\n OndoNamespaceImpl,\n} from '@/universal/core/checkout/ondo/ondo-namespace';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport type { OndoSwapTransactionCore } from '@/universal/types/providers/ondo/ondo';\nimport type { OrderBookSide } from '@/universal/types/trading';\n\n/**\n * The Ondo namespace plus the halves of placing an order that need a wallet,\n * and so cannot live on the shared namespace.\n *\n * Preparing and executing are two calls rather than one because the flow is\n * two user decisions: the trader commits to an amount (approving the spend),\n * reviews firm numbers, and only then places the order. Bundling them would\n * mean approving and filling behind a single button, and would burn most of\n * the transaction's ~60-second life on the approval.\n *\n * Preparing is two methods and executing is one, mirroring where the two\n * directions actually differ: a purchase approves the funding token and a sale\n * approves the asset, while broadcasting reads calldata and a deadline and\n * knows nothing about either.\n *\n * `erc20` is supplied internally, so callers hand over only a wallet and an\n * order.\n */\nexport interface ClientOndoNamespace extends OndoNamespace {\n /**\n * Approves the swap contract to spend `amount` of the funding token, then\n * builds the purchase that spends it. Returns a step-tagged result rather\n * than throwing.\n */\n prepareBuy(\n params: Omit<PrepareOndoBuyParams, 'ondo' | 'erc20'>\n ): Promise<OndoBuyPreparationResult>;\n /**\n * Approves the swap contract to pull `amount` of the **asset**, then builds\n * the sale that delivers it. Returns a step-tagged result rather than\n * throwing.\n */\n prepareSell(\n params: Omit<PrepareOndoSellParams, 'ondo' | 'erc20'>\n ): Promise<OndoSellPreparationResult>;\n /**\n * Broadcasts a built transaction and waits for it to mine, refusing one that\n * has expired. Returns a step-tagged result rather than throwing.\n *\n * Does not check the destination: frontline compares it to the contract it\n * serves on the offer before answering, so the address here and the one it\n * checked are the same value.\n *\n * Takes either direction's transaction and hands the same one back. The\n * `side` tag is required here and not by {@link executeOndoSwap} itself\n * because this is the layer that logs: a flow event without a direction\n * cannot be read back.\n */\n executeSwap<T extends OndoSwapTransactionCore & { side: OrderBookSide }>(\n params: ExecuteOndoSwapParams<T>\n ): Promise<OndoSwapExecutionResult<T>>;\n}\n\nexport class ClientOndoNamespaceImpl\n extends OndoNamespaceImpl\n implements ClientOndoNamespace\n{\n constructor(\n ctx: UniversalNamespaceContext,\n private readonly erc20: Erc20Namespace\n ) {\n super(ctx);\n }\n\n prepareBuy(\n params: Omit<PrepareOndoBuyParams, 'ondo' | 'erc20'>\n ): Promise<OndoBuyPreparationResult> {\n return withFlowLogging(\n this.log,\n 'prepareBuy',\n { side: 'buy' },\n params.onProgress,\n (onProgress) =>\n prepareOndoBuy({\n ...params,\n onProgress,\n ondo: this,\n erc20: this.erc20,\n })\n );\n }\n\n prepareSell(\n params: Omit<PrepareOndoSellParams, 'ondo' | 'erc20'>\n ): Promise<OndoSellPreparationResult> {\n return withFlowLogging(\n this.log,\n 'prepareSell',\n { side: 'sell' },\n params.onProgress,\n (onProgress) =>\n prepareOndoSell({\n ...params,\n onProgress,\n ondo: this,\n erc20: this.erc20,\n })\n );\n }\n\n executeSwap<T extends OndoSwapTransactionCore & { side: OrderBookSide }>(\n params: ExecuteOndoSwapParams<T>\n ): Promise<OndoSwapExecutionResult<T>> {\n return withFlowLogging(\n this.log,\n 'executeSwap',\n { side: params.transaction.side },\n params.onProgress,\n (onProgress) => executeOndoSwap({ ...params, onProgress })\n );\n }\n}\n","import type { Hash, Hex, TransactionReceipt } from 'viem';\nimport {\n type Erc20AllowanceError,\n ensureErc20Allowance,\n} from '@/client/core/shared/blockchain/erc20/approval';\nimport { classifyWalletError } from '@/client/core/shared/blockchain/wallet-error';\nimport { SUPERSTATE_SWAP_ABI } from '@/universal/core/checkout/superstate/blockchain/abi';\nimport {\n computePrice,\n computeSlip,\n} from '@/universal/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport { isSwapAvailable } from '@/universal/core/checkout/superstate/blockchain/status';\nimport { decodeSwappedOutputAmount } from '@/universal/core/checkout/superstate/blockchain/swapped-event';\nimport type { SuperstateSwapNamespace } from '@/universal/core/checkout/superstate/swap-namespace';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { WalletsNamespace } from '@/universal/core/wallets/wallets-namespace';\nimport {\n BlockchainAmount,\n type Bps,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/universal/types/blockchain/wallet-error';\nimport type { OfferId } from '@/universal/types/offer';\nimport type {\n AllowWalletResponse,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\nimport type { WalletOwnershipChallenge } from '@/universal/types/wallet-ownership-challenge';\n\n// ---------------------------------------------------------------------------\n// executeSwap\n// ---------------------------------------------------------------------------\n\n/**\n * Progress phases emitted by {@link executeSwap}, in the order they occur. An\n * allowance that already covers the swap skips the approval phases.\n */\nexport type SwapExecutionPhase =\n | 'checking-status'\n | 'checking-allowance'\n | 'resetting-allowance'\n | 'confirming-allowance-reset'\n | 'approving'\n | 'confirming-approval'\n | 'swapping'\n | 'confirming-swap';\n\n/** A step-tagged reason {@link executeSwap} failed. */\nexport type SwapExecutionError =\n | { step: 'status-check' }\n /**\n * The contract has suspended swapping and may resume. Distinct from\n * `swap-stopped`, which is permanent, so a host can say \"try again shortly\"\n * to one and \"this swap has closed\" to the other.\n */\n | { step: 'swap-paused' }\n | { step: 'swap-stopped' }\n | Erc20AllowanceError\n | { step: 'swap'; cause: WalletError }\n | { step: 'swap-reverted' };\n\nexport type SwapExecutionResult =\n | {\n type: 'success';\n swapTxHash: Hash;\n inputAmount: BlockchainAmount;\n fee: BlockchainAmount;\n /**\n * What the swap produced. Decoded from the `Swapped` event when the\n * receipt yields one, and the quote's estimate when it does not — see\n * `outputAmountConfirmed`.\n */\n outputAmount: BlockchainAmount;\n /**\n * Whether `outputAmount` is what the chain says arrived, rather than what\n * the quote predicted would.\n *\n * `false` is the fallback path: the swap mined, so the money moved and\n * the caller has a settled order to report, but the `Swapped` event would\n * not decode and the estimate is standing in for the fill. A caller that\n * puts the number in front of a user has to say so — an estimate labelled\n * as a confirmed fill is the one way this flow can lie about what\n * happened. `pricePerShare` is derived from the same number and inherits\n * the caveat.\n */\n outputAmountConfirmed: boolean;\n pricePerShare: BlockchainAmount | null;\n recipientAddress: EvmWalletAddress;\n }\n | { type: 'error'; error: SwapExecutionError };\n\nexport type ExecuteSwapParams = {\n swap: SuperstateSwapNamespace;\n erc20: Erc20Namespace;\n wallet: EvmWallet;\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n inputTokenAddress: EvmContractAddress;\n quote: SwapQuote;\n slippageBps: Bps;\n onProgress?: (phase: SwapExecutionPhase) => void;\n};\n\n/**\n * Executes an on-chain swap end-to-end: verifies the contract is not paused,\n * ensures a sufficient ERC-20 allowance (resetting a stale non-zero allowance\n * first for USDT-style tokens), submits the swap, waits for it to mine, and\n * decodes the confirmed output from the `Swapped` event (falling back to the\n * quote's estimate).\n *\n * The wallet is only asked to sign after all read-only checks pass, so a user\n * never signs a transaction the swap would revert. Progress is reported via\n * `onProgress` for consumers rendering loading states.\n */\nexport async function executeSwap(\n params: ExecuteSwapParams\n): Promise<SwapExecutionResult> {\n const {\n swap,\n erc20,\n wallet,\n contractAddress,\n chain,\n inputTokenAddress,\n quote,\n slippageBps,\n onProgress,\n } = params;\n const emit = (phase: SwapExecutionPhase) => onProgress?.(phase);\n\n // The contract pulls the quoted input plus the fee, so both the approval and\n // the swap must authorize the combined amount.\n const inputAmount = BlockchainAmount.add(quote.inputTokenAmount, quote.fee);\n const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;\n\n // Step 0: Refuse to swap when the contract will not accept one. Run before\n // any approval so the user never signs a tx that the swap would revert.\n // `isSwapAvailable`, not `state`: a contract can pause an unrelated\n // operation and go on swapping.\n emit('checking-status');\n let status: SwapStatus;\n try {\n status = await swap.getStatus({ contractAddress, chain });\n } catch {\n // Fail closed: block when we cannot verify the contract status.\n return { type: 'error', error: { step: 'status-check' } };\n }\n if (!isSwapAvailable(status)) {\n return {\n type: 'error',\n error: {\n step: status.state === 'stopped' ? 'swap-stopped' : 'swap-paused',\n },\n };\n }\n\n // Steps 1-2: Ensure the swap contract may pull the input (resetting a stale\n // non-zero allowance first for USDT-style tokens).\n const allowanceRes = await ensureErc20Allowance({\n erc20,\n chain,\n tokenAddress: inputTokenAddress,\n amount: inputAmount,\n wallet,\n spender: contractAddress,\n onProgress: emit,\n });\n if (allowanceRes.type === 'error') {\n return allowanceRes;\n }\n\n // Step 3: Execute the swap.\n emit('swapping');\n let swapTxHash: Hash;\n try {\n swapTxHash = await wallet.writeContract({\n abi: SUPERSTATE_SWAP_ABI,\n address: contractAddress,\n functionName: 'swap',\n args: [inputTokenAddress, inputAmount.raw, minOut],\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'swap', cause: classifyWalletError(error) },\n };\n }\n\n // Step 4: Await the swap receipt.\n emit('confirming-swap');\n let receipt: TransactionReceipt;\n try {\n receipt = await wallet.awaitTx(swapTxHash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: {\n step: 'swap',\n cause: classifyWalletError(error, { hash: swapTxHash }),\n },\n };\n }\n // Only complete when the swap mined successfully (not reverted).\n if (receipt.status !== 'success') {\n return { type: 'error', error: { step: 'swap-reverted' } };\n }\n\n // Step 5: Read the confirmed output from the Swapped event, falling back to\n // the quote estimate when the event can't be decoded. The swap has mined\n // either way, so falling back beats failing an order the user has already\n // paid for — but which of the two this is travels with the number, because\n // only the caller knows whether it is about to be labelled as a fill.\n const decoded = decodeSwappedOutputAmount(\n receipt,\n quote.outputTokenAmount.decimals\n );\n const outputAmount = decoded ?? quote.outputTokenAmount;\n const finalQuote: SwapQuote = { ...quote, outputTokenAmount: outputAmount };\n\n return {\n type: 'success',\n swapTxHash,\n inputAmount: finalQuote.inputTokenAmount,\n fee: finalQuote.fee,\n outputAmount,\n outputAmountConfirmed: decoded !== null,\n pricePerShare: computePrice(finalQuote),\n recipientAddress: wallet.address,\n };\n}\n\n// ---------------------------------------------------------------------------\n// authorizeWallet\n// ---------------------------------------------------------------------------\n\n/** Progress phases emitted by {@link authorizeWallet}, in order. */\nexport type WalletAuthorizationPhase =\n | 'checking-authorization'\n | 'requesting-challenge'\n | 'signing-message'\n | 'submitting-signature'\n | 'broadcasting-transaction'\n | 'awaiting-confirmation'\n | 'verifying-authorization';\n\n/** A step-tagged reason {@link authorizeWallet} failed. */\nexport type WalletAuthorizationError =\n | { step: 'authorization-check' }\n | { step: 'challenge-request' }\n | { step: 'signing'; cause: WalletError }\n | { step: 'allow-wallet' }\n | { step: 'broadcast'; cause: WalletError }\n | { step: 'not-authorized' };\n\nexport type WalletAuthorizationResult =\n | { type: 'success' }\n | { type: 'error'; error: WalletAuthorizationError };\n\nexport type AuthorizeWalletParams = {\n swap: SuperstateSwapNamespace;\n /** Supplies the wallet-ownership challenge the allow-list step consumes. */\n wallets: WalletsNamespace;\n wallet: EvmWallet;\n offerId: OfferId;\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n onProgress?: (phase: WalletAuthorizationPhase) => void;\n};\n\n/**\n * Proves ownership of a wallet and allow-lists it for an offer's swap: checks\n * whether it is already authorized, otherwise signs a challenge, submits it,\n * broadcasts any returned allow-list transaction, and re-verifies on-chain.\n *\n * Wallet selection/connection is the app's responsibility — this operates on an\n * already-connected {@link EvmWallet}. Progress is reported via\n * `onProgress`.\n */\nexport async function authorizeWallet(\n params: AuthorizeWalletParams\n): Promise<WalletAuthorizationResult> {\n const { swap, wallets, wallet, offerId, contractAddress, chain, onProgress } =\n params;\n const emit = (phase: WalletAuthorizationPhase) => onProgress?.(phase);\n const walletAddress = wallet.address;\n\n // Step 1: Check if the wallet is already authorized.\n emit('checking-authorization');\n let authorized: boolean;\n try {\n authorized = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (authorized) return { type: 'success' };\n\n // Step 2: Request a challenge to sign.\n emit('requesting-challenge');\n let challenge: WalletOwnershipChallenge;\n try {\n challenge = await wallets.createOwnershipChallenge({\n walletAddress,\n chain,\n challengeType: 'plain',\n });\n } catch {\n return { type: 'error', error: { step: 'challenge-request' } };\n }\n\n // Step 3: Sign the challenge message.\n emit('signing-message');\n let signature: Hex;\n try {\n signature = await wallet.signMessage(challenge.message);\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'signing', cause: classifyWalletError(error) },\n };\n }\n\n // Step 4: Submit the signature to allow-list the wallet.\n emit('submitting-signature');\n let allow: AllowWalletResponse;\n try {\n allow = await swap.allowWallet({\n offerId,\n walletAddress,\n chain,\n signature,\n });\n } catch {\n return { type: 'error', error: { step: 'allow-wallet' } };\n }\n\n // Step 5: Broadcast the allow-list transaction when one is required.\n if (allow.action === 'broadcast_transaction') {\n emit('broadcasting-transaction');\n let hash: Hash;\n try {\n hash = await wallet.broadcastRawTx({\n to: allow.to,\n data: allow.data,\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'broadcast', cause: classifyWalletError(error) },\n };\n }\n\n emit('awaiting-confirmation');\n try {\n await wallet.awaitTx(hash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: {\n step: 'broadcast',\n cause: classifyWalletError(error, { hash }),\n },\n };\n }\n }\n\n // Step 6: Re-verify authorization on-chain.\n emit('verifying-authorization');\n let reCheck: boolean;\n try {\n reCheck = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (!reCheck) {\n return { type: 'error', error: { step: 'not-authorized' } };\n }\n\n return { type: 'success' };\n}\n","import {\n type AuthorizeWalletParams,\n authorizeWallet,\n type ExecuteSwapParams,\n executeSwap,\n type SwapExecutionResult,\n type WalletAuthorizationResult,\n} from '@/client/core/checkout/superstate/swap-flows';\nimport { withFlowLogging } from '@/client/core/shared/observability/flow-logging';\nimport {\n type SuperstateSwapNamespace,\n SuperstateSwapNamespaceImpl,\n} from '@/universal/core/checkout/superstate/swap-namespace';\nimport type { Erc20Namespace } from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport type { WalletsNamespace } from '@/universal/core/wallets/wallets-namespace';\n\n/**\n * The client-side swap namespace: everything the shared\n * {@link SuperstateSwapNamespace} reads/writes over the API, plus the on-chain flows\n * that drive a wallet (`execute`, `authorizeWallet`). The flows take the\n * wallet and addresses per call; the namespace itself supplies the API reads\n * they depend on.\n */\nexport interface ClientSuperstateSwapNamespace extends SuperstateSwapNamespace {\n /**\n * Runs an on-chain swap end-to-end against the given wallet: status check,\n * ERC-20 allowance/approval, swap submission, and receipt confirmation.\n *\n * Total: returns a step-tagged {@link SwapExecutionResult} rather than\n * throwing, so each failure can be mapped to UI copy.\n */\n execute(\n params: Omit<ExecuteSwapParams, 'swap' | 'erc20'>\n ): Promise<SwapExecutionResult>;\n\n /**\n * Proves ownership of a wallet and allow-lists it for an offer's swap,\n * broadcasting any required allow-list transaction. The ownership challenge\n * comes from `WalletsNamespace`, which this namespace supplies.\n */\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap' | 'wallets'>\n ): Promise<WalletAuthorizationResult>;\n}\n\nexport class ClientSuperstateSwapNamespaceImpl\n extends SuperstateSwapNamespaceImpl\n implements ClientSuperstateSwapNamespace\n{\n constructor(\n ctx: UniversalNamespaceContext,\n private readonly erc20: Erc20Namespace,\n private readonly wallets: WalletsNamespace\n ) {\n super(ctx);\n }\n\n execute(\n params: Omit<ExecuteSwapParams, 'swap' | 'erc20'>\n ): Promise<SwapExecutionResult> {\n return withFlowLogging(\n this.log,\n 'execute',\n undefined,\n params.onProgress,\n (onProgress) =>\n executeSwap({ ...params, onProgress, swap: this, erc20: this.erc20 })\n );\n }\n\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap' | 'wallets'>\n ): Promise<WalletAuthorizationResult> {\n return withFlowLogging(\n this.log,\n 'authorizeWallet',\n undefined,\n params.onProgress,\n (onProgress) =>\n authorizeWallet({\n ...params,\n onProgress,\n swap: this,\n wallets: this.wallets,\n })\n );\n }\n}\n","/**\n * Opens a URL in a new tab, without handing the opened page a reference back\n * to this one (`noopener`) or a referrer.\n *\n * Browsers block popups that are not triggered by a user gesture, so call this\n * from a click handler.\n */\nexport function openInNewTab(url: string): void {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n","import { openInNewTab } from '@/client/core/shared/utils/open-in-new-tab';\nimport {\n COINLIST_BASE_URL,\n VERIFY_IDENTITY_ACCREDITATION_PATH,\n VERIFY_IDENTITY_PATH,\n WALLET_PATH,\n} from '@/universal/api/frontline/config';\nimport {\n type RequirementsNamespace,\n RequirementsNamespaceImpl,\n} from '@/universal/core/requirements/requirements-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport type { Requirement } from '@/universal/types/requirement';\n\n/**\n * The client-side requirements namespace: everything the shared\n * {@link RequirementsNamespace} reads/writes over the API, plus\n * {@link handle}, which sends the user to the CoinList page that satisfies a\n * requirement.\n */\nexport interface ClientRequirementsNamespace extends RequirementsNamespace {\n /**\n * Opens the CoinList page for completing a requirement in a new tab.\n *\n * **No-op for `jurisdiction` and `document`**: neither has a CoinList page\n * to send the user to. A `document` requirement is satisfied in-app instead,\n * via {@link RequirementsNamespace.getPii} and\n * {@link RequirementsNamespace.submitDocument} — e.g. from a custom\n * `onRequirementActionOverride`.\n */\n handle(requirement: Requirement): void;\n}\n\nexport class ClientRequirementsNamespaceImpl\n extends RequirementsNamespaceImpl\n implements ClientRequirementsNamespace\n{\n constructor(\n ctx: UniversalNamespaceContext,\n private readonly coinlistBaseUrl: string | undefined\n ) {\n super(ctx);\n }\n\n handle(requirement: Requirement): void {\n const path = requirementPath(requirement);\n if (path === null) return;\n const baseUrl = this.coinlistBaseUrl ?? COINLIST_BASE_URL;\n openInNewTab(new URL(path, baseUrl).toString());\n }\n}\n\n/** The CoinList page that satisfies a requirement, or `null` when there is none. */\nfunction requirementPath(requirement: Requirement): string | null {\n switch (requirement.type) {\n case 'kyc_approved':\n return VERIFY_IDENTITY_PATH;\n case 'accreditation':\n return VERIFY_IDENTITY_ACCREDITATION_PATH;\n case 'external_wallet':\n case 'whitelisted_wallet':\n return WALLET_PATH;\n // Satisfied outside CoinList's web app: `jurisdiction` is decided by the\n // user's country, `document` is signed in-app via submitDocument.\n case 'jurisdiction':\n case 'document':\n return null;\n // Unreachable for the union as declared - the assignment below fails to\n // compile if a type is added without a case here. It is still reachable at\n // runtime, because `RequirementType` is an unvalidated claim about the\n // backend's JSON: a type the backend ships first arrives as an unknown\n // string. Send the user nowhere rather than to a 404.\n default: {\n const _exhaustive: never = requirement.type;\n return null;\n }\n }\n}\n","import { openInNewTab } from '@/client/core/shared/utils/open-in-new-tab';\nimport { SUPPORT_NEW_TICKET_URL } from '@/universal/api/frontline/config';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * Getting the user to a human at CoinList.\n *\n * This namespace is client-only: it opens a browser tab and has no\n * `CoinListServer` counterpart. No method here requires authentication.\n */\nexport interface ClientSupportNamespace {\n /**\n * Opens the CoinList support ticket page in a new tab. Browsers block\n * popups outside a user gesture, so call this from a click handler.\n */\n contact(): void;\n}\n\nexport class ClientSupportNamespaceImpl implements ClientSupportNamespace {\n private readonly log: InternalLogger;\n\n constructor(logger: Logger | null = null) {\n this.log = internalLogger(logger, 'SUPPORT');\n }\n\n contact(): void {\n // No `wrap`: this opens a tab rather than awaiting anything, so there is\n // no result and no throw to report - only that it happened, and that a\n // popup blocker is the usual reason nothing appears to.\n this.log.child({ op: 'contact' }).info(() => ({\n msg: 'opening the support ticket page',\n fields: { supportUrl: SUPPORT_NEW_TICKET_URL },\n }));\n openInNewTab(SUPPORT_NEW_TICKET_URL);\n }\n}\n","/**\n * Base URL of CoinList's public token registry (Nabu), a static CDN serving\n * token display metadata keyed by chain + contract address. Override per\n * environment via `Config.tokensBaseUrl`.\n */\nexport const NABU_BASE_URL = 'https://asset.coinlist.co';\n","import {\n createPublicClient,\n http,\n type PublicClient,\n type Transport,\n} from 'viem';\nimport type { Sender } from '@/universal/api/http-client';\nimport { frontlineTransport } from '@/universal/api/rpc/frontline-transport';\nimport { viemChain } from '@/universal/core/shared/blockchain/chain';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport type { RpcConfig } from '@/universal/types/config';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * Resolves a chain to the viem `PublicClient` the SDK reads it through.\n *\n * One function rather than a client per read, because the client is where the\n * batching lives: viem's multicall scheduler is keyed on the client's `uid`,\n * so two reads only ever share an `eth_call` if they share a client. Hence the\n * memoisation - it is correctness for batching, not a performance tweak.\n */\nexport type PublicClients = (chain: EthereumChain) => PublicClient;\n\n/**\n * Builds the per-chain `PublicClient` factory, lazily and once per chain.\n *\n * `batch: { multicall: true }` routes concurrent `eth_call`s through\n * Multicall3, whose address comes from viem's own chain definitions (see\n * `viemChain`). A checkout screen mounts several hooks that each read\n * independently - status, authorization, allowance, balance - and they collapse\n * into a single request. Per-call failures survive it: viem calls `aggregate3`\n * with `allowFailure: true` and re-throws each revert on its own call.\n *\n * **A read reached through these clients must take its subject as an\n * argument.** Batching makes `msg.sender` the Multicall3 address rather than\n * the caller, so a view that reads `msg.sender` would answer differently under\n * batching than without. Nothing the SDK reads does - `allowance(owner,\n * spender)`, `balanceOf(account)`, `authorized(user)` all name theirs - and a\n * new read must keep it that way.\n */\nexport function publicClients(\n api: Sender,\n config: RpcConfig | undefined,\n logger: Logger | null = null\n): PublicClients {\n const cache = new Map<EthereumChain, PublicClient>();\n\n return (chain) => {\n const cached = cache.get(chain);\n if (cached) return cached;\n\n const client = createPublicClient({\n chain: viemChain(chain),\n transport: transportFor(api, config?.[chain], chain, logger),\n batch: { multicall: true },\n });\n cache.set(chain, client);\n return client;\n };\n}\n\n/**\n * A host's override, or CoinList's proxy. A string is a URL the SDK wraps in\n * `http()`; a {@link Transport} is used as it stands, so `fallback([...])` and\n * a partner's own transport both pass through untouched.\n *\n * Only the proxy transport is given the logger. A host's own transport reports\n * however they built it, and viem's `http()` has no logging seam, so a host on\n * their own node gets whatever they wired up and nothing from the SDK.\n */\nfunction transportFor(\n api: Sender,\n override: string | Transport | undefined,\n chain: EthereumChain,\n logger: Logger | null\n): Transport {\n if (override === undefined) return frontlineTransport(api, chain, logger);\n return typeof override === 'string' ? http(override) : override;\n}\n","import { custom, RpcRequestError, type Transport } from 'viem';\nimport { HttpError } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * A viem {@link Transport} that speaks JSON-RPC to CoinList's proxy,\n * `POST /v1/chains/{chain}/rpc`.\n *\n * Built over the SDK's own {@link Sender} rather than viem's `http()`, so an\n * on-chain read is an SDK request like any other: it carries the bearer token,\n * renews a stale session on a 401 and retries, is stamped with a request id,\n * and is reported by `HttpClient` by construction. Pointing `http()` at the\n * same URL would mean a second HTTP path through the SDK with none of that.\n * Retrying is the `Sender`'s job alone: viem's own `retryCount` is set to `0`\n * here, because it would otherwise rerun that whole pipeline on top of itself.\n *\n * **This is where the session requirement lives**, and it is the proxy that\n * enforces it: the endpoint is OAuth-gated, so a logged-out read comes back\n * `401` and reaches the caller as viem's `ContractFunctionExecutionError`\n * wrapping the SDK's own `HttpError`. Deliberately *not* translated to\n * `NotAuthenticatedError` - viem re-wraps whatever a `Transport` throws, so the\n * translation would not survive to the caller anyway and would only buy a\n * promise the SDK cannot keep. `classifyLogCause` walks the chain, so the\n * failure still logs as the HTTP failure it is.\n *\n * A partner who supplies their own node via {@link RpcConfig} never reaches\n * this transport and correctly needs no CoinList session.\n *\n * **What its `RPC` lines add over the `HTTP` ones for the same request.** The\n * JSON-RPC method, which the path `/v1/chains/{chain}/rpc` does not carry; and\n * a JSON-RPC error, which usually arrives with HTTP 200 and is therefore an\n * `info` success as far as `HttpClient` can tell.\n *\n * **They do not name the contract call**, and cannot: `publicClients` batches\n * through Multicall3, so one `eth_call` here may be several reads and its `to`\n * is Multicall3 rather than any contract. What is available is on the `debug`\n * line - the raw params, so the target address and the calldata. Which method\n * asked for the read, and whether it reverted, come from the namespace above.\n */\nexport function frontlineTransport(\n api: Sender,\n chain: EthereumChain,\n logger: Logger | null = null\n): Transport {\n const log = internalLogger(logger, 'RPC');\n let nextId = 0;\n\n return custom(\n {\n async request({ method, params }) {\n const id = ++nextId;\n return sendRpc({ api, log, chain, id, method, params });\n },\n },\n // The `Sender` below already retries: `requestRetryMiddleware` makes three\n // attempts at a 5xx and `renewSessionMiddleware` re-sends once after a 401.\n // viem's own default is `retryCount: 3`, and it applies on top: an\n // `HttpError` carries no numeric `code`, so `buildRequest` wraps it in\n // `UnknownRpcError` (`code === -1`) and `shouldRetry` says yes. That reruns\n // the whole pipeline four times - twelve requests for one `eth_call`, and\n // with multicall batching one `eth_call` is a screen's worth of reads. The\n // SDK's retry policy is the one that applies, so viem's is turned off.\n { retryCount: 0 }\n );\n}\n\nasync function sendRpc({\n api,\n log,\n chain,\n id,\n method,\n params,\n}: {\n api: Sender;\n log: InternalLogger;\n chain: EthereumChain;\n /** The JSON-RPC envelope's `id`, unique per request within one transport. */\n id: number;\n method: string;\n /** The JSON-RPC method's own params, passed through untouched. */\n params: unknown;\n}): Promise<unknown> {\n const url = rpcPath(chain);\n const startedAt = Date.now();\n\n // `params` carries calldata, so the envelope is a `'debug'` disclosure.\n log.debug(() => ({\n msg: 'rpc call sent',\n fields: { id, method, chain, params },\n }));\n\n const response = await sendEnvelope(api, url, {\n jsonrpc: '2.0',\n id,\n method,\n params,\n });\n const elapsed = Date.now() - startedAt;\n\n // A JSON-RPC error usually arrives with HTTP 200, so the `Sender` hands it\n // back as a success. viem's own `http()` transport raises `RpcRequestError`\n // here, and every viem action above - `readContract`'s revert decoding\n // included - is written against that.\n if (response.error) {\n const error = new RpcRequestError({\n body: { method, params },\n error: response.error,\n url,\n });\n // `warn`: the node declined, and only the namespace above knows whether\n // that broke anything. The code is the node's own, not a message anyone\n // wrote about this request.\n //\n // The cause is stated rather than classified. viem's `buildRequest` maps a\n // `RpcRequestError` onto one of its `RpcError` subclasses on the way out,\n // which is what `classifyLogCause` recognises - but that happens *above*\n // this throw, so classifying here would answer `'unknown'` for every\n // rejection. This call site knows: the node answered with an error object.\n log.warning(\n () => ({\n msg: 'rpc call rejected',\n cause: { type: 'rpc', reason: 'node-rejected' },\n fields: {\n method,\n chain,\n duration_ms: elapsed,\n 'rpc.error_code': response.error?.code ?? null,\n },\n }),\n error\n );\n throw error;\n }\n\n log.info(() => ({\n msg: 'rpc call',\n fields: { method, chain, duration_ms: elapsed },\n }));\n return response.result;\n}\n\nfunction rpcPath(chain: EthereumChain): string {\n return `/v1/chains/${encodeURIComponent(chain)}/rpc`;\n}\n\n/**\n * Posts the envelope, and reads a JSON-RPC error out of a non-2xx as well.\n *\n * The proxy forwards the node's status alongside its body, so a node that\n * answers a JSON-RPC error with, say, a `400` reaches the `Sender` as an\n * {@link HttpError}. Left as that, the node's error code and any revert data\n * would be lost behind an opaque HTTP failure. An `HttpError` whose body is not\n * a JSON-RPC error - frontline's own `422` for an unsupported chain or a\n * disallowed method, a `401`, a `5xx` - is the HTTP failure it looks like and\n * propagates untouched.\n */\nasync function sendEnvelope(\n api: Sender,\n url: string,\n body: { jsonrpc: '2.0'; id: number; method: string; params: unknown }\n): Promise<JsonRpcResponse> {\n try {\n return await api.send<JsonRpcResponse>({\n method: 'POST',\n url,\n body,\n attributes: Attributes.protected(),\n });\n } catch (error) {\n if (error instanceof HttpError && isJsonRpcError(error.response.body)) {\n return error.response.body;\n }\n throw error;\n }\n}\n\nfunction isJsonRpcError(\n body: unknown\n): body is Required<Pick<JsonRpcResponse, 'error'>> {\n if (typeof body !== 'object' || body === null || !('error' in body)) {\n return false;\n }\n const { error } = body;\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n typeof error.code === 'number'\n );\n}\n\n/**\n * Only what the transport branches on. The SDK does not model the envelope as\n * a DTO: it is JSON-RPC's shape, not frontline's, and every field but these\n * two is handed straight back to viem.\n */\ntype JsonRpcResponse = {\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n};\n","import { EpochMillis, type Millis } from '@/universal/types/time';\n\n/**\n * Reading the clock, as an effect: code that takes a `TimeEff` can be driven\n * by a fake clock in specs instead of real time.\n */\nexport type TimeEff = {\n readonly time: { readonly now: () => EpochMillis };\n};\n\n/** Waiting, as an effect, for the same reason as {@link TimeEff}. */\nexport type DelayEff = {\n readonly delay: (duration: Millis) => Promise<void>;\n};\n\n/** The real clock, wired in at the construction edges. */\nexport const systemTime: TimeEff = { time: { now: EpochMillis.now } };\n\n/** Real waiting on `setTimeout`, wired in at the construction edges. */\nexport const systemDelay: DelayEff = {\n delay: (duration) => new Promise((resolve) => setTimeout(resolve, duration)),\n};\n","import { ApiClient } from '@/client/core/api/api-client';\nimport { ClientAccessToken } from '@/client/core/auth/client-access-token';\nimport {\n type ClientAuthNamespace,\n ClientAuthNamespaceImpl,\n} from '@/client/core/auth/client-auth-namespace';\nimport type { AuthState } from '@/client/core/auth/types';\nimport {\n type ClientCoinListTokenSaleNamespace,\n ClientCoinListTokenSaleNamespaceImpl,\n} from '@/client/core/checkout/coin-list/client-token-sale-namespace';\nimport {\n type ClientOndoNamespace,\n ClientOndoNamespaceImpl,\n} from '@/client/core/checkout/ondo/client-ondo-namespace';\nimport {\n type ClientSuperstateSwapNamespace,\n ClientSuperstateSwapNamespaceImpl,\n} from '@/client/core/checkout/superstate/client-swap-namespace';\nimport {\n type ClientRequirementsNamespace,\n ClientRequirementsNamespaceImpl,\n} from '@/client/core/requirements/client-requirements-namespace';\nimport {\n type ClientSupportNamespace,\n ClientSupportNamespaceImpl,\n} from '@/client/core/support/client-support-namespace';\nimport {\n API_VERSION,\n PUBLIC_API_BASE_URL,\n} from '@/universal/api/frontline/config';\nimport { NABU_BASE_URL } from '@/universal/api/nabu/config';\nimport { publicClients } from '@/universal/api/rpc/public-clients';\nimport {\n type OffersNamespace,\n OffersNamespaceImpl,\n} from '@/universal/core/offers/offers-namespace';\nimport {\n type Erc20Namespace,\n Erc20NamespaceImpl,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport { systemDelay } from '@/universal/core/shared/effects';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type TokensNamespace,\n TokensNamespaceImpl,\n} from '@/universal/core/tokens/tokens-namespace';\nimport {\n type WalletsNamespace,\n WalletsNamespaceImpl,\n} from '@/universal/core/wallets/wallets-namespace';\nimport type { Config } from '@/universal/types/config';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport interface ClientConfig extends Config {\n /**\n * The SDK user must provide this function. It fetches a valid\n * {@link OAuthAccessToken} from your backend. If your backend is in\n * TypeScript, serve `CoinListServer#auth.getAccessToken` from it.\n *\n * Two answers, and they must not be confused:\n *\n * - **Resolve `null`** when there is no session - e.g. your endpoint\n * answered 204. After a 401 the SDK asks once more a second later before\n * it believes it, then signs the user out and calls\n * {@link Config.onSessionExpired}.\n * - **Throw** when you could not find out - a 5xx, a network failure. The\n * SDK keeps its current auth state and fails only the request in hand.\n *\n * So a backend that answers \"no session\" for its own failures turns every\n * outage into a logout. Map those to an error status and throw on it.\n *\n * The SDK calls this at most once at a time: concurrent requests that all\n * need a new token share one call.\n */\n getAccessToken: () => Promise<OAuthAccessToken | null>;\n /**\n * Recommended to leave undefined. Used to change the CoinList environment;\n * default is production.\n */\n coinlistBaseUrl?: string;\n}\n\n/**\n * Browser-side CoinList SDK client.\n *\n * Functionality is grouped into namespaces — `coinlist.offers.list()`,\n * `coinlist.requirements.statuses(offerId)`, `coinlist.superstate.getPreview(...)`.\n * Only {@link init} sits at the top level, because it is lifecycle rather than\n * domain.\n *\n * Unless a namespace says otherwise, its API-backed methods require\n * {@link AuthState} `'logged-in'` and throw {@link NotAuthenticatedError}\n * when the user is not authenticated.\n */\nexport interface CoinListClient {\n /**\n * Authentication: the current {@link AuthState}, and the browser half of the\n * OAuth 2.0 + PKCE flow — e.g. `coinlist.auth.startOAuth()`.\n */\n readonly auth: ClientAuthNamespace;\n\n /**\n * The offer catalogue: listing offers and reading one in full — e.g.\n * `coinlist.offers.get(offerId)`.\n */\n readonly offers: OffersNamespace;\n\n /**\n * What the user must satisfy before participating in an offer: the\n * checklist and its statuses, identity verification (KYC), and tax-document\n * signing — e.g. `coinlist.requirements.statuses(offerId)`.\n *\n * Also exposes `handle(requirement)`, which sends the user to the CoinList\n * page that satisfies a requirement.\n */\n readonly requirements: ClientRequirementsNamespace;\n\n /**\n * The user's external wallets: proving ownership, binding a wallet to an\n * offer option, and managing those bindings — e.g.\n * `coinlist.wallets.connectExternal({ ... })`.\n */\n readonly wallets: WalletsNamespace;\n\n /**\n * Generic ERC-20 reads (token allowance and balance) shared across the\n * on-chain flows — e.g. `coinlist.erc20.getBalance({ ... })`.\n */\n readonly erc20: Erc20Namespace;\n\n /**\n * Token-sale operations: listing/reading/recording participations, plus the\n * on-chain `execute` flow that submits the ERC-20 approval and records the\n * participation over a caller-supplied {@link EvmWallet} — e.g.\n * `coinlist.tokenSale.execute({ ... })`.\n *\n * `execute` drives a caller-supplied wallet and returns a step-tagged result\n * rather than throwing.\n */\n readonly tokenSale: ClientCoinListTokenSaleNamespace;\n\n /**\n * On-chain swap operations: quoting a swap, reading swap-contract state, and\n * allow-listing a proven wallet — e.g.\n * `coinlist.superstate.getOutputToken({ contractAddress, chain })`.\n *\n * The on-chain flows (`execute`, `authorizeWallet`) additionally drive a\n * caller-supplied wallet.\n */\n readonly superstate: ClientSuperstateSwapNamespace;\n\n /**\n * Ondo swaps: whether an asset is tradable right now and what it costs - e.g.\n * `coinlist.ondo.getQuote({ ... })` - plus placing an order, in the two\n * halves the flow actually has: `prepareBuy` / `prepareSell` (approve, then\n * commit a firm quote) and `executeSwap` (broadcast it).\n *\n * Preparing is two methods because the directions approve different tokens -\n * the funding coin on a purchase, the asset on a sale - and commit to\n * different terms; broadcasting is one, because it reads calldata and a\n * deadline and knows about neither.\n *\n * The reads are free to poll while the user edits an order. Preparing is\n * not: committing a quote spends an attestation.\n *\n * No CoinList fee is applied to a read quote; see\n * {@link ClientOndoNamespace}.\n */\n readonly ondo: ClientOndoNamespace;\n\n /**\n * Token display metadata (name, symbol, decimals, logos) from CoinList's\n * public token registry, keyed by chain + contract address — e.g.\n * `coinlist.tokens.get({ chain, address })` for an entry of\n * `Offer.tokens`, or `coinlist.tokens.list()` for the whole\n * catalogue in one request.\n *\n * Public and unauthenticated: unlike the other namespaces, its methods never\n * require a logged-in user.\n */\n readonly tokens: TokensNamespace;\n\n /**\n * Contacting CoinList support — `coinlist.support.contact()`.\n */\n readonly support: ClientSupportNamespace;\n\n /**\n * Calls the provided {@link ClientConfig.getAccessToken} lambda to determine\n * the user's {@link AuthState}. This is called automatically by\n * {@link CoinListProvider}; you typically do not need to call it yourself\n * unless you are using the client outside of the provider.\n *\n * @throws whatever {@link ClientConfig.getAccessToken} throws. The auth\n * state is then left as it was (`'unknown'` on a first call), since a\n * failure to find out is not a logout.\n */\n init(): Promise<AuthState>;\n}\n\nclass CoinListClientImpl implements CoinListClient {\n private readonly accessToken: ClientAccessToken;\n private readonly api: ApiClient;\n readonly auth: ClientAuthNamespace;\n readonly offers: OffersNamespace;\n readonly requirements: ClientRequirementsNamespace;\n readonly wallets: WalletsNamespace;\n readonly erc20: Erc20Namespace;\n readonly tokenSale: ClientCoinListTokenSaleNamespace;\n readonly superstate: ClientSuperstateSwapNamespace;\n readonly ondo: ClientOndoNamespace;\n readonly tokens: TokensNamespace;\n readonly support: ClientSupportNamespace;\n\n constructor(readonly config: ClientConfig) {\n const logger = config.logger ?? null;\n const accessToken = new ClientAccessToken({\n getAccessToken: () => config.getAccessToken(),\n onSessionExpired: config.onSessionExpired,\n logger,\n ...systemDelay,\n });\n this.accessToken = accessToken;\n this.api = new ApiClient(\n {\n baseUrl: config.baseUrl || PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n (trigger) => accessToken.get(trigger),\n logger\n );\n const ctx: UniversalNamespaceContext = {\n api: this.api,\n rpc: publicClients(this.api, config.rpc, config.logger ?? null),\n logger,\n ensureUserAuthenticated: async () => this.ensureAuthenticated(),\n };\n this.auth = new ClientAuthNamespaceImpl(config, {\n getState: () => accessToken.authState(),\n clearAccessToken: () => accessToken.clear(),\n });\n this.offers = new OffersNamespaceImpl(ctx);\n this.requirements = new ClientRequirementsNamespaceImpl(\n ctx,\n config.coinlistBaseUrl\n );\n this.wallets = new WalletsNamespaceImpl(ctx);\n this.erc20 = new Erc20NamespaceImpl(ctx);\n this.tokenSale = new ClientCoinListTokenSaleNamespaceImpl(ctx, this.erc20);\n this.superstate = new ClientSuperstateSwapNamespaceImpl(\n ctx,\n this.erc20,\n this.wallets\n );\n this.ondo = new ClientOndoNamespaceImpl(ctx, this.erc20);\n this.tokens = new TokensNamespaceImpl(\n config.tokensBaseUrl ?? NABU_BASE_URL,\n logger\n );\n this.support = new ClientSupportNamespaceImpl(logger);\n }\n\n async init(): Promise<AuthState> {\n return this.accessToken.load();\n }\n\n private ensureAuthenticated() {\n if (this.accessToken.authState() !== 'logged-in') {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nexport function createCoinListClient(config: ClientConfig): CoinListClient {\n return new CoinListClientImpl(config);\n}\n","'use client';\n\n/**\n * Locale for SDK UI components.\n *\n * Internal: this module is not re-exported from `@/client`. The public seam is\n * the `locale` prop on {@link CoinListProvider}; SDK components read it via\n * {@link useLocale}.\n */\n\nimport { createContext, useContext } from 'react';\n\n/**\n * BCP-47 tag used when the host does not set `locale` on CoinListProvider.\n * A fixed constant (not `navigator.language`) so the server and the client\n * render identically and hydration never mismatches.\n */\nexport const DEFAULT_LOCALE = 'en-US';\n\n/**\n * The locale for SDK UI, as a BCP-47 tag.\n *\n * Deliberately a separate context from `CoinListContext` so changing the locale\n * does not re-render every `useCoinList()` consumer. The context default is\n * {@link DEFAULT_LOCALE}, so a component rendered with no provider above it\n * (unit test, Storybook) still formats sensibly instead of throwing.\n */\nexport const CoinListLocaleContext = createContext<string>(DEFAULT_LOCALE);\n\n/**\n * The locale for SDK UI: the BCP-47 tag passed to `<CoinListProvider locale>`,\n * or `'en-US'` when the host did not set one (or there is no provider above).\n * Never throws, so a component that only needs formatting can still be rendered\n * standalone in tests and Storybook.\n *\n * Feed it to `Intl`, or to the shared formatters in\n * `@/universal/core/shared/blockchain/formatters` (`formatAmount`, `formattedUsdPrice`),\n * which all take an explicit `locale: string`.\n *\n * @example\n * const locale = useLocale();\n * const price = formattedUsdPrice(amount, locale);\n */\nexport function useLocale(): string {\n return useContext(CoinListLocaleContext);\n}\n","'use client';\n\n/**\n * The host's {@link Logger}, made available to the hooks layer.\n *\n * Internal: this module is not re-exported from `@/client`. The public seam is\n * `config.logger` on {@link CoinListProvider}; SDK hooks read it via\n * {@link useLogger}.\n */\n\nimport { createContext, useContext, useMemo } from 'react';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * The host's logger, or `null`.\n *\n * A separate context from `CoinListContext` for the same reason\n * {@link CoinListLocaleContext} is: it never changes after mount, so reading it\n * must not re-render every `useCoinList()` consumer. Publishing it here rather\n * than as a member of `CoinListClient` also keeps the client's public surface\n * namespaces-and-`init()`, which `coinlist-client.contract.ts` pins exactly.\n *\n * Defaults to `null`, so a component rendered with no provider above it (a unit\n * test, a story) simply logs nothing instead of throwing.\n */\nexport const CoinListLoggerContext = createContext<Logger | null>(null);\n\n/**\n * A logger scoped to one hook, under `HOOKS`.\n *\n * Hooks are where a failure stops being an exception and becomes an error\n * state the user sees, and the `reason` a hook picks is exactly the\n * information a stack trace does not carry. Log it here and the host can read\n * a rendered error back to its cause.\n *\n * @example\n * const log = useLogger('useOffers');\n * // ...\n * .catch((error: unknown) => {\n * log.failure(() => ({ msg: 'settled', fields: { state: 'ERROR', reason } }), error);\n * });\n * // { scope: 'HOOKS', hook: 'useOffers', state: 'ERROR',\n * // reason: 'generic-error', cause: { type: 'validation', ... },\n * // msg: 'settled' }\n */\nexport function useLogger(hook: string): InternalLogger {\n const logger = useContext(CoinListLoggerContext);\n return useMemo(\n () => internalLogger(logger, 'HOOKS').child({ hook }),\n [logger, hook]\n );\n}\n","'use client';\n\n/**\n * Styling scope for SDK visual components.\n * Wrap any SDK visual components (CoinListSignInCardContainer, OffersGridContainer, ...) in this so\n * they render fully styled, with all SDK CSS scoped to .clco-sdk-root and no leak\n * to the host page. Does NOT provide the React context: that's CoinListContextProvider.\n *\n * Idempotent: nesting is a no-op. A CoinListStyleScope rendered inside another\n * CoinListStyleScope (directly, or because a self-scoping SDK component renders\n * another one) detects the outer scope via ScopeContext and renders transparently\n * with no second .clco-sdk-root div and no duplicate <style>. So the SDK's own components\n * can each self-scope without stacking wrappers.\n */\n\nimport { createContext, type ReactNode, useContext } from 'react';\nimport { sdkStyles } from '@/client/generated/sdk-styles.gen';\n\n/**\n * True when the subtree is already inside a .clco-sdk-root scope. Internal only,\n * not exported. Read by CoinListStyleScope to collapse nested scopes.\n */\nconst ScopeContext = createContext(false);\n\nexport type CoinListStyleScopeProps = {\n children: ReactNode;\n};\n\n/**\n * Render the SDK styling wrapper: the Inter font links and the .clco-sdk-root div\n * with the self-contained, scoped <style> injection. Mount this around SDK visual\n * components only. Keep it off the host's own pages to avoid styling them.\n *\n * This component self-injects all SDK styles via a <style> tag so consumers do not\n * need to import any CSS files or configure their bundler. Styles are fully scoped\n * to .clco-sdk-root and do not leak to the host page. On React 19 the <style> is a\n * hoistable resource (href + precedence), so it is lifted to <head> and deduplicated\n * across every scope on the page; on React 18 the extra attributes are inert and it\n * renders in place.\n *\n * The wrapper div uses `display: contents` so it generates no box of its own, so an\n * SDK component wrapped by this stays the layout element in the host's flex/grid.\n * Inheritance (font, color, custom-property tokens) and the scoped descendant reset\n * (`.clco-sdk-root *`) still apply through it.\n */\nexport function CoinListStyleScope({ children }: CoinListStyleScopeProps) {\n const alreadyScoped = useContext(ScopeContext);\n if (alreadyScoped) {\n // Already inside a .clco-sdk-root: render transparently so nested scopes\n // (e.g. OffersGrid → OfferSaleCard, both self-scoping) collapse to a single scope.\n return <>{children}</>;\n }\n\n return (\n <>\n {/*\n Inter font. React 19 hoists <link rel=\"preconnect\"> to <head> and dedupes it.\n A <link rel=\"stylesheet\"> is only hoisted/deduped when it carries a\n `precedence` prop; without one (as here) it renders in place, which is fine:\n the browser still loads it once. Using <link> rather than @import inside the\n injected <style> because @import in an injected style element is unreliable\n cross-browser.\n */}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link\n rel=\"preconnect\"\n href=\"https://fonts.gstatic.com\"\n crossOrigin=\"anonymous\"\n />\n <link\n rel=\"stylesheet\"\n href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\"\n />\n {/*\n All SDK CSS is injected here as a self-contained <style> resource.\n - Classes are prefixed clco-sdk-* to prevent collisions with the host app.\n - Design tokens are scoped to .clco-sdk-root (not :root) to prevent leaking.\n - Tailwind Preflight is excluded; a minimal scoped reset lives in globals.css.\n - `href` + `precedence` make it a React 19 hoistable stylesheet: one copy in\n <head> regardless of how many scopes/components render.\n */}\n <div className=\"clco-sdk-root\" style={{ display: 'contents' }}>\n <style\n href=\"clco-sdk-styles\"\n precedence=\"default\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: sdkStyles is build-time compiled CSS, not user input\n dangerouslySetInnerHTML={{ __html: sdkStyles }}\n />\n <ScopeContext.Provider value={true}>{children}</ScopeContext.Provider>\n </div>\n </>\n );\n}\n","// AUTO-GENERATED — do not edit manually.\n// Run `npm run build:css` to regenerate after CSS changes.\nexport const sdkStyles = \"/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--clcosdk-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace;--clcosdk-color-red-400:oklch(70.4% .191 22.216);--clcosdk-color-red-500:oklch(63.7% .237 25.331);--clcosdk-color-amber-500:oklch(76.9% .188 70.08);--clcosdk-color-gray-400:oklch(70.7% .022 261.325);--clcosdk-color-gray-500:oklch(55.1% .027 264.364);--clcosdk-color-black:#000;--clcosdk-spacing:.25rem;--clcosdk-container-sm:24rem;--clcosdk-container-md:28rem;--clcosdk-container-xl:36rem;--clcosdk-text-xs:.75rem;--clcosdk-text-xs--line-height:calc(1 / .75);--clcosdk-text-sm:.875rem;--clcosdk-text-sm--line-height:calc(1.25 / .875);--clcosdk-text-base:1rem;--clcosdk-text-base--line-height:calc(1.5 / 1);--clcosdk-text-lg:1.125rem;--clcosdk-text-lg--line-height:calc(1.75 / 1.125);--clcosdk-font-weight-normal:400;--clcosdk-font-weight-medium:500;--clcosdk-font-weight-semibold:600;--clcosdk-radius-md:.375rem;--clcosdk-radius-lg:.5rem;--clcosdk-radius-xl:.75rem;--clcosdk-radius-2xl:1rem;--clcosdk-ease-out:cubic-bezier(0, 0, .2, 1);--clcosdk-ease-in-out:cubic-bezier(.4, 0, .2, 1);--clcosdk-animate-spin:spin 1s linear infinite;--clcosdk-animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--clcosdk-color-brand-primary:var(--color-brand-primary)}}@layer base{.clco-sdk-root{--color-brand-primary:#171717;--color-brand-primary-hover:#000;--color-brand-primary-active:#262626;--color-accent:#2b3a67;--color-accent-hover:#243057;--color-accent-active:#1d2647;--color-accent-focus:#c7d2fe;--color-accent-subtle:#eef1f8;--color-text-primary:#171717;--color-text-secondary:#8c8c8c;--color-text-disabled:#d1d1d1;--color-text-inverse:#fff;--color-background:#fff;--color-surface:#fafafa;--color-section:#f3f3f3;--color-border:#e5e5e5;--color-divider:#ececec;--color-overlay:#00000080;--color-positive:#15803d;--color-positive-subtle:#dcfce7;--color-negative:#dc2626;--color-negative-subtle:#fee2e2;--color-success:#2c8c5e;--color-success-subtle:#e6f4ec;--color-success-border:#cfe9db;--color-warning:#e08a1a;--color-warning-subtle:#fff7ed;--color-warning-border:#fdead7;--color-error:#b42318;--color-error-subtle:#feeceb;--color-error-border:#fbd5d2;--shadow-step-active:0px 0px 10px 0px #0000001a;--shadow-dialog:0px 8px 32px 0px #0000001a;--btn-primary-gradient:linear-gradient(180deg, #262626 0%, #1c1c1c 50%, #0f0f0f 100%);--btn-primary-shadow:inset 0px -1px 3px 0px #00000059, inset 0px 1px 2px 0px #ffffff2e, inset 0px 1px 0px 0px #ffffff1a;--sale-card-surface:linear-gradient(to top, #0a0a0a 0%, #1a1a1a 100%);--color-sale-card-text:#f4f4f5;--color-sale-card-text-muted:#a1a1aa;--color-sale-card-text-strong:#fff;--color-sale-card-border:#ffffff40;--color-sale-card-chrome-border:#ffffff4d;--color-sale-card-chrome-bg:#ffffff26;--color-sale-card-chrome-emphasis-border:#fff6;--color-sale-card-chrome-emphasis-bg:#ffffff40;--color-sale-card-focus-ring:#ffffff80;--display-on-light:block;--display-on-dark:none}@media (prefers-color-scheme:dark){.clco-sdk-root:not(:where(.light,.light *)){--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140;--shadow-step-active:0px 0px 10px 0px #00000080;--shadow-dialog:0px 8px 32px 0px #0009;--btn-primary-gradient:linear-gradient(180deg, #fafafa 0%, #f0f0f0 50%, #e4e4e7 100%);--btn-primary-shadow:inset 0px -1px 3px 0px #0000001f, inset 0px 1px 2px 0px #fff9, inset 0px 1px 0px 0px #fff6;--display-on-light:none;--display-on-dark:block}}:where(.dark,.dark *) .clco-sdk-root{--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140;--shadow-step-active:0px 0px 10px 0px #00000080;--shadow-dialog:0px 8px 32px 0px #0009;--btn-primary-gradient:linear-gradient(180deg, #fafafa 0%, #f0f0f0 50%, #e4e4e7 100%);--btn-primary-shadow:inset 0px -1px 3px 0px #0000001f, inset 0px 1px 2px 0px #fff9, inset 0px 1px 0px 0px #fff6;--display-on-light:none;--display-on-dark:block}.clco-sdk-root{color:var(--color-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Inter,sans-serif}.clco-sdk-root *,.clco-sdk-root :before,.clco-sdk-root :after{box-sizing:border-box}.clco-sdk-root button{appearance:none;cursor:pointer;font:inherit;color:inherit;background:0 0;border:none;padding:0}.clco-sdk-root input,.clco-sdk-root textarea,.clco-sdk-root select{font:inherit;color:inherit;background:0 0;border:none;border-radius:0;padding:0}.clco-sdk-root a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}.clco-sdk-root ul,.clco-sdk-root ol{margin:0;padding:0;list-style:none}.clco-sdk-root h1,.clco-sdk-root h2,.clco-sdk-root h3,.clco-sdk-root h4,.clco-sdk-root h5,.clco-sdk-root h6,.clco-sdk-root p,.clco-sdk-root figure,.clco-sdk-root blockquote,.clco-sdk-root dl,.clco-sdk-root dd,.clco-sdk-root pre{margin:0}.clco-sdk-root img,.clco-sdk-root svg{max-width:100%;display:block}@keyframes clco-status-ping{0%{opacity:.7;transform:scale(1)}75%,to{opacity:0;transform:scale(3.25)}}.clco-sdk-root .clcosdk-status-dot-ping{animation:1.6s cubic-bezier(0,0,.2,1) infinite clco-status-ping}.clco-sdk-root .clcosdk-on-light{display:var(--display-on-light)}.clco-sdk-root .clcosdk-on-dark{display:var(--display-on-dark)}@media (prefers-reduced-motion:reduce){.clco-sdk-root .clcosdk-status-dot-ping{opacity:0;animation:none}}}@layer components;@layer utilities{.clcosdk\\\\:pointer-events-none{pointer-events:none}.clcosdk\\\\:invisible{visibility:hidden}.clcosdk\\\\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.clcosdk\\\\:absolute{position:absolute}.clcosdk\\\\:fixed{position:fixed}.clcosdk\\\\:relative{position:relative}.clcosdk\\\\:inset-0{inset:0}.clcosdk\\\\:top-1\\\\/2{top:50%}.clcosdk\\\\:top-4{top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:top-full{top:100%}.clcosdk\\\\:-right-0\\\\.5{right:calc(var(--clcosdk-spacing) * -.5)}.clcosdk\\\\:right-4{right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:right-\\\\[-14\\\\%\\\\]{right:-14%}.clcosdk\\\\:-bottom-0\\\\.5{bottom:calc(var(--clcosdk-spacing) * -.5)}.clcosdk\\\\:bottom-full{bottom:100%}.clcosdk\\\\:left-1\\\\/2{left:50%}.clcosdk\\\\:z-0{z-index:0}.clcosdk\\\\:z-10{z-index:10}.clcosdk\\\\:z-50{z-index:50}.clcosdk\\\\:order-1{order:1}.clcosdk\\\\:order-2{order:2}.clcosdk\\\\:-mx-2{margin-inline:calc(var(--clcosdk-spacing) * -2)}.clcosdk\\\\:mt-2{margin-top:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:mt-4{margin-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:mt-auto{margin-top:auto}.clcosdk\\\\:mb-2{margin-bottom:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:flex{display:flex}.clcosdk\\\\:grid{display:grid}.clcosdk\\\\:inline-flex{display:inline-flex}.clcosdk\\\\:size-2{width:calc(var(--clcosdk-spacing) * 2);height:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:size-3{width:calc(var(--clcosdk-spacing) * 3);height:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:size-3\\\\.5{width:calc(var(--clcosdk-spacing) * 3.5);height:calc(var(--clcosdk-spacing) * 3.5)}.clcosdk\\\\:size-4{width:calc(var(--clcosdk-spacing) * 4);height:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:size-5{width:calc(var(--clcosdk-spacing) * 5);height:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:size-10{width:calc(var(--clcosdk-spacing) * 10);height:calc(var(--clcosdk-spacing) * 10)}.clcosdk\\\\:size-12{width:calc(var(--clcosdk-spacing) * 12);height:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:size-16{width:calc(var(--clcosdk-spacing) * 16);height:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\\\:size-24{width:calc(var(--clcosdk-spacing) * 24);height:calc(var(--clcosdk-spacing) * 24)}.clcosdk\\\\:size-\\\\[15rem\\\\]{width:15rem;height:15rem}.clcosdk\\\\:size-full{width:100%;height:100%}.clcosdk\\\\:h-1{height:var(--clcosdk-spacing)}.clcosdk\\\\:h-3{height:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:h-4{height:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:h-5{height:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:h-6{height:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:h-8{height:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:h-9{height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:h-10{height:calc(var(--clcosdk-spacing) * 10)}.clcosdk\\\\:h-11{height:calc(var(--clcosdk-spacing) * 11)}.clcosdk\\\\:h-12{height:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:h-14{height:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:h-\\\\[1em\\\\]{height:1em}.clcosdk\\\\:h-\\\\[18px\\\\]{height:18px}.clcosdk\\\\:h-\\\\[54px\\\\]{height:54px}.clcosdk\\\\:h-\\\\[71px\\\\]{height:71px}.clcosdk\\\\:h-auto{height:auto}.clcosdk\\\\:h-full{height:100%}.clcosdk\\\\:h-px{height:1px}.clcosdk\\\\:max-h-\\\\[92vh\\\\]{max-height:92vh}.clcosdk\\\\:max-h-full{max-height:100%}.clcosdk\\\\:min-h-0{min-height:0}.clcosdk\\\\:min-h-9{min-height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:min-h-40{min-height:calc(var(--clcosdk-spacing) * 40)}.clcosdk\\\\:min-h-\\\\[1lh\\\\]{min-height:1lh}.clcosdk\\\\:min-h-screen{min-height:100vh}.clcosdk\\\\:w-1{width:var(--clcosdk-spacing)}.clcosdk\\\\:w-1\\\\/2{width:50%}.clcosdk\\\\:w-2\\\\/5{width:40%}.clcosdk\\\\:w-3\\\\/5{width:60%}.clcosdk\\\\:w-4{width:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:w-5{width:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:w-6{width:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:w-8{width:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:w-10{width:calc(var(--clcosdk-spacing) * 10)}.clcosdk\\\\:w-12{width:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:w-16{width:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\\\:w-20{width:calc(var(--clcosdk-spacing) * 20)}.clcosdk\\\\:w-24{width:calc(var(--clcosdk-spacing) * 24)}.clcosdk\\\\:w-28{width:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\\\:w-32{width:calc(var(--clcosdk-spacing) * 32)}.clcosdk\\\\:w-40{width:calc(var(--clcosdk-spacing) * 40)}.clcosdk\\\\:w-48{width:calc(var(--clcosdk-spacing) * 48)}.clcosdk\\\\:w-80{width:calc(var(--clcosdk-spacing) * 80)}.clcosdk\\\\:w-96{width:calc(var(--clcosdk-spacing) * 96)}.clcosdk\\\\:w-\\\\[16px\\\\]{width:16px}.clcosdk\\\\:w-\\\\[28rem\\\\]{width:28rem}.clcosdk\\\\:w-\\\\[36rem\\\\]{width:36rem}.clcosdk\\\\:w-\\\\[448px\\\\]{width:448px}.clcosdk\\\\:w-\\\\[calc\\\\(100\\\\%\\\\+16px\\\\)\\\\]{width:calc(100% + 16px)}.clcosdk\\\\:w-component{width:448px}.clcosdk\\\\:w-fit{width:fit-content}.clcosdk\\\\:w-full{width:100%}.clcosdk\\\\:w-max{width:max-content}.clcosdk\\\\:max-w-\\\\[16rem\\\\]{max-width:16rem}.clcosdk\\\\:max-w-\\\\[28rem\\\\]{max-width:28rem}.clcosdk\\\\:max-w-\\\\[30rem\\\\]{max-width:30rem}.clcosdk\\\\:max-w-\\\\[40rem\\\\]{max-width:40rem}.clcosdk\\\\:max-w-\\\\[56rem\\\\]{max-width:56rem}.clcosdk\\\\:max-w-\\\\[64rem\\\\]{max-width:64rem}.clcosdk\\\\:max-w-\\\\[760px\\\\]{max-width:760px}.clcosdk\\\\:max-w-full{max-width:100%}.clcosdk\\\\:max-w-md{max-width:var(--clcosdk-container-md)}.clcosdk\\\\:max-w-sm{max-width:var(--clcosdk-container-sm)}.clcosdk\\\\:max-w-xl{max-width:var(--clcosdk-container-xl)}.clcosdk\\\\:min-w-0{min-width:0}.clcosdk\\\\:flex-1{flex:1}.clcosdk\\\\:shrink-0{flex-shrink:0}.clcosdk\\\\:-translate-x-1\\\\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\\\:-translate-y-1\\\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\\\:rotate-90{rotate:90deg}.clcosdk\\\\:rotate-180{rotate:180deg}.clcosdk\\\\:animate-pulse{animation:var(--clcosdk-animate-pulse)}.clcosdk\\\\:animate-spin{animation:var(--clcosdk-animate-spin)}.clcosdk\\\\:cursor-pointer{cursor:pointer}.clcosdk\\\\:cursor-text{cursor:text}.clcosdk\\\\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.clcosdk\\\\:grid-rows-\\\\[0fr\\\\]{grid-template-rows:0fr}.clcosdk\\\\:grid-rows-\\\\[1fr\\\\]{grid-template-rows:1fr}.clcosdk\\\\:flex-col{flex-direction:column}.clcosdk\\\\:flex-row{flex-direction:row}.clcosdk\\\\:flex-wrap{flex-wrap:wrap}.clcosdk\\\\:items-center{align-items:center}.clcosdk\\\\:items-end{align-items:flex-end}.clcosdk\\\\:items-start{align-items:flex-start}.clcosdk\\\\:justify-between{justify-content:space-between}.clcosdk\\\\:justify-center{justify-content:center}.clcosdk\\\\:justify-end{justify-content:flex-end}.clcosdk\\\\:justify-start{justify-content:flex-start}.clcosdk\\\\:gap-1{gap:var(--clcosdk-spacing)}.clcosdk\\\\:gap-1\\\\.5{gap:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:gap-2{gap:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:gap-2\\\\.5{gap:calc(var(--clcosdk-spacing) * 2.5)}.clcosdk\\\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}:where(.clcosdk\\\\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\\\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\\\:divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.clcosdk\\\\:divide-divider>:not(:last-child)){border-color:var(--color-divider)}.clcosdk\\\\:self-start{align-self:flex-start}.clcosdk\\\\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.clcosdk\\\\:overflow-hidden{overflow:hidden}.clcosdk\\\\:overflow-y-auto{overflow-y:auto}.clcosdk\\\\:rounded{border-radius:.25rem}.clcosdk\\\\:rounded-2xl{border-radius:var(--clcosdk-radius-2xl)}.clcosdk\\\\:rounded-\\\\[20px\\\\]{border-radius:20px}.clcosdk\\\\:rounded-\\\\[28px\\\\]{border-radius:28px}.clcosdk\\\\:rounded-btn{border-radius:12px}.clcosdk\\\\:rounded-card{border-radius:24px}.clcosdk\\\\:rounded-full{border-radius:3.40282e38px}.clcosdk\\\\:rounded-lg{border-radius:var(--clcosdk-radius-lg)}.clcosdk\\\\:rounded-md{border-radius:var(--clcosdk-radius-md)}.clcosdk\\\\:rounded-xl{border-radius:var(--clcosdk-radius-xl)}.clcosdk\\\\:border{border-style:var(--tw-border-style);border-width:1px}.clcosdk\\\\:border-2{border-style:var(--tw-border-style);border-width:2px}.clcosdk\\\\:border-\\\\[1\\\\.5px\\\\]{border-style:var(--tw-border-style);border-width:1.5px}.clcosdk\\\\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.clcosdk\\\\:border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.clcosdk\\\\:border-accent\\\\/60{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-accent\\\\/60{border-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}.clcosdk\\\\:border-amber-500{border-color:var(--clcosdk-color-amber-500)}.clcosdk\\\\:border-background{border-color:var(--color-background)}.clcosdk\\\\:border-border{border-color:var(--color-border)}.clcosdk\\\\:border-brand-primary{border-color:var(--color-brand-primary)}.clcosdk\\\\:border-current{border-color:currentColor}.clcosdk\\\\:border-divider{border-color:var(--color-divider)}.clcosdk\\\\:border-error-border{border-color:var(--color-error-border)}.clcosdk\\\\:border-sale-card-border{border-color:var(--color-sale-card-border)}.clcosdk\\\\:border-sale-card-chrome-border{border-color:var(--color-sale-card-chrome-border)}.clcosdk\\\\:border-success-border{border-color:var(--color-success-border)}.clcosdk\\\\:border-text-primary{border-color:var(--color-text-primary)}.clcosdk\\\\:border-transparent{border-color:#0000}.clcosdk\\\\:border-warning-border{border-color:var(--color-warning-border)}.clcosdk\\\\:border-t-transparent{border-top-color:#0000}.clcosdk\\\\:bg-background{background-color:var(--color-background)}.clcosdk\\\\:bg-black\\\\/50{background-color:var(--clcosdk-color-black)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:bg-black\\\\/50{background-color:color-mix(in oklab, var(--clcosdk-color-black) 50%, transparent)}}.clcosdk\\\\:bg-brand-primary{background-color:var(--color-brand-primary)}.clcosdk\\\\:bg-divider{background-color:var(--color-divider)}.clcosdk\\\\:bg-error-subtle{background-color:var(--color-error-subtle)}.clcosdk\\\\:bg-overlay{background-color:var(--color-overlay)}.clcosdk\\\\:bg-positive{background-color:var(--color-positive)}.clcosdk\\\\:bg-positive-subtle{background-color:var(--color-positive-subtle)}.clcosdk\\\\:bg-sale-card-chrome-bg{background-color:var(--color-sale-card-chrome-bg)}.clcosdk\\\\:bg-section{background-color:var(--color-section)}.clcosdk\\\\:bg-success-subtle{background-color:var(--color-success-subtle)}.clcosdk\\\\:bg-surface{background-color:var(--color-surface)}.clcosdk\\\\:bg-text-disabled{background-color:var(--color-text-disabled)}.clcosdk\\\\:bg-text-primary{background-color:var(--color-text-primary)}.clcosdk\\\\:bg-transparent{background-color:#0000}.clcosdk\\\\:bg-warning-subtle{background-color:var(--color-warning-subtle)}.clcosdk\\\\:bg-\\\\[image\\\\:var\\\\(--btn-primary-gradient\\\\)\\\\]{background-image:var(--btn-primary-gradient)}.clcosdk\\\\:bg-\\\\[image\\\\:var\\\\(--sale-card-surface\\\\)\\\\]{background-image:var(--sale-card-surface)}.clcosdk\\\\:object-contain{object-fit:contain}.clcosdk\\\\:object-cover{object-fit:cover}.clcosdk\\\\:p-0{padding:0}.clcosdk\\\\:p-1\\\\.5{padding:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:p-3{padding:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:p-3\\\\.5{padding:calc(var(--clcosdk-spacing) * 3.5)}.clcosdk\\\\:p-4{padding:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:p-5{padding:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:p-8{padding:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:p-16{padding:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\\\:px-2{padding-inline:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:px-3{padding-inline:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:px-4{padding-inline:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:px-5{padding-inline:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:px-6{padding-inline:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:py-1\\\\.5{padding-block:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:py-2{padding-block:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:py-3{padding-block:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:py-8{padding-block:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:py-12{padding-block:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:pt-1{padding-top:var(--clcosdk-spacing)}.clcosdk\\\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pt-14{padding-top:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:pr-1\\\\.5{padding-right:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:pr-3{padding-right:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:pr-4{padding-right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pb-1{padding-bottom:var(--clcosdk-spacing)}.clcosdk\\\\:pb-4{padding-bottom:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pl-3{padding-left:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:text-center{text-align:center}.clcosdk\\\\:text-left{text-align:left}.clcosdk\\\\:text-right{text-align:right}.clcosdk\\\\:font-mono{font-family:var(--clcosdk-font-mono)}.clcosdk\\\\:text-base{font-size:var(--clcosdk-text-base);line-height:var(--tw-leading,var(--clcosdk-text-base--line-height))}.clcosdk\\\\:text-lg{font-size:var(--clcosdk-text-lg);line-height:var(--tw-leading,var(--clcosdk-text-lg--line-height))}.clcosdk\\\\:text-sm{font-size:var(--clcosdk-text-sm);line-height:var(--tw-leading,var(--clcosdk-text-sm--line-height))}.clcosdk\\\\:text-xs{font-size:var(--clcosdk-text-xs);line-height:var(--tw-leading,var(--clcosdk-text-xs--line-height))}.clcosdk\\\\:text-\\\\[11px\\\\]{font-size:11px}.clcosdk\\\\:text-\\\\[12px\\\\]{font-size:12px}.clcosdk\\\\:text-\\\\[13px\\\\]{font-size:13px}.clcosdk\\\\:text-\\\\[14px\\\\]{font-size:14px}.clcosdk\\\\:text-\\\\[15px\\\\]{font-size:15px}.clcosdk\\\\:text-\\\\[16px\\\\]{font-size:16px}.clcosdk\\\\:text-\\\\[18px\\\\]{font-size:18px}.clcosdk\\\\:text-\\\\[22px\\\\]{font-size:22px}.clcosdk\\\\:text-\\\\[28px\\\\]{font-size:28px}.clcosdk\\\\:text-\\\\[36px\\\\]{font-size:36px}.clcosdk\\\\:text-\\\\[48px\\\\]{font-size:48px}.clcosdk\\\\:text-\\\\[64px\\\\]{font-size:64px}.clcosdk\\\\:leading-\\\\[105\\\\%\\\\]{--tw-leading:105%;line-height:105%}.clcosdk\\\\:leading-\\\\[108\\\\%\\\\]{--tw-leading:108%;line-height:108%}.clcosdk\\\\:leading-\\\\[110\\\\%\\\\]{--tw-leading:110%;line-height:110%}.clcosdk\\\\:leading-\\\\[120\\\\%\\\\]{--tw-leading:120%;line-height:120%}.clcosdk\\\\:leading-\\\\[130\\\\%\\\\]{--tw-leading:130%;line-height:130%}.clcosdk\\\\:leading-\\\\[140\\\\%\\\\]{--tw-leading:140%;line-height:140%}.clcosdk\\\\:leading-\\\\[150\\\\%\\\\]{--tw-leading:150%;line-height:150%}.clcosdk\\\\:leading-\\\\[160\\\\%\\\\]{--tw-leading:160%;line-height:160%}.clcosdk\\\\:font-medium{--tw-font-weight:var(--clcosdk-font-weight-medium);font-weight:var(--clcosdk-font-weight-medium)}.clcosdk\\\\:font-normal{--tw-font-weight:var(--clcosdk-font-weight-normal);font-weight:var(--clcosdk-font-weight-normal)}.clcosdk\\\\:font-semibold{--tw-font-weight:var(--clcosdk-font-weight-semibold);font-weight:var(--clcosdk-font-weight-semibold)}.clcosdk\\\\:tracking-\\\\[0\\\\.28px\\\\]{--tw-tracking:.28px;letter-spacing:.28px}.clcosdk\\\\:break-words{overflow-wrap:break-word}.clcosdk\\\\:whitespace-nowrap{white-space:nowrap}.clcosdk\\\\:whitespace-pre{white-space:pre}.clcosdk\\\\:text-background{color:var(--color-background)}.clcosdk\\\\:text-brand-primary{color:var(--color-brand-primary)}.clcosdk\\\\:text-error{color:var(--color-error)}.clcosdk\\\\:text-positive{color:var(--color-positive)}.clcosdk\\\\:text-sale-card-text{color:var(--color-sale-card-text)}.clcosdk\\\\:text-sale-card-text-muted{color:var(--color-sale-card-text-muted)}.clcosdk\\\\:text-sale-card-text-strong{color:var(--color-sale-card-text-strong)}.clcosdk\\\\:text-success{color:var(--color-success)}.clcosdk\\\\:text-text-disabled{color:var(--color-text-disabled)}.clcosdk\\\\:text-text-inverse{color:var(--color-text-inverse)}.clcosdk\\\\:text-text-primary{color:var(--color-text-primary)}.clcosdk\\\\:text-text-secondary{color:var(--color-text-secondary)}.clcosdk\\\\:text-warning{color:var(--color-warning)}.clcosdk\\\\:capitalize{text-transform:capitalize}.clcosdk\\\\:lining-nums{--tw-numeric-figure:lining-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.clcosdk\\\\:tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.clcosdk\\\\:no-underline{text-decoration-line:none}.clcosdk\\\\:underline{text-decoration-line:underline}.clcosdk\\\\:underline-offset-2{text-underline-offset:2px}.clcosdk\\\\:underline-offset-4{text-underline-offset:4px}.clcosdk\\\\:opacity-0{opacity:0}.clcosdk\\\\:opacity-60{opacity:.6}.clcosdk\\\\:shadow-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.2\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f633);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0px_1px_1px_0px_rgba\\\\(10\\\\,10\\\\,10\\\\,0\\\\.04\\\\)\\\\,0px_8px_12px_0px_rgba\\\\(10\\\\,10\\\\,10\\\\,0\\\\.08\\\\)\\\\]{--tw-shadow:0px 1px 1px 0px var(--tw-shadow-color,#0a0a0a0a), 0px 8px 12px 0px var(--tw-shadow-color,#0a0a0a14);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0px_4px_12px_0px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.08\\\\)\\\\,0px_12px_28px_0px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.13\\\\)\\\\]{--tw-shadow:0px 4px 12px 0px var(--tw-shadow-color,#00000014), 0px 12px 28px 0px var(--tw-shadow-color,#00000021);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[var\\\\(--btn-primary-shadow\\\\)\\\\]{--tw-shadow:var(--btn-primary-shadow);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-card{--tw-shadow:0px 4px 6px -2px var(--tw-shadow-color,#0000000d), 0px 12px 24px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-dialog{--tw-shadow:var(--shadow-dialog);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-step-active{--tw-shadow:var(--shadow-step-active);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:transition-\\\\[background-color\\\\,border-color\\\\]{transition-property:background-color,border-color;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-\\\\[grid-template-rows\\\\]{transition-property:grid-template-rows;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:duration-200{--tw-duration:.2s;transition-duration:.2s}.clcosdk\\\\:duration-300{--tw-duration:.3s;transition-duration:.3s}.clcosdk\\\\:duration-500{--tw-duration:.5s;transition-duration:.5s}.clcosdk\\\\:ease-in-out{--tw-ease:var(--clcosdk-ease-in-out);transition-timing-function:var(--clcosdk-ease-in-out)}.clcosdk\\\\:ease-out{--tw-ease:var(--clcosdk-ease-out);transition-timing-function:var(--clcosdk-ease-out)}.clcosdk\\\\:outline-none{--tw-outline-style:none;outline-style:none}.clcosdk\\\\:group-focus-within\\\\:opacity-100:is(:where(.clcosdk\\\\:group):focus-within *){opacity:1}@media (hover:hover){.clcosdk\\\\:group-hover\\\\:border-sale-card-chrome-emphasis-border:is(:where(.clcosdk\\\\:group):hover *){border-color:var(--color-sale-card-chrome-emphasis-border)}.clcosdk\\\\:group-hover\\\\:bg-sale-card-chrome-emphasis-bg:is(:where(.clcosdk\\\\:group):hover *){background-color:var(--color-sale-card-chrome-emphasis-bg)}.clcosdk\\\\:group-hover\\\\:opacity-100:is(:where(.clcosdk\\\\:group):hover *){opacity:1}}.clcosdk\\\\:group-focus-visible\\\\:border-sale-card-chrome-emphasis-border:is(:where(.clcosdk\\\\:group):focus-visible *){border-color:var(--color-sale-card-chrome-emphasis-border)}.clcosdk\\\\:group-focus-visible\\\\:bg-sale-card-chrome-emphasis-bg:is(:where(.clcosdk\\\\:group):focus-visible *){background-color:var(--color-sale-card-chrome-emphasis-bg)}.clcosdk\\\\:placeholder\\\\:text-text-disabled::placeholder{color:var(--color-text-disabled)}@media (hover:hover){.clcosdk\\\\:hover\\\\:scale-\\\\[1\\\\.02\\\\]:hover{scale:1.02}.clcosdk\\\\:hover\\\\:border-text-disabled:hover{border-color:var(--color-text-disabled)}.clcosdk\\\\:hover\\\\:bg-\\\\[\\\\#fcdcd8\\\\]:hover{background-color:#fcdcd8}.clcosdk\\\\:hover\\\\:bg-border:hover{background-color:var(--color-border)}.clcosdk\\\\:hover\\\\:bg-brand-primary:hover{background-color:var(--color-brand-primary)}.clcosdk\\\\:hover\\\\:bg-brand-primary-hover:hover{background-color:var(--color-brand-primary-hover)}.clcosdk\\\\:hover\\\\:bg-section:hover{background-color:var(--color-section)}.clcosdk\\\\:hover\\\\:bg-surface:hover{background-color:var(--color-surface)}.clcosdk\\\\:hover\\\\:text-\\\\[\\\\#8b1a13\\\\]:hover{color:#8b1a13}.clcosdk\\\\:hover\\\\:text-text-primary:hover{color:var(--color-text-primary)}.clcosdk\\\\:hover\\\\:underline:hover{text-decoration-line:underline}.clcosdk\\\\:hover\\\\:opacity-80:hover{opacity:.8}.clcosdk\\\\:hover\\\\:opacity-90:hover{opacity:.9}}.clcosdk\\\\:focus-visible\\\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:focus-visible\\\\:ring-gray-400:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-400)}.clcosdk\\\\:focus-visible\\\\:ring-gray-500:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-500)}.clcosdk\\\\:focus-visible\\\\:ring-red-400:focus-visible{--tw-ring-color:var(--clcosdk-color-red-400)}.clcosdk\\\\:focus-visible\\\\:ring-red-500:focus-visible{--tw-ring-color:var(--clcosdk-color-red-500)}.clcosdk\\\\:focus-visible\\\\:ring-sale-card-focus-ring:focus-visible{--tw-ring-color:var(--color-sale-card-focus-ring)}.clcosdk\\\\:focus-visible\\\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.clcosdk\\\\:focus-visible\\\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.clcosdk\\\\:active\\\\:bg-\\\\[\\\\#d9d9d9\\\\]:active{background-color:#d9d9d9}.clcosdk\\\\:active\\\\:bg-\\\\[\\\\#f9c9c4\\\\]:active{background-color:#f9c9c4}.clcosdk\\\\:active\\\\:bg-border:active{background-color:var(--color-border)}.clcosdk\\\\:active\\\\:bg-brand-primary-active:active{background-color:var(--color-brand-primary-active)}.clcosdk\\\\:active\\\\:text-\\\\[\\\\#6d1510\\\\]:active{color:#6d1510}.clcosdk\\\\:active\\\\:opacity-80:active{opacity:.8}.clcosdk\\\\:disabled\\\\:pointer-events-none:disabled{pointer-events:none}.clcosdk\\\\:disabled\\\\:cursor-not-allowed:disabled{cursor:not-allowed}.clcosdk\\\\:disabled\\\\:opacity-40:disabled{opacity:.4}.clcosdk\\\\:disabled\\\\:opacity-50:disabled{opacity:.5}.clcosdk\\\\:aria-disabled\\\\:cursor-not-allowed[aria-disabled=true]{cursor:not-allowed}.clcosdk\\\\:aria-disabled\\\\:opacity-50[aria-disabled=true]{opacity:.5}@media not all and (min-width:48rem){.clcosdk\\\\:max-md\\\\:hidden{display:none}.clcosdk\\\\:max-md\\\\:w-full{width:100%}.clcosdk\\\\:max-md\\\\:justify-start{justify-content:flex-start}.clcosdk\\\\:max-md\\\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:max-md\\\\:rounded-none{border-radius:0}.clcosdk\\\\:max-md\\\\:border-0{border-style:var(--tw-border-style);border-width:0}.clcosdk\\\\:max-md\\\\:bg-transparent{background-color:#0000}.clcosdk\\\\:max-md\\\\:p-0{padding:0}@media (hover:hover){.clcosdk\\\\:max-md\\\\:hover\\\\:scale-100:hover{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}}}@media (min-width:40rem){.clcosdk\\\\:sm\\\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:48rem){.clcosdk\\\\:md\\\\:right-\\\\[-10\\\\%\\\\]{right:-10%}.clcosdk\\\\:md\\\\:order-1{order:1}.clcosdk\\\\:md\\\\:order-2{order:2}.clcosdk\\\\:md\\\\:hidden{display:none}.clcosdk\\\\:md\\\\:size-\\\\[20rem\\\\]{width:20rem;height:20rem}.clcosdk\\\\:md\\\\:h-9{height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:md\\\\:h-12{height:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:md\\\\:h-\\\\[54px\\\\]{height:54px}.clcosdk\\\\:md\\\\:w-9{width:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:md\\\\:w-12{width:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:md\\\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.clcosdk\\\\:md\\\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.clcosdk\\\\:md\\\\:grid-cols-\\\\[minmax\\\\(0\\\\,11fr\\\\)_minmax\\\\(0\\\\,8fr\\\\)\\\\]{grid-template-columns:minmax(0,11fr) minmax(0,8fr)}.clcosdk\\\\:md\\\\:flex-row{flex-direction:row}.clcosdk\\\\:md\\\\:items-center{align-items:center}.clcosdk\\\\:md\\\\:items-end{align-items:flex-end}.clcosdk\\\\:md\\\\:justify-between{justify-content:space-between}.clcosdk\\\\:md\\\\:justify-end{justify-content:flex-end}.clcosdk\\\\:md\\\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:md\\\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:md\\\\:gap-x-12{column-gap:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:md\\\\:self-end{align-self:flex-end}.clcosdk\\\\:md\\\\:rounded-\\\\[40px\\\\]{border-radius:40px}.clcosdk\\\\:md\\\\:rounded-card{border-radius:24px}.clcosdk\\\\:md\\\\:rounded-dialog{border-radius:32px}.clcosdk\\\\:md\\\\:p-4{padding:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:md\\\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:md\\\\:p-8{padding:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:md\\\\:px-6{padding-inline:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:md\\\\:px-8{padding-inline:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:md\\\\:py-2{padding-block:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:md\\\\:pr-2{padding-right:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:md\\\\:pr-4{padding-right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:md\\\\:pl-4{padding-left:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:md\\\\:text-base{font-size:var(--clcosdk-text-base);line-height:var(--tw-leading,var(--clcosdk-text-base--line-height))}.clcosdk\\\\:md\\\\:text-\\\\[14px\\\\]{font-size:14px}.clcosdk\\\\:md\\\\:text-\\\\[16px\\\\]{font-size:16px}.clcosdk\\\\:md\\\\:text-\\\\[18px\\\\]{font-size:18px}.clcosdk\\\\:md\\\\:text-\\\\[28px\\\\]{font-size:28px}.clcosdk\\\\:md\\\\:leading-\\\\[120\\\\%\\\\]{--tw-leading:120%;line-height:120%}.clcosdk\\\\:md\\\\:leading-\\\\[160\\\\%\\\\]{--tw-leading:160%;line-height:160%}}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.20\\\\)\\\\]:not(:where(.light,.light *)):hover{background-color:#f8717133}}}@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.20\\\\)\\\\]:where(.dark,.dark *):hover{background-color:#f8717133}}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:text-\\\\[\\\\#fca5a5\\\\]:not(:where(.light,.light *)):hover{color:#fca5a5}}}@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:text-\\\\[\\\\#fca5a5\\\\]:where(.dark,.dark *):hover{color:#fca5a5}}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.30\\\\)\\\\]:not(:where(.light,.light *)):active{background-color:#f871714d}}.clcosdk\\\\:dark\\\\:active\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.30\\\\)\\\\]:where(.dark,.dark *):active{background-color:#f871714d}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:bg-divider:not(:where(.light,.light *)):active{background-color:var(--color-divider)}}.clcosdk\\\\:dark\\\\:active\\\\:bg-divider:where(.dark,.dark *):active{background-color:var(--color-divider)}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:text-\\\\[\\\\#f87171\\\\]:not(:where(.light,.light *)):active{color:#f87171}}.clcosdk\\\\:dark\\\\:active\\\\:text-\\\\[\\\\#f87171\\\\]:where(.dark,.dark *):active{color:#f87171}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-error-subtle circle{fill:var(--color-error-subtle)}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-success-subtle circle{fill:var(--color-success-subtle)}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-warning-subtle circle{fill:var(--color-warning-subtle)}}@property --tw-translate-x{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-translate-y{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-translate-z{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-border-style{syntax:\\\"*\\\";inherits:false;initial-value:solid}@property --tw-leading{syntax:\\\"*\\\";inherits:false}@property --tw-font-weight{syntax:\\\"*\\\";inherits:false}@property --tw-tracking{syntax:\\\"*\\\";inherits:false}@property --tw-ordinal{syntax:\\\"*\\\";inherits:false}@property --tw-slashed-zero{syntax:\\\"*\\\";inherits:false}@property --tw-numeric-figure{syntax:\\\"*\\\";inherits:false}@property --tw-numeric-spacing{syntax:\\\"*\\\";inherits:false}@property --tw-numeric-fraction{syntax:\\\"*\\\";inherits:false}@property --tw-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\\\"*\\\";inherits:false}@property --tw-shadow-alpha{syntax:\\\"<percentage>\\\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\\\"*\\\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\\\"<percentage>\\\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\\\"*\\\";inherits:false}@property --tw-ring-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\\\"*\\\";inherits:false}@property --tw-inset-ring-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\\\"*\\\";inherits:false}@property --tw-ring-offset-width{syntax:\\\"<length>\\\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\\\"*\\\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:\\\"*\\\";inherits:false}@property --tw-ease{syntax:\\\"*\\\";inherits:false}@property --tw-scale-x{syntax:\\\"*\\\";inherits:false;initial-value:1}@property --tw-scale-y{syntax:\\\"*\\\";inherits:false;initial-value:1}@property --tw-scale-z{syntax:\\\"*\\\";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}\";\n","'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { type ButtonHTMLAttributes, forwardRef, type ReactNode } from 'react';\nimport { cn } from '@/client/components/design-system/utils';\n\n// Button variants using class-variance-authority for consistent styling\nexport const buttonVariants = cva(\n 'clcosdk:inline-flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-3 clcosdk:whitespace-nowrap clcosdk:transition-colors clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-offset-2 clcosdk:disabled:pointer-events-none clcosdk:disabled:opacity-40 clcosdk:cursor-pointer',\n {\n variants: {\n variant: {\n // Primary — tokens auto-switch: dark bg (#171717) → light bg (#f4f4f5) in dark mode\n primary:\n 'clcosdk:bg-brand-primary clcosdk:text-text-inverse clcosdk:font-semibold clcosdk:hover:bg-brand-primary-hover clcosdk:active:bg-brand-primary-active clcosdk:focus-visible:ring-gray-500',\n // Gradient — the raised checkout CTA. Same ink as primary, but the\n // vertical gradient and inset highlights come from tokens that flip\n // with the theme, so there is no dark: override here either.\n gradient:\n 'clcosdk:bg-[image:var(--btn-primary-gradient)] clcosdk:shadow-[var(--btn-primary-shadow)] clcosdk:text-text-inverse clcosdk:font-semibold clcosdk:hover:opacity-90 clcosdk:active:opacity-80 clcosdk:focus-visible:ring-gray-500',\n // Secondary — bg-section, border-border, text-text-primary all auto-switch\n // hover maps to border token value; active has no token so uses dark: override\n secondary:\n 'clcosdk:bg-section clcosdk:border clcosdk:border-border clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-border clcosdk:active:bg-[#d9d9d9] clcosdk:dark:active:bg-divider clcosdk:focus-visible:ring-gray-400',\n // Destructive — error tokens auto-switch to translucent dark equivalents\n // hover/active have no tokens so use dark: overrides\n destructive:\n 'clcosdk:bg-error-subtle clcosdk:border clcosdk:border-error-border clcosdk:text-error clcosdk:font-semibold clcosdk:hover:bg-[#fcdcd8] clcosdk:active:bg-[#f9c9c4] clcosdk:dark:hover:bg-[rgba(248,113,113,0.20)] clcosdk:dark:active:bg-[rgba(248,113,113,0.30)] clcosdk:focus-visible:ring-red-400',\n // Ghost — transparent base; hover/active use section/border tokens (auto-switch)\n ghost:\n 'clcosdk:bg-transparent clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-section clcosdk:active:bg-border clcosdk:focus-visible:ring-gray-400',\n // Link — text-text-primary auto-switches light/dark\n link: 'clcosdk:h-auto clcosdk:p-0 clcosdk:text-text-primary clcosdk:font-medium clcosdk:underline-offset-4 clcosdk:hover:underline clcosdk:focus-visible:ring-gray-500',\n // Destructive link — text-error auto-switches (#b42318 → #f87171 in dark)\n destructiveLink:\n 'clcosdk:h-auto clcosdk:p-0 clcosdk:text-error clcosdk:font-medium clcosdk:hover:text-[#8b1a13] clcosdk:active:text-[#6d1510] clcosdk:dark:hover:text-[#fca5a5] clcosdk:dark:active:text-[#f87171] clcosdk:focus-visible:ring-red-500',\n },\n size: {\n sm: 'clcosdk:h-9 clcosdk:px-4 clcosdk:text-sm clcosdk:tracking-[0.28px]',\n default:\n 'clcosdk:h-11 clcosdk:px-5 clcosdk:text-sm clcosdk:tracking-[0.28px]',\n lg: 'clcosdk:h-14 clcosdk:px-6 clcosdk:text-base',\n // The checkout \"Place order\" CTA: 54px tall, full-bleed inside its card.\n cta: 'clcosdk:h-[54px] clcosdk:px-5 clcosdk:text-base',\n icon: 'clcosdk:h-12 clcosdk:w-12',\n },\n radius: {\n pill: 'clcosdk:rounded-full',\n // compound variants below handle size-specific radii\n rounded: '',\n },\n fullWidth: {\n true: 'clcosdk:w-full',\n false: '',\n },\n },\n compoundVariants: [\n { size: 'sm', radius: 'rounded', className: 'clcosdk:rounded-lg' },\n { size: 'default', radius: 'rounded', className: 'clcosdk:rounded-2xl' },\n { size: 'lg', radius: 'rounded', className: 'clcosdk:rounded-2xl' },\n { size: 'cta', radius: 'rounded', className: 'clcosdk:rounded-2xl' },\n { size: 'icon', radius: 'rounded', className: 'clcosdk:rounded-md' },\n ],\n defaultVariants: {\n variant: 'primary',\n size: 'default',\n radius: 'pill',\n fullWidth: false,\n },\n }\n);\n\nexport interface ClButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n children?: ReactNode;\n isLoading?: boolean;\n loadingText?: string;\n startIcon?: ReactNode;\n endIcon?: ReactNode;\n}\n\nexport const ClButton = forwardRef<HTMLButtonElement, ClButtonProps>(\n (\n {\n className,\n variant,\n size,\n radius,\n fullWidth,\n children,\n isLoading = false,\n loadingText,\n startIcon,\n endIcon,\n disabled,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || isLoading;\n\n return (\n <button\n className={cn(\n buttonVariants({ variant, size, radius, fullWidth }),\n className\n )}\n ref={ref}\n disabled={isDisabled}\n {...props}\n >\n {isLoading && (\n <span\n className=\"clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0 clcosdk:animate-spin clcosdk:rounded-full clcosdk:border-2 clcosdk:border-current clcosdk:border-t-transparent clcosdk:opacity-60\"\n aria-hidden=\"true\"\n />\n )}\n\n {startIcon && !isLoading && (\n <span className=\"clcosdk:shrink-0\">{startIcon}</span>\n )}\n\n <span className={cn(isLoading && 'clcosdk:opacity-60')}>\n {isLoading && loadingText ? loadingText : children}\n </span>\n\n {endIcon && !isLoading && (\n <span className=\"clcosdk:shrink-0\">{endIcon}</span>\n )}\n </button>\n );\n }\n);\n\nClButton.displayName = 'ClButton';\n","import { type ClassValue, clsx } from 'clsx';\n\n/**\n * Utility function to merge class names using clsx.\n */\nexport function cn(...inputs: ClassValue[]) {\n return clsx(inputs);\n}\n","import type { SVGProps } from 'react';\n\nexport function CoinListLogomark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"115\"\n height=\"125\"\n viewBox=\"0 0 115 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M69.7519 123.966C75.8021 124.172 81.7491 123.519 87.4899 121.799C98.3871 118.531 107.531 112.58 114.922 103.947C114.922 103.947 114.922 103.947 114.888 103.912C112.859 102.193 110.831 100.507 108.837 98.8218L106.809 97.1363C106.431 96.8268 106.087 96.5172 105.709 96.2076C104.919 95.5197 104.128 94.8662 103.303 94.2126C96.2902 98.8562 88.5899 101.539 80.0991 101.883C75.8364 102.055 71.6082 101.642 67.4831 100.507C60.5047 98.6154 54.2483 95.1757 49.2294 89.7755C40.0854 79.938 36.854 68.1743 39.226 55.0348C40.7041 46.9172 44.4168 40.0723 50.0888 34.5C48.8856 34.7408 47.6825 35.016 46.5137 35.3943C37.5072 38.2148 30.5976 43.6839 25.6131 51.6639C21.6598 58.0273 19.5629 64.9411 19.3223 72.4739C19.1848 76.7047 19.4598 80.7979 20.4223 84.7879C23.4818 97.2395 30.2882 107.043 40.6698 114.335H40.7729V114.403C41.1167 114.644 41.4604 114.919 41.8042 115.16C50.2607 120.801 59.5766 123.691 69.7519 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M73.1896 89.052C69.1676 90.8406 65.0081 91.8725 60.6768 92.2165C65.9707 95.209 71.7802 96.688 78.1054 96.8256C80.168 96.86 82.2305 96.6536 84.3962 96.3097C89.7245 95.4841 94.6746 93.5579 99.281 90.7374C94.9153 87.057 90.5839 83.4109 86.2181 79.7305C82.5055 83.6861 78.1741 86.8506 73.1896 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M67.9643 0.241609C67.4143 0.276006 66.8643 0.344799 66.3486 0.413592C71.6425 1.4111 76.7646 3.13093 81.6116 5.71068C91.0306 10.7326 98.3527 17.9215 103.268 27.4494L105.915 25.1448C108.631 22.7714 111.347 20.3981 114.063 18.0247C107.634 11.1797 100.072 6.15784 91.2025 3.06214C85.2898 0.998336 79.2396 -0.0335643 73.0176 0.000832322C71.3675 0.000832322 69.6831 0.138419 67.9643 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M26.4037 107.871C18.4628 97.9988 14.1314 86.7167 14.2002 73.818C14.2002 67.317 15.5409 61.0568 18.1191 55.1062C21.9348 46.2662 27.9506 39.1805 36.4071 34.2962C44.348 29.687 52.9763 27.8984 62.1547 29.2743C71.5738 30.7189 79.3771 35.2249 85.6336 42.2762C85.6336 42.2762 85.8398 42.5514 85.9429 42.6546C86.8711 41.8291 87.8336 41.0035 88.7618 40.178L89.8962 39.1805C90.8587 38.355 91.8212 37.4951 92.7838 36.6696C94.9838 34.7434 97.1495 32.8515 99.3152 30.9253C95.087 22.223 88.7274 15.55 80.3053 10.8377C70.3706 5.26541 59.6797 3.54557 48.37 5.02463C42.7323 5.78136 37.3352 7.50119 32.1788 10.0465C14.6815 18.7145 2.06546 36.532 1.03418 58.4771C0.862296 62.0887 1.10293 65.7348 1.65294 69.3464C3.02798 78.3239 6.32808 86.4759 11.622 93.8368C15.7471 99.5123 20.6629 104.19 26.3693 107.871H26.4037Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport {\n ClButton,\n type ClButtonProps,\n} from '@/client/components/design-system/ClButton';\nimport { CoinListLogomark } from '@/client/components/design-system/logos/CoinListLogomark';\n\ninterface CoinListSignInButtonProps\n extends Pick<\n ClButtonProps,\n 'onClick' | 'disabled' | 'fullWidth' | 'isLoading' | 'className'\n > {}\n\n/**\n * The \"Continue with CoinList\" button.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed. Also composed by {@link CoinListSignInCardView}.\n */\nexport function CoinListSignInButton(\n props: CoinListSignInButtonProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <CoinListSignInButtonBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction CoinListSignInButtonBody({\n onClick,\n disabled = false,\n fullWidth = false,\n isLoading = false,\n className,\n}: CoinListSignInButtonProps) {\n return (\n <ClButton\n variant=\"primary\"\n size=\"lg\"\n fullWidth={fullWidth}\n onClick={onClick}\n disabled={disabled}\n isLoading={isLoading}\n loadingText=\"Signing in...\"\n startIcon={\n <CoinListLogomark className=\"clcosdk:h-[18px] clcosdk:w-[16px] clcosdk:shrink-0\" />\n }\n className={className}\n >\n Continue with CoinList\n </ClButton>\n );\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type AlertBannerVariant = 'info' | 'success' | 'warning' | 'error';\n\ninterface AlertBannerProps {\n variant: AlertBannerVariant;\n content: ReactNode;\n icon?: boolean;\n className?: string;\n}\n\nconst variantConfig: Record<\n AlertBannerVariant,\n { container: string; text: string; Icon: LucideIcon }\n> = {\n info: {\n container: 'clcosdk:bg-surface clcosdk:border-border',\n text: 'clcosdk:text-text-secondary',\n Icon: Info,\n },\n success: {\n container: 'clcosdk:bg-success-subtle clcosdk:border-success-border',\n text: 'clcosdk:text-success',\n Icon: CircleCheck,\n },\n warning: {\n container: 'clcosdk:bg-warning-subtle clcosdk:border-warning-border',\n text: 'clcosdk:text-warning',\n Icon: Info,\n },\n error: {\n container: 'clcosdk:bg-error-subtle clcosdk:border-error-border',\n text: 'clcosdk:text-error',\n Icon: Info,\n },\n};\n\nexport function AlertBanner({\n variant,\n content,\n icon = false,\n className,\n}: AlertBannerProps) {\n const { container, text, Icon } = variantConfig[variant];\n\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:rounded-btn clcosdk:border clcosdk:p-3',\n icon && 'clcosdk:gap-2',\n container,\n className\n )}\n >\n {icon && (\n <Icon\n className={cn('clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0', text)}\n aria-hidden=\"true\"\n />\n )}\n <p className={cn(typeClasses.bodySm, text)}>{content}</p>\n </div>\n );\n}\n","/**\n * CoinList Sale SDK — Typography Tokens\n *\n * Scale from Clay (Inter). Sizes in px, lineHeight as percentage string,\n * fontWeight as number. Use `typeClasses` in components; `typeScale` is for\n * programmatic access or non-Tailwind contexts.\n */\n\nexport const typeScale = {\n hero: {\n fontSize: 64,\n lineHeight: '105%',\n fontWeight: 600,\n },\n display: {\n fontSize: 48,\n lineHeight: '108%',\n fontWeight: 600,\n },\n h1: {\n fontSize: 36,\n lineHeight: '110%',\n fontWeight: 500,\n },\n h2: {\n fontSize: 28,\n lineHeight: '120%',\n fontWeight: 500,\n },\n h3: {\n fontSize: 22,\n lineHeight: '130%',\n fontWeight: 500,\n },\n h4: {\n fontSize: 18,\n lineHeight: '140%',\n fontWeight: 500,\n },\n body: {\n fontSize: 16,\n lineHeight: '160%',\n fontWeight: 400,\n },\n bodyMedium: {\n fontSize: 16,\n lineHeight: '160%',\n fontWeight: 500,\n },\n bodySm: {\n fontSize: 15,\n lineHeight: '160%',\n fontWeight: 400,\n },\n subhead: {\n fontSize: 14,\n lineHeight: '150%',\n fontWeight: 400,\n },\n caption: {\n fontSize: 12,\n lineHeight: '140%',\n fontWeight: 400,\n },\n label: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 500,\n },\n data: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 500,\n },\n} as const;\n\n/**\n * Tailwind class mappings for each type style.\n * Use these className strings directly in components.\n *\n * e.g. <h1 className={typeClasses.h1}>Hello</h1>\n */\nexport const typeClasses = {\n hero: 'clcosdk:text-[64px] clcosdk:leading-[105%] clcosdk:font-semibold',\n display: 'clcosdk:text-[48px] clcosdk:leading-[108%] clcosdk:font-semibold',\n h1: 'clcosdk:text-[36px] clcosdk:leading-[110%] clcosdk:font-medium',\n h2: 'clcosdk:text-[28px] clcosdk:leading-[120%] clcosdk:font-medium',\n h3: 'clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium',\n h4: 'clcosdk:text-[18px] clcosdk:leading-[140%] clcosdk:font-medium',\n body: 'clcosdk:text-[16px] clcosdk:leading-[160%] clcosdk:font-normal',\n // Same metrics as `body` at medium weight. `cn(typeClasses.body, 'font-medium')`\n // leaves both weights in the class list (`cn` is clsx), and stylesheet order\n // decides which wins. Clay lists Body Regular only; this is the medium pair.\n bodyMedium: 'clcosdk:text-[16px] clcosdk:leading-[160%] clcosdk:font-medium',\n bodySm: 'clcosdk:text-[15px] clcosdk:leading-[160%] clcosdk:font-normal',\n subhead: 'clcosdk:text-[14px] clcosdk:leading-[150%] clcosdk:font-normal',\n caption: 'clcosdk:text-[12px] clcosdk:leading-[140%] clcosdk:font-normal',\n label: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-medium',\n // Clay Data: Inter Medium + lining/tabular figures.\n data: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-medium clcosdk:lining-nums clcosdk:tabular-nums',\n} as const;\n\nexport type TypeScale = keyof typeof typeScale;\n","'use client';\n\nimport { X } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface CloseButtonProps {\n onClick: () => void;\n 'aria-label'?: string;\n className?: string;\n}\n\nexport function CloseButton({\n onClick,\n 'aria-label': ariaLabel = 'Close',\n className,\n}: CloseButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n className={cn(\n 'clcosdk:cursor-pointer clcosdk:rounded-full clcosdk:p-1.5 clcosdk:text-text-secondary clcosdk:transition-colors clcosdk:hover:bg-surface clcosdk:hover:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2',\n className\n )}\n >\n <X className=\"clcosdk:h-5 clcosdk:w-5\" />\n </button>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CoinListSignInButton } from '@/client/components/auth/CoinListSignInButton';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n CoinListSignInCardUiEvent,\n CoinListSignInCardUiState,\n} from '@/client/hooks/auth/useCoinListSignInCardViewModel.types';\n\nexport interface CoinListSignInCardViewProps {\n state: CoinListSignInCardUiState;\n onEvent: (event: CoinListSignInCardUiEvent) => void;\n className?: string;\n}\n\n/**\n * Sign-in card that prompts the user to authenticate with CoinList. Pure: it\n * renders the state it is given and reports clicks through `onEvent`.\n *\n * Self-scoped: renders fully styled on its own, no `CoinListStyleScope` needed.\n */\nexport function CoinListSignInCardView({\n state,\n onEvent,\n className,\n}: CoinListSignInCardViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:shadow-card',\n className\n )}\n >\n {state.closable && (\n <CloseButton\n onClick={() => onEvent({ type: 'ON_CLOSE' })}\n className=\"clcosdk:absolute clcosdk:right-4 clcosdk:top-4\"\n />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n Sign in to participate\n </h3>\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n A CoinList account is required to participate in this sale.\n </p>\n </div>\n\n <CoinListSignInButton\n onClick={() => onEvent({ type: 'ON_SIGN_IN' })}\n fullWidth\n className=\"clcosdk:mt-4\"\n />\n\n {state.type === 'error' && (\n <AlertBanner\n variant=\"error\"\n icon\n content={state.message}\n className=\"clcosdk:mt-4\"\n />\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport type {\n CoinListSignInCardUiEvent,\n CoinListSignInCardUiState,\n} from '@/client/hooks/auth/useCoinListSignInCardViewModel.types';\nimport { useCoinList } from '@/client/hooks/useCoinList';\n\nexport interface UseCoinListSignInCardViewModelOptions {\n /** `error` renders the sign-in failure banner. Defaults to `idle`. */\n status?: 'idle' | 'error';\n /**\n * Called when the user clicks the sign-in button. Defaults to\n * `CoinListClient#auth.startOAuth`, which redirects to the CoinList\n * authorization page.\n */\n onSignIn?: () => void;\n /** Called when the user closes the card. When omitted, no close button is rendered. */\n onClose?: () => void;\n}\n\nexport interface UseCoinListSignInCardViewModelResult {\n state: CoinListSignInCardUiState;\n onEvent: (event: CoinListSignInCardUiEvent) => void;\n}\n\nconst ERROR_MESSAGE = 'Error signing in. Please try again.';\n\n/**\n * Drives {@link CoinListSignInCardView}. Starts the OAuth flow on sign-in\n * unless the host overrides it, and reports whether the card can be closed.\n */\nexport function useCoinListSignInCardViewModel(\n options: UseCoinListSignInCardViewModelOptions = {}\n): UseCoinListSignInCardViewModelResult {\n const { status = 'idle', onSignIn, onClose } = options;\n const { coinlist } = useCoinList();\n\n const state = useMemo<CoinListSignInCardUiState>(() => {\n const closable = onClose !== undefined;\n return status === 'error'\n ? { type: 'error', message: ERROR_MESSAGE, closable }\n : { type: 'idle', closable };\n }, [status, onClose]);\n\n const onEvent = useCallback(\n (event: CoinListSignInCardUiEvent) => {\n switch (event.type) {\n case 'ON_SIGN_IN':\n if (onSignIn) {\n onSignIn();\n return;\n }\n void coinlist.auth.startOAuth();\n return;\n case 'ON_CLOSE':\n onClose?.();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n },\n [coinlist, onSignIn, onClose]\n );\n\n return { state, onEvent };\n}\n","import { useContext } from 'react';\nimport { CoinListContext } from '@/client/CoinListProvider';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\n\nexport interface UseCoinListResult {\n /**\n * Indicates whether the CoinList client has been initialized and ready to use.\n * While isReady is false, then the current user state will be `unknown`.\n */\n isReady: boolean;\n coinlist: CoinListClient;\n}\n\nexport function useCoinList(): UseCoinListResult {\n const context = useContext(CoinListContext);\n if (context === null) {\n throw new CoinListClientInitializationError();\n }\n\n return {\n isReady: context.isReady,\n coinlist: context.coinlist,\n };\n}\n\nexport class CoinListClientInitializationError extends Error {\n constructor(\n message = 'useCoinList() must be used within CoinListProvider. Wrap your app with <CoinListProvider config={...}>.'\n ) {\n super(message);\n this.name = 'CoinListClientInitializationError';\n }\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListSignInCardView } from '@/client/components/auth/CoinListSignInCardView';\nimport { useCoinListSignInCardViewModel } from '@/client/hooks/auth/useCoinListSignInCardViewModel';\n\nexport interface CoinListSignInCardContainerProps {\n /** `error` renders the sign-in failure banner. Defaults to `idle`. */\n state?: 'idle' | 'error';\n /**\n * Called when the user clicks the sign-in button. Defaults to\n * {@link CoinListClient#auth.startOAuth}, which redirects to the CoinList\n * authorization page. Pass your own handler to override this behavior.\n */\n onSignIn?: () => void;\n /** Called when the user clicks the close button. When omitted, no close button is rendered. */\n onClose?: () => void;\n className?: string;\n}\n\n/**\n * Sign-in card that prompts the user to authenticate with CoinList, backed by\n * {@link useCoinListSignInCardViewModel}.\n *\n * Use this component inside a tree wrapped by {@link CoinListProvider} (for the\n * client context). By default, clicking the sign-in button starts the CoinList\n * OAuth flow via {@link CoinListClient#auth.startOAuth}; pass `onSignIn` to\n * override.\n *\n * Self-scoped: renders fully styled on its own, no `CoinListStyleScope` needed.\n */\nexport function CoinListSignInCardContainer({\n state = 'idle',\n onSignIn,\n onClose,\n className,\n}: CoinListSignInCardContainerProps = {}): ReactNode {\n const { state: uiState, onEvent } = useCoinListSignInCardViewModel({\n status: state,\n onSignIn,\n onClose,\n });\n\n return (\n <CoinListSignInCardView\n state={uiState}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport { type ReactNode, useState } from 'react';\nimport { OndoBuyCheckoutContainer } from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer';\nimport { OndoSellCheckoutContainer } from '@/client/components/checkout/ondo/sell/OndoSellCheckoutContainer';\nimport { SuperstateSwapCheckoutContainer } from '@/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer';\nimport type { OndoOrderPlaced } from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type { SuperstateOrderPlaced } from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel';\nimport type {\n AssetSymbol,\n EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { OfferType } from '@/universal/types/offer';\nimport type {\n CoinListTokenSaleOfferDetail,\n OfferDetail,\n OndoSwapOfferDetail,\n SuperstateSwapOfferDetail,\n} from '@/universal/types/offer-detail';\nimport type { OrderBookSide } from '@/universal/types/trading';\n\n/**\n * Everything `CheckoutContainer` needs that the offer cannot tell it, keyed by\n * the offer type it belongs to.\n *\n * Keyed by `OfferType` rather than by provider name, and with every key\n * required, because a host that renders `CheckoutContainer` is saying it will\n * handle whatever offer it is given. Adding a member to `OfferTypeDto` then\n * breaks every host at compile time, which is the point: a new offer type\n * arriving in a catalogue is a thing they have to decide about, not a blank\n * screen their users find first.\n *\n * Almost nothing here is per-offer: it is per-*integration*, so a host builds\n * it once and passes the same object for every offer it renders. The one\n * exception is `ondo::swap`'s `side`, which is per-*render* rather than per\n * offer or per integration - the same Ondo offer is both buyable and sellable -\n * so a host with a buy page and a sell page rebuilds the object, or closes its\n * `side` thunk over whatever selects the direction. See\n * {@link OndoCheckoutConfig}.\n */\nexport type CheckoutConfig = {\n [K in OfferType]: CheckoutConfigByOfferType[K];\n};\n\n/**\n * What each offer type needs, before {@link CheckoutConfig} maps `OfferType`\n * over it.\n *\n * Private, and separate from `CheckoutConfig`, because the mapping is what\n * enforces the promise above: a new member of `OfferTypeDto` with no entry here\n * fails to index this type, so the compile error lands in the SDK *and* the\n * shape hosts must satisfy changes with it. Declaring the keys directly on\n * `CheckoutConfig` would leave both sides compiling happily against a type that\n * had quietly stopped covering every offer.\n */\ntype CheckoutConfigByOfferType = {\n 'ondo::swap': OndoCheckoutConfig;\n 'superstate::swap': SuperstateCheckoutConfig;\n 'coinlist::token_sale': CoinListTokenSaleCheckoutConfig;\n};\n\nexport type OndoCheckoutConfig = {\n /**\n * Ondo's API symbol for the offer's asset, e.g. `AAPLon`.\n *\n * A function of the offer rather than a bare value, because the symbol is\n * per-*asset* while this config is per-integration: a host listing `AAPLon`\n * and `TSLAon` side by side has one config and two answers. Same reason the\n * token-sale key takes `render(offer)`.\n *\n * The SDK cannot answer it either. Ondo's symbol tracks the underlying\n * ticker and changes on a rebrand, and it already disagrees with\n * `offer.asset.code` on Sepolia, where a mock asset stands in. A host whose\n * catalogue does agree can return `AssetSymbol(offer.asset.code)`; one whose\n * does not maps the exceptions.\n *\n * Called only for an `ondo::swap` offer, when that branch is mounted. A\n * Superstate or token-sale checkout never runs it.\n */\n symbol: (offer: OndoSwapOfferDetail) => AssetSymbol;\n /**\n * Which way the trade runs: `buy` invests in the asset, `sell` liquidates a\n * holding of it.\n *\n * A thunk rather than a resolver like `symbol` above, because no offer can\n * answer it: `offer.type` is `ondo::swap` for both directions, since\n * frontline exposes one Ondo offer type and the side is a property of the\n * page rather than of the catalogue. A host closes over whatever selects the\n * direction - a route, a tab - and returns it.\n *\n * Called only for an `ondo::swap` offer, when that branch is mounted. A\n * Superstate or token-sale checkout never runs it.\n *\n * Required, with no default. The wire parameter behind it defaults to `buy`\n * silently, and the day sell ships an unstated direction should be a compile\n * error rather than a purchase.\n *\n * **Read once, at mount.** The Ondo flow holds a committed quote and an\n * approval granted for one specific token, so a resolver that starts\n * answering differently mid-flow is ignored rather than obeyed - see the\n * remount note on {@link CheckoutContainer}.\n */\n side: () => OrderBookSide;\n /** Fired once an Ondo swap has mined, either way. The dialog shows anyway. */\n onOrderConfirmed?: (order: OndoOrderPlaced) => void;\n};\n\n/**\n * Superstate needs nothing required today — the swap contract is looked up from\n * the chain, and the funding assets and issuer are the provider's own\n * constants. The key still has to be supplied, so that the day it does need\n * something the omission is a compile error rather than a runtime surprise.\n */\nexport type SuperstateCheckoutConfig = {\n /** Fired once a Superstate swap has mined. The dialog shows either way. */\n onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;\n};\n\n/**\n * The SDK ships no token-sale UI, so the host supplies it.\n *\n * A render function rather than a `ReactNode`, because the container knows\n * which offer it is being asked about and a host with a working token-sale page\n * of its own needs that offer to render it. A host that never lists token-sale\n * offers returns `null`.\n */\nexport type CoinListTokenSaleCheckoutConfig = {\n render: (offer: CoinListTokenSaleOfferDetail) => ReactNode;\n};\n\n/**\n * The parts of {@link CheckoutConfig} only the host can know.\n *\n * What is missing from this list is what {@link defaultCheckoutConfig} can fill\n * in on its own.\n */\nexport type RequiredCheckoutConfig = Pick<\n CheckoutConfig,\n 'ondo::swap' | 'coinlist::token_sale'\n>;\n\n/**\n * Fills in the config entries that have a sensible default, so a host only\n * writes the ones that do not.\n *\n * It exists mostly for the future: today it defaults one empty object, but a\n * provider that gains an *optional* setting can be defaulted here instead of\n * appearing in every host's config object.\n *\n * ```ts\n * const config = defaultCheckoutConfig({\n * 'ondo::swap': {\n * symbol: (offer) => AssetSymbol(offer.asset.code),\n * side: () => 'buy',\n * },\n * 'coinlist::token_sale': { render: (offer) => <MyTokenSalePage offer={offer} /> },\n * });\n * ```\n */\nexport function defaultCheckoutConfig(\n config: RequiredCheckoutConfig & Partial<CheckoutConfig>\n): CheckoutConfig {\n return { 'superstate::swap': {}, ...config };\n}\n\nexport interface CheckoutContainerProps {\n /**\n * The offer being bought. Its `type` decides which provider renders.\n *\n * Fixed for the lifetime of the mount — see the note on\n * {@link CheckoutContainer} about switching offers.\n */\n offer: OfferDetail;\n /**\n * The chain the order executes on. Applies to whichever provider handles the\n * offer: the balance reads, the approval and the broadcast all go here.\n *\n * Fixed for the lifetime of the mount, as `offer` is.\n */\n chain: EthereumChain;\n /**\n * The wallets the buyer can spend from, and the lambdas that connect and\n * disconnect an external one. The SDK ships no wallet stack, so this is how\n * a host plugs in Privy, AppKit, or its own.\n */\n wallets: CheckoutWalletSelection;\n /** What each offer type needs beyond the offer itself. */\n config: CheckoutConfig;\n /**\n * Default `true`. `false` turns off every request and timer in the mounted\n * provider, for a checkout that is on the tree but not on screen yet.\n */\n enabled?: boolean;\n className?: string;\n}\n\n/**\n * The plug-and-play checkout: hand it an offer and it renders the right\n * provider's flow.\n *\n * Only the matching provider's container is mounted, so its viewmodel is the\n * only one that runs. `enabled` is forwarded as-is — a pause for a checkout\n * that is mounted but not on screen yet, not a stand-in for the offer-type\n * switch.\n *\n * The `switch` is exhaustive against `OfferType`, and the `default` branch\n * assigns to `const exhaustive: never`, so a new offer type is a compile error\n * here as well as in {@link CheckoutConfig}.\n *\n * ## One mount, one offer, one chain, one side\n *\n * `offer`, `chain` and the Ondo `side` are read as fixed for the lifetime of\n * the mount. Each provider's viewmodel owns a step machine — which wallet was\n * authorized, how much is being spent — and that progress is bound to the order\n * it was made against: a Superstate wallet authorization is allow-listed per\n * offer, and an ERC-20 approval is granted per chain, for one specific token.\n * Changing any of the three in place would carry a completed step onto an order\n * it was never made for — a flipped side most sharply of all, since the\n * approval covers the coin the *old* direction spent. So the container does not\n * try to: `side` is resolved once into state and later answers are ignored. A\n * swap could also land mid-execution, between an approval and the broadcast it\n * was granted for, which is worse than not switching at all.\n *\n * **To render a different offer, chain or side, remount rather than\n * reassign** — give the container a `key` that changes with them:\n *\n * ```tsx\n * <CheckoutContainer\n * key={`${offer.id}:${chain}:${side}`}\n * offer={offer}\n * chain={chain}\n * wallets={wallets}\n * config={config}\n * />\n * ```\n *\n * React then discards the old flow's state along with its component instance,\n * which is exactly the reset that is wanted and the only one that cannot strand\n * an in-flight transaction.\n *\n * ### A page per side\n *\n * The simplest way to ship both Ondo directions, and the one that needs no\n * `key` at all: each page hard-codes its own direction, and a mount only ever\n * sees one of them.\n *\n * ```tsx\n * // The sell page. `side: () => 'buy'` on the buy page, everything else equal.\n * const config = defaultCheckoutConfig({\n * 'ondo::swap': { symbol: (o) => AssetSymbol(o.asset.code), side: () => 'sell' },\n * 'coinlist::token_sale': { render: (o) => <MyTokenSalePage offer={o} /> },\n * });\n * ```\n *\n * A sell page reached from a position also knows which wallet holds it, so it\n * usually sets {@link CheckoutWalletSelection.preselected} and opens on the\n * amount.\n *\n * ### A buy/sell toggle on one page\n *\n * Also supported, but **React state alone will not switch it**: `side` is\n * latched at mount, so a re-render with a new answer is ignored by design. Put\n * the direction in the `key` and the toggle works, because the container\n * remounts rather than reassigns.\n *\n * ```tsx\n * const [side, setSide] = useState<OrderBookSide>('buy');\n *\n * <BuySellTabs value={side} onChange={setSide} />\n * <CheckoutContainer\n * key={`${offer.id}:${chain}:${side}`} // `side` in the key, or the toggle is inert\n * offer={offer}\n * chain={chain}\n * wallets={wallets}\n * config={{\n * ...config,\n * 'ondo::swap': { ...config['ondo::swap'], side: () => side },\n * }}\n * />\n * ```\n *\n * Rebuilding the config object on every render costs nothing here: `side` is\n * called once per mount, so the thunk's identity never matters.\n *\n * Two things a host owns rather than the SDK:\n *\n * - **The remount clears the flow** — chosen wallet, entered amount, granted\n * approval. That is the point, but it is visible, so expect the card to reset\n * under a user who flips the tabs half way down it.\n * - **A swap already in flight is not cancelled by unmounting it.** It still\n * mines; the UI just stops following it, and `onOrderConfirmed` never fires\n * for it. The container cannot tell a host that one is in flight, so gate the\n * toggle where it can reach an executing flow — disable the tabs once the\n * user is past the amount step, or confirm before switching.\n */\nexport function CheckoutContainer({\n offer,\n chain,\n wallets,\n config,\n enabled = true,\n className,\n}: CheckoutContainerProps): ReactNode {\n return renderOffer(offer, {\n ondo: (ondoOffer) => (\n <OndoCheckoutContainer\n offer={ondoOffer}\n chain={chain}\n wallets={wallets}\n config={config['ondo::swap']}\n enabled={enabled}\n className={className}\n />\n ),\n superstate: (superstateOffer) => (\n <SuperstateSwapCheckoutContainer\n offer={superstateOffer}\n chain={chain}\n wallets={wallets}\n enabled={enabled}\n onOrderConfirmed={config['superstate::swap'].onOrderConfirmed}\n className={className}\n />\n ),\n tokenSale: (tokenSaleOffer) =>\n config['coinlist::token_sale'].render(tokenSaleOffer),\n });\n}\n\n/**\n * The Ondo branch of {@link CheckoutContainer}: latches `side`, then mounts\n * only the buy or sell container.\n *\n * Its own component so that `side()` and `symbol()` run only when an Ondo\n * offer is showing — Superstate and the token sale never call them — and so\n * the latch lives in React state without `CheckoutContainer` itself holding\n * hooks.\n */\nfunction OndoCheckoutContainer({\n offer,\n chain,\n wallets,\n config,\n enabled,\n className,\n}: {\n offer: OndoSwapOfferDetail;\n chain: EthereumChain;\n wallets: CheckoutWalletSelection;\n config: OndoCheckoutConfig;\n enabled: boolean;\n className?: string;\n}): ReactNode {\n // Resolved once, on mount. A resolver that changes its answer later is\n // ignored: the flow below it holds an approval granted for whichever coin\n // this side spends, and switching under that approval strands it.\n const [side] = useState<OrderBookSide>(() => config.side());\n const ondoSymbol = config.symbol(offer);\n\n return renderOndoSide(side, {\n buy: () => (\n <OndoBuyCheckoutContainer\n offer={offer}\n ondoSymbol={ondoSymbol}\n chain={chain}\n wallets={wallets}\n enabled={enabled}\n onOrderConfirmed={config.onOrderConfirmed}\n className={className}\n />\n ),\n sell: () => (\n <OndoSellCheckoutContainer\n offer={offer}\n ondoSymbol={ondoSymbol}\n chain={chain}\n wallets={wallets}\n enabled={enabled}\n onOrderConfirmed={config.onOrderConfirmed}\n className={className}\n />\n ),\n });\n}\n\n/**\n * Picks the branch for an offer, and hands it the variant it is for.\n *\n * Split out so the dispatch is one exhaustive `switch` over `offer.type` with\n * nothing else in it. Each branch mounts that provider's container with the\n * narrowed offer, so only that viewmodel runs and it never has to ask what\n * kind of offer it was given.\n */\nfunction renderOffer(\n offer: OfferDetail,\n branches: {\n ondo: (offer: OndoSwapOfferDetail) => ReactNode;\n superstate: (offer: SuperstateSwapOfferDetail) => ReactNode;\n tokenSale: (offer: CoinListTokenSaleOfferDetail) => ReactNode;\n }\n): ReactNode {\n switch (offer.type) {\n case 'ondo::swap':\n return branches.ondo(offer);\n case 'superstate::swap':\n return branches.superstate(offer);\n case 'coinlist::token_sale':\n return branches.tokenSale(offer);\n default: {\n // A new offer type without a case here is a compile error.\n const exhaustive: never = offer;\n return exhaustive;\n }\n }\n}\n\nfunction renderOndoSide(\n side: OrderBookSide,\n branches: {\n buy: () => ReactNode;\n sell: () => ReactNode;\n }\n): ReactNode {\n switch (side) {\n case 'buy':\n return branches.buy();\n case 'sell':\n return branches.sell();\n default: {\n // A new side without a case here is a compile error.\n const exhaustive: never = side;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { type ReactNode, useId } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CheckoutAmountInputProps {\n /** The field's label, e.g. `Amount`. */\n label: string;\n /** The raw text the user typed. Kept as a string: it is mid-edit. */\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n /**\n * Paints the number, the border and a `primary` prefix in the error tone, and\n * marks the input `aria-invalid` so the state is not colour-only. A `muted`\n * prefix stays muted: it labels the field rather than reporting on it.\n */\n invalid?: boolean;\n disabled?: boolean;\n /**\n * Slot: rendered left of the number. A currency sign, which reads as part\n * of the figure, such as `$`.\n */\n prefix?: ReactNode;\n /**\n * How the prefix is weighted against the number.\n *\n * `primary` (the default) reads as part of the figure, which is what a\n * currency sign is: `$1,000` is one number. `muted` reads as a label beside\n * it, and stays muted in the error tone: it names the field rather than\n * reporting on it.\n */\n prefixTone?: 'primary' | 'muted';\n /**\n * Slot: rendered immediately after the number, naming its unit — Ondo's\n * `USDC`. Always muted, for the same reason a muted prefix is: a token\n * symbol is a label, and painting it like a digit makes it look like one.\n *\n * It is drawn over the field rather than sizing the input to the text. The\n * input itself fills the row, so the space after the symbol still focuses it.\n */\n suffix?: ReactNode;\n /** Slot: the trailing control, e.g. a Max button. */\n action?: ReactNode;\n className?: string;\n}\n\n/**\n * The amount field of a checkout step: a label, a large number, what it is\n * denominated in, and a trailing action.\n *\n * The denomination is a slot rather than a prop, because it is not always the\n * asset being paid. A token symbol follows the number (`suffix`). A currency\n * sign leads it (`prefix`).\n */\nexport function CheckoutAmountInput({\n label,\n value,\n onChange,\n placeholder,\n invalid = false,\n disabled = false,\n prefix,\n prefixTone = 'primary',\n suffix,\n action,\n className,\n}: CheckoutAmountInputProps) {\n const inputId = useId();\n const toneClass = invalid\n ? 'clcosdk:text-error'\n : 'clcosdk:text-text-primary';\n const prefixToneClass =\n prefixTone === 'muted' ? 'clcosdk:text-text-secondary' : toneClass;\n // The suffix is positioned from a copy of whatever the field is showing, so\n // it stays against the last glyph. An empty value shows the placeholder.\n const measure = value || placeholder || '\\u00a0';\n const input = (\n <input\n id={inputId}\n // Text, not `number`: the browser sanitizes a number field's value, so\n // a mid-edit `\"1.\"` can reach `onChange` as `\"\"`.\n type=\"text\"\n inputMode=\"decimal\"\n autoComplete=\"off\"\n placeholder={placeholder}\n value={value}\n disabled={disabled}\n aria-invalid={invalid}\n onChange={(event) => {\n // Digits and one dot only, including an unfinished `1.`. A letter\n // cannot parse, so that keystroke is dropped.\n const next = event.target.value;\n if (!/^\\d*\\.?\\d*$/.test(next)) return;\n onChange(next);\n }}\n className={cn(\n typeClasses.h4,\n 'clcosdk:w-full clcosdk:min-w-0 clcosdk:bg-transparent',\n 'clcosdk:outline-none clcosdk:font-medium clcosdk:placeholder:text-text-disabled',\n toneClass,\n // Without a suffix the input fills the row. Sizing it to its text\n // made an empty field one character wide. With one, it covers the\n // measured number so the symbol can sit against the last glyph.\n suffix ? 'clcosdk:absolute clcosdk:inset-0' : 'clcosdk:flex-1'\n )}\n />\n );\n\n return (\n <CoinListStyleScope>\n <div\n className={cn('clcosdk:flex clcosdk:flex-col clcosdk:gap-2', className)}\n >\n <label\n htmlFor={inputId}\n className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}\n >\n {label}\n </label>\n\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-2',\n 'clcosdk:rounded-2xl clcosdk:border clcosdk:px-4 clcosdk:py-3',\n invalid ? 'clcosdk:border-error-border' : 'clcosdk:border-border'\n )}\n >\n {/* A press on the field, anywhere but the action, focuses the input. */}\n <label\n htmlFor={inputId}\n className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:cursor-text clcosdk:items-center clcosdk:gap-1\"\n >\n {prefix && (\n <span\n className={cn(\n typeClasses.h4,\n 'clcosdk:shrink-0 clcosdk:font-medium',\n prefixToneClass\n )}\n >\n {prefix}\n </span>\n )}\n {suffix ? (\n // Only as wide as the number, so the symbol sits against it.\n // This is what shrinks when the value outgrows the row, which\n // keeps the symbol whole.\n <div className=\"clcosdk:relative clcosdk:min-w-0 clcosdk:overflow-hidden\">\n <span\n aria-hidden\n className={cn(\n typeClasses.h4,\n 'clcosdk:invisible clcosdk:whitespace-pre clcosdk:font-medium'\n )}\n >\n {measure}\n </span>\n {input}\n </div>\n ) : (\n input\n )}\n {suffix && (\n <span\n className={cn(\n typeClasses.h4,\n 'clcosdk:pointer-events-none clcosdk:shrink-0 clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-secondary'\n )}\n >\n {suffix}\n </span>\n )}\n </label>\n\n {action}\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n","import { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\n\nexport interface AssetIconProps {\n asset: CheckoutAssetUi;\n /** Edge length in px. The network badge scales with it. */\n size?: number;\n className?: string;\n}\n\n/**\n * An asset's icon, with its network as a corner badge.\n *\n * Both images are optional in the model and both are optional here: an asset\n * with no `iconUrl` renders a neutral circle, and an asset whose network has no\n * icon renders no badge. Absence is a designed state, not a fallback.\n */\nexport function AssetIcon({ asset, size = 40, className }: AssetIconProps) {\n const badgeSize = Math.round(size * 0.45);\n\n return (\n <CoinListStyleScope>\n <div\n className={cn('clcosdk:relative clcosdk:shrink-0', className)}\n style={{ width: size, height: size }}\n >\n {asset.iconUrl ? (\n <img\n src={asset.iconUrl}\n alt={asset.name}\n width={size}\n height={size}\n className=\"clcosdk:size-full clcosdk:rounded-full clcosdk:object-contain\"\n />\n ) : (\n <div\n className=\"clcosdk:size-full clcosdk:rounded-full clcosdk:bg-section\"\n aria-hidden=\"true\"\n />\n )}\n\n {asset.network.iconUrl && (\n <div\n className={cn(\n 'clcosdk:absolute clcosdk:-bottom-0.5 clcosdk:-right-0.5',\n 'clcosdk:overflow-hidden clcosdk:rounded-full',\n 'clcosdk:border-2 clcosdk:border-background clcosdk:bg-background'\n )}\n style={{ width: badgeSize, height: badgeSize }}\n >\n <img\n src={asset.network.iconUrl}\n alt={asset.network.name}\n width={badgeSize}\n height={badgeSize}\n className=\"clcosdk:size-full clcosdk:object-contain\"\n />\n </div>\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n","import { cn } from '@/client/components/design-system/utils';\n\n/**\n * The 1.5px border that marks a selectable checkout option (a wallet row, an\n * input-asset card) as chosen.\n *\n * A shared helper rather than a shared component, because the two callers that\n * need it — `SelectableOptionRow` and `PayWithAssetCard` — differ in layout and\n * in element type, and only agree on the border.\n */\nexport function selectableOptionBorderClass(selected: boolean): string {\n return cn(\n 'clcosdk:border-[1.5px]',\n selected\n ? 'clcosdk:border-brand-primary'\n : 'clcosdk:border-border clcosdk:hover:border-text-disabled'\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { selectableOptionBorderClass } from '@/client/components/checkout/shared/selection/classes';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\n\n/**\n * `static` is the sole-option render: nothing to choose, so nothing to click.\n * `selectable` is one of several — it carries the selection border and fires\n * `onSelect`.\n */\nexport type PayWithAssetCardVariant = 'static' | 'selectable';\n\nexport type PayWithAssetCardProps = {\n asset: CheckoutAssetUi;\n /** The user's holding, already formatted, e.g. `1,850.00 USDC`. */\n balance: ReactNode;\n} & (\n | { variant: 'static' }\n | {\n variant: 'selectable';\n selected: boolean;\n onSelect: () => void;\n /** Non-interactive while true - used to freeze the choice during a submit. */\n disabled?: boolean;\n }\n);\n\n/**\n * The card naming what an order is funded with.\n *\n * The two variants are a union rather than optional props, so a `static` card\n * cannot be handed an `onSelect` that it would silently drop, and a\n * `selectable` one cannot be rendered without a handler.\n */\nexport function PayWithAssetCard(props: PayWithAssetCardProps) {\n const { asset, balance } = props;\n const body = <PayWithAssetBody asset={asset} balance={balance} />;\n\n if (props.variant === 'static') {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:gap-3',\n 'clcosdk:rounded-2xl clcosdk:border clcosdk:border-border',\n 'clcosdk:bg-surface clcosdk:p-3'\n )}\n >\n {body}\n </div>\n );\n }\n\n return (\n <CoinListStyleScope>\n <button\n type=\"button\"\n onClick={props.onSelect}\n aria-pressed={props.selected}\n disabled={props.disabled}\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:gap-3',\n 'clcosdk:cursor-pointer clcosdk:rounded-2xl clcosdk:p-3',\n 'clcosdk:text-left clcosdk:transition-colors',\n 'clcosdk:disabled:cursor-not-allowed clcosdk:disabled:opacity-50',\n selectableOptionBorderClass(props.selected)\n )}\n >\n {body}\n </button>\n </CoinListStyleScope>\n );\n}\n\nfunction PayWithAssetBody({\n asset,\n balance,\n}: {\n asset: CheckoutAssetUi;\n balance: ReactNode;\n}): ReactNode {\n return (\n <>\n <AssetIcon asset={asset} size={40} />\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col\">\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {asset.name}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n {balance}\n </span>\n </div>\n </>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\n/**\n * Where a step sits in the flow.\n *\n * - `inactive` — not reached yet: the title alone, no content.\n * - `active` — the step the user is on: raised, and the only state with a footer.\n * - `completed` — done: a summary of what was chosen, flat.\n */\nexport type CheckoutStepCardState = 'inactive' | 'active' | 'completed';\n\nexport interface CheckoutStepCardProps {\n state: CheckoutStepCardState;\n /** Slot: the numbered heading, e.g. `1. Choose your wallet`. */\n title: ReactNode;\n /** Slot: sub-copy under the heading. Rendered in every state. */\n description?: ReactNode;\n /** Slot: the step's body. Not rendered while `inactive`. */\n children?: ReactNode;\n /** Slot: the divider-and-actions row. Rendered only while `active`. */\n footer?: ReactNode;\n className?: string;\n}\n\n/**\n * The card one checkout step renders inside. Every provider's steps use it, so\n * it knows nothing about wallets, amounts or quotes — it is title, body and\n * footer slots plus the three-state chrome around them.\n */\nexport function CheckoutStepCard({\n state,\n title,\n description,\n children,\n footer,\n className,\n}: CheckoutStepCardProps) {\n const isActive = state === 'active';\n const showBody = state !== 'inactive';\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col',\n 'clcosdk:p-4 clcosdk:md:p-6',\n 'clcosdk:rounded-2xl clcosdk:md:rounded-card',\n 'clcosdk:border clcosdk:border-border clcosdk:bg-background',\n // Every step is a solid card; only the one in play is raised above the\n // others, and it is the elevation alone that says which that is.\n isActive\n ? 'clcosdk:gap-6 clcosdk:shadow-step-active'\n : 'clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-2\">\n <h2 className={cn(typeClasses.h4, 'clcosdk:text-text-primary')}>\n {title}\n </h2>\n {description}\n </div>\n\n {showBody && children}\n\n {isActive && footer && (\n <>\n <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />\n {footer}\n </>\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CheckoutStepFooterProps {\n /**\n * Slot: muted copy left of the CTA — a hint (\"You'll review your order\n * details before purchasing.\") or the message of a running step.\n *\n * Hidden while `error` is set: the failure takes this slot rather than\n * stacking under the hint.\n */\n message?: ReactNode;\n /** Failure copy, rendered in the error tone. Replaces `message` when set. */\n error?: string | null;\n /** Slot: the step's call-to-action. */\n cta: ReactNode;\n className?: string;\n}\n\n/**\n * The actions row at the bottom of an active step: copy on the left, the CTA on\n * the right, stacking to full width below `md`.\n *\n * With nothing to say on the left the CTA right-aligns on its own, which is how\n * the wallet step renders before anything has gone wrong.\n */\nexport function CheckoutStepFooter({\n message,\n error,\n cta,\n className,\n}: CheckoutStepFooterProps) {\n const leftCopy = error ? (\n <span\n className={cn(typeClasses.subhead, 'clcosdk:min-w-0 clcosdk:text-error')}\n >\n {error}\n </span>\n ) : message ? (\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0 clcosdk:text-text-secondary'\n )}\n >\n {message}\n </span>\n ) : null;\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:flex-col clcosdk:gap-4',\n 'clcosdk:md:flex-row clcosdk:md:items-center clcosdk:md:gap-6',\n leftCopy ? 'clcosdk:md:justify-between' : 'clcosdk:md:justify-end',\n className\n )}\n >\n {leftCopy}\n <div className=\"clcosdk:flex clcosdk:shrink-0 clcosdk:max-md:w-full\">\n {cta}\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CompletedStepSummaryProps {\n /** Slot: what was chosen, iconographically — a wallet glyph, an asset icon. */\n icon: ReactNode;\n /** Slot: the headline of the choice, e.g. the address or `1,000.00 USDC`. */\n title: ReactNode;\n /** Slot: supporting line under the title. */\n subtitle?: ReactNode;\n onEdit: () => void;\n editLabel: string;\n className?: string;\n}\n\n/**\n * The body of a completed step: a summary of the choice on the left, and the\n * pill that sends the user back to change it on the right.\n *\n * Shared because every step collapses to this same shape once it is done, and\n * the only thing that varies is what fills the three slots.\n */\nexport function CompletedStepSummary({\n icon,\n title,\n subtitle,\n onEdit,\n editLabel,\n className,\n}: CompletedStepSummaryProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n {icon}\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col\">\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {title}\n </span>\n {subtitle && (\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n {subtitle}\n </span>\n )}\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={onEdit}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:h-9 clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:whitespace-nowrap',\n 'clcosdk:rounded-full clcosdk:bg-section clcosdk:px-5',\n 'clcosdk:font-medium clcosdk:text-text-primary',\n 'clcosdk:transition-colors clcosdk:hover:bg-border'\n )}\n >\n {editLabel}\n </button>\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutAmountInput } from '@/client/components/checkout/shared/amount/CheckoutAmountInput';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { PayWithAssetCard } from '@/client/components/checkout/shared/selection/PayWithAssetCard';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { CheckoutStepFooter } from '@/client/components/checkout/shared/step/CheckoutStepFooter';\nimport { CompletedStepSummary } from '@/client/components/checkout/shared/step/CompletedStepSummary';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoBuyAmountUiEvent,\n OndoBuyAmountUiState,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel.types';\nimport type { CheckoutSelectableInputAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\n\nconst TITLE = '2. Enter amount';\nconst AMOUNT_LABEL = 'Amount';\nconst AMOUNT_PLACEHOLDER = '0.00';\nconst PAY_WITH_LABEL = 'Pay with';\nconst REVIEW_NOTE = \"You'll review your order details before purchasing.\";\n\nexport interface OndoBuyAmountViewProps {\n state: OndoBuyAmountUiState;\n onEvent: (event: OndoBuyAmountUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 2 of the Ondo checkout. Pure: amounts arrive already formatted, and\n * every interaction leaves through `onEvent`.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoBuyAmountView(props: OndoBuyAmountViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoAmountViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoAmountViewBody({\n state,\n onEvent,\n className,\n}: OndoBuyAmountViewProps): ReactNode {\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={TITLE}\n className={className}\n />\n );\n case 'active':\n return (\n <ActiveView state={state} onEvent={onEvent} className={className} />\n );\n case 'complete':\n return (\n <CompletedView state={state} onEvent={onEvent} className={className} />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<OndoBuyAmountUiState, { type: 'active' }>;\n onEvent: (event: OndoBuyAmountUiEvent) => void;\n className?: string;\n}): ReactNode {\n const isLoading = state.confirmCta.type === 'loading';\n const selectedAsset =\n state.inputAssets.find((asset) => asset.selected) ?? null;\n\n return (\n <CheckoutStepCard\n state=\"active\"\n title={TITLE}\n className={className}\n footer={\n <CheckoutStepFooter\n message={\n state.confirmCta.type === 'loading'\n ? state.confirmCta.message\n : REVIEW_NOTE\n }\n error={state.error}\n cta={\n <ClButton\n variant=\"primary\"\n disabled={state.confirmCta.type === 'disabled'}\n isLoading={isLoading}\n loadingText=\"Confirming\"\n onClick={() => onEvent({ type: 'ON_CONFIRM_AMOUNT' })}\n className=\"clcosdk:h-12 clcosdk:max-md:w-full\"\n >\n Confirm amount\n </ClButton>\n }\n />\n }\n >\n <CheckoutAmountInput\n label={AMOUNT_LABEL}\n value={state.amountInput}\n onChange={(value) => onEvent({ type: 'ON_AMOUNT_CHANGE', value })}\n placeholder={AMOUNT_PLACEHOLDER}\n invalid={state.error !== null}\n disabled={isLoading}\n suffix={selectedAsset?.symbol}\n action={\n selectedAsset && (\n <MaxButton\n disabled={isLoading}\n onClick={() => onEvent({ type: 'ON_MAX_AMOUNT_CLICK' })}\n />\n )\n }\n />\n\n {state.inputAssets.length > 0 && (\n <PayWithSection\n inputAssets={state.inputAssets}\n walletAddress={state.walletAddress}\n disabled={isLoading}\n onEvent={onEvent}\n />\n )}\n </CheckoutStepCard>\n );\n}\n\nfunction PayWithSection({\n inputAssets,\n walletAddress,\n disabled,\n onEvent,\n}: {\n inputAssets: CheckoutSelectableInputAssetUi[];\n walletAddress: string;\n /** Frozen while the amount is being confirmed, like the field above it. */\n disabled: boolean;\n onEvent: (event: OndoBuyAmountUiEvent) => void;\n}): ReactNode {\n // One fundable asset is a statement, not a choice: render it as a plain card.\n const isChoice = inputAssets.length >= 2;\n\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {PAY_WITH_LABEL}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n from {walletAddress}\n </span>\n </div>\n\n <div\n className={cn(\n isChoice\n ? 'clcosdk:grid clcosdk:grid-cols-1 clcosdk:gap-2 clcosdk:sm:grid-cols-2'\n : 'clcosdk:flex clcosdk:flex-col'\n )}\n >\n {inputAssets.map((inputAsset) =>\n isChoice ? (\n <PayWithAssetCard\n key={inputAsset.symbol}\n variant=\"selectable\"\n asset={inputAsset.asset}\n balance={inputAsset.balance}\n selected={inputAsset.selected}\n disabled={disabled}\n onSelect={() =>\n onEvent({\n type: 'ON_SELECT_PAY_WITH',\n value: inputAsset.symbol,\n })\n }\n />\n ) : (\n <PayWithAssetCard\n key={inputAsset.symbol}\n variant=\"static\"\n asset={inputAsset.asset}\n balance={inputAsset.balance}\n />\n )\n )}\n </div>\n </div>\n );\n}\n\nfunction CompletedView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<OndoBuyAmountUiState, { type: 'complete' }>;\n onEvent: (event: OndoBuyAmountUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"completed\" title={TITLE} className={className}>\n <CompletedStepSummary\n icon={<AssetIcon asset={state.inputAsset} size={40} />}\n title={state.amountFormatted}\n editLabel=\"Edit\"\n onEdit={() => onEvent({ type: 'ON_EDIT_AMOUNT' })}\n />\n </CheckoutStepCard>\n );\n}\n\nfunction MaxButton({\n disabled,\n onClick,\n}: {\n disabled: boolean;\n onClick: () => void;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onClick}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:h-9 clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:rounded-full',\n 'clcosdk:border clcosdk:border-border clcosdk:px-5',\n 'clcosdk:font-medium clcosdk:text-text-primary',\n 'clcosdk:transition-colors clcosdk:hover:bg-surface',\n 'clcosdk:disabled:cursor-not-allowed clcosdk:disabled:opacity-40'\n )}\n >\n Max\n </button>\n );\n}\n","'use client';\n\nimport { Check, ExternalLink } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutConfirmationDialog } from '@/client/components/checkout/shared/confirmation/CheckoutConfirmationDialog';\nimport { AssetSummaryRow } from '@/client/components/checkout/shared/summary/AssetSummaryRow';\nimport type { CheckoutDetailRowUi } from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoOrderConfirmedUiEvent,\n OndoOrderConfirmedUiState,\n} from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\nimport type { AssetSymbol } from '@/universal/types/blockchain/core';\n\nconst TITLE = 'Order confirmed';\nconst SHARES_RECEIVED_LABEL = 'Shares received';\nconst TOTAL_COST_LABEL = 'Total cost';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst DELIVERED_TO_LABEL = 'Delivered to';\nconst DONE_LABEL = 'Done';\nconst VIEW_TRANSACTION_LABEL = 'View transaction onchain';\n\nconst subtitle = (symbol: AssetSymbol): string =>\n `Your ${symbol} shares have been delivered to your wallet.`;\n\nexport interface OndoOrderConfirmedProps {\n state: OndoOrderConfirmedUiState;\n onEvent: (event: OndoOrderConfirmedUiEvent) => void;\n className?: string;\n}\n\n/**\n * The dialog that closes the Ondo checkout: what arrived, what it cost, and\n * where it went.\n *\n * Pure: every figure is handed over formatted, and the explorer link is\n * rendered from the URL the viewmodel built rather than raised as an event.\n *\n * Self-scoped: renders fully styled on its own. It bails before the scope while\n * hidden, so a closed dialog leaves nothing in the DOM.\n */\nexport function OndoBuyOrderConfirmed({\n state,\n onEvent,\n className,\n}: OndoOrderConfirmedProps): ReactNode {\n if (state.type === 'hidden') {\n return null;\n }\n\n const onClose = () => onEvent({ type: 'ON_CLOSE_ORDER_CONFIRMED' });\n\n return (\n <CoinListStyleScope>\n <CheckoutConfirmationDialog\n icon={<SuccessGlyph />}\n title={TITLE}\n subtitle={subtitle(state.outputAsset.symbol)}\n header={<AssetSummaryRow asset={state.outputAsset} wrapIdentity />}\n rows={detailRows(state)}\n actions={\n <>\n <ClButton variant=\"gradient\" fullWidth onClick={onClose}>\n {DONE_LABEL}\n </ClButton>\n <ExplorerLink url={state.txExplorerUrl} />\n </>\n }\n onClose={onClose}\n className={className}\n />\n </CoinListStyleScope>\n );\n}\n\nfunction detailRows(\n state: Extract<OndoOrderConfirmedUiState, { type: 'visible' }>\n): CheckoutDetailRowUi[] {\n return [\n { label: SHARES_RECEIVED_LABEL, value: state.outputAmount },\n { label: TOTAL_COST_LABEL, value: state.totalCost },\n { label: PRICE_PER_SHARE_LABEL, value: state.pricePerShare },\n { label: DELIVERED_TO_LABEL, value: state.recipientAddress },\n ];\n}\n\nfunction SuccessGlyph(): ReactNode {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:size-10 clcosdk:shrink-0 clcosdk:items-center clcosdk:justify-center',\n 'clcosdk:rounded-full clcosdk:bg-positive-subtle'\n )}\n >\n <Check\n className=\"clcosdk:size-5 clcosdk:text-positive\"\n strokeWidth={2.5}\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n\n/**\n * An anchor rather than a button: the URL is known, so middle-click, copy-link\n * and the host's own link handling all keep working.\n */\nfunction ExplorerLink({ url }: { url: string }): ReactNode {\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n typeClasses.label,\n 'clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:items-center clcosdk:justify-center clcosdk:gap-1.5',\n 'clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:px-4',\n 'clcosdk:text-text-primary clcosdk:no-underline',\n 'clcosdk:transition-colors clcosdk:hover:bg-section'\n )}\n >\n {VIEW_TRANSACTION_LABEL}\n <ExternalLink\n className=\"clcosdk:size-3.5 clcosdk:shrink-0\"\n strokeWidth={1.5}\n aria-hidden=\"true\"\n />\n </a>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface DetailRowProps {\n label: string;\n /** The right-aligned value. A slot, so a row may render an address or a link. */\n value: ReactNode;\n /** Slot: an explainer beside the label, usually a `Tooltip`. */\n tooltip?: ReactNode;\n /** Emphasises the row — used by the total line under the divider. */\n emphasis?: boolean;\n className?: string;\n}\n\n/**\n * One `label — value` line of an order summary.\n *\n * The value wraps rather than truncates: an address or an amount losing its\n * tail is worse than a two-line row.\n */\nexport function DetailRow({\n label,\n value,\n tooltip,\n emphasis = false,\n className,\n}: DetailRowProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:shrink-0 clcosdk:items-center clcosdk:gap-2\">\n <span\n className={cn(\n emphasis ? typeClasses.bodyMedium : typeClasses.body,\n emphasis\n ? 'clcosdk:text-text-primary'\n : 'clcosdk:text-text-secondary'\n )}\n >\n {label}\n </span>\n {tooltip}\n </div>\n <span\n className={cn(\n emphasis ? typeClasses.bodyMedium : typeClasses.body,\n 'clcosdk:min-w-0 clcosdk:break-words clcosdk:text-right clcosdk:text-text-primary'\n )}\n >\n {value}\n </span>\n </div>\n </CoinListStyleScope>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { DetailRow } from '@/client/components/checkout/shared/common/DetailRow';\nimport { cn } from '@/client/components/design-system/utils';\n\n/**\n * One line of a detail list.\n *\n * A components-layer model, not a UI model from the hooks tree: a viewmodel\n * hands a screen named, typed fields, and it is the View that decides which of\n * them become rows and in what order.\n */\nexport type CheckoutDetailRowUi = {\n label: string;\n /**\n * `null` drops the row entirely. Absence is common — a fee nobody discloses,\n * an identifier the API does not carry — and a label with a dash beside it\n * reads as a broken value rather than an inapplicable one.\n */\n value: ReactNode | null;\n /** Slot: an explainer beside the label, usually a `Tooltip`. */\n tooltip?: ReactNode;\n /** Emphasises the row — the total under a divider. */\n emphasis?: boolean;\n};\n\n/** How tightly the rows stack. */\nexport type CheckoutDetailListDensity = 'compact' | 'default';\n\nexport interface CheckoutDetailListProps {\n rows: CheckoutDetailRowUi[];\n /** `compact` (8px) for a reference panel, `default` (12px) for an order summary. */\n density?: CheckoutDetailListDensity;\n /** For an `aria-controls` pointing here, as the sidebar's disclosure does. */\n id?: string;\n className?: string;\n}\n\nconst densityClasses: Record<CheckoutDetailListDensity, string> = {\n compact: 'clcosdk:gap-2',\n default: 'clcosdk:gap-3',\n};\n\n/**\n * A stack of `label — value` rows, with the null ones dropped.\n *\n * The dropping lives here rather than in each caller so that every screen\n * treats a missing value the same way, and a View can build its rows straight\n * from nullable state without filtering first.\n */\nexport function CheckoutDetailList({\n rows,\n density = 'default',\n id,\n className,\n}: CheckoutDetailListProps) {\n const visibleRows = rows.filter((row) => row.value !== null);\n\n return (\n <CoinListStyleScope>\n <div\n id={id}\n className={cn(\n 'clcosdk:flex clcosdk:flex-col',\n densityClasses[density],\n className\n )}\n >\n {visibleRows.map((row) => (\n <DetailRow\n key={row.label}\n label={row.label}\n value={row.value}\n tooltip={row.tooltip}\n emphasis={row.emphasis}\n />\n ))}\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { type ReactNode, useEffect, useRef } from 'react';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface ModalProps {\n /**\n * The dialog's accessible name, announced when it opens.\n *\n * A plain string rather than a slot, and separate from the visible heading:\n * designs disagree about what sits above the title — the order-confirmed\n * dialog leads with a glyph — so the heading itself is rendered by\n * `children`, where it can be placed freely.\n */\n label: string;\n /** Escape, or the caller's own control. */\n onClose: () => void;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * A centered dialog over a dimmed page. Rendering it means it is open — there\n * is no `isOpen`; a caller with nothing to show renders nothing.\n *\n * Deliberately small: it owns the overlay, the dialog semantics, Escape and\n * focus (moved in on open, returned to the invoking element on close), and\n * nothing about layout. What the dialog looks like inside is the caller's\n * business.\n *\n * No portal, matching {@link ConnectWalletModalView} and\n * {@link TaxDocumentModalView}: the SDK renders inside the host's tree rather\n * than escaping to `document.body`, so a host's own stacking context stays in\n * charge. Those two and `VerificationOverlay` still hand-roll this chrome and\n * should be moved onto it.\n */\nexport function Modal({ label, onClose, children, className }: ModalProps) {\n const surfaceRef = useRef<HTMLDivElement>(null);\n\n // Keep the latest handler without re-binding the listener, so a caller\n // passing an inline arrow does not detach and re-attach it on every render.\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n\n useEffect(() => {\n const previouslyFocused = document.activeElement;\n surfaceRef.current?.focus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') onCloseRef.current();\n };\n document.addEventListener('keydown', onKeyDown);\n\n return () => {\n document.removeEventListener('keydown', onKeyDown);\n // Returning focus is what makes the dialog navigable by keyboard: the\n // user lands back on the control that opened it, not at the top of the\n // page.\n if (previouslyFocused instanceof HTMLElement) previouslyFocused.focus();\n };\n }, []);\n\n return (\n // The backdrop dims and traps nothing: Escape and the dialog's own controls\n // are how it closes. A click-to-dismiss handler here would be an\n // interaction on a static element with no keyboard equivalent, and the two\n // hand-rolled modals this replaces do not offer one either.\n <div className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4\">\n <div\n ref={surfaceRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={label}\n // Focusable so the dialog can take focus on open without stealing it\n // from a specific control inside it.\n tabIndex={-1}\n className={cn(\n 'clcosdk:flex clcosdk:max-h-full clcosdk:w-component clcosdk:max-w-full clcosdk:flex-col clcosdk:overflow-y-auto',\n 'clcosdk:rounded-2xl clcosdk:md:rounded-dialog',\n 'clcosdk:border-[1.5px] clcosdk:border-border clcosdk:bg-background',\n 'clcosdk:p-6 clcosdk:shadow-dialog clcosdk:focus-visible:outline-none',\n className\n )}\n >\n {children}\n </div>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport {\n CheckoutDetailList,\n type CheckoutDetailRowUi,\n} from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { Modal } from '@/client/components/design-system/Modal';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CheckoutConfirmationDialogProps {\n /** Slot: the glyph above the title, e.g. a check in a tinted circle. */\n icon: ReactNode;\n /**\n * The heading, and the dialog's accessible name.\n *\n * A plain string rather than a slot: every confirmation heading is one line\n * of copy, and the dialog needs it as text to announce itself.\n */\n title: string;\n /** Slot: the line under the title, e.g. what was delivered and where. */\n subtitle?: ReactNode;\n /** Slot: the headline block, usually an `AssetSummaryRow`. */\n header?: ReactNode;\n /** The order's figures. Null-valued rows are dropped by the list. */\n rows: CheckoutDetailRowUi[];\n /** Slot: the stacked buttons at the foot of the dialog. */\n actions: ReactNode;\n onClose: () => void;\n className?: string;\n}\n\n/**\n * The dialog that closes a checkout: what was bought, what it cost, and where\n * it went.\n *\n * Every provider's success screen is this shape, so what varies — the glyph,\n * the copy, which figures are worth listing, whether there is a transaction to\n * link to — arrives through slots. Rendering it means the order is done; a\n * provider with nothing to confirm renders nothing.\n */\nexport function CheckoutConfirmationDialog({\n icon,\n title,\n subtitle,\n header,\n rows,\n actions,\n onClose,\n className,\n}: CheckoutConfirmationDialogProps) {\n return (\n <CoinListStyleScope>\n <Modal label={title} onClose={onClose} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-2\">\n {icon}\n <h2 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {title}\n </h2>\n {subtitle && (\n <p\n className={cn(\n typeClasses.bodySm,\n 'clcosdk:text-text-secondary'\n )}\n >\n {subtitle}\n </p>\n )}\n </div>\n\n {header}\n\n <Divider />\n\n <CheckoutDetailList rows={rows} />\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3\">\n {actions}\n </div>\n </div>\n </Modal>\n </CoinListStyleScope>\n );\n}\n\nfunction Divider() {\n return <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />;\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\n\nexport interface AssetSummaryRowProps {\n asset: CheckoutAssetUi;\n /** Icon edge length in px. */\n iconSize?: number;\n /** Slot: the emphasised figure on the right — a price, a quantity. */\n value?: ReactNode;\n /** Slot: the muted line under `value` — a market status, a unit. */\n caption?: ReactNode;\n /**\n * The name and symbol wrap onto further lines. The confirmation dialog sets\n * this so a fund's full name stays on the card; the sidebar leaves it off\n * so a long name stays one line beside the price.\n */\n wrapIdentity?: boolean;\n className?: string;\n}\n\n/**\n * An asset headline: icon, name and symbol on the left, a figure and its\n * caption on the right.\n *\n * The right-hand pair are slots. The sidebar shows a price over a market\n * status. A confirmation dialog passes neither and lists the share count as a\n * detail row, so a long name has the row to itself.\n */\nexport function AssetSummaryRow({\n asset,\n iconSize = 48,\n value,\n caption,\n wrapIdentity = false,\n className,\n}: AssetSummaryRowProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n <AssetIcon asset={asset} size={iconSize} />\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:justify-center\">\n <span\n className={cn(\n typeClasses.h4,\n 'clcosdk:text-text-primary',\n wrapIdentity ? 'clcosdk:break-words' : 'clcosdk:truncate'\n )}\n >\n {asset.name}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:text-text-secondary',\n wrapIdentity ? 'clcosdk:break-words' : 'clcosdk:truncate'\n )}\n >\n {asset.symbol}\n </span>\n </div>\n </div>\n\n {(value || caption) && (\n <div className=\"clcosdk:flex clcosdk:shrink-0 clcosdk:flex-col clcosdk:items-end clcosdk:justify-center\">\n {/* Both slots are `div`s rather than `span`s: a caller may pass an\n element as readily as copy — a `Skeleton` while the figure is in\n flight — and a block element inside an inline one is invalid. */}\n {value && (\n // `min-h-[1lh]` + flex center: a Skeleton sized to `1em` (cap\n // height) sits in the same line box as loaded copy, so leading\n // keeps the two rows apart instead of two full-lh bars colliding.\n <div\n className={cn(\n typeClasses.h4,\n 'clcosdk:flex clcosdk:min-h-[1lh] clcosdk:items-center',\n 'clcosdk:justify-end clcosdk:text-text-primary'\n )}\n >\n {value}\n </div>\n )}\n {caption && (\n // Styled here so a caption passed as plain copy needs no classes of\n // its own; a caption that brings its own (a `StatusIndicator`) sets\n // them on the element inside and wins.\n <div\n className={cn(\n typeClasses.subhead,\n 'clcosdk:flex clcosdk:min-h-[1lh] clcosdk:items-center',\n 'clcosdk:justify-end clcosdk:text-text-secondary'\n )}\n >\n {caption}\n </div>\n )}\n </div>\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { ONDO_TOS_URL } from '@/client/components/checkout/ondo/shared/constants';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { DetailRow } from '@/client/components/checkout/shared/common/DetailRow';\nimport {\n COINLIST_PRIVACY_URL,\n COINLIST_TOS_URL,\n} from '@/client/components/checkout/shared/constants';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { Tooltip } from '@/client/components/design-system/Tooltip';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoBuyQuoteStatusUi,\n OndoBuyReviewUiEvent,\n OndoBuyReviewUiState,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel.types';\n\nconst TITLE = '3. Review and confirm';\nconst YOU_RECEIVE_LABEL = 'You receive';\nconst RECEIVING_WALLET_LABEL = 'Receiving wallet';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst PRICE_PER_SHARE_TOOLTIP =\n 'The price of one whole token at the time of this quote.';\nconst COINLIST_FEE_LABEL = 'CoinList fee';\nconst COINLIST_FEE_TOOLTIP =\n \"CoinList's fee for this order. It is already included in the total you pay.\";\nconst TOTAL_LABEL = 'Total';\nconst REFRESH_QUOTE_LABEL = 'Refresh quote';\nconst LOADING_STATUS = 'Loading your order details…';\nconst ERROR_TITLE = 'Something went wrong';\nconst ERROR_DESCRIPTION =\n \"We couldn't load your order details. Please try again.\";\n\nexport interface OndoBuyReviewViewProps {\n state: OndoBuyReviewUiState;\n onEvent: (event: OndoBuyReviewUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 3 of the Ondo checkout. Pure: every number arrives formatted, and\n * whether the order can be placed is decided by `placeOrderCta` rather than\n * re-derived here from the quote's status.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoBuyReviewView(props: OndoBuyReviewViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoReviewViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoReviewViewBody({\n state,\n onEvent,\n className,\n}: OndoBuyReviewViewProps): ReactNode {\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={TITLE}\n className={className}\n />\n );\n case 'loading':\n return <LoadingView className={className} />;\n case 'error':\n return <ErrorView onEvent={onEvent} className={className} />;\n case 'active':\n return (\n <ActiveView state={state} onEvent={onEvent} className={className} />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<OndoBuyReviewUiState, { type: 'active' }>;\n onEvent: (event: OndoBuyReviewUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {YOU_RECEIVE_LABEL}\n </span>\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n <AssetIcon asset={state.outputAsset} size={40} />\n <span className=\"clcosdk:min-w-0 clcosdk:break-words clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium clcosdk:text-text-primary\">\n {state.outputAmount}\n </span>\n </div>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n <DetailRow\n label={RECEIVING_WALLET_LABEL}\n value={state.recipientAddress}\n />\n <DetailRow\n label={PRICE_PER_SHARE_LABEL}\n tooltip={\n <Tooltip content={PRICE_PER_SHARE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.pricePerShare}\n />\n {state.coinlistFee !== null && (\n <DetailRow\n label={COINLIST_FEE_LABEL}\n tooltip={\n <Tooltip content={COINLIST_FEE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.coinlistFee}\n />\n )}\n </div>\n\n <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />\n\n <DetailRow\n label={TOTAL_LABEL}\n value={state.total}\n emphasis\n className=\"clcosdk:px-2\"\n />\n </div>\n\n {/* Both lines, never one or the other. Placing an order takes longer\n than a quote lives, so a failure usually arrives on a quote that has\n already expired - and the quote line carries the only refresh link.\n Letting the error stand in for it left the user with a disabled CTA\n and no way to ask for a new quote (ENG-1733). */}\n {state.error !== null && (\n <QuoteLine tone=\"error\">{state.error}</QuoteLine>\n )}\n <QuoteStatusLine quote={state.quote} onEvent={onEvent} />\n\n <ClButton\n variant=\"gradient\"\n size=\"cta\"\n fullWidth\n disabled={state.placeOrderCta.type === 'disabled'}\n isLoading={state.placeOrderCta.type === 'loading'}\n loadingText={\n state.placeOrderCta.type === 'loading'\n ? state.placeOrderCta.message\n : undefined\n }\n onClick={() => onEvent({ type: 'ON_PLACE_ORDER' })}\n >\n Place order\n </ClButton>\n\n <Disclaimer />\n </CheckoutStepCard>\n );\n}\n\n/**\n * The line above the CTA saying whether the numbers can still be traded on.\n *\n * Every arm but `refreshing` offers the refresh action, because in every one of\n * them refreshing is the thing that helps.\n */\nfunction QuoteStatusLine({\n quote,\n onEvent,\n}: {\n quote: OndoBuyQuoteStatusUi;\n onEvent: (event: OndoBuyReviewUiEvent) => void;\n}): ReactNode {\n const refreshLink = (\n <button\n type=\"button\"\n onClick={() => onEvent({ type: 'ON_REFRESH_QUOTE' })}\n className=\"clcosdk:cursor-pointer clcosdk:underline clcosdk:transition-opacity clcosdk:hover:opacity-80\"\n >\n {REFRESH_QUOTE_LABEL}\n </button>\n );\n\n switch (quote.type) {\n case 'valid':\n return (\n <QuoteLine tone=\"muted\">\n {quote.expiresInLabel} {refreshLink}\n </QuoteLine>\n );\n case 'refreshing':\n return <QuoteLine tone=\"muted\">Refreshing quote…</QuoteLine>;\n case 'expired':\n return <QuoteLine tone=\"warning\">Quote expired. {refreshLink}</QuoteLine>;\n case 'refresh-failed':\n return (\n <QuoteLine tone=\"warning\">\n {quote.message} {refreshLink}\n </QuoteLine>\n );\n default: {\n const exhaustive: never = quote;\n return exhaustive;\n }\n }\n}\n\nfunction QuoteLine({\n tone,\n children,\n}: {\n tone: 'muted' | 'warning' | 'error';\n children: ReactNode;\n}): ReactNode {\n const toneClass = {\n muted: 'clcosdk:text-text-secondary',\n warning: 'clcosdk:text-warning',\n error: 'clcosdk:text-error',\n }[tone];\n\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:md:px-6',\n toneClass\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction LoadingView({ className }: { className?: string }): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n {/* Every skeleton below is aria-hidden, so this line is the only thing a\n screen reader has to go on while the order details load. */}\n <output className=\"clcosdk:sr-only\">{LOADING_STATUS}</output>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-20\" />\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-3\">\n <Skeleton\n variant=\"circular\"\n className=\"clcosdk:size-10 clcosdk:shrink-0\"\n />\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <Skeleton className=\"clcosdk:h-5 clcosdk:w-32\" />\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-24\" />\n </div>\n </div>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n {['wallet', 'price', 'fee'].map((row) => (\n <div\n key={row}\n className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\"\n >\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-28\" />\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-24\" />\n </div>\n ))}\n </div>\n\n <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />\n\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4 clcosdk:px-2\">\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-16\" />\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-20\" />\n </div>\n\n <Skeleton\n variant=\"rectangular\"\n className=\"clcosdk:h-[54px] clcosdk:w-full clcosdk:rounded-full\"\n />\n </CheckoutStepCard>\n );\n}\n\nfunction ErrorView({\n onEvent,\n className,\n}: {\n onEvent: (event: OndoBuyReviewUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-4 clcosdk:py-8 clcosdk:text-center\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-2\">\n <h3\n className={cn(\n typeClasses.h4,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {ERROR_TITLE}\n </h3>\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:max-w-md clcosdk:text-text-secondary'\n )}\n >\n {ERROR_DESCRIPTION}\n </p>\n </div>\n <ClButton\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_RETRY' })}\n >\n Try again\n </ClButton>\n </div>\n </CheckoutStepCard>\n );\n}\n\nfunction Disclaimer(): ReactNode {\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:text-text-secondary clcosdk:md:px-6'\n )}\n >\n By placing this order, you agree to CoinList's{' '}\n <DisclaimerLink href={COINLIST_TOS_URL}>Terms of Service</DisclaimerLink>{' '}\n and{' '}\n <DisclaimerLink href={COINLIST_PRIVACY_URL}>\n Privacy Policy\n </DisclaimerLink>\n , and <DisclaimerLink href={ONDO_TOS_URL}>Ondo's Terms</DisclaimerLink>.\n </p>\n );\n}\n\nfunction DisclaimerLink({\n href,\n children,\n}: {\n href: string;\n children: ReactNode;\n}): ReactNode {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"clcosdk:underline clcosdk:transition-colors clcosdk:hover:text-text-primary\"\n >\n {children}\n </a>\n );\n}\n\nfunction InfoIcon(): ReactNode {\n return (\n <Info\n className=\"clcosdk:size-4 clcosdk:text-text-secondary\"\n aria-hidden=\"true\"\n />\n );\n}\n","/**\n * Ondo's own terms, which a user accepts by placing an Ondo order.\n *\n * Hardcoded rather than taken as a prop: the disclaimer names Ondo\n * specifically, so a partner substituting their own link would be misstating\n * whose terms apply.\n *\n * CoinList's terms and privacy policy are linked from the same disclaimer but\n * live in `checkout/shared/constants`: they are the platform's, not this\n * provider's.\n */\nexport const ONDO_TOS_URL = 'https://docs.ondo.finance/legal/terms-of-service';\n","/**\n * CoinList's own agreements, which a user accepts by placing an order with\n * any provider.\n *\n * Hardcoded rather than taken as a prop: the disclaimer names CoinList\n * specifically, so a partner substituting their own links would be misstating\n * whose terms apply.\n *\n * Literal URLs rather than derived from the configured `coinlistBaseUrl`:\n * these are the same legal documents whichever API host a partner is pointed\n * at, so a beta host must not send its users to a beta copy of them.\n *\n * They live here rather than in the one provider directory that reads them\n * today because whose terms these are is a fact about the platform, not about\n * Ondo: every checkout the SDK ships is served by CoinList, and the\n * `coinlist::token_sale` flow will link the same two documents.\n */\nexport const COINLIST_TOS_URL = 'https://coinlist.co/terms';\nexport const COINLIST_PRIVACY_URL = 'https://coinlist.co/privacy';\n","import { cn } from '@/client/components/design-system/utils';\n\n/**\n * The shape a skeleton stands in for. `text` is the default because most\n * placeholders replace a line of copy.\n */\nexport type SkeletonVariant = 'text' | 'circular' | 'rectangular';\n\nexport interface SkeletonProps {\n variant?: SkeletonVariant;\n /** Size and spacing are the caller's call — pass `h-*` / `w-*` here. */\n className?: string;\n}\n\nconst variantClasses: Record<SkeletonVariant, string> = {\n text: 'clcosdk:rounded-md',\n circular: 'clcosdk:rounded-full',\n rectangular: 'clcosdk:rounded-2xl',\n};\n\n/**\n * A pulsing placeholder for content that has not arrived yet.\n *\n * Purely decorative: it carries `aria-hidden`, so a screen reader hears the\n * loading state from the region that owns it rather than from a pile of empty\n * boxes.\n */\nexport function Skeleton({ variant = 'text', className }: SkeletonProps) {\n return (\n <div\n aria-hidden=\"true\"\n className={cn(\n 'clcosdk:animate-pulse clcosdk:bg-section',\n variantClasses[variant],\n className\n )}\n />\n );\n}\n","'use client';\n\nimport { type ReactNode, useId } from 'react';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type TooltipPosition = 'top' | 'bottom';\n\nexport interface TooltipProps {\n /** What the tooltip says. A slot, so callers may pass rich content. */\n content: ReactNode;\n position?: TooltipPosition;\n /** The element the tooltip describes — usually a small info icon. */\n children: ReactNode;\n className?: string;\n}\n\nconst positionClasses: Record<TooltipPosition, string> = {\n top: 'clcosdk:bottom-full clcosdk:mb-2',\n bottom: 'clcosdk:top-full clcosdk:mt-2',\n};\n\n/**\n * A hover/focus tooltip.\n *\n * CSS-only: it shows on `:hover` and on `:focus-within`, so it is reachable by\n * keyboard without a popover library or an effect. The bubble stays mounted and\n * hidden rather than being conditionally rendered, which is what lets\n * `aria-describedby` point at it at all times.\n */\nexport function Tooltip({\n content,\n position = 'top',\n children,\n className,\n}: TooltipProps) {\n const tooltipId = useId();\n\n return (\n <span\n // biome-ignore lint/a11y/noNoninteractiveTabindex: focusable on purpose — it is what makes the tooltip keyboard-reachable.\n tabIndex={0}\n aria-describedby={tooltipId}\n className={cn(\n 'clcosdk:group clcosdk:relative clcosdk:inline-flex clcosdk:items-center',\n // The trigger is focusable, so it needs a focus ring of its own: the\n // same one ClButton and CloseButton use.\n 'clcosdk:rounded-full clcosdk:focus-visible:outline-none',\n 'clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2',\n className\n )}\n >\n {children}\n <span\n id={tooltipId}\n role=\"tooltip\"\n className={cn(\n typeClasses.caption,\n 'clcosdk:pointer-events-none clcosdk:absolute clcosdk:left-1/2 clcosdk:z-50 clcosdk:-translate-x-1/2',\n 'clcosdk:w-max clcosdk:max-w-[16rem] clcosdk:rounded-btn clcosdk:px-3 clcosdk:py-2',\n 'clcosdk:bg-text-primary clcosdk:text-background clcosdk:text-center',\n 'clcosdk:opacity-0 clcosdk:transition-opacity',\n 'clcosdk:group-hover:opacity-100 clcosdk:group-focus-within:opacity-100',\n positionClasses[position]\n )}\n >\n {content}\n </span>\n </span>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { OndoCheckoutErrorReason } from '@/client/hooks/checkout/ondo/shared/ondo-checkout-error.types';\n\nconst UNSUPPORTED_CHAIN_TITLE = 'Not available on this network';\nconst UNSUPPORTED_CHAIN_DESCRIPTION =\n 'Ondo orders cannot be placed on the selected network.';\nconst NOT_TRADABLE_TITLE = 'Trading is closed right now';\nconst NOT_TRADABLE_DESCRIPTION =\n 'This asset cannot be traded at the moment. Come back when the market opens.';\n\nexport interface OndoCheckoutErrorProps {\n reason: OndoCheckoutErrorReason;\n className?: string;\n}\n\n/**\n * What an Ondo checkout renders when there is no checkout to render, or none\n * the user can act on right now.\n *\n * Shared by both products rather than duplicated in each, because the reason\n * is a property of the integration and not of the direction: a chain that\n * cannot serve a buy cannot serve a sell, and the copy would be the same\n * sentence twice.\n *\n * No retry, deliberately. Superstate's equivalent offers one for `load-failed`,\n * where a re-fetch can genuinely succeed. Here `unsupported-chain` is settled\n * at mount and cannot change under a button, and `not-tradable` clears on its\n * own once the market opens, since the viewmodel keeps polling underneath it.\n * Offering a button that provably cannot help is worse than offering none.\n *\n * Self-scoped, like every exported component: it renders fully styled with no\n * provider in the tree, and the scope is idempotent so nesting costs nothing.\n */\nexport function OndoCheckoutError({\n reason,\n className,\n}: OndoCheckoutErrorProps): ReactNode {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:min-w-0 clcosdk:flex-col',\n 'clcosdk:items-center clcosdk:gap-4 clcosdk:py-12 clcosdk:text-center',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-2\">\n <h2\n className={cn(\n typeClasses.h3,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {title(reason)}\n </h2>\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:max-w-md clcosdk:text-text-secondary'\n )}\n >\n {description(reason)}\n </p>\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction title(reason: OndoCheckoutErrorReason): string {\n switch (reason) {\n case 'unsupported-chain':\n return UNSUPPORTED_CHAIN_TITLE;\n case 'not-tradable':\n return NOT_TRADABLE_TITLE;\n default: {\n const exhaustive: never = reason;\n return exhaustive;\n }\n }\n}\n\nfunction description(reason: OndoCheckoutErrorReason): string {\n switch (reason) {\n case 'unsupported-chain':\n return UNSUPPORTED_CHAIN_DESCRIPTION;\n case 'not-tradable':\n return NOT_TRADABLE_DESCRIPTION;\n default: {\n const exhaustive: never = reason;\n return exhaustive;\n }\n }\n}\n","import { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutStatusUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\n\nexport interface StatusIndicatorProps {\n status: CheckoutStatusUi;\n className?: string;\n}\n\n/**\n * Renders a {@link CheckoutStatusUi} as its label — `Market open`, `Market\n * closed`, a countdown, whatever copy the viewmodel already formatted.\n */\nexport function StatusIndicator({ status, className }: StatusIndicatorProps) {\n return (\n <CoinListStyleScope>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary',\n className\n )}\n >\n {status.label}\n </span>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { ChevronDown, ChevronUp } from 'lucide-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutCard } from '@/client/components/checkout/shared/common/CheckoutCard';\nimport {\n CheckoutDetailList,\n type CheckoutDetailRowUi,\n} from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CheckoutSidebarCardProps {\n /** Slot: the panel's heading, e.g. `Asset details`. Hidden below `md`. */\n title: ReactNode;\n /** Slot: the headline block, usually an `AssetSummaryRow`. */\n header: ReactNode;\n /** The reference rows. Null-valued ones are dropped by the list. */\n rows: CheckoutDetailRowUi[];\n /** Copy for the mobile disclosure, e.g. `Show details`. */\n showDetailsLabel: string;\n /** Copy for the mobile disclosure once open, e.g. `Hide details`. */\n hideDetailsLabel: string;\n className?: string;\n}\n\n/**\n * The reference panel beside a checkout: what is being bought, and the facts\n * about it that do not change as the order is filled in.\n *\n * Below `md` it stops being a card — no border, no background, no padding — and\n * folds its rows behind a disclosure, because on a phone it sits above the\n * steps and must not push the flow off the screen. Whether it is open is\n * ephemeral visual state and stays here; nothing upstream needs to know.\n */\nexport function CheckoutSidebarCard({\n title,\n header,\n rows,\n showDetailsLabel,\n hideDetailsLabel,\n className,\n}: CheckoutSidebarCardProps) {\n const [expanded, setExpanded] = useState(false);\n const rowsId = useId();\n\n return (\n <CoinListStyleScope>\n <CheckoutCard\n className={cn(\n 'clcosdk:max-md:gap-4 clcosdk:max-md:rounded-none clcosdk:max-md:border-0',\n 'clcosdk:max-md:bg-transparent clcosdk:max-md:p-0',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-4\">\n <h2\n className={cn(\n typeClasses.h4,\n 'clcosdk:text-text-primary clcosdk:max-md:hidden'\n )}\n >\n {title}\n </h2>\n {header}\n </div>\n\n <div\n className={cn(\n 'clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider',\n !expanded && 'clcosdk:max-md:hidden'\n )}\n />\n\n <CheckoutDetailList\n id={rowsId}\n rows={rows}\n density=\"compact\"\n className={cn('clcosdk:px-2', !expanded && 'clcosdk:max-md:hidden')}\n />\n\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={rowsId}\n onClick={() => setExpanded((value) => !value)}\n className={cn(\n typeClasses.label,\n 'clcosdk:flex clcosdk:w-fit clcosdk:items-center clcosdk:gap-1.5 clcosdk:self-start',\n 'clcosdk:h-9 clcosdk:rounded-full clcosdk:bg-section clcosdk:px-4',\n 'clcosdk:cursor-pointer clcosdk:text-text-primary',\n 'clcosdk:transition-colors clcosdk:hover:bg-border',\n // The disclosure exists for the collapsed mobile layout only; from\n // `md` up every row is on screen already.\n 'clcosdk:md:hidden'\n )}\n >\n {expanded ? hideDetailsLabel : showDetailsLabel}\n {expanded ? (\n <ChevronUp className=\"clcosdk:size-4\" aria-hidden=\"true\" />\n ) : (\n <ChevronDown className=\"clcosdk:size-4\" aria-hidden=\"true\" />\n )}\n </button>\n </CheckoutCard>\n </CoinListStyleScope>\n );\n}\n","import type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface CheckoutCardProps {\n children?: ReactNode;\n className?: string;\n}\n\n/**\n * The plain card surface a checkout panel sits on: border, background, radius\n * and padding, plus the column its blocks stack in.\n *\n * Chrome only — it has no title, no states and no opinion about its contents,\n * so a panel that needs different behaviour (the sidebar's mobile disclosure)\n * composes it rather than configuring it.\n *\n * `CheckoutStepCard` deliberately does *not* build on this: a step's padding,\n * gap and elevation all change with its state, and `cn` is plain `clsx` with no\n * Tailwind conflict resolution, so overriding those through `className` would\n * leave both classes in the markup and let stylesheet order decide.\n */\nexport function CheckoutCard({ children, className }: CheckoutCardProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-6',\n 'clcosdk:p-4 clcosdk:md:p-6',\n 'clcosdk:rounded-2xl clcosdk:md:rounded-card',\n 'clcosdk:border clcosdk:border-border clcosdk:bg-background',\n className\n )}\n >\n {children}\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { StatusIndicator } from '@/client/components/checkout/shared/common/StatusIndicator';\nimport { CheckoutSidebarCard } from '@/client/components/checkout/shared/sidebar/CheckoutSidebarCard';\nimport { AssetSummaryRow } from '@/client/components/checkout/shared/summary/AssetSummaryRow';\nimport type { CheckoutDetailRowUi } from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport type {\n OndoSidebarPriceUi,\n OndoSidebarUiState,\n} from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel.types';\n\nconst TITLE = 'Asset details';\nconst SHOW_DETAILS_LABEL = 'Show details';\nconst HIDE_DETAILS_LABEL = 'Hide details';\nconst ISSUER_LABEL = 'Issuer';\nconst TICKER_SYMBOL_LABEL = 'Ticker symbol';\nconst ISIN_LABEL = 'ISIN';\nconst ASSET_TYPE_LABEL = 'Asset type';\nconst LISTING_VENUE_LABEL = 'Listing venue';\nconst NETWORK_LABEL = 'Network';\nconst PRICE_UNAVAILABLE = '-';\n\nexport interface OndoSidebarViewProps {\n state: OndoSidebarUiState;\n className?: string;\n}\n\n/**\n * The panel beside the Ondo checkout: what is being bought, what one share\n * costs, and the reference facts about the asset.\n *\n * Read-only, so it takes no `onEvent`. Rows the SDK has no source for arrive as\n * `null` and are dropped by `CheckoutDetailList` rather than rendered empty.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoSidebarView({\n state,\n className,\n}: OndoSidebarViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <CheckoutSidebarCard\n title={TITLE}\n header={\n <AssetSummaryRow\n asset={state.asset}\n value={<PriceValue price={state.price} />}\n caption={<PriceCaption price={state.price} />}\n />\n }\n rows={detailRows(state)}\n showDetailsLabel={SHOW_DETAILS_LABEL}\n hideDetailsLabel={HIDE_DETAILS_LABEL}\n className={className}\n />\n </CoinListStyleScope>\n );\n}\n\nfunction detailRows(state: OndoSidebarUiState): CheckoutDetailRowUi[] {\n return [\n { label: ISSUER_LABEL, value: state.issuer },\n { label: TICKER_SYMBOL_LABEL, value: state.tickerSymbol },\n { label: ISIN_LABEL, value: state.isin },\n { label: ASSET_TYPE_LABEL, value: state.assetType },\n { label: LISTING_VENUE_LABEL, value: state.listingVenue },\n { label: NETWORK_LABEL, value: state.networkName },\n ];\n}\n\nfunction PriceValue({ price }: { price: OndoSidebarPriceUi }): ReactNode {\n switch (price.type) {\n case 'loading':\n return <Skeleton className=\"clcosdk:h-[1em] clcosdk:w-24\" />;\n case 'known':\n return price.price;\n case 'unavailable':\n return PRICE_UNAVAILABLE;\n default: {\n // A new price arm without a case here is a compile error.\n const exhaustive: never = price;\n return exhaustive;\n }\n }\n}\n\nfunction PriceCaption({ price }: { price: OndoSidebarPriceUi }): ReactNode {\n switch (price.type) {\n case 'loading':\n return <Skeleton className=\"clcosdk:h-[1em] clcosdk:w-20\" />;\n case 'known':\n return <StatusIndicator status={price.market} />;\n // Nothing to say about a market whose price never arrived: the order steps\n // are where that failure is reported and retried.\n case 'unavailable':\n return null;\n default: {\n const exhaustive: never = price;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { Wallet } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport {\n OptionMetaRow,\n SelectableOptionRow,\n} from '@/client/components/checkout/shared/selection/SelectableOptionRow';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { CheckoutStepFooter } from '@/client/components/checkout/shared/step/CheckoutStepFooter';\nimport { CompletedStepSummary } from '@/client/components/checkout/shared/step/CompletedStepSummary';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoWalletSelectUiEvent,\n OndoWalletSelectUiState,\n} from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel.types';\nimport type {\n CheckoutConfirmedWalletUi,\n CheckoutEmbeddedWalletUi,\n CheckoutWalletUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\n\nconst TITLE = '1. Choose your wallet';\n/**\n * What a buy asks the wallet for. A sell asks for something else, so the copy\n * is a prop with this as its default: it is the same screen and the same\n * decision, and only the sentence explaining it differs.\n */\nconst DEFAULT_DESCRIPTION =\n 'Choose your wallet to fund your purchase and receive your assets.';\nconst EMBEDDED_WALLET_LABEL = 'CoinList Wallet';\nconst EXTERNAL_WALLET_LABEL = 'External wallet';\n\nexport interface OndoWalletSelectViewProps {\n state: OndoWalletSelectUiState;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n /**\n * The line under the heading. Defaults to the buy copy.\n *\n * A plain string rather than a slot: every Ondo product renders one sentence\n * here in the same style, and the only thing that varies is what the wallet\n * is for.\n */\n description?: string;\n className?: string;\n}\n\n/**\n * The wallet step of an Ondo checkout: which wallet the order runs through.\n * Pure - the wallets arrive already shaped, and every interaction leaves\n * through `onEvent`.\n *\n * Shared by both Ondo products, because nothing about choosing a wallet\n * differs between them: an Ondo wallet is not allow-listed either way, so the\n * decision is local and synchronous on both. Only the sentence under the\n * heading changes, and that is a prop.\n *\n * It is always step 1 where it renders at all. A sell that skips it does not\n * render this component, rather than rendering it with another number.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoWalletSelectView(\n props: OndoWalletSelectViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoWalletSelectViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoWalletSelectViewBody({\n state,\n onEvent,\n description = DEFAULT_DESCRIPTION,\n className,\n}: OndoWalletSelectViewProps): ReactNode {\n switch (state.type) {\n case 'active':\n return (\n <ActiveView\n state={state}\n onEvent={onEvent}\n description={description}\n className={className}\n />\n );\n case 'completed':\n return (\n <CompletedView\n wallet={state.wallet}\n onEvent={onEvent}\n className={className}\n />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n description,\n className,\n}: {\n state: Extract<OndoWalletSelectUiState, { type: 'active' }>;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n description: string;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard\n state=\"active\"\n title={TITLE}\n description={\n <p className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {description}\n </p>\n }\n className={className}\n footer={\n <CheckoutStepFooter\n error={state.error}\n cta={\n <ClButton\n variant=\"primary\"\n disabled={!state.confirmEnabled}\n onClick={() => onEvent({ type: 'ON_CONFIRM_WALLET' })}\n className=\"clcosdk:h-12 clcosdk:max-md:w-full\"\n >\n Confirm wallet\n </ClButton>\n }\n />\n }\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\">\n <ExternalWalletRow\n wallet={state.externalWallet}\n canDisconnect={state.canDisconnect}\n onEvent={onEvent}\n />\n {state.embeddedWallets.map((wallet) => (\n <EmbeddedWalletRow\n key={wallet.walletAddress}\n wallet={wallet}\n onEvent={onEvent}\n />\n ))}\n </div>\n </CheckoutStepCard>\n );\n}\n\n/**\n * The external-wallet row is always rendered, connected or not: disconnected it\n * is the invitation to connect one, connected it is a wallet like any other.\n */\nfunction ExternalWalletRow({\n wallet,\n canDisconnect,\n onEvent,\n}: {\n wallet: CheckoutWalletUi | null;\n canDisconnect: boolean;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n}): ReactNode {\n if (wallet === null) {\n return (\n <SelectableOptionRow\n selected={false}\n onSelect={() => onEvent({ type: 'ON_CONNECT_WALLET' })}\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {EXTERNAL_WALLET_LABEL}\n </span>\n </SelectableOptionRow>\n );\n }\n\n return (\n <SelectableOptionRow\n selected={wallet.selected}\n onSelect={() =>\n onEvent({ type: 'ON_SELECT_WALLET', value: { type: 'external' } })\n }\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {wallet.address}\n </span>\n {/*\n Below `md` the chain is omitted, so this cannot share `OptionMetaRow`\n with the desktop line: that helper inserts a dot for every child, even\n one that is only CSS-hidden, and the bullet would dangle after the\n address. Disconnect sits on its own here; the desktop meta row below\n keeps `Ethereum • Disconnect`.\n */}\n {canDisconnect && (\n <DisconnectControl\n onDisconnect={() => onEvent({ type: 'ON_DISCONNECT_WALLET' })}\n className=\"clcosdk:md:hidden\"\n />\n )}\n <div className=\"clcosdk:max-md:hidden\">\n <OptionMetaRow>\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n {wallet.network}\n </span>\n {canDisconnect && (\n <DisconnectControl\n onDisconnect={() => onEvent({ type: 'ON_DISCONNECT_WALLET' })}\n />\n )}\n </OptionMetaRow>\n </div>\n </SelectableOptionRow>\n );\n}\n\nfunction EmbeddedWalletRow({\n wallet,\n onEvent,\n}: {\n wallet: CheckoutEmbeddedWalletUi;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n}): ReactNode {\n return (\n <SelectableOptionRow\n selected={wallet.selected}\n onSelect={() =>\n onEvent({\n type: 'ON_SELECT_WALLET',\n value: { type: 'embedded', address: wallet.walletAddress },\n })\n }\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {EMBEDDED_WALLET_LABEL}\n </span>\n {/* Address only below `md`. Same reason as the external row: hiding the\n chain with CSS still leaves OptionMetaRow's separator in the markup. */}\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary clcosdk:md:hidden'\n )}\n >\n {wallet.address}\n </span>\n <div className=\"clcosdk:max-md:hidden\">\n <OptionMetaRow>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n {wallet.address}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:shrink-0 clcosdk:text-text-secondary'\n )}\n >\n {wallet.network}\n </span>\n </OptionMetaRow>\n </div>\n </SelectableOptionRow>\n );\n}\n\nfunction CompletedView({\n wallet,\n onEvent,\n className,\n}: {\n wallet: CheckoutConfirmedWalletUi;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"completed\" title={TITLE} className={className}>\n <CompletedStepSummary\n icon={<WalletGlyph />}\n title={\n wallet.type === 'embedded' ? EMBEDDED_WALLET_LABEL : wallet.address\n }\n subtitle={wallet.type === 'embedded' ? wallet.address : null}\n editLabel=\"Edit\"\n onEdit={() => onEvent({ type: 'ON_EDIT_WALLET' })}\n />\n </CheckoutStepCard>\n );\n}\n\nfunction DisconnectControl({\n onDisconnect,\n className,\n}: {\n onDisconnect: () => void;\n className?: string;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n onClick={(event) => {\n // The row behind it would otherwise take this as a selection.\n event.stopPropagation();\n onDisconnect();\n }}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:w-fit clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:self-start clcosdk:underline',\n 'clcosdk:text-text-secondary clcosdk:transition-colors clcosdk:hover:text-text-primary',\n className\n )}\n >\n Disconnect\n </button>\n );\n}\n\nfunction WalletGlyph(): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:size-10 clcosdk:shrink-0 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-xl clcosdk:bg-section\">\n <Wallet\n className=\"clcosdk:size-5 clcosdk:text-text-primary\"\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n","'use client';\n\nimport { Children, Fragment, type KeyboardEvent, type ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { selectableOptionBorderClass } from '@/client/components/checkout/shared/selection/classes';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport interface SelectableOptionRowProps {\n selected: boolean;\n /** Non-interactive while true — used to freeze the list during a submit. */\n disabled?: boolean;\n onSelect: () => void;\n /** Slot: the leading glyph — a wallet icon, an asset icon. */\n icon: ReactNode;\n /** Slot: the row's labels. */\n children: ReactNode;\n className?: string;\n}\n\n/**\n * A radio-style row the user picks from a list: leading icon, labels, and a\n * selection circle on the right.\n *\n * Rendered as a `div[role=button]` rather than a `<button>` because rows may\n * carry their own nested control — the external wallet row holds a\n * \"Disconnect\" button — and a button inside a button is invalid HTML.\n */\nexport function SelectableOptionRow({\n selected,\n disabled = false,\n onSelect,\n icon,\n children,\n className,\n}: SelectableOptionRowProps) {\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return;\n // Keys pressed on a nested control (the \"Disconnect\" button) bubble here.\n // Activating that button must not also select the row.\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onSelect();\n }\n };\n\n return (\n <CoinListStyleScope>\n {/* biome-ignore lint/a11y/useSemanticElements: a nested control cannot live inside a button. */}\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-pressed={selected}\n aria-disabled={disabled}\n onClick={() => {\n if (!disabled) onSelect();\n }}\n onKeyDown={handleKeyDown}\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:justify-between',\n 'clcosdk:gap-3 clcosdk:rounded-2xl clcosdk:py-3 clcosdk:pl-3 clcosdk:pr-4',\n 'clcosdk:cursor-pointer clcosdk:text-left clcosdk:transition-colors',\n 'clcosdk:aria-disabled:cursor-not-allowed clcosdk:aria-disabled:opacity-50',\n selectableOptionBorderClass(selected),\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n {icon}\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col\">\n {children}\n </div>\n </div>\n <RadioCircle selected={selected} />\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction RadioCircle({ selected }: { selected: boolean }): ReactNode {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"clcosdk:shrink-0\"\n >\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n className={\n selected ? 'clcosdk:text-text-primary' : 'clcosdk:text-text-disabled'\n }\n />\n {selected && (\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"4\"\n fill=\"currentColor\"\n className=\"clcosdk:text-text-primary\"\n />\n )}\n </svg>\n );\n}\n\n/**\n * A meta line whose items are separated by a dot — `Ethereum • Disconnect`,\n * `0xkA31…mJ0da • Ethereum`.\n *\n * Takes its items as children so a caller can mix plain text with a control,\n * and inserts the separators itself so no caller has to render a bare `•`.\n * Falsy children drop out, which is how the optional \"Disconnect\" disappears\n * without leaving a dangling dot.\n */\nexport function OptionMetaRow({ children }: { children: ReactNode }) {\n const items = Children.toArray(children).filter(Boolean);\n\n return (\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-1.5\">\n {items.map((item, index) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: positional separators, and the list is caller-authored JSX.\n <Fragment key={index}>\n {index > 0 && <MetaDot />}\n {item}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction MetaDot(): ReactNode {\n return (\n <span className=\"clcosdk:h-1 clcosdk:w-1 clcosdk:shrink-0 clcosdk:rounded-full clcosdk:bg-text-disabled\" />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { OndoBuyAmountView } from '@/client/components/checkout/ondo/buy/amount/OndoBuyAmountView';\nimport { OndoBuyOrderConfirmed } from '@/client/components/checkout/ondo/buy/confirmation/OndoBuyOrderConfirmed';\nimport { OndoBuyReviewView } from '@/client/components/checkout/ondo/buy/review/OndoBuyReviewView';\nimport { OndoCheckoutError } from '@/client/components/checkout/ondo/shared/error/OndoCheckoutError';\nimport { OndoSidebarView } from '@/client/components/checkout/ondo/shared/sidebar/OndoSidebarView';\nimport { OndoWalletSelectView } from '@/client/components/checkout/ondo/shared/wallet/OndoWalletSelectView';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoBuyCheckoutUiEvent,\n OndoBuyCheckoutUiState,\n} from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\n\nexport interface OndoBuyCheckoutViewProps {\n state: OndoBuyCheckoutUiState;\n onEvent: (event: OndoBuyCheckoutUiEvent) => void;\n className?: string;\n}\n\n/**\n * The whole Ondo buy checkout: the three step cards, the asset panel beside\n * them, and the dialog that closes the flow.\n *\n * `onEvent` is handed to each step unwrapped. A handler that accepts the wider\n * union is assignable where a step's narrower one is expected, so there is no\n * per-step lambda here and no re-dispatch on the way back up.\n *\n * The panel leads on a phone and moves to the right column from `md` up, where\n * it is reference material rather than the first thing to read. No page heading\n * is rendered — the host titles its own page.\n *\n * An `error` state replaces the whole layout rather than appearing inside it:\n * it means there is no checkout, so there is nothing for the cards and the\n * panel to be laid out around.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it. The steps scope themselves too, and the scope is\n * idempotent, so nesting costs nothing.\n */\nexport function OndoBuyCheckoutView({\n state,\n onEvent,\n className,\n}: OndoBuyCheckoutViewProps): ReactNode {\n switch (state.type) {\n case 'error':\n return <OndoCheckoutError reason={state.reason} className={className} />;\n case 'content':\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-6',\n 'clcosdk:md:grid-cols-[minmax(0,11fr)_minmax(0,8fr)] clcosdk:md:gap-x-12',\n className\n )}\n >\n <div className=\"clcosdk:order-2 clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-4 clcosdk:md:order-1\">\n <OndoWalletSelectView state={state.wallet} onEvent={onEvent} />\n <OndoBuyAmountView state={state.amount} onEvent={onEvent} />\n <OndoBuyReviewView state={state.review} onEvent={onEvent} />\n </div>\n\n <aside className=\"clcosdk:order-1 clcosdk:min-w-0 clcosdk:md:order-2\">\n <OndoSidebarView state={state.sidebar} />\n </aside>\n </div>\n\n <OndoBuyOrderConfirmed\n state={state.orderConfirmed}\n onEvent={onEvent}\n />\n </CoinListStyleScope>\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useState } from 'react';\nimport {\n type OndoBuyAmountStepInput,\n useOndoBuyAmountViewModel,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel';\nimport {\n type OndoBuyReviewStepInput,\n useOndoBuyReviewViewModel,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel';\nimport type {\n OndoBuyCheckoutUiEvent,\n OndoBuyCheckoutUiState,\n OndoOrderConfirmedUiState,\n} from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\nimport { useOndoPrice } from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nimport {\n isNotTradable,\n useOndoTradingStatus,\n} from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\nimport { OndoCheckoutErrorReason } from '@/client/hooks/checkout/ondo/shared/ondo-checkout-error.types';\nimport type {\n OndoBuyOrderPlaced,\n OndoOrderPlaced,\n} from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport { useOndoSidebarViewModel } from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel';\nimport {\n type OndoWalletSelectStepInput,\n useOndoWalletSelectViewModel,\n} from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel';\nimport { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport {\n tokenMetadataOf,\n useCheckoutOfferTokenMetadata,\n} from '@/client/hooks/checkout/shared/data/useCheckoutOfferTokenMetadata';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport {\n DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE,\n ONDO_POLL_INTERVAL_MS,\n} from '@/universal/core/checkout/ondo/constants';\nimport { computeOndoBuyPrice } from '@/universal/core/checkout/ondo/math';\nimport type { OndoQuoteSize } from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport { swapSpender } from '@/universal/core/offers/swap-contracts';\nimport {\n getNetworkName,\n txExplorerUrl,\n} from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n formatShareAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n type AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type EthereumChain,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\nimport type {\n OndoBuyTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Which step is being filled in, carrying everything the ones before it\n * settled.\n *\n * A union rather than a step index plus nullable fields: the amount step\n * cannot run without a wallet, and the review step cannot run without a built\n * transaction, so neither is representable here.\n */\nexport type OndoBuyStep =\n | { type: 'wallet' }\n | { type: 'amount'; wallet: EvmWallet }\n | {\n type: 'review';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n /** Built by `prepareBuy` when the amount was confirmed. */\n transaction: OndoBuyTransaction;\n };\n\nexport interface UseOndoBuyCheckoutViewModelOptions {\n /**\n * The offer being bought: names the asset and supplies its logo.\n *\n * Fixed for the lifetime of the hook — see the note on\n * {@link useOndoBuyCheckoutViewModel} about switching offers.\n */\n offer: OndoSwapOfferDetail;\n /**\n * Ondo's API symbol for the asset, e.g. `AAPLon`.\n *\n * Explicit rather than derived from `offer.asset.code`: Ondo's symbol tracks\n * the underlying ticker and changes on a rebrand, and the two already\n * disagree on Sepolia, where a mock asset stands in.\n */\n ondoSymbol: AssetSymbol;\n /**\n * The chain the order executes on: the balance read, the approval and the\n * broadcast. Quotes are priced against Ondo production whatever this says,\n * since Ondo runs no sandbox, so on a testnet the price is real and the\n * money is not.\n *\n * Fixed for the lifetime of the hook, as `offer` is.\n */\n chain: EthereumChain;\n /** The host's wallets, and the lambdas that connect and disconnect one. */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. When `false` nothing is fetched and no timer runs, for a\n * checkout that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /**\n * Fired once the swap has mined. The confirmation dialog shows either way;\n * this is for a host that wants to navigate, refresh a portfolio, or log.\n */\n onOrderConfirmed?: (order: OndoOrderPlaced) => void;\n}\n\nexport interface UseOndoBuyCheckoutViewModelResult {\n state: OndoBuyCheckoutUiState;\n onEvent: (event: OndoBuyCheckoutUiEvent) => void;\n}\n\n/**\n * Drives the whole Ondo buy checkout: the three steps, the reference panel\n * beside them, and the dialog that closes the flow.\n *\n * It owns the step machine and the two polls; each step's own viewmodel owns\n * its screen. The polls live here because they are shared - the sidebar shows\n * the price and the amount step gates on the market - and because the price is\n * sized by whatever the flow has settled on so far.\n *\n * Every failure a step can cause belongs to that step: a price that will not\n * load leaves the panel's corner unavailable, and an order that will not go\n * through is reported on the review step, next to the button that caused it.\n *\n * The one exception is the flow-level `error` state, and it is an exception\n * about whether there is a flow rather than about how one went. A chain with\n * no Ondo integration contract is known before any step runs, and there is no\n * region to report it in that would not first have to render something untrue:\n * a wallet picker leading nowhere, a balance read for a token this flow will\n * never spend. A market known to be closed while the user is still choosing a\n * wallet is the same kind of answer for as long as it lasts. See\n * {@link OndoCheckoutErrorReason}.\n *\n * `offer` and `chain` are read as fixed for the lifetime of the hook. The step\n * machine holds a committed quote and an approval granted on one chain for one\n * order, so changing either in place would carry them onto an order they were\n * never priced for. Remount instead: give the component holding this hook a\n * `key` that changes with the offer and the chain, as {@link CheckoutContainer}\n * documents. That discards the flow with its component instance, which is the\n * only reset that cannot land between an approval and the broadcast it was\n * granted for.\n */\nexport function useOndoBuyCheckoutViewModel({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled = true,\n onOrderConfirmed,\n}: UseOndoBuyCheckoutViewModelOptions): UseOndoBuyCheckoutViewModelResult {\n const locale = useLocale();\n\n const [step, setStep] = useState<OndoBuyStep>({ type: 'wallet' });\n // The placed order, not its rendering: the dialog's asset is derived during\n // render (see `uiState`), so a registry lookup that settles while the order\n // is being placed still reaches the dialog instead of the fallback logo the\n // completion callback captured.\n const [orderConfirmed, setOrderConfirmed] =\n useState<OndoBuyOrderPlaced | null>(null);\n\n // An offer that cannot be swapped on this chain has no checkout, so every\n // hook below is turned off as surely as `enabled: false` would - no price\n // poll, no market poll, and no balance read against a token this flow will\n // never spend. `offer` and `chain` are both fixed for the lifetime of the\n // hook, so this cannot flip.\n const swappableHere = swapSpender(offer.swapContracts, chain) !== null;\n const live = enabled && swappableHere;\n\n const { state: tradingStatusState } = useOndoTradingStatus({\n symbol: ondoSymbol,\n side: 'buy',\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled: live,\n });\n const notTradable = isNotTradable(tradingStatusState);\n\n // Paused while the market is known to be closed: Ondo refuses every quote\n // then, so each tick would only fail. The last price stays on screen, and\n // the poll resumes once the trading-status poll above says it may.\n const { state: priceState } = useOndoPrice({\n symbol: ondoSymbol,\n side: 'buy',\n size: priceSize(step),\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled: live && !notTradable,\n });\n\n // One registry lookup for the flow: the sidebar, the review card and the\n // confirmation dialog all show the same asset, so they share one answer\n // rather than tripling the request. Fetched once - registry content is\n // immutable per version - and passed down as a value so the steps stay\n // pure renderers of what they were given.\n const { state: outputTokenMetadataState } = useCheckoutOfferTokenMetadata({\n offer,\n chain,\n enabled: live,\n });\n const outputTokenMetadata = tokenMetadataOf(outputTokenMetadataState);\n\n /**\n * The confirmation dialog, derived at render from the placed order and the\n * *latest* metadata. Building it inside the review completion callback\n * would bake in whichever metadata that closure captured, so a lookup that\n * settles while the order is being placed would leave the dialog on the\n * fallback logo forever.\n */\n const orderConfirmedUi = (\n order: OndoBuyOrderPlaced | null\n ): OndoOrderConfirmedUiState =>\n order === null\n ? { type: 'hidden' }\n : toOrderConfirmedUi({\n order,\n chain,\n locale,\n offer,\n ondoSymbol,\n outputTokenMetadata,\n });\n\n const { state: walletState, onEvent: onWalletEvent } =\n useOndoWalletSelectViewModel({\n stepInput: walletStepInput(step),\n wallets,\n chain,\n onComplete: (wallet) => setStep({ type: 'amount', wallet }),\n onEdit: () => setStep({ type: 'wallet' }),\n });\n\n const { state: amountState, onEvent: onAmountEvent } =\n useOndoBuyAmountViewModel({\n stepInput: amountStepInput(step, {\n tradingStatus:\n tradingStatusState.type === 'CONTENT'\n ? tradingStatusState.status\n : null,\n minimumPurchaseUsd: offer.options[0]?.minimumPurchaseUsd ?? null,\n }),\n ondoSymbol,\n chain,\n swapContracts: offer.swapContracts,\n enabled: live,\n // Both transitions read the step through the updater rather than the one\n // this render closed over. Preparing an amount takes an approval to mine,\n // and the wallet step's Edit stays live throughout, so a preparation can\n // succeed after the user has walked back to a step it knows nothing\n // about. Reading the step as it is when the result lands is what makes\n // these guards hold: reopening a step abandons the order, and the built\n // transaction goes with it. The approval does not, since the allowance\n // it left behind is what a retry finds.\n onComplete: ({ amount, inputAsset, transaction }) => {\n setStep((current) =>\n current.type === 'amount'\n ? {\n type: 'review',\n wallet: current.wallet,\n amount,\n inputAsset,\n transaction,\n }\n : current\n );\n },\n onEdit: () => {\n setStep((current) =>\n current.type === 'review'\n ? { type: 'amount', wallet: current.wallet }\n : current\n );\n },\n });\n\n const { state: reviewState, onEvent: onReviewEvent } =\n useOndoBuyReviewViewModel({\n stepInput: reviewStepInput(step),\n ondoSymbol,\n chain,\n offer,\n outputTokenMetadata,\n enabled: live,\n onComplete: (order) => {\n setOrderConfirmed(order);\n // The quote is spent and the allowance with it, so what is left behind\n // the dialog is a fresh checkout rather than a filled-in one.\n setStep({ type: 'wallet' });\n onOrderConfirmed?.(order);\n },\n });\n\n const { state: sidebarState } = useOndoSidebarViewModel({\n offer,\n ondoSymbol,\n chain,\n tokenMetadata: outputTokenMetadata,\n priceState,\n tradingStatusState,\n });\n\n const errorReason = OndoCheckoutErrorReason.of({\n swappableHere,\n notTradable,\n atEntry: step.type === 'wallet' && orderConfirmed === null,\n });\n const state: OndoBuyCheckoutUiState =\n errorReason !== null\n ? { type: 'error', reason: errorReason }\n : {\n type: 'content',\n wallet: walletState,\n amount: amountState,\n review: reviewState,\n sidebar: sidebarState,\n orderConfirmed: orderConfirmedUi(orderConfirmed),\n };\n\n // The event union is flat, so this is one switch rather than a nested one.\n // Every tag belongs to exactly one step, which is why the edit events are\n // `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared `ON_EDIT`.\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over each step's own handler for this render, so a memo could only ever hand back a stale one.\n const onEvent = (event: OndoBuyCheckoutUiEvent) => {\n switch (event.type) {\n case 'ON_SELECT_WALLET':\n case 'ON_CONNECT_WALLET':\n case 'ON_DISCONNECT_WALLET':\n case 'ON_CONFIRM_WALLET':\n case 'ON_EDIT_WALLET':\n onWalletEvent(event);\n return;\n case 'ON_AMOUNT_CHANGE':\n case 'ON_MAX_AMOUNT_CLICK':\n case 'ON_SELECT_PAY_WITH':\n case 'ON_CONFIRM_AMOUNT':\n case 'ON_EDIT_AMOUNT':\n onAmountEvent(event);\n return;\n case 'ON_REFRESH_QUOTE':\n case 'ON_RETRY':\n case 'ON_PLACE_ORDER':\n onReviewEvent(event);\n return;\n case 'ON_CLOSE_ORDER_CONFIRMED':\n setOrderConfirmed(null);\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state, onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Step inputs\n// ---------------------------------------------------------------------------\n\nfunction walletStepInput(step: OndoBuyStep): OndoWalletSelectStepInput {\n return step.type === 'wallet'\n ? { type: 'active' }\n : { type: 'completed', wallet: step.wallet };\n}\n\nfunction amountStepInput(\n step: OndoBuyStep,\n context: {\n tradingStatus: OndoTradingStatus | null;\n minimumPurchaseUsd: number | null;\n }\n): OndoBuyAmountStepInput {\n switch (step.type) {\n case 'wallet':\n return { type: 'incomplete' };\n case 'amount':\n return {\n type: 'active',\n wallet: step.wallet,\n tradingStatus: context.tradingStatus,\n minimumPurchaseUsd: context.minimumPurchaseUsd,\n };\n case 'review':\n return {\n type: 'complete',\n wallet: step.wallet,\n amount: step.amount,\n inputAsset: step.inputAsset,\n };\n default: {\n const exhaustive: never = step;\n return exhaustive;\n }\n }\n}\n\nfunction reviewStepInput(step: OndoBuyStep): OndoBuyReviewStepInput {\n return step.type === 'review'\n ? {\n type: 'active',\n wallet: step.wallet,\n amount: step.amount,\n inputAsset: step.inputAsset,\n transaction: step.transaction,\n }\n : { type: 'incomplete' };\n}\n\n/**\n * What size the indicative price is quoted for.\n *\n * Ondo prices by size, so something has to be sent. Until the user has\n * committed to an amount that is a default: quoting each keystroke would fire\n * a request per character and make the panel's price jump while they type.\n */\nfunction priceSize(step: OndoBuyStep): OndoQuoteSize {\n return step.type === 'review'\n ? { notionalValue: DecimalString(formatRawAmount(step.amount)) }\n : { notionalValue: DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE };\n}\n\n// ---------------------------------------------------------------------------\n// The confirmation dialog\n// ---------------------------------------------------------------------------\n\n/**\n * The dialog is a projection of the order that just filled: every figure comes\n * from the transaction that was broadcast, so nothing here can disagree with\n * what the user approved on the review step. `pricePerShare` is derived from\n * the same two amounts the review step derived it from, so the two screens\n * cannot drift either.\n */\nfunction toOrderConfirmedUi({\n order,\n chain,\n locale,\n offer,\n ondoSymbol,\n outputTokenMetadata,\n}: {\n order: OndoBuyOrderPlaced;\n chain: EthereumChain;\n locale: string;\n offer: OndoSwapOfferDetail;\n ondoSymbol: AssetSymbol;\n outputTokenMetadata: TokenMetadata | null;\n}): OndoOrderConfirmedUiState {\n const inputSymbol = TOKEN_REGISTRY.erc20(order.inputAsset).symbol;\n return {\n type: 'visible',\n outputAsset: CheckoutAssetUi.fromOffer(offer, {\n symbol: ondoSymbol,\n networkName: getNetworkName(chain),\n tokenMetadata: outputTokenMetadata,\n }),\n outputAmount: assetAmount(\n formatShareAmount(order.transaction.receiveOutputAmount, locale),\n ondoSymbol\n ),\n totalCost: assetAmount(\n formatAmount(order.transaction.spendInputAmount, locale),\n inputSymbol\n ),\n pricePerShare: formattedUsdPrice(\n computeOndoBuyPrice(order.transaction),\n locale\n ),\n recipientAddress: shortenAddress(order.wallet.address),\n txExplorerUrl: txExplorerUrl(chain, order.txHash),\n };\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport type {\n OndoSwapPreparationError,\n OndoSwapPreparationPhase,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport type {\n OndoBuyAmountUiEvent,\n OndoBuyAmountUiState,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoBuyAmountViewModel.types';\nimport {\n CheckoutAssetUi,\n type CheckoutCtaUi,\n type CheckoutSelectableInputAssetUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport { useErc20TokenBalances } from '@/client/hooks/shared/erc20/useErc20TokenBalances';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { stablecoinIconUrl } from '@/client/ui/format/asset-icon';\nimport { ONDO_SUPPORTED_INPUT_ASSETS } from '@/universal/core/checkout/ondo/constants';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/universal/core/shared/blockchain/math';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n type AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type DecimalString,\n type EthereumChain,\n EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OfferSwapContract } from '@/universal/types/offer-detail';\nimport type {\n OndoBuyTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\n/** Stands in for a wallet address while the step is not active and nothing is read. */\nconst NO_WALLET = EvmWalletAddress(\n '0x0000000000000000000000000000000000000000'\n);\n\nconst MARKET_CLOSED = 'This market is closed right now.';\nconst INVALID_AMOUNT = 'Enter a valid amount.';\nconst AMOUNT_ZERO = 'Enter an amount greater than 0.';\n\n/**\n * How much the user is spending, and the transaction built for it.\n *\n * It names no asset. The transaction publishes the scale of every amount on\n * it, and the offer names what is being bought, so there is nothing about the\n * purchase left for this step to carry downstream.\n */\nexport type OndoBuyAmountConfirmed = {\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n transaction: OndoBuyTransaction;\n};\n\nexport type OndoBuyAmountStepInput =\n | { type: 'incomplete' }\n | {\n type: 'active';\n /** The wallet confirmed in step 1: it holds the funds and signs. */\n wallet: EvmWallet;\n /**\n * The market as last read, or `null` while it is unknown. Unknown does\n * not block: a dropped poll is not evidence the market is closed, and\n * building will fail with a real reason if it is.\n */\n tradingStatus: OndoTradingStatus | null;\n /** The offer's minimum, in whole USD. `null` when it publishes none. */\n minimumPurchaseUsd: number | null;\n }\n | {\n type: 'complete';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n };\n\nexport interface UseOndoBuyAmountViewModelOptions {\n stepInput: OndoBuyAmountStepInput;\n /** Ondo's API symbol, e.g. `AAPLon`. */\n ondoSymbol: AssetSymbol;\n /** The chain the order executes on: balances, approval, and the contract. */\n chain: EthereumChain;\n /** The offer's swap contracts, forwarded to the preparation. */\n swapContracts: OfferSwapContract[];\n /**\n * When false, the step neither fetches nor polls. Defaults to true.\n *\n * The step being `incomplete` is not the same thing and does not stand in\n * for it: a checkout switched off mid-flow leaves this step `active`, and\n * the balance poll would run on behind a screen nobody is looking at.\n */\n enabled?: boolean;\n /** Called once the approval has mined and the transaction has been built. */\n onComplete: (confirmed: OndoBuyAmountConfirmed) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n}\n\nexport interface UseOndoBuyAmountViewModelResult {\n state: OndoBuyAmountUiState;\n onEvent: (event: OndoBuyAmountUiEvent) => void;\n}\n\n/**\n * Drives step 2 of the Ondo checkout: how much to spend, and getting the order\n * ready to place.\n *\n * Confirming does real work - it approves the swap contract to pull the\n * amount, then builds the transaction that spends it - so the CTA reports the on-chain phase\n * as loading copy and every failure comes back as copy under the field.\n *\n * Everything checkable locally is checked before the wallet is asked to sign:\n * the balance, the offer's minimum, and Ondo's own order caps. Each of those\n * would otherwise cost the user a real approval transaction before failing.\n */\nexport function useOndoBuyAmountViewModel({\n stepInput,\n ondoSymbol,\n chain,\n swapContracts,\n enabled = true,\n onComplete,\n onEdit,\n}: UseOndoBuyAmountViewModelOptions): UseOndoBuyAmountViewModelResult {\n const { coinlist } = useCoinList();\n const locale = useLocale();\n\n const [amountInput, setAmountInput] = useState('');\n const [selectedAsset, setSelectedAsset] = useState<StablecoinSymbol>(\n ONDO_SUPPORTED_INPUT_ASSETS[0]\n );\n const [error, setError] = useState<string | null>(null);\n const [phase, setPhase] = useState<OndoSwapPreparationPhase | null>(null);\n\n /**\n * Which preparation the state below belongs to.\n *\n * A preparation outlives the step that started it: the approval takes most\n * of a minute to mine, and the wallet step's Edit stays live throughout, so\n * the user can reopen it, pick a different wallet and confirm again before\n * the first `prepareSwap` resolves. Bumping this on every start and on every\n * reset is what lets a result that comes back to a different order be\n * dropped - which matters because the transaction was built for the *old*\n * wallet, and nothing downstream can tell: `OndoBuyTransaction` does not\n * carry the address it was built for, so `executeSwap` would broadcast\n * it from the new one and pay for the revert.\n */\n const preparationIdRef = useRef(0);\n\n const isActive = stepInput.type === 'active';\n const networkName = getNetworkName(chain);\n const marketClosed =\n isActive && stepInput.tradingStatus?.type === 'not-tradable';\n\n const { balances, isLoading: balancesLoading } = useErc20TokenBalances({\n address:\n stepInput.type === 'incomplete' ? NO_WALLET : stepInput.wallet.address,\n chain,\n assets: ONDO_SUPPORTED_INPUT_ASSETS,\n enabled: enabled && isActive,\n });\n\n // Start over when the user leaves the step, so reopening it does not restore\n // an amount they have since abandoned. A preparation still in flight is\n // abandoned with it: the order it belongs to is gone.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n ++preparationIdRef.current;\n setAmountInput('');\n setSelectedAsset(ONDO_SUPPORTED_INPUT_ASSETS[0]);\n setError(null);\n setPhase(null);\n }\n }, [stepInput.type]);\n\n const selectedBalance = balances.get(selectedAsset) ?? null;\n const selectedDecimals = TOKEN_REGISTRY.erc20(selectedAsset).decimals;\n\n const uiState = (): OndoBuyAmountUiState => {\n switch (stepInput.type) {\n case 'incomplete':\n return { type: 'incomplete' };\n case 'active':\n return {\n type: 'active',\n amountInput,\n walletAddress: shortenAddress(stepInput.wallet.address),\n inputAssets: ONDO_SUPPORTED_INPUT_ASSETS.map((symbol) =>\n toInputAssetUi({\n symbol,\n balance: balances.get(symbol) ?? null,\n selected: symbol === selectedAsset,\n networkName,\n locale,\n })\n ),\n confirmCta: confirmCta(),\n error: marketClosed ? MARKET_CLOSED : error,\n };\n case 'complete':\n return {\n type: 'complete',\n inputAsset: CheckoutAssetUi.fromErc20(\n TOKEN_REGISTRY.erc20(stepInput.inputAsset),\n {\n networkName,\n iconUrl: stablecoinIconUrl(stepInput.inputAsset),\n }\n ),\n amountFormatted: assetAmount(\n formatAmount(stepInput.amount, locale),\n TOKEN_REGISTRY.erc20(stepInput.inputAsset).symbol\n ),\n };\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n const confirmCta = (): CheckoutCtaUi => {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n // A balance is what the amount is validated against, so confirming before\n // one has arrived could only guess.\n const blocked =\n marketClosed || balancesLoading || amountInput.trim() === '';\n return blocked ? { type: 'disabled' } : { type: 'enabled' };\n };\n\n const confirmAmount = async () => {\n if (stepInput.type !== 'active' || phase !== null || marketClosed) return;\n\n const validated = validateAmount({\n input: amountInput,\n decimals: selectedDecimals,\n balance: selectedBalance,\n symbol: TOKEN_REGISTRY.erc20(selectedAsset).symbol,\n minimumPurchaseUsd: stepInput.minimumPurchaseUsd,\n tradingStatus: stepInput.tradingStatus,\n locale,\n });\n if (!validated.valid) {\n setError(validated.error);\n return;\n }\n\n setError(null);\n setPhase('checking-allowance');\n const preparationId = ++preparationIdRef.current;\n const result = await coinlist.ondo.prepareBuy({\n wallet: stepInput.wallet,\n symbol: ondoSymbol,\n chain,\n swapContracts,\n // The input asset is USDC on every chain the SDK models (it is the\n // only member of `ONDO_SUPPORTED_INPUT_ASSETS`), and its registry\n // table is total, so the address is never null.\n tokenAddress: TOKEN_REGISTRY.usdcAddress(chain),\n amount: validated.amount,\n // Guarded for the same reason as the result: an abandoned preparation\n // goes on emitting phases, and they would otherwise report themselves as\n // the progress of whatever the user is doing now.\n onProgress: (nextPhase) => {\n if (preparationId !== preparationIdRef.current) return;\n setPhase(nextPhase);\n },\n });\n // The step was reopened, or confirmed again, while this ran. The\n // transaction belongs to an order the user has walked away from - and to\n // the wallet that order was for - so it is dropped rather than carried\n // forward. The approval is not wasted: the allowance it left behind is what\n // the next attempt finds.\n if (preparationId !== preparationIdRef.current) return;\n setPhase(null);\n\n if (result.type === 'error') {\n setError(preparationErrorMessage(result.error));\n return;\n }\n onComplete({\n amount: validated.amount,\n inputAsset: selectedAsset,\n transaction: result.transaction,\n });\n };\n\n /**\n * Ignores a symbol the checkout does not fund. The event carries a plain\n * `AssetSymbol` (the View knows nothing of stablecoins), so this is the seam\n * where it becomes one of the assets actually on offer.\n */\n const selectInputAsset = (symbol: AssetSymbol) => {\n const supported = ONDO_SUPPORTED_INPUT_ASSETS.find(\n (candidate) => candidate === symbol\n );\n if (supported === undefined) return;\n setSelectedAsset(supported);\n setError(null);\n };\n\n const fillMaxAmount = () => {\n if (selectedBalance === null) return;\n setAmountInput(\n formatRawAmount(\n BlockchainAmount({ raw: selectedBalance, decimals: selectedDecimals })\n )\n );\n setError(null);\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step, the typed amount and the balances this render was given, so a memo could only ever hand back a stale one.\n const onEvent = (event: OndoBuyAmountUiEvent) => {\n switch (event.type) {\n case 'ON_AMOUNT_CHANGE':\n setAmountInput(event.value);\n setError(null);\n return;\n case 'ON_MAX_AMOUNT_CLICK':\n fillMaxAmount();\n return;\n case 'ON_SELECT_PAY_WITH':\n selectInputAsset(event.value);\n return;\n case 'ON_CONFIRM_AMOUNT':\n void confirmAmount();\n return;\n case 'ON_EDIT_AMOUNT':\n onEdit();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nexport type OndoBuyAmountValidation =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; error: string };\n\n/**\n * The checks that can be made without asking the wallet for anything, in the\n * order a user would hit them: is it a number, is it more than nothing, can\n * they afford it, does the offer accept it, will Ondo fill it.\n *\n * Exported for the property tests: the ladder is money logic, and the property\n * that matters (nothing above the balance or the caps is ever accepted) is\n * about the whole ladder rather than any one rung.\n */\nexport function validateAmount({\n input,\n decimals,\n balance,\n symbol,\n minimumPurchaseUsd,\n tradingStatus,\n locale,\n}: {\n input: string;\n decimals: AssetDecimals;\n /** `null` while no balance has been read; the check is then skipped. */\n balance: bigint | null;\n symbol: AssetSymbol;\n minimumPurchaseUsd: number | null;\n tradingStatus: OndoTradingStatus | null;\n locale: string;\n}): OndoBuyAmountValidation {\n const parsed = parseBlockchainAmount(input, decimals);\n if (!parsed.valid) return { valid: false, error: INVALID_AMOUNT };\n const amount = parsed.amount;\n if (amount.raw === 0n) return { valid: false, error: AMOUNT_ZERO };\n\n if (balance !== null && amount.raw > balance) {\n return { valid: false, error: `Insufficient ${symbol}.` };\n }\n\n const minimum = minimumAmount(minimumPurchaseUsd, decimals);\n if (minimum !== null && amount.raw < minimum.raw) {\n return {\n valid: false,\n error: `The minimum purchase is ${assetAmount(formatAmount(minimum, locale), symbol)}.`,\n };\n }\n\n const cap = orderCap(tradingStatus, decimals);\n if (cap !== null && amount.raw > cap.raw) {\n return {\n valid: false,\n error: `The maximum order size right now is ${assetAmount(formatAmount(cap, locale), symbol)}.`,\n };\n }\n\n return { valid: true, amount };\n}\n\nfunction minimumAmount(\n minimumPurchaseUsd: number | null,\n decimals: AssetDecimals\n): BlockchainAmount | null {\n if (minimumPurchaseUsd === null) return null;\n const parsed = parseBlockchainAmount(String(minimumPurchaseUsd), decimals);\n return parsed.valid ? parsed.amount : null;\n}\n\n/**\n * The smaller of the two USD caps Ondo publishes, or `null` when the market is\n * closed, unknown, or publishes neither.\n *\n * A closed market is not a cap of zero: the CTA is already disabled for it, and\n * reporting \"maximum order size $0.00\" would be a worse explanation than the\n * one the step already shows.\n */\nfunction orderCap(\n status: OndoTradingStatus | null,\n decimals: AssetDecimals\n): BlockchainAmount | null {\n if (status === null || status.type !== 'tradable') return null;\n const caps = [\n status.grossMaxNotionalValue,\n status.grossMaxActiveNotionalValue,\n ]\n .map((cap) => capAmount(cap, decimals))\n .filter((cap): cap is BlockchainAmount => cap !== null);\n if (caps.length === 0) return null;\n return caps.reduce((min, cap) => (cap.raw < min.raw ? cap : min));\n}\n\n/**\n * A cap as an amount in the spending token's decimals.\n *\n * Ondo publishes caps with 18 fractional digits, more than a stablecoin has,\n * so the surplus is truncated rather than rounded: rounding up would raise the\n * cap above what Ondo will actually fill.\n */\nfunction capAmount(\n cap: DecimalString | null,\n decimals: AssetDecimals\n): BlockchainAmount | null {\n if (cap === null) return null;\n const [whole, fraction = ''] = cap.split('.');\n const truncated =\n fraction === '' ? whole : `${whole}.${fraction.slice(0, decimals)}`;\n const parsed = parseBlockchainAmount(truncated, decimals);\n return parsed.valid ? parsed.amount : null;\n}\n\n// ---------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------\n\nfunction phaseMessage(phase: OndoSwapPreparationPhase): string {\n switch (phase) {\n case 'checking-allowance':\n return 'Checking your approval...';\n case 'resetting-allowance':\n return 'Resetting your approval...';\n case 'confirming-allowance-reset':\n return 'Confirming the reset...';\n case 'approving':\n return 'Approving in your wallet...';\n case 'confirming-approval':\n return 'Confirming the approval...';\n case 'building-transaction':\n return 'Getting your quote...';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\nfunction preparationErrorMessage(error: OndoSwapPreparationError): string {\n switch (error.step) {\n case 'unsupported-chain':\n return 'Ondo orders are not available on this network yet.';\n case 'allowance-check':\n return 'Could not check your approval. Please try again.';\n case 'approval':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Approval declined. Approve it in your wallet to continue.';\n case 'insufficient_funds':\n return 'Not enough ETH to cover the gas for the approval.';\n case 'timeout':\n return 'The approval is taking too long to confirm. Please try again.';\n default:\n return 'Could not approve the spend. Please try again.';\n }\n case 'approval-reverted':\n return 'The approval transaction failed. Please try again.';\n // Frontline read the allowance itself and found it short of the order.\n // The remedy is to try again, not to approve again: the approval is mined\n // by the time this can fire, so the usual cause is frontline's node being\n // a block behind it.\n case 'insufficient-allowance':\n return 'Your approval has not landed yet. Please try again in a moment.';\n case 'build-transaction':\n return 'Could not get a quote for that amount. Please try again.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// UI models\n// ---------------------------------------------------------------------------\n\nfunction toInputAssetUi({\n symbol,\n balance,\n selected,\n networkName,\n locale,\n}: {\n symbol: StablecoinSymbol;\n balance: bigint | null;\n selected: boolean;\n networkName: string;\n locale: string;\n}): CheckoutSelectableInputAssetUi {\n const erc20 = TOKEN_REGISTRY.erc20(symbol);\n // A balance that has not arrived reads as zero rather than as a placeholder:\n // the CTA stays disabled until one has, so no order can be sized on it.\n const raw = balance ?? 0n;\n return {\n symbol,\n asset: CheckoutAssetUi.fromErc20(erc20, {\n networkName,\n iconUrl: stablecoinIconUrl(symbol),\n }),\n balance: assetAmount(\n formatAmount(BlockchainAmount({ raw, decimals: erc20.decimals }), locale),\n erc20.symbol\n ),\n rawBalance: raw,\n selected,\n };\n}\n","import type { StablecoinSymbol } from '@/universal/types/blockchain/core';\nimport { AssetIconUrl } from '@/universal/types/blockchain/ui';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type {\n TokenLogo,\n TokenLogoImage,\n TokenMetadata,\n} from '@/universal/types/token-metadata';\n\n/**\n * The icon for USDC, served from CoinList's CDN.\n *\n * Exported so a host that renders its own funding-asset row gets the same\n * artwork the SDK's checkout does, rather than sourcing a second copy.\n */\nexport const USDC_ICON_URL = AssetIconUrl(\n 'https://cdn.coinlist.co/frontline/atlas/assets/usd_coin_081fef98bf-ab2f6b11.svg'\n);\n\n/** The icon for USDT, served from CoinList's CDN. */\nexport const USDT_ICON_URL = AssetIconUrl(\n 'https://cdn.coinlist.co/frontline/atlas/assets/tether_31aea27f68-a6f88f4e.svg'\n);\n\n/**\n * The icon for a stablecoin a checkout can be funded with.\n *\n * Not the SDK's only source of token artwork - `coinlist.tokens` serves logos\n * for every token the public registry lists - but deliberately the one the\n * funding-asset row uses. That row renders on the amount step's first paint,\n * next to a balance and a preselected coin, and a lookup that is synchronous\n * and total needs no loading state, no fallback and no `null` branch. Routing\n * it through the registry would buy nothing and cost all three.\n *\n * `StablecoinSymbol` is a closed union of the two coins the swap flows accept,\n * so the lookup is total and stays total: adding a third funding coin is a\n * compile error here. Every other asset a checkout renders is an offer's,\n * whose artwork `offerAssetIconUrl` resolves registry-first; the funding\n * asset has no offer behind it, which is why `CheckoutAssetUi.fromErc20`\n * still takes `iconUrl` from its caller and still defaults to `null`.\n *\n * It lives in the SDK rather than in each host because the alternative was\n * every partner mapping the same two symbols to the same two URLs - which is\n * what frontline-web had to do - and because a checkout showing a grey circle\n * where the USDC logo belongs reads as broken rather than as unstyled.\n *\n * A partner's page therefore loads these two images from CoinList's CDN. That\n * is already true of every offer logo the SDK renders.\n */\nexport function stablecoinIconUrl(symbol: StablecoinSymbol): AssetIconUrl {\n switch (symbol) {\n case 'USDC':\n return USDC_ICON_URL;\n case 'USDT':\n return USDT_ICON_URL;\n default: {\n const exhaustive: never = symbol;\n return exhaustive;\n }\n }\n}\n\n/**\n * The artwork an offer carries for the asset it sells, or `null` where it\n * carries none.\n *\n * A swap publishes without artwork, which `OfferDetail.fromDto` maps to\n * `null`. The empty string frontline has sent in its place is recognised here\n * too, because an `OfferDetail` need not have come through `fromDto` - a host\n * may build one - and a `\"\"` that reaches an `<img>` renders as a broken\n * image. Every consumer wants the same answer, and writing the convention out\n * at each of them is how one of them ends up disagreeing.\n *\n * Absence is ordinary, not an error: `AssetIcon` renders a neutral placeholder\n * for `null`, which is what the offers grid already does.\n */\nexport function offerIconUrl(offer: OfferDetail): AssetIconUrl | null {\n return offer.logoUrl ? AssetIconUrl(offer.logoUrl) : null;\n}\n\n/**\n * The URL of a token-registry logo, or `null` when the logo carries no usable\n * image (unrepresentable for a registry logo today, but a consumer must not\n * crash on it).\n *\n * A vector logo is a single SVG and needs no picking. A raster logo ships\n * webp variants at 32/64/128/256/512px plus an original, and `minWidth` picks\n * the smallest variant that covers it — a 64px webp for a 40px render beats\n * the 250px original, and beats an upscaled 32px. When no variant covers\n * `minWidth`, the original is used rather than the largest variant: the\n * registry never upscales past it, and a render that wide is the one case an\n * original-sized image is right for. The smallest qualifying variant is\n * chosen by width rather than by position, so a registry that serves its\n * variants out of order still resolves the same answer. Defaults to 40, the\n * edge length `AssetIcon` renders a checkout asset at.\n */\nexport function tokenLogoUrl(\n logo: TokenLogo,\n minWidth = 40\n): AssetIconUrl | null {\n switch (logo.kind) {\n case 'VECTOR':\n return AssetIconUrl(logo.url);\n case 'RASTER': {\n const chosen = logo.variants.reduce<TokenLogoImage | null>(\n (smallest, variant) =>\n variant.width >= minWidth &&\n (smallest === null || variant.width < smallest.width)\n ? variant\n : smallest,\n null\n );\n return AssetIconUrl((chosen ?? logo.original).url);\n }\n default: {\n const exhaustive: never = logo;\n return exhaustive;\n }\n }\n}\n\n/**\n * The `srcset` candidates for a registry logo, or `null` when the browser has\n * nothing to choose between.\n *\n * A raster logo ships webp variants at ascending widths (32, 64, 128, 256,\n * 512, capped at the source width), and listing every one with its width\n * descriptor lets the browser pick the smallest that covers the rendered size\n * at the screen's pixel density - a choice `tokenLogoUrl` can only make for\n * one width, and only at 1x. The registry's contract is that the variants\n * *are* the complete candidate list and the original is never merged in: the\n * largest variant already is the original's width (capped at 512), sharing\n * its URL below that. Candidates are listed by ascending width whatever order\n * the wire used. A vector logo scales itself and offers no candidates.\n *\n * A raster logo with no variants is unrepresentable under that contract, but\n * the type allows it, so the original stands in as the one candidate rather\n * than an empty `srcset` that would render nothing.\n *\n * The companion of `tokenLogoUrl`, not a replacement: `src` still carries the\n * one-width answer for a consumer that takes a single URL, and `srcset` is\n * only ever meaningful next to a `sizes` the renderer knows.\n */\nexport function tokenLogoSrcSet(logo: TokenLogo): string | null {\n switch (logo.kind) {\n case 'VECTOR':\n return null;\n case 'RASTER': {\n const candidates =\n logo.variants.length > 0 ? logo.variants : [logo.original];\n return [...candidates]\n .sort((a, b) => a.width - b.width)\n .map((image) => `${image.url} ${image.width}w`)\n .join(', ');\n }\n default: {\n const exhaustive: never = logo;\n return exhaustive;\n }\n }\n}\n\n/**\n * The artwork a checkout shows for the asset an offer sells.\n *\n * Resolved from the public token registry when the caller has metadata for\n * the offered token — `(chain, address)` entries of `OfferDetail.tokens`\n * key a `coinlist.tokens.get` lookup, which `useCheckoutOfferTokenMetadata`\n * performs for checkout screens — and from the offer's own logo otherwise.\n * The registry logo wins when both exist, because it is the token's real\n * artwork where `Offer.logoUrl` is catalogue artwork; the offer logo stays\n * as the fallback for `tokenMetadata: null`, which covers every way the\n * registry answer can be absent: the token is unlisted, the lookup has not\n * settled, or it failed. `null` is returned only when neither source\n * carries one.\n */\nexport function offerAssetIconUrl(\n offer: OfferDetail,\n tokenMetadata: TokenMetadata | null\n): AssetIconUrl | null {\n return (\n (tokenMetadata ? tokenLogoUrl(tokenMetadata.logo) : null) ??\n offerIconUrl(offer)\n );\n}\n","import { offerAssetIconUrl } from '@/client/ui/format/asset-icon';\nimport type {\n AssetSymbol,\n Erc20Asset,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type {\n AssetIconUrl,\n FormattedAmountAssetUi,\n ShortenedWalletAddress,\n} from '@/universal/types/blockchain/ui';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * UI models every checkout provider needs. Provider-specific models stay in\n * that provider's `use{X}ViewModel.types`; these live here because Ondo and\n * Superstate both render them.\n *\n * Models only. A screen's `{X}UiState` and `{X}UiEvent` stay in that screen's\n * `use{X}ViewModel.types` even when two providers' happen to agree today: a\n * state machine is where providers diverge, and sharing one would make the\n * divergence a breaking change rather than a local edit. Ondo's wallet step\n * confirms synchronously and Superstate's allow-lists on-chain, from the same\n * rows and the same models.\n *\n * No React and no hooks: this is the module Views and leaf components import.\n */\n\n/**\n * The state of a step's call-to-action.\n *\n * A SUM type rather than `disabled`/`isLoading` booleans, so \"disabled while\n * loading\" and \"loading without a message\" are both unrepresentable. The\n * message is what the user reads while an on-chain step runs (e.g. \"Approving\n * USDC…\"), so it belongs to the loading arm alone.\n */\nexport type CheckoutCtaUi =\n | { type: 'enabled' }\n | { type: 'disabled' }\n | { type: 'loading'; message: string };\n\n/**\n * A status and the copy that names it: an Ondo market that is open, a sale\n * still running, a window that has closed.\n *\n * A SUM type rather than a `label` plus an `isActive` flag, so the label always\n * arrives with the state it describes. The label is already formatted — a\n * countdown ticking down to zero is a `label` change, not a state change, until\n * the window actually closes.\n */\nexport type CheckoutStatusUi =\n | { type: 'active'; label: string }\n | { type: 'inactive'; label: string };\n\n/** An asset as a checkout screen renders it: name, symbol and iconography. */\nexport type CheckoutAssetUi = {\n /** Display name, e.g. `USD Coin`. */\n name: string;\n symbol: AssetSymbol;\n /**\n * `null` when no icon is known for this asset: no registry metadata, and no\n * logo on the offer. `AssetIcon` renders a neutral placeholder for it.\n */\n iconUrl: AssetIconUrl | null;\n network: CheckoutNetworkUi;\n};\n\nexport const CheckoutAssetUi = {\n /**\n * The view of an ERC-20 a checkout screen renders: the token supplies its\n * name and symbol, the caller supplies the chain it is being traded on and\n * whatever icon it has for it.\n *\n * `iconUrl` is a caller's parameter rather than the token's own because an\n * `Erc20Asset` does not carry one, and which source supplies it is the\n * caller's to decide. Which is also why it defaults to `null`: the input\n * asset a user pays with has no offer behind it.\n *\n * An asset sourced from the offer rather than from a token has its own\n * companion, {@link fromOffer}. One companion per source, not one per call\n * site.\n */\n fromErc20: (\n asset: Erc20Asset,\n {\n networkName,\n iconUrl = null,\n }: { networkName: string; iconUrl?: AssetIconUrl | null }\n ): CheckoutAssetUi => ({\n name: asset.name,\n symbol: asset.symbol,\n iconUrl,\n network: { name: networkName, iconUrl: null },\n }),\n\n /**\n * The view of the asset an offer sells: the offer supplies its name and the\n * fallback artwork, the caller supplies the symbol and the chain.\n *\n * `symbol` is a parameter rather than `offer.asset.code` because the symbol a\n * provider trades under is the provider's, not the catalogue's - Ondo's\n * `AAPLon` and the offer's code already disagree on Sepolia, where a mock\n * asset stands in. Keeping it out here is what lets one companion serve every\n * provider instead of forking per provider.\n *\n * The icon is resolved from the public token registry when `tokenMetadata`\n * carries a listed token — `useCheckoutOfferTokenMetadata` fetches it,\n * keyed by the token `OfferDetail.tokens` lists for this chain — and falls\n * back to the offer's own logo otherwise. `null` covers every way the\n * registry answer can be absent (unlisted, not settled, lookup failed);\n * which one it is stays the concern of the hook's state machine, not of\n * this model, because the icon is the same either way.\n *\n * Deliberately no decimals. An offer names an asset; it does not answer for\n * the scale of any particular quantity, and every amount a checkout renders\n * arrives as a `BlockchainAmount` carrying its own.\n */\n fromOffer: (\n offer: OfferDetail,\n {\n symbol,\n networkName,\n tokenMetadata,\n }: {\n symbol: AssetSymbol;\n networkName: string;\n tokenMetadata: TokenMetadata | null;\n }\n ): CheckoutAssetUi => ({\n name: offer.name,\n symbol,\n iconUrl: offerAssetIconUrl(offer, tokenMetadata),\n network: { name: networkName, iconUrl: null },\n }),\n};\n\n/** The chain an asset lives on, as a checkout screen renders it. */\nexport type CheckoutNetworkUi = {\n /** Display name, e.g. `Ethereum`. */\n name: string;\n /** `null` until network iconography lands (ENG-1540); the badge is omitted. */\n iconUrl: AssetIconUrl | null;\n};\n\n/**\n * A wallet as a selectable checkout row renders it.\n *\n * `network` is the checkout's execution chain rather than whatever the wallet\n * is currently pointed at: that is the chain the transaction goes to, so it is\n * the chain the row must name.\n */\nexport type CheckoutWalletUi = {\n /** Shortened for display, e.g. `0x1234…abcd`. */\n address: ShortenedWalletAddress;\n /** Display name of the chain, e.g. `Ethereum`. */\n network: string;\n selected: boolean;\n};\n\n/**\n * One of the user's CoinList wallets.\n *\n * Carries the full address as well, because that is what identifies the wallet\n * when the row is selected — the shortened `address` is lossy by construction\n * and two wallets can share a rendering.\n */\nexport type CheckoutEmbeddedWalletUi = CheckoutWalletUi & {\n walletAddress: EvmWalletAddress;\n};\n\n/**\n * The wallet the user settled on.\n *\n * Which kind it is decides the copy: a CoinList wallet is named as such with\n * its address beneath, an external one is shown by address alone. A SUM rather\n * than an `isEmbedded` flag so a screen has to answer the question before it\n * can render.\n */\nexport type CheckoutConfirmedWalletUi =\n | { type: 'embedded'; address: ShortenedWalletAddress }\n | { type: 'external'; address: ShortenedWalletAddress };\n\n/**\n * Which wallet a selection refers to.\n *\n * The external arm carries no address: there is at most one connected external\n * wallet, so naming it would be a second source of truth for something the\n * host already owns.\n */\nexport type CheckoutWalletTypeUi =\n | { type: 'external' }\n | { type: 'embedded'; address: EvmWalletAddress };\n\n/** One fundable asset, with the user's holding of it. */\nexport type CheckoutSelectableInputAssetUi = {\n symbol: AssetSymbol;\n asset: CheckoutAssetUi;\n /**\n * The user's holding, formatted, e.g. `1,850.00 USDC`.\n *\n * Reads `0.00` whenever the balance is unknown: before the first read\n * settles, and after one that failed. An unknown balance is therefore\n * **indistinguishable from a genuine zero** on screen, and the CTA does not\n * cover the difference — it gates on the poll having settled, which a\n * rejected read also does.\n *\n * That is a display defect, not the amount check being loose: skipping the\n * funds guard on an unknown balance is deliberate, since a dropped read is\n * not evidence the user cannot afford the order. Fixing the display means\n * giving this field a way to say \"unknown\", which is a change both providers\n * rendering these rows would take.\n */\n balance: FormattedAmountAssetUi;\n /** Base units, so \"Max\" can fill the field without re-parsing the display. */\n rawBalance: bigint;\n selected: boolean;\n};\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport {\n TOKEN_REGISTRY,\n USDC_SYMBOL,\n} from '@/universal/core/shared/blockchain/token-registry';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { NonEmptyArray } from '@/universal/types/collections';\n\n/**\n * How often balances refresh when the caller names no interval. Matches the\n * cadence the checkout flows poll everything else at, and is slow enough that\n * a whole tab of open positions does not hammer the node.\n */\nexport const ERC20_BALANCE_POLL_INTERVAL_MS = 15_000;\n\nexport interface UseErc20TokenBalancesOptions {\n address: EvmWalletAddress;\n chain: EthereumChain;\n /** The assets to read balances for. */\n assets: NonEmptyArray<StablecoinSymbol>;\n /**\n * How often to refresh balances. Defaults to\n * {@link ERC20_BALANCE_POLL_INTERVAL_MS}.\n */\n pollIntervalMs?: number;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseErc20TokenBalancesResult {\n /**\n * Raw on-chain balances keyed by the requested assets. Each requested asset\n * with a deployment on the chain has an entry once a fetch settles\n * (`bigint` on success, `null` on a failed read). Assets the chain has no\n * deployment for (e.g. USDT on Base Sepolia) are omitted entirely, so\n * absence and failure stay tellable apart.\n */\n balances: Map<StablecoinSymbol, bigint | null>;\n isLoading: boolean;\n}\n\n/**\n * Polls the raw ERC-20 balances of `assets` for `address`, refreshing every\n * `pollIntervalMs`. Each asset settles independently: a failed read maps to\n * `null` while the others still resolve, and an asset the chain has no\n * deployment for is omitted from the result rather than read at a fake\n * address. A poll tick is skipped while the previous fetch is still in\n * flight. `assets` is compared by contents, so passing an inline array does\n * not restart the poll.\n *\n * `isLoading` is true only until the first poll settles; background polls do\n * not toggle it. Disabled (or before the provider is ready) the hook does not\n * fetch.\n */\nexport function useErc20TokenBalances(\n options: UseErc20TokenBalancesOptions\n): UseErc20TokenBalancesResult {\n const {\n address,\n chain,\n assets,\n pollIntervalMs = ERC20_BALANCE_POLL_INTERVAL_MS,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n\n const [balances, setBalances] = useState<\n Map<StablecoinSymbol, bigint | null>\n >(new Map());\n const [isLoading, setIsLoading] = useState(true);\n\n const fetchIdRef = useRef(0);\n const isFetchingRef = useRef(false);\n\n // Compare `assets` by contents, not reference, so callers may pass an\n // inline array without restarting the poll every render.\n const assetsKey = assets.join(',');\n\n useEffect(() => {\n if (!isReady) return;\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n const symbols = assetsKey.split(',') as NonEmptyArray<StablecoinSymbol>;\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n let isFirstFetch = true;\n\n async function fetchBalances() {\n // Skip a poll tick while the previous fetch is still in flight so a\n // slow earlier read cannot resolve last and overwrite fresher balances.\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n if (isFirstFetch) {\n setIsLoading(true);\n }\n const results = await Promise.allSettled(\n symbols.map((symbol) => {\n const tokenAddress =\n symbol === USDC_SYMBOL\n ? TOKEN_REGISTRY.usdcAddress(chain)\n : TOKEN_REGISTRY.usdtAddress(chain);\n // A token the chain has no deployment for (e.g. USDT on Base\n // Sepolia) settles to `null` without a read rather than being called\n // at a fake address.\n if (tokenAddress === null) return null;\n return coinlist.erc20.getBalance({\n tokenAddress,\n owner: address,\n chain,\n });\n })\n );\n if (currentFetchId !== fetchIdRef.current) return;\n isFetchingRef.current = false;\n\n const next = new Map<StablecoinSymbol, bigint | null>();\n symbols.forEach((symbol, i) => {\n const result = results[i];\n if (result.status === 'fulfilled' && result.value !== null) {\n next.set(symbol, result.value);\n } else if (result.status === 'rejected') {\n next.set(symbol, null);\n }\n // A fulfilled `null` value is an asset with no deployment on the\n // chain: it gets no entry, so callers can tell \"not deployed\" apart\n // from \"read failed\".\n });\n setBalances(next);\n setIsLoading(false);\n isFirstFetch = false;\n }\n\n fetchBalances();\n const interval = setInterval(fetchBalances, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, address, chain, assetsKey, pollIntervalMs, enabled]);\n\n return { balances, isLoading };\n}\n","'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n OndoSwapExecutionError,\n OndoSwapExecutionPhase,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport {\n type LoadOndoBuyTransactionState,\n useOndoBuyTransaction,\n} from '@/client/hooks/checkout/ondo/buy/data/useOndoBuyTransaction';\nimport type {\n OndoBuyQuoteStatusUi,\n OndoBuyReviewUiEvent,\n OndoBuyReviewUiState,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoBuyReviewViewModel.types';\nimport type { OndoLoadErrorReason } from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport type { OndoBuyOrderPlaced } from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport {\n CheckoutAssetUi,\n type CheckoutCtaUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { useCountdown } from '@/client/ui/hooks/useCountdown';\nimport {\n computeOndoBuyPrice,\n ondoQuoteOfferDeadline,\n} from '@/universal/core/checkout/ondo/math';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatShareAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n EthereumChain,\n StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\nimport type { OndoBuyTransaction } from '@/universal/types/providers/ondo/ondo';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\nexport type OndoBuyReviewStepInput =\n | { type: 'incomplete' }\n | {\n type: 'active';\n /** The wallet that signs, pays, and receives. */\n wallet: EvmWallet;\n /** What the user is spending, in the input asset's base units. */\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n /**\n * The purchase `prepareBuy` already built for this order. Omitting\n * it makes this step build one itself, which is the path a partner\n * driving the review on its own takes - and the only way its `loading`\n * and `error` states are reached.\n */\n transaction?: OndoBuyTransaction;\n };\n\nexport interface UseOndoBuyReviewViewModelOptions {\n stepInput: OndoBuyReviewStepInput;\n /**\n * Ondo's API symbol, e.g. `AAPLon`. Rebuilds the transaction, and names the\n * bought asset on the card.\n */\n ondoSymbol: AssetSymbol;\n /** The chain the order executes on. */\n chain: EthereumChain;\n /**\n * The offer being bought: the asset's name and its fallback artwork.\n *\n * The identity comes from here rather than from the price poll, so the card\n * agrees with the reference panel beside it and a dropped poll cannot leave\n * the review unable to say what was bought.\n */\n offer: OndoSwapOfferDetail;\n /**\n * Registry metadata for the bought asset; `null` falls back to the offer's\n * logo.\n */\n outputTokenMetadata: TokenMetadata | null;\n /**\n * When false, the step neither builds a transaction nor counts down, and\n * neither refreshing the quote nor placing an order does anything. Defaults\n * to true.\n *\n * The step being `incomplete` is not the same thing and does not stand in\n * for it: a checkout switched off mid-flow leaves this step `active`, so the\n * committed quote is still here to render and its clock would tick on behind\n * a screen nobody is looking at.\n */\n enabled?: boolean;\n /** Called once the swap has mined. */\n /** Always a buy: this step only ever places one. */\n onComplete: (order: OndoBuyOrderPlaced) => void;\n}\n\nexport interface UseOndoBuyReviewViewModelResult {\n state: OndoBuyReviewUiState;\n onEvent: (event: OndoBuyReviewUiEvent) => void;\n}\n\n/**\n * Drives step 3 of the Ondo checkout: what the order comes to, how long the\n * price holds, and placing it.\n *\n * The quote is firm and short-lived, so most of this is about time. The\n * countdown drives the line above the CTA. The SDK offers the quote for at\n * most {@link ONDO_QUOTE_MAX_TTL_MS}.\n *\n * Refreshing is always something the user asks for. Each refresh builds a new\n * transaction, which spends an attestation, so nothing here is on a timer.\n */\nexport function useOndoBuyReviewViewModel({\n stepInput,\n ondoSymbol,\n chain,\n offer,\n outputTokenMetadata,\n enabled = true,\n onComplete,\n}: UseOndoBuyReviewViewModelOptions): UseOndoBuyReviewViewModelResult {\n const { coinlist } = useCoinList();\n const locale = useLocale();\n\n const [phase, setPhase] = useState<OndoSwapExecutionPhase | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const isActive = stepInput.type === 'active';\n const { state: transactionState, refetch } = useOndoBuyTransaction({\n request: isActive\n ? {\n symbol: ondoSymbol,\n chain,\n walletAddress: stepInput.wallet.address,\n amount: stepInput.amount,\n }\n : null,\n data: isActive ? stepInput.transaction : undefined,\n enabled: enabled && isActive,\n });\n\n /**\n * Which order the error below belongs to.\n *\n * Same guard, and same reason, as the amount step's `preparationIdRef`. The\n * effect below is not enough on its own: it has already run by the time a\n * rejection lands for an order the user has walked away from, so the late\n * `setError` writes the message back and holds it there for the next order\n * to be blamed for.\n *\n * It guards the failure only. A fill is reported whatever step the user is\n * on, because the purchase happened: an order that reached the chain is not\n * the viewmodel's to discard.\n */\n const executionIdRef = useRef(0);\n\n // A failure belongs to the order that caused it. Leaving the step abandons\n // that order, so its message goes too - otherwise editing the amount and\n // confirming a new one brings the review step back with the old failure\n // sitting above a freshly built transaction. Nothing else clears it: the\n // parent calls this viewmodel unconditionally and only flips `stepInput`, so\n // the hook never unmounts and React does not reset it.\n //\n // `phase` deliberately survives. It is the only guard `placeOrder` has, and\n // an execution in flight outlives the step being reopened - clearing it here\n // would let a second order be broadcast against the first transaction.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n ++executionIdRef.current;\n setError(null);\n }\n }, [stepInput.type]);\n\n const transaction =\n transactionState.type === 'CONTENT' ? transactionState.transaction : null;\n const offerUntil = useMemo(\n () =>\n transaction === null\n ? null\n : ondoQuoteOfferDeadline(transaction.expiresAt),\n [transaction]\n );\n const secondsLeft = useCountdown({\n until: offerUntil,\n enabled,\n });\n const quoteStatus = toQuoteStatusUi(transactionState, secondsLeft);\n\n const uiState = (): OndoBuyReviewUiState => {\n if (stepInput.type === 'incomplete') return { type: 'incomplete' };\n switch (transactionState.type) {\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR':\n return { type: 'error' };\n case 'CONTENT':\n return activeState(stepInput, transactionState.transaction);\n default: {\n const exhaustive: never = transactionState;\n return exhaustive;\n }\n }\n };\n\n function activeState(\n active: Extract<OndoBuyReviewStepInput, { type: 'active' }>,\n built: OndoBuyTransaction\n ): Extract<OndoBuyReviewUiState, { type: 'active' }> {\n const inputSymbol = TOKEN_REGISTRY.erc20(active.inputAsset).symbol;\n return {\n type: 'active',\n outputAsset: CheckoutAssetUi.fromOffer(offer, {\n symbol: ondoSymbol,\n networkName: getNetworkName(chain),\n tokenMetadata: outputTokenMetadata,\n }),\n outputAmount: assetAmount(\n formatShareAmount(built.receiveOutputAmount, locale),\n ondoSymbol\n ),\n recipientAddress: shortenAddress(active.wallet.address),\n // Derived, because the endpoint publishes no price. This is what the\n // order actually fills at rather than the sidebar's polled figure, which\n // has moved since and is struck against a different size.\n pricePerShare: formattedUsdPrice(computeOndoBuyPrice(built), locale),\n // A zero fee is not a fee: the row is hidden rather than reading\n // \"0.00 USDC\", which would imply a fee exists and happens to round away.\n coinlistFee:\n built.fee.raw === 0n\n ? null\n : assetAmount(formatAmount(built.fee, locale), inputSymbol),\n // The server's echo, not the locally typed amount: they should agree, and\n // showing the one that was actually signed for is what makes it visible\n // when they do not.\n total: assetAmount(\n formatAmount(built.spendInputAmount, locale),\n inputSymbol\n ),\n quote: quoteStatus,\n placeOrderCta: placeOrderCta(),\n error,\n };\n }\n\n function placeOrderCta(): CheckoutCtaUi {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n // The CTA, not the View, decides whether an order can be placed - and a\n // quote that is not `valid` is one the contract would reject.\n return quoteStatus.type === 'valid'\n ? { type: 'enabled' }\n : { type: 'disabled' };\n }\n\n const placeOrder = async () => {\n // A switched-off checkout starts no order. The View that would raise this\n // event is one the host has stopped rendering, so this is the guard that\n // says so to a partner driving the viewmodel directly.\n if (!enabled) return;\n // No side to guard any more: `useOndoBuyTransaction` calls\n // `POST /v1/ondo/swap/buy`, so a purchase is the only thing `transaction`\n // can be, and the filled order carries the matching arm by construction.\n if (stepInput.type !== 'active' || transaction === null || phase !== null) {\n return;\n }\n if (quoteStatus.type !== 'valid') return;\n\n const executionId = ++executionIdRef.current;\n setError(null);\n setPhase('broadcasting-swap');\n const result = await coinlist.ondo.executeSwap({\n wallet: stepInput.wallet,\n transaction,\n chain,\n onProgress: setPhase,\n });\n setPhase(null);\n\n if (result.type === 'error') {\n // Silence rather than a message when the order has been abandoned: the\n // step it would be reported on belongs to a different one now.\n if (executionId !== executionIdRef.current) return;\n setError(executionErrorMessage(result.error));\n return;\n }\n onComplete({\n side: 'buy',\n txHash: result.txHash,\n // The local rather than the echo. They are the same object -\n // `executeOndoSwap` hands back what it was given - and reading the one\n // this screen already holds keeps the order and the numbers on it from\n // being two different reads.\n transaction,\n amount: stepInput.amount,\n inputAsset: stepInput.inputAsset,\n wallet: stepInput.wallet,\n });\n };\n\n const refreshQuote = () => {\n // Same reason as `placeOrder`, and doubly so here: a build spends an\n // attestation, so a switched-off checkout must not be able to spend one.\n if (!enabled) return;\n // An order in flight is signed against the quote on screen. Replacing it\n // now would spend an attestation and rewrite the numbers under a\n // transaction the user has already approved in their wallet. `placeOrder`\n // guards on the same flag; the refresh link is a plain button with no\n // disabled state, so this is where the two are kept from overlapping.\n if (phase !== null) return;\n // A failed order and a stale quote are different problems; clear the first\n // so a fresh quote does not arrive under an old error message.\n setError(null);\n refetch();\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step, the quote and the phase this render was given, so a memo could only ever hand back a stale one.\n const onEvent = (event: OndoBuyReviewUiEvent) => {\n switch (event.type) {\n case 'ON_REFRESH_QUOTE':\n case 'ON_RETRY':\n refreshQuote();\n return;\n case 'ON_PLACE_ORDER':\n void placeOrder();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Quote status\n// ---------------------------------------------------------------------------\n\n/**\n * Whether the numbers on screen can still be traded on.\n *\n * Order matters. A refresh in flight outranks everything, because the answer\n * is about to change. A failed refresh outranks expiry, because refreshing\n * again is the remedy for both and the failure is the more useful thing to\n * say. Only then does the clock decide.\n */\nfunction toQuoteStatusUi(\n state: LoadOndoBuyTransactionState,\n secondsLeft: number | null\n): OndoBuyQuoteStatusUi {\n if (state.type !== 'CONTENT') return { type: 'expired' };\n if (state.isRefreshing) return { type: 'refreshing' };\n if (state.refreshError !== null) {\n return {\n type: 'refresh-failed',\n message: refreshErrorMessage(state.refreshError),\n };\n }\n if (secondsLeft === null || secondsLeft === 0) {\n return { type: 'expired' };\n }\n return { type: 'valid', expiresInLabel: expiresInLabel(secondsLeft) };\n}\n\nfunction expiresInLabel(secondsLeft: number): string {\n const unit = secondsLeft === 1 ? 'second' : 'seconds';\n return `Quote expires in ${secondsLeft} ${unit}`;\n}\n\n// ---------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------\n\nfunction phaseMessage(phase: OndoSwapExecutionPhase): string {\n switch (phase) {\n case 'broadcasting-swap':\n return 'Confirm in your wallet...';\n case 'confirming-swap':\n return 'Placing your order...';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\nfunction refreshErrorMessage(reason: OndoLoadErrorReason): string {\n switch (reason) {\n case 'not-authenticated':\n return 'Sign in to refresh this quote.';\n case 'not-tradable':\n return 'Trading is paused for this asset. Try again when the market opens.';\n case 'generic-error':\n return 'Could not refresh the quote.';\n default: {\n const exhaustive: never = reason;\n return exhaustive;\n }\n }\n}\n\nfunction executionErrorMessage(error: OndoSwapExecutionError): string {\n switch (error.step) {\n case 'quote-expired':\n return 'That quote expired. Get a new one to place your order.';\n case 'swap':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Order declined. Confirm it in your wallet to continue.';\n case 'insufficient_funds':\n return 'Not enough ETH to cover the gas for this order.';\n case 'timeout':\n return 'Your order is taking a while to confirm. Check your wallet before retrying.';\n default:\n return 'Could not place your order. Please try again.';\n }\n case 'swap-reverted':\n return 'Your order did not go through and nothing was charged. Get a new quote and try again.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n type OndoLoadErrorReason,\n ondoLoadErrorReason,\n} from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { BuildOndoBuyParams } from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport type { OndoBuyTransaction } from '@/universal/types/providers/ondo/ondo';\n\n/**\n * The state of the built purchase a review step acts on.\n *\n * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in\n * flight never blanks the numbers the user is reading. A refresh that fails\n * keeps them too, and reports why alongside - the previous purchase may still\n * be good, and a failed refresh is fixed by refreshing again.\n */\nexport type LoadOndoBuyTransactionState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: OndoLoadErrorReason }\n | {\n type: 'CONTENT';\n transaction: OndoBuyTransaction;\n isRefreshing: boolean;\n /** Why the last refresh failed; `null` when the purchase is fresh. */\n refreshError: OndoLoadErrorReason | null;\n };\n\nexport interface UseOndoBuyTransactionOptions {\n /**\n * The order to build, or `null` while there is not one yet - before the\n * amount step is confirmed. A `null` request fetches nothing.\n */\n request: BuildOndoBuyParams | null;\n /**\n * A purchase the caller already holds, typically the one `prepareBuy`\n * returned with the approval. When present the hook adopts it and skips the\n * initial fetch; `refetch` still fetches. This is what keeps the flow to one\n * attestation per order.\n */\n data?: OndoBuyTransaction;\n /** When false, the hook does not fetch. */\n enabled: boolean;\n}\n\nexport interface UseOndoBuyTransactionResult {\n state: LoadOndoBuyTransactionState;\n /** Builds a fresh purchase for the same order. Spends an attestation. */\n refetch: () => void;\n}\n\n/**\n * Holds the firm, expiring purchase the buy review step places an order\n * against, and rebuilds it on demand.\n *\n * **Never polls.** Building spends an attestation, so a new one is only ever\n * obtained when the caller asks - on `refetch`, or on the first render if no\n * `data` was supplied. That is also why an expired purchase is left expired\n * here: whether to replace it is the user's call, not a timer's.\n *\n * Disabled it fetches nothing and stays on whatever state it opened with. That\n * is `LOADING` and not an empty `CONTENT` because there is no empty\n * purchase: firm calldata for an order that does not exist is not\n * representable. A caller that switches this hook off should switch its own\n * rendering off with it - which is what the review step does, since a step\n * that is not active is `incomplete` and never reads this state at all.\n *\n * One of a pair with `useOndoSellTransaction`, and deliberately not one hook\n * over both. The two endpoints answer different shapes - a purchase commits to\n * an exact quantity, a sale to a range - so a shared hook would hand every\n * review step a union to narrow after its own directory had already settled\n * which trade it was. The machinery below is the price of that, and it is the\n * cheaper half: what a screen reads off `CONTENT` is the expensive half.\n */\nexport function useOndoBuyTransaction(\n options: UseOndoBuyTransactionOptions\n): UseOndoBuyTransactionResult {\n const { request, data, enabled } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOndoBuyTransaction');\n\n const [state, setState] = useState<LoadOndoBuyTransactionState>(() =>\n data === undefined\n ? { type: 'LOADING' }\n : {\n type: 'CONTENT',\n transaction: data,\n isRefreshing: false,\n refreshError: null,\n }\n );\n\n const fetchIdRef = useRef(0);\n // `fetchIdRef` decides which *response* wins; this decides which *request*\n // leaves at all. Both are needed, and this one more than in the polling\n // hooks: a build spends an attestation, so two overlapping calls cost two\n // of them however carefully the answers are then discarded. `refetch` is\n // part of the Level-2 surface, so the guard belongs here rather than in a\n // View that happens to hide its refresh link while one is in flight.\n const isFetchingRef = useRef(false);\n // The request keys the effect by value: the same order re-created on a\n // render must not spend a second attestation.\n const requestKey = request === null ? null : stableKey(request);\n const requestRef = useRef(request);\n requestRef.current = request;\n\n const build = useCallback(async () => {\n const params = requestRef.current;\n if (!isReady || !enabled || params === null) return;\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n const currentFetchId = ++fetchIdRef.current;\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: true, refreshError: null }\n : { type: 'LOADING' }\n );\n\n try {\n const transaction = await coinlist.ondo.buildBuyTransaction(params);\n if (currentFetchId !== fetchIdRef.current) return;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT' },\n }));\n setState({\n type: 'CONTENT',\n transaction,\n isRefreshing: false,\n refreshError: null,\n });\n } catch (error) {\n if (currentFetchId !== fetchIdRef.current) return;\n const reason = ondoLoadErrorReason(error);\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: false, refreshError: reason }\n : { type: 'ERROR', reason }\n );\n } finally {\n isFetchingRef.current = false;\n }\n }, [coinlist, isReady, enabled, log]);\n\n // Adopt a transaction the caller supplies, whenever it arrives. It usually\n // arrives after mount: the review step is rendered (collapsed) from the first\n // frame, and `prepareBuy` only hands one over when the amount is confirmed.\n // A later `refetch` replaces it without this firing again, because the\n // caller's own `data` has not changed.\n useEffect(() => {\n if (data === undefined) return;\n ++fetchIdRef.current;\n setState({\n type: 'CONTENT',\n transaction: data,\n isRefreshing: false,\n refreshError: null,\n });\n }, [data]);\n\n // Fetch only what the caller did not provide. A seeded transaction is the\n // normal path - `prepareBuy` built one moments ago, as part of approving -\n // so this branch belongs to a partner driving the review step themselves.\n const hasSeed = data !== undefined;\n useEffect(() => {\n if (hasSeed || requestKey === null) return;\n build();\n return () => {\n ++fetchIdRef.current;\n };\n }, [build, requestKey, hasSeed]);\n\n const refetch = useCallback(() => {\n build();\n }, [build]);\n\n return { state, refetch };\n}\n\n/** Key-order-independent identity for a request, for effect comparison. */\nfunction stableKey(request: BuildOndoBuyParams): string {\n return [\n request.symbol,\n request.chain,\n request.walletAddress,\n request.amount.raw.toString(),\n request.amount.decimals,\n ].join('|');\n}\n","import { isOndoNotTradableError } from '@/universal/core/checkout/ondo/not-tradable';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\n\n/**\n * Why an Ondo read failed, in the three flavours a UI acts on differently.\n *\n * `not-authenticated` is split out because no retry helps until the user signs\n * in, and because the remedy is one the UI can name. `not-tradable` is split\n * out for the same reason: the market is closed or paused, so the remedy is to\n * wait for it to open, and a retry before then fails the same way. Everything\n * else collapses into `generic-error` and is offered a retry.\n *\n * That is a deliberate over-offer, not a claim that every such failure is\n * retryable. A `ValidationError` from the DTO boundary - an unreadable expiry,\n * a zero output amount, a scale no amount could be denominated in - is\n * deterministic, and refreshing spends an attestation to fail again. It stays\n * lumped in because each one means frontline changed its encoding, which is\n * unreachable in a deployed pair and not worth a public union member and a\n * branch in every consumer to distinguish. Split it out if that stops being\n * true.\n */\nexport type OndoLoadErrorReason =\n | 'not-authenticated'\n | 'not-tradable'\n | 'generic-error';\n\nexport function ondoLoadErrorReason(error: unknown): OndoLoadErrorReason {\n if (error instanceof NotAuthenticatedError) return 'not-authenticated';\n if (isOndoNotTradableError(error)) return 'not-tradable';\n return 'generic-error';\n}\n","'use client';\n\nimport { useEffect, useReducer } from 'react';\n\nexport interface UseCountdownOptions {\n /**\n * The moment being counted down to. `null` stops the tick entirely - pass it\n * when there is nothing to count down to yet (no quote, no deadline).\n */\n until: Date | null;\n /** How often to re-read the clock. Defaults to one second. */\n tickMs?: number;\n /**\n * Default `true`. `false` starts no timer, but still reports the seconds\n * remaining as of this render.\n *\n * Distinct from `until: null`, which says there is nothing to count down to\n * and reports `null`. This one says there is a deadline and no one is\n * watching it: a checkout mounted off screen beside another provider's still\n * has a sale window, and reporting it as absent would make the panel read\n * `Sale ended` for a sale that is running.\n */\n enabled?: boolean;\n}\n\nconst DEFAULT_TICK_MS = 1_000;\n\n/**\n * Whole seconds remaining until `until`, re-read every `tickMs` and clamped at\n * zero. `null` while there is nothing to count down to.\n *\n * Presentation only: it reports time, and the caller decides what a number\n * means - what copy to render, and how many seconds early something should be\n * treated as already over. Keeping the threshold out of here is what lets one\n * tick serve a quote expiry, a sale window and a resend timer.\n *\n * Re-reads the clock rather than decrementing a counter, so a backgrounded tab\n * (where timers are throttled) resumes with the truth instead of a drifted\n * count.\n *\n * The remainder is derived during render rather than held in state, and the\n * timer only schedules the re-render. State would go stale exactly where it is\n * least expected: a disabled countdown runs no timer, so a value written by an\n * effect would keep whatever it was when the effect last ran, and a parent\n * rerendering minutes later would still be handed that number.\n */\nexport function useCountdown({\n until,\n tickMs = DEFAULT_TICK_MS,\n enabled = true,\n}: UseCountdownOptions): number | null {\n const untilMs = until?.getTime() ?? null;\n const [, tick] = useReducer(nextTick, 0);\n\n useEffect(() => {\n // Nothing to count down to, nobody watching, or already over: the answer\n // cannot change on its own, so a timer would only re-render to the same\n // number forever.\n if (untilMs === null || !enabled || remainingSeconds(untilMs) === 0) return;\n\n const interval = setInterval(() => {\n tick();\n // Reaching zero leaves the effect's dependencies untouched, so the\n // interval has to retire itself rather than wait to be re-run.\n if (remainingSeconds(untilMs) === 0) clearInterval(interval);\n }, tickMs);\n return () => clearInterval(interval);\n }, [untilMs, tickMs, enabled]);\n\n return remainingSeconds(untilMs);\n}\n\nfunction nextTick(count: number): number {\n return count + 1;\n}\n\nfunction remainingSeconds(untilMs: number | null): number | null {\n if (untilMs === null) return null;\n return Math.max(0, Math.ceil((untilMs - Date.now()) / 1000));\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport {\n type OndoLoadErrorReason,\n ondoLoadErrorReason,\n} from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { ONDO_POLL_INTERVAL_MS } from '@/universal/core/checkout/ondo/constants';\nimport type { OndoQuoteSize } from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport {\n AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n DecimalString,\n} from '@/universal/types/blockchain/core';\nimport type { OndoQuote } from '@/universal/types/providers/ondo/ondo';\nimport type { OrderBookSide } from '@/universal/types/trading';\n\n/**\n * The state of the indicative-price poll.\n *\n * - `LOADING`: no price yet (initial, or the provider is still initializing).\n * - `ERROR`: no price could be fetched at all.\n * - `CONTENT`: a price is in hand; `isRefreshing` says whether a newer one is\n * on the way.\n *\n * A poll that fails with a price already in hand stays `CONTENT`: the last\n * price is worth more to a user than a blank panel, and the next tick retries\n * within seconds. `ERROR` therefore means \"never got one\", which is exactly\n * when the UI has nothing to show.\n */\nexport type LoadOndoPriceState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: OndoLoadErrorReason }\n | { type: 'CONTENT'; quote: OndoQuote; isRefreshing: boolean };\n\nexport interface UseOndoPriceOptions {\n /** Ondo's API symbol, e.g. `AAPLon`. */\n symbol: AssetSymbol;\n side: OrderBookSide;\n /**\n * The order size to price. Ondo prices by size, so this changes the answer:\n * pass what the user is actually buying once they have named it.\n */\n size: OndoQuoteSize;\n /** How often to refresh. Defaults to {@link ONDO_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /**\n * A price the caller already holds, typically fetched server-side, used as\n * the state the hook opens on so a server-rendered panel needs no loading\n * pass.\n *\n * It seeds the first render only: the poll still fetches immediately, unlike\n * the `data` of a hook that reads a snapshot. A price is worth as much as it\n * is fresh, and the size being priced changes as the flow advances, so a seed\n * that suppressed the first read would be offering the server's answer - or\n * another size's - as this one's.\n */\n data?: OndoQuote;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseOndoPriceResult {\n state: LoadOndoPriceState;\n}\n\nconst LOADING: LoadOndoPriceState = { type: 'LOADING' };\n\n/**\n * Polls Ondo's indicative price for `size` of `symbol`.\n *\n * Free to poll: this quote spends no attestation and commits nothing, which is\n * why it may run while the user is still deciding. It also cannot be executed\n * - committing a fillable quote is `coinlist.ondo.prepareBuy` or\n * `coinlist.ondo.prepareSell`, whichever way the trade runs.\n *\n * Disabled (or before the provider is ready) it neither fetches nor holds a\n * timer, and stays on whatever state it opened with - `LOADING`, or the `data`\n * seed - rather than reporting an error.\n *\n * That is `LOADING` and not an empty `CONTENT` because there is no empty price:\n * a hook whose content is a list can fall back to `[]` the way\n * `useOptionAddresses` does, and one whose content is a number cannot. A caller\n * that switches this hook off should switch its own rendering off with it,\n * rather than read `LOADING` as \"a price is coming\".\n *\n * A `data` price opens the state instead of `LOADING` and is otherwise left to\n * the poll: the first tick fires as it always does, and only replaces the seed\n * once it has a price of its own. Until it does the state is `CONTENT` with\n * `isRefreshing` set, which is what that flag is for.\n */\nexport function useOndoPrice(options: UseOndoPriceOptions): UseOndoPriceResult {\n const {\n symbol,\n side,\n size,\n pollIntervalMs = ONDO_POLL_INTERVAL_MS,\n data,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOndoPrice');\n\n const [state, setState] = useState<LoadOndoPriceState>(() =>\n data === undefined\n ? LOADING\n : { type: 'CONTENT', quote: data, isRefreshing: false }\n );\n\n const fetchIdRef = useRef(0);\n const isFetchingRef = useRef(false);\n // Whether a quote is already on screen, for deciding at what level a failed\n // tick is reported. A ref rather than `state`, which the poll loop closes\n // over once and would read stale for the life of the effect.\n const hasQuoteRef = useRef(data !== undefined);\n\n // The effect depends on the size by value rather than by reference, so a\n // caller passing an inline object - which the checkout viewmodel does, since\n // the size follows the step - does not restart the poll on every render.\n const sizeKey = quoteSizeKey(size);\n\n useEffect(() => {\n if (!isReady || !enabled) return;\n const size = quoteSizeFromKey(sizeKey);\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n\n const load = async () => {\n // Skip a tick while the previous fetch is in flight, so a slow read\n // cannot resolve last and overwrite a fresher price.\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: true }\n : previous\n );\n\n try {\n const quote = await coinlist.ondo.getQuote({ symbol, side, ...size });\n if (currentFetchId !== fetchIdRef.current) return;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT' },\n }));\n hasQuoteRef.current = true;\n setState({ type: 'CONTENT', quote, isRefreshing: false });\n } catch (error) {\n if (currentFetchId !== fetchIdRef.current) return;\n const reason = ondoLoadErrorReason(error);\n // Report at the level the outcome actually has: a tick that fails\n // while a quote is already on screen is recoverable and the next tick\n // retries it, so an `error` per tick would flood a host's tracker\n // through an outage the user never saw. Only the transition to ERROR\n // is a failure. Logging here rather than inside the updater below,\n // which React may call more than once and must stay pure.\n if (hasQuoteRef.current) {\n log.warning(\n () => ({\n msg: 'poll failed; keeping the last quote',\n fields: { reason },\n }),\n error\n );\n } else {\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n }\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: false }\n : { type: 'ERROR', reason }\n );\n } finally {\n if (currentFetchId === fetchIdRef.current) {\n isFetchingRef.current = false;\n }\n }\n };\n\n load();\n const interval = setInterval(load, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, enabled, symbol, side, sizeKey, pollIntervalMs, log]);\n\n return { state };\n}\n\n/**\n * A quote size as a render-stable identity, and the way back from it.\n *\n * Round-tripping through a string rather than holding the object in a ref\n * keeps the effect's dependency honest: it uses exactly what it depends on.\n * That only works because both arms are made of primitives - which is also why\n * `JSON.stringify` is not the tool here, since a `tokenAmount` carries a\n * `bigint` and it throws on those.\n */\nfunction quoteSizeKey(size: OndoQuoteSize): string {\n return 'tokenAmount' in size\n ? `token:${size.tokenAmount.raw}:${size.tokenAmount.decimals}`\n : `notional:${size.notionalValue}`;\n}\n\nfunction quoteSizeFromKey(key: string): OndoQuoteSize {\n const [kind, ...rest] = key.split(':');\n if (kind === 'token') {\n const [raw, decimals] = rest;\n return {\n tokenAmount: BlockchainAmount({\n raw: BigInt(raw),\n decimals: AssetDecimals(Number(decimals)),\n }),\n };\n }\n // A decimal string can contain no colon, so re-joining is lossless.\n return { notionalValue: DecimalString(rest.join(':')) };\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport {\n type OndoLoadErrorReason,\n ondoLoadErrorReason,\n} from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { ONDO_POLL_INTERVAL_MS } from '@/universal/core/checkout/ondo/constants';\nimport type { AssetSymbol } from '@/universal/types/blockchain/core';\nimport type { OndoTradingStatus } from '@/universal/types/providers/ondo/ondo';\nimport type { OrderBookSide } from '@/universal/types/trading';\n\n/**\n * The state of the market-status poll.\n *\n * Stale-preserving for the same reason as {@link LoadOndoPriceState}: a failed\n * tick with a status in hand keeps it, so a flaky read never reads as \"market\n * closed\". `ERROR` means the status is unknown - which is not the same as\n * `CONTENT` carrying a `not-tradable`, and callers must not conflate them. A\n * market that is *known* to be closed may block an order; one that is merely\n * unknown may not.\n */\nexport type LoadOndoTradingStatusState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: OndoLoadErrorReason }\n | { type: 'CONTENT'; status: OndoTradingStatus };\n\n/**\n * Whether the market is *known* to be closed for this side: the one reading of\n * the poll a caller may block an order on. `LOADING` and `ERROR` are unknown,\n * and unknown never blocks.\n */\nexport function isNotTradable(state: LoadOndoTradingStatusState): boolean {\n return state.type === 'CONTENT' && state.status.type === 'not-tradable';\n}\n\nexport interface UseOndoTradingStatusOptions {\n /** Ondo's API symbol, e.g. `AAPLon`. */\n symbol: AssetSymbol;\n /**\n * Required by the endpoint: `tradable` and both order caps describe one side\n * only, so a buy status says nothing about selling.\n */\n side: OrderBookSide;\n /** How often to refresh. Defaults to {@link ONDO_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /**\n * A status the caller already holds, typically fetched server-side, used as\n * the state the hook opens on so a server-rendered panel needs no loading\n * pass.\n *\n * It seeds the first render only: the poll still fetches immediately, unlike\n * the `data` of a hook that reads a snapshot. A market opens and closes on a\n * schedule of its own and the caps come with it, so a seed that suppressed\n * the first read would be answering \"can I trade right now\" with whenever the\n * page was rendered.\n */\n data?: OndoTradingStatus;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseOndoTradingStatusResult {\n state: LoadOndoTradingStatusState;\n}\n\nconst LOADING: LoadOndoTradingStatusState = { type: 'LOADING' };\n\n/**\n * Polls whether Ondo is filling orders for `symbol` on `side` right now, and\n * the order caps that apply while it is.\n *\n * Free to poll - it spends no attestation. Markets open and close on a\n * schedule the SDK does not model, so the poll is the only way a checkout\n * notices mid-order.\n *\n * A `data` status opens the state instead of `LOADING` and is otherwise left to\n * the poll: the first tick fires as it always does, and only replaces the seed\n * once it has a status of its own.\n *\n * Disabled it neither fetches nor holds a timer, and stays on whatever state it\n * opened with. That is `LOADING` and not an empty `CONTENT` because there is no\n * empty market status - and an invented one would be worse than none, since\n * `CONTENT` here is what a caller is allowed to block an order on. A caller\n * that switches this hook off should switch its own rendering off with it.\n */\nexport function useOndoTradingStatus(\n options: UseOndoTradingStatusOptions\n): UseOndoTradingStatusResult {\n const {\n symbol,\n side,\n pollIntervalMs = ONDO_POLL_INTERVAL_MS,\n data,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOndoTradingStatus');\n\n const [state, setState] = useState<LoadOndoTradingStatusState>(() =>\n data === undefined ? LOADING : { type: 'CONTENT', status: data }\n );\n\n const fetchIdRef = useRef(0);\n const isFetchingRef = useRef(false);\n // Whether a status is already on screen, for deciding at what level a failed\n // tick is reported. A ref rather than `state`, which the poll loop closes\n // over once and would read stale for the life of the effect.\n const hasStatusRef = useRef(data !== undefined);\n\n useEffect(() => {\n if (!isReady || !enabled) return;\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n\n const load = async () => {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n try {\n const status = await coinlist.ondo.getTradingStatus({ symbol, side });\n if (currentFetchId !== fetchIdRef.current) return;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', status: status.type },\n }));\n hasStatusRef.current = true;\n setState({ type: 'CONTENT', status });\n } catch (error) {\n if (currentFetchId !== fetchIdRef.current) return;\n const reason = ondoLoadErrorReason(error);\n // A dropped tick with a status already on screen is recoverable and\n // the next tick retries it, so it is a warning; only the transition to\n // ERROR is a failure. Logging here rather than inside the updater\n // below, which React may call more than once and must stay pure.\n if (hasStatusRef.current) {\n log.warning(\n () => ({\n msg: 'poll failed; keeping the last status',\n fields: { reason },\n }),\n error\n );\n } else {\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n }\n // Keep a known status rather than replacing it with \"unknown\": a\n // dropped tick is not news about the market.\n setState((previous) =>\n previous.type === 'CONTENT' ? previous : { type: 'ERROR', reason }\n );\n } finally {\n if (currentFetchId === fetchIdRef.current) {\n isFetchingRef.current = false;\n }\n }\n };\n\n load();\n const interval = setInterval(load, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, enabled, symbol, side, pollIntervalMs, log]);\n\n return { state };\n}\n","/**\n * Why an Ondo checkout cannot run right now, as opposed to a step of it\n * failing.\n *\n * A union rather than a bare flag because the View switches on it for copy.\n *\n * Shared by both products because each reason is a property of the integration\n * or of the market rather than of a direction: buying and selling go through\n * the same contract, so a chain that cannot serve one cannot serve the other,\n * and a closed market reads the same whichever way the trade runs. That is the\n * exception the provider-level `shared/` exists for, and it is narrow - the\n * step states stay per-product, since that is where the two genuinely diverge.\n */\nexport type OndoCheckoutErrorReason =\n /**\n * The offer names no CoinList swap contract on the chain the host asked for,\n * so there is no spender to approve and nothing to broadcast to.\n *\n * Not retryable, and not the host's mistake to correct at runtime: both the\n * offer and the chain are fixed for the lifetime of the mount. See\n * `swapSpender`.\n */\n | 'unsupported-chain'\n /**\n * Ondo is not filling orders for this asset on this side right now: the\n * market is closed or paused, or the asset is paused or closed for the\n * session. Known from the trading-status poll, never assumed from a status\n * that is still loading or failed to load.\n *\n * Unlike `unsupported-chain` this one clears on its own. The trading-status\n * poll keeps running underneath it, and the checkout comes back once the\n * asset is tradable again. Only shown while the user is on the step the flow\n * opened on: once they are past it, a pause is a step's to report, so it\n * cannot pull an order out from under the user mid-flow.\n */\n | 'not-tradable';\n\nexport const OndoCheckoutErrorReason = {\n /**\n * Which reason, if any, replaces the whole checkout. `null` means the steps\n * render.\n *\n * `unsupported-chain` wins because it is settled at mount: no market state\n * can make a chain with no contract tradable. `not-tradable` needs both a\n * market *known* to be closed and a user still at the start of the flow,\n * with no order confirmation on screen. Past the first step a pause belongs\n * to the step it interrupts, and a just-placed order's dialog must not be\n * hidden by a market that closed after it filled.\n */\n of: ({\n swappableHere,\n notTradable,\n atEntry,\n }: {\n swappableHere: boolean;\n notTradable: boolean;\n atEntry: boolean;\n }): OndoCheckoutErrorReason | null => {\n if (!swappableHere) return 'unsupported-chain';\n if (notTradable && atEntry) return 'not-tradable';\n return null;\n },\n};\n","'use client';\n\nimport type { LoadOndoPriceState } from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nimport type { LoadOndoTradingStatusState } from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\nimport type {\n OndoSidebarPriceUi,\n OndoSidebarUiState,\n} from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel.types';\nimport {\n CheckoutAssetUi,\n type CheckoutStatusUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport { formattedUsdPrice } from '@/universal/core/shared/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/universal/core/shared/blockchain/math';\nimport {\n AssetDecimals,\n type AssetSymbol,\n type BlockchainAmount,\n type DecimalString,\n type EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\nconst MARKET_OPEN = 'Market open';\nconst MARKET_CLOSED = 'Market closed';\n/** Shown when the status poll has told us nothing, which is not the same as closed. */\nconst MARKET_UNKNOWN = 'Market status unavailable';\n\n/** The exponent Ondo's per-token price is quoted at. */\nconst PRICE_DECIMALS = AssetDecimals(18);\n\nexport interface UseOndoSidebarViewModelOptions {\n /** Where the asset's identity comes from: name and logo. */\n offer: OndoSwapOfferDetail;\n /** Ondo's API symbol, e.g. `AAPLon`. */\n ondoSymbol: AssetSymbol;\n /** The chain the order executes on, and so the network shown. */\n chain: EthereumChain;\n /**\n * Registry metadata for the offered token, from the checkout flow above.\n * `null` covers every way the answer can be absent (unlisted, not settled,\n * lookup failed); the panel falls back to the offer's own logo for it.\n */\n tokenMetadata: TokenMetadata | null;\n /** The indicative price poll. */\n priceState: LoadOndoPriceState;\n /** The market-status poll. */\n tradingStatusState: LoadOndoTradingStatusState;\n}\n\nexport interface UseOndoSidebarViewModelResult {\n state: OndoSidebarUiState;\n}\n\n/**\n * Drives the reference panel beside the Ondo checkout.\n *\n * Read-only, so it raises no events. The polls are passed in rather than\n * started here: the god viewmodel already runs them - the price is sized by\n * the amount the user has chosen - and a second copy would double the request\n * rate for the same numbers.\n *\n * Only the price corner waits on the network. The asset's identity comes from\n * the offer and is on screen from the first render, so a failed or in-flight\n * poll never blanks it.\n */\nexport function useOndoSidebarViewModel({\n offer,\n ondoSymbol,\n chain,\n tokenMetadata,\n priceState,\n tradingStatusState,\n}: UseOndoSidebarViewModelOptions): UseOndoSidebarViewModelResult {\n const locale = useLocale();\n\n const state: OndoSidebarUiState = {\n asset: CheckoutAssetUi.fromOffer(offer, {\n symbol: ondoSymbol,\n networkName: getNetworkName(chain),\n tokenMetadata,\n }),\n // Reference data for the security the token tracks. Each is null on an\n // offer that tokenizes none, and the detail list drops a null row rather\n // than dashing it.\n issuer: offer.issuer,\n tickerSymbol: offer.ticker,\n isin: offer.isin,\n assetType: offer.instrumentType,\n listingVenue: offer.listingVenue,\n networkName: getNetworkName(chain),\n price: toPriceUi(priceState, tradingStatusState, locale),\n };\n\n return { state };\n}\n\nfunction toPriceUi(\n priceState: LoadOndoPriceState,\n tradingStatusState: LoadOndoTradingStatusState,\n locale: string\n): OndoSidebarPriceUi {\n switch (priceState.type) {\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR':\n return { type: 'unavailable' };\n case 'CONTENT':\n return {\n type: 'known',\n price: formattedUsdPrice(toPriceAmount(priceState.quote.price), locale),\n market: toMarketUi(tradingStatusState),\n };\n default: {\n const exhaustive: never = priceState;\n return exhaustive;\n }\n }\n}\n\n/**\n * Ondo's price arrives as an unscaled decimal string, and the formatter takes\n * an amount, so it is scaled by the 18 decimals Ondo quotes at. A price that\n * will not parse is reported as absent rather than as zero, which would read\n * as a free share.\n */\nfunction toPriceAmount(price: DecimalString): BlockchainAmount | null {\n const parsed = parseBlockchainAmount(price, PRICE_DECIMALS);\n return parsed.valid ? parsed.amount : null;\n}\n\n/**\n * An unknown market is reported as inactive with its own copy, never as open:\n * `CheckoutStatusUi` has two arms, and claiming a market is open on the\n * strength of a failed poll is the one of the two that could cost a user\n * something.\n *\n * This is display only. Whether an order is blocked is decided by the amount\n * step, which acts on a *known* closed market and lets an unknown one through.\n */\nfunction toMarketUi(state: LoadOndoTradingStatusState): CheckoutStatusUi {\n switch (state.type) {\n case 'LOADING':\n case 'ERROR':\n return { type: 'inactive', label: MARKET_UNKNOWN };\n case 'CONTENT':\n return state.status.type === 'tradable'\n ? { type: 'active', label: MARKET_OPEN }\n : { type: 'inactive', label: MARKET_CLOSED };\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useState } from 'react';\nimport type {\n OndoWalletSelectUiEvent,\n OndoWalletSelectUiState,\n} from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel.types';\nimport type {\n CheckoutConfirmedWalletUi,\n CheckoutEmbeddedWalletUi,\n CheckoutWalletTypeUi,\n CheckoutWalletUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport { shortenAddress } from '@/universal/core/shared/blockchain/formatters';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\n\nconst CONNECT_FAILED = 'Could not connect that wallet. Please try again.';\n\n/**\n * Whether step 1 is being filled in or already answered.\n *\n * There is no `incomplete` arm: this is the first step, so it is never waiting\n * on one above it.\n */\nexport type OndoWalletSelectStepInput =\n | { type: 'active' }\n | { type: 'completed'; wallet: EvmWallet };\n\nexport interface UseOndoWalletSelectViewModelOptions {\n stepInput: OndoWalletSelectStepInput;\n /** The host's wallets, and the lambdas that connect and disconnect one. */\n wallets: CheckoutWalletSelection;\n /** The chain the order executes on, which names the network on each row. */\n chain: EthereumChain;\n /** Called with the wallet the user settled on. */\n onComplete: (wallet: EvmWallet) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n}\n\nexport interface UseOndoWalletSelectViewModelResult {\n state: OndoWalletSelectUiState;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n}\n\n/**\n * Drives step 1 of the Ondo checkout: which wallet funds the purchase and\n * receives the asset.\n *\n * Nothing here touches the network. Unlike Superstate's equivalent, an Ondo\n * wallet is not allow-listed, so confirming is a local decision the viewmodel\n * makes on its own - which is why the step's CTA is a plain `confirmEnabled`\n * rather than a `CheckoutCtaUi` with loading copy.\n *\n * Connecting an external wallet is the host's job: `connectExternal` opens\n * whatever connector it ships, and the result is read from `wallets.external`\n * on the next render rather than from a return value, so a connector that\n * redirects works as well as one that opens a modal.\n */\nexport function useOndoWalletSelectViewModel({\n stepInput,\n wallets,\n chain,\n onComplete,\n onEdit,\n}: UseOndoWalletSelectViewModelOptions): UseOndoWalletSelectViewModelResult {\n const log = useLogger('useOndoWalletSelectViewModel');\n const [selected, setSelected] = useState<CheckoutWalletTypeUi | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const networkName = getNetworkName(chain);\n const selectedWallet = resolveWallet(wallets, selected);\n\n const uiState = (): OndoWalletSelectUiState => {\n switch (stepInput.type) {\n case 'active':\n return {\n type: 'active',\n embeddedWallets: wallets.embedded.map((wallet) =>\n toEmbeddedWalletUi(wallet, networkName, selected)\n ),\n externalWallet: toExternalWalletUi(\n wallets.external,\n networkName,\n selected\n ),\n // Disconnecting is offered whenever there is something to\n // disconnect: a user who connected the wrong account needs the way\n // out whether or not that row happens to be selected.\n canDisconnect: wallets.external !== null,\n confirmEnabled: selectedWallet !== null,\n error,\n };\n case 'completed':\n return {\n type: 'completed',\n wallet: toConfirmedWalletUi(wallets, stepInput.wallet),\n };\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n const selectWallet = (value: CheckoutWalletTypeUi) => {\n setError(null);\n // Ignore a selection the host cannot back with a wallet: the row it came\n // from has already gone.\n if (resolveWallet(wallets, value) === null) return;\n setSelected(value);\n };\n\n const connectWallet = async () => {\n setError(null);\n try {\n await wallets.connectExternal();\n } catch (error) {\n log.failure(\n () => ({ msg: 'the host connectExternal handler threw' }),\n error\n );\n setError(CONNECT_FAILED);\n return;\n }\n // The wallet itself arrives through `wallets.external` on the next render;\n // selecting the row is all this can do now.\n setSelected({ type: 'external' });\n };\n\n const disconnectWallet = async () => {\n setError(null);\n await wallets.disconnectExternal();\n setSelected((previous) =>\n previous?.type === 'external' ? null : previous\n );\n };\n\n const confirmWallet = () => {\n if (selectedWallet === null) return;\n onComplete(selectedWallet);\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the wallets and the selection this render was given, so a memo could only ever hand back a stale one.\n const onEvent = (event: OndoWalletSelectUiEvent) => {\n switch (event.type) {\n case 'ON_SELECT_WALLET':\n selectWallet(event.value);\n return;\n case 'ON_CONNECT_WALLET':\n void connectWallet();\n return;\n case 'ON_DISCONNECT_WALLET':\n void disconnectWallet();\n return;\n case 'ON_CONFIRM_WALLET':\n confirmWallet();\n return;\n case 'ON_EDIT_WALLET':\n onEdit();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n/**\n * The wallet a selection refers to, or `null` when the host no longer offers\n * it - an embedded wallet that disappeared, or an external row tapped before\n * anything is connected.\n */\nfunction resolveWallet(\n wallets: CheckoutWalletSelection,\n selected: CheckoutWalletTypeUi | null\n): EvmWallet | null {\n if (selected === null) return null;\n switch (selected.type) {\n case 'external':\n return wallets.external;\n case 'embedded':\n return findEmbedded(wallets, selected.address);\n default: {\n const exhaustive: never = selected;\n return exhaustive;\n }\n }\n}\n\nfunction findEmbedded(\n wallets: CheckoutWalletSelection,\n address: EvmWalletAddress\n): EvmWallet | null {\n return wallets.embedded.find((wallet) => wallet.address === address) ?? null;\n}\n\nfunction toEmbeddedWalletUi(\n wallet: EvmWallet,\n networkName: string,\n selected: CheckoutWalletTypeUi | null\n): CheckoutEmbeddedWalletUi {\n return {\n address: shortenAddress(wallet.address),\n network: networkName,\n selected:\n selected?.type === 'embedded' && selected.address === wallet.address,\n walletAddress: wallet.address,\n };\n}\n\nfunction toExternalWalletUi(\n wallet: EvmWallet | null,\n networkName: string,\n selected: CheckoutWalletTypeUi | null\n): CheckoutWalletUi | null {\n if (wallet === null) return null;\n return {\n address: shortenAddress(wallet.address),\n network: networkName,\n selected: selected?.type === 'external',\n };\n}\n\n/**\n * Which kind of wallet was confirmed, decided by whether the host lists it as\n * an embedded one. The two are shown differently: a CoinList wallet is named\n * as such, an external one is shown by address.\n */\nfunction toConfirmedWalletUi(\n wallets: CheckoutWalletSelection,\n wallet: EvmWallet\n): CheckoutConfirmedWalletUi {\n const isEmbedded = findEmbedded(wallets, wallet.address) !== null;\n return {\n type: isEmbedded ? 'embedded' : 'external',\n address: shortenAddress(wallet.address),\n };\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { TokenIdentifier } from '@/universal/types/blockchain/core';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * The state of a token-metadata lookup.\n *\n * `CONTENT` with `null` means the registry answered and does not list the\n * token — a real domain answer callers render on (fall back to your own\n * display defaults). `ERROR` means the answer is unknown; the two must not be\n * conflated. `DISABLED` means the hook was switched off before an answer\n * arrived, so there is nothing to render a loading UI for. No\n * `not-authenticated` reason: the registry is public.\n */\nexport type LoadTokenMetadataState =\n | { type: 'DISABLED' }\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: 'generic-error' }\n | { type: 'CONTENT'; tokenMetadata: TokenMetadata | null };\n\nexport interface UseTokenMetadataOptions extends TokenIdentifier {\n /**\n * Metadata pre-fetched on the server (via `CoinListServer#tokens.get`).\n * When provided, the hook uses it as-is and skips the initial client-side\n * fetch; {@link UseTokenMetadataResult.refetch} still fetches. `null` is a\n * valid seed — it means \"not in the registry\" — and is distinct from\n * leaving `data` undefined.\n */\n data?: TokenMetadata | null;\n /** When false: no request; see {@link LoadTokenMetadataState}. Default true. */\n enabled?: boolean;\n}\n\nexport interface UseTokenMetadataResult {\n state: LoadTokenMetadataState;\n /**\n * Fetches again: the recovery path after a transient `ERROR`, and the way\n * past a server seed (`data`), which only the first fetch honours. No-op\n * while disabled.\n */\n refetch: () => void;\n}\n\nconst DISABLED_STATE: LoadTokenMetadataState = { type: 'DISABLED' };\nconst LOADING_STATE: LoadTokenMetadataState = { type: 'LOADING' };\n\n/**\n * Loads one token's display metadata (name, symbol, decimals, logos) from\n * CoinList's public token registry — the lookup `OfferDetail.tokens` entries\n * are keyed for. To display a whole catalogue, prefer one\n * `CoinListClient#tokens.list(chain)` over mounting this hook per token.\n *\n * No polling: registry content is immutable per version, so a\n * `(chain, address)` answer does not change under the page. `refetch` exists\n * for error recovery and for bypassing a server seed, not for freshness.\n *\n * Disabled without an answer in hand it reports `DISABLED` rather than\n * `LOADING` (nothing is in flight, so a spinner would wait forever) and\n * rather than an empty `CONTENT` (`CONTENT: null` asserts \"not in the\n * registry\" — an answer this hook would not actually have). A seeded or\n * already-fetched `CONTENT` survives disabling.\n */\nexport function useTokenMetadata(\n options: UseTokenMetadataOptions\n): UseTokenMetadataResult {\n const { chain, address, data, enabled = true } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useTokenMetadata');\n\n const [state, setState] = useState<LoadTokenMetadataState>(() =>\n data !== undefined\n ? { type: 'CONTENT', tokenMetadata: data }\n : LOADING_STATE\n );\n const [refetchCount, setRefetchCount] = useState(0);\n\n const refetch = useCallback(() => {\n setRefetchCount((count) => count + 1);\n }, []);\n\n useEffect(() => {\n let isCancelled = false;\n\n // The seed answers the initial render only; an explicit refetch is a\n // request for the client's own answer.\n const seedActive = data !== undefined && refetchCount === 0;\n if (!isReady || !enabled || seedActive) {\n return () => {\n isCancelled = true;\n };\n }\n\n setState(LOADING_STATE);\n coinlist.tokens\n .get({ chain, address })\n .then((tokenMetadata) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: {\n state: 'CONTENT',\n listed: tokenMetadata !== null,\n symbol: tokenMetadata?.symbol ?? null,\n },\n }));\n setState({ type: 'CONTENT', tokenMetadata });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n log.failure(\n () => ({\n msg: 'settled',\n fields: { state: 'ERROR', reason: 'generic-error' },\n }),\n error\n );\n setState({ type: 'ERROR', reason: 'generic-error' });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, chain, address, data, refetchCount, log]);\n\n return {\n // LOADING would be a lie while disabled: nothing is in flight and nothing\n // will replace it. Settled states (a seed, a previous answer) survive.\n state: !enabled && state.type === 'LOADING' ? DISABLED_STATE : state,\n refetch,\n };\n}\n","'use client';\n\nimport type { LoadTokenMetadataState } from '@/client/hooks/shared/useTokenMetadata';\nimport { useTokenMetadata } from '@/client/hooks/shared/useTokenMetadata';\nimport { offerDisplayTokens } from '@/universal/core/tokens/token-registry-snapshot';\nimport {\n type EthereumChain,\n EvmContractAddress,\n type TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Stands in for an address while the offer lists no token on this chain.\n *\n * Never sent anywhere: the underlying lookup is seeded with \"not listed\"\n * whenever this is in play, so no request is made with it.\n */\nconst NO_TOKEN_ADDRESS = EvmContractAddress(\n '0x0000000000000000000000000000000000000000'\n);\n\nexport interface UseCheckoutOfferTokenMetadataOptions {\n /**\n * The offer being checked out: its `tokens` list supplies the\n * `(chain, address)` key the registry lookup is made with.\n */\n offer: OfferDetail;\n /** The chain the checkout executes on, which selects the token entry. */\n chain: EthereumChain;\n /**\n * Metadata pre-fetched on the server (via `CoinListServer#tokens.get`).\n * When provided, the hook uses it as-is and skips the client-side fetch.\n * `null` is a valid seed — it means \"not in the registry\" — and is distinct\n * from leaving `data` undefined.\n */\n data?: TokenMetadata | null;\n /**\n * When false: no request; see {@link LoadTokenMetadataState}. Default true.\n */\n enabled?: boolean;\n}\n\nexport interface UseCheckoutOfferTokenMetadataResult {\n state: LoadTokenMetadataState;\n}\n\n/**\n * The `(chain, address)` the public token registry keys the offer's asset by,\n * or `null` when the offer lists no token on this chain.\n *\n * The checkout renders the asset an offer sells, which is the `swap` entry on\n * its chain; a `distribution` entry names the same token for a sale product,\n * so it is accepted as the fallback. `funding` entries name what a swap is\n * paid with, never what it sells, so they are skipped — the funding row has\n * its own icon source in `stablecoinIconUrl`. That ordering is\n * `offerDisplayTokens`', shared with the catalogue's any-chain lookup; the\n * checkout adds only the chain it executes on.\n */\nexport function offerTokenIdentifier(\n offer: OfferDetail,\n chain: EthereumChain\n): TokenIdentifier | null {\n const asset = offerDisplayTokens(offer).find(\n (token) => token.chain === chain\n );\n return asset === undefined ? null : { chain, address: asset.address };\n}\n\n/**\n * The metadata value `CheckoutAssetUi.fromOffer` wants, from the shared\n * lookup's state: `null` while the answer is unknown (loading, error,\n * disabled), which is the signal that renders the offer's own logo.\n *\n * Exported because every checkout god viewmodel projects its state exactly\n * once for the same reason — the steps below them render a value, not a\n * state machine — and three hand-written copies of the load-bearing\n * fallback rule would drift the first time the state union grows an arm.\n */\nexport function tokenMetadataOf(\n state: LoadTokenMetadataState\n): TokenMetadata | null {\n return state.type === 'CONTENT' ? state.tokenMetadata : null;\n}\n\n/**\n * Loads the public token registry's display metadata for the asset an offer\n * sells, keyed by the token `OfferDetail.tokens` lists for the checkout's\n * chain. Checkout screens feed the result into `CheckoutAssetUi.fromOffer`,\n * which prefers the registry logo and falls back to the offer's own.\n *\n * A composition rather than a re-implementation: `useTokenMetadata` already\n * owns the `(chain, address)` lookup and its state machine, so this hook\n * contributes only the offer step — which token entry is the asset being\n * sold — and delegates the rest. An offer that lists no token on this chain\n * is seeded with \"not listed\", which is a settled answer rather than a\n * spinner. There is deliberately no `refetch`: the offer and chain are fixed\n * for the lifetime of the checkout, and a failed lookup renders the offer\n * logo — there is no user-visible recovery to hang a retry on.\n */\nexport function useCheckoutOfferTokenMetadata({\n offer,\n chain,\n data,\n enabled = true,\n}: UseCheckoutOfferTokenMetadataOptions): UseCheckoutOfferTokenMetadataResult {\n const identifier = offerTokenIdentifier(offer, chain);\n\n const { state } = useTokenMetadata({\n // Primitive keys, not the identifier object: the underlying hook re-fetches\n // only when `(chain, address)` changes, so a host that rebuilds the offer\n // object per render does not refetch the registry per render.\n chain: identifier?.chain ?? chain,\n address: identifier?.address ?? NO_TOKEN_ADDRESS,\n // Nothing to look up when the offer lists no token here: seed \"not\n // listed\" and never fire a request against the placeholder address.\n enabled: enabled && identifier !== null,\n data: data !== undefined ? data : identifier === null ? null : undefined,\n });\n\n return { state };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { OndoBuyCheckoutView } from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutView';\nimport { useOndoBuyCheckoutViewModel } from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel';\nimport type { OndoOrderPlaced } from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type {\n AssetSymbol,\n EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\n\nexport interface OndoBuyCheckoutContainerProps {\n /** The offer being bought: names the asset and supplies its logo. */\n offer: OndoSwapOfferDetail;\n /**\n * Ondo's API symbol for the asset, e.g. `AAPLon`.\n *\n * Explicit rather than derived from the offer: Ondo's symbol tracks the\n * underlying ticker and changes on a rebrand, and on Sepolia the two already\n * disagree, where a mock asset stands in.\n */\n ondoSymbol: AssetSymbol;\n /**\n * The chain the order executes on: the balance read, the approval and the\n * broadcast. Ondo prices against production whatever this says, since it\n * runs no sandbox.\n */\n chain: EthereumChain;\n /**\n * The wallets the buyer can spend from, and the lambdas that connect and\n * disconnect an external one. The SDK ships no wallet stack, so this is how\n * a host plugs in Privy, AppKit, or its own.\n */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. `false` turns off every request and timer, for a checkout\n * that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /** Fired once the swap has mined. The dialog shows either way. */\n onOrderConfirmed?: (order: OndoOrderPlaced) => void;\n className?: string;\n}\n\n/**\n * The Ondo buy checkout, ready to drop in: three steps, the asset panel beside\n * them, and the dialog that closes the flow.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoBuyCheckoutContainer({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n className,\n}: OndoBuyCheckoutContainerProps): ReactNode {\n const { state, onEvent } = useOndoBuyCheckoutViewModel({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n });\n\n return (\n <OndoBuyCheckoutView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutAmountInput } from '@/client/components/checkout/shared/amount/CheckoutAmountInput';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { PayWithAssetCard } from '@/client/components/checkout/shared/selection/PayWithAssetCard';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { CheckoutStepFooter } from '@/client/components/checkout/shared/step/CheckoutStepFooter';\nimport { CompletedStepSummary } from '@/client/components/checkout/shared/step/CompletedStepSummary';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoSellAmountUiEvent,\n OndoSellAmountUiState,\n OndoSellSourceWalletUi,\n} from '@/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel.types';\n\nconst TITLE = 'Enter amount';\nconst AMOUNT_LABEL = 'Amount';\nconst AMOUNT_PLACEHOLDER = '0.00';\nconst BALANCE_LABEL = 'Balance';\nconst EMBEDDED_WALLET_LABEL = 'CoinList Wallet';\nconst REVIEW_NOTE = \"You'll review your order details before selling.\";\n\nexport interface OndoSellAmountViewProps {\n state: OndoSellAmountUiState;\n onEvent: (event: OndoSellAmountUiEvent) => void;\n /**\n * Where this card sits in the flow, which is 2 normally and 1 when the host\n * preselected a wallet and the step above was skipped.\n *\n * A prop rather than a constant because the sell flow has two lengths. The\n * god View derives it from the one fact that decides it, so the two cards\n * cannot disagree about how many steps there are.\n */\n stepNumber: number;\n className?: string;\n}\n\n/**\n * The amount step of the Ondo sell checkout. Pure: amounts arrive already\n * formatted, and every interaction leaves through `onEvent`.\n *\n * The balance is a statement rather than a choice - a sell has exactly one\n * input, the asset the offer names - so it renders as a static card where the\n * buy step renders a picker. `Max` is offered all the same, and means more\n * here than there: selling a whole position is the common case.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoSellAmountView(props: OndoSellAmountViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoSellAmountViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoSellAmountViewBody({\n state,\n onEvent,\n stepNumber,\n className,\n}: OndoSellAmountViewProps): ReactNode {\n const title = `${stepNumber}. ${TITLE}`;\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={title}\n className={className}\n />\n );\n case 'active':\n return (\n <ActiveView\n state={state}\n onEvent={onEvent}\n title={title}\n className={className}\n />\n );\n case 'complete':\n return (\n <CompletedView\n state={state}\n onEvent={onEvent}\n title={title}\n className={className}\n />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n title,\n className,\n}: {\n state: Extract<OndoSellAmountUiState, { type: 'active' }>;\n onEvent: (event: OndoSellAmountUiEvent) => void;\n title: string;\n className?: string;\n}): ReactNode {\n const isLoading = state.confirmCta.type === 'loading';\n\n return (\n <CheckoutStepCard\n state=\"active\"\n title={title}\n className={className}\n footer={\n <CheckoutStepFooter\n message={\n state.confirmCta.type === 'loading'\n ? state.confirmCta.message\n : REVIEW_NOTE\n }\n error={state.error}\n cta={\n <ClButton\n variant=\"primary\"\n disabled={state.confirmCta.type === 'disabled'}\n isLoading={isLoading}\n loadingText=\"Confirming\"\n onClick={() => onEvent({ type: 'ON_CONFIRM_SELL_AMOUNT' })}\n className=\"clcosdk:h-12 clcosdk:max-md:w-full\"\n >\n Confirm amount\n </ClButton>\n }\n />\n }\n >\n <CheckoutAmountInput\n label={AMOUNT_LABEL}\n value={state.amountInput}\n onChange={(value) => onEvent({ type: 'ON_SELL_AMOUNT_CHANGE', value })}\n placeholder={AMOUNT_PLACEHOLDER}\n invalid={state.error !== null}\n disabled={isLoading}\n suffix={state.balance?.asset.symbol}\n action={\n state.balance !== null && (\n <MaxButton\n disabled={isLoading}\n onClick={() => onEvent({ type: 'ON_SELL_MAX_AMOUNT_CLICK' })}\n />\n )\n }\n />\n\n <BalanceSection state={state} />\n </CheckoutStepCard>\n );\n}\n\n/**\n * The asset being sold and the holding the amount is validated against.\n *\n * Rendered as `PayWithAssetCard` in its `static` variant - the same row the\n * buy step shows when only one funding coin is on offer, which is exactly the\n * shape a sell is always in.\n */\nfunction BalanceSection({\n state,\n}: {\n state: Extract<OndoSellAmountUiState, { type: 'active' }>;\n}): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {BALANCE_LABEL}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n from {walletLabel(state.wallet)}\n </span>\n </div>\n\n {state.balance === null ? (\n // The asset's address and decimals arrive with the sell quote, so\n // there is nothing to name until it lands - and a zero holding under\n // the real symbol would be a claim rather than a wait.\n <Skeleton\n variant=\"rectangular\"\n className=\"clcosdk:h-[71px] clcosdk:w-full clcosdk:rounded-2xl\"\n />\n ) : (\n <PayWithAssetCard\n variant=\"static\"\n asset={state.balance.asset}\n balance={state.balance.balance}\n />\n )}\n </div>\n );\n}\n\nfunction walletLabel(wallet: OndoSellSourceWalletUi): string {\n switch (wallet.type) {\n case 'embedded':\n return EMBEDDED_WALLET_LABEL;\n case 'external':\n return wallet.address;\n default: {\n const exhaustive: never = wallet;\n return exhaustive;\n }\n }\n}\n\nfunction CompletedView({\n state,\n onEvent,\n title,\n className,\n}: {\n state: Extract<OndoSellAmountUiState, { type: 'complete' }>;\n onEvent: (event: OndoSellAmountUiEvent) => void;\n title: string;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"completed\" title={title} className={className}>\n <CompletedStepSummary\n icon={<AssetIcon asset={state.asset} size={40} />}\n title={state.amountFormatted}\n editLabel=\"Edit\"\n onEdit={() => onEvent({ type: 'ON_EDIT_SELL_AMOUNT' })}\n />\n </CheckoutStepCard>\n );\n}\n\nfunction MaxButton({\n disabled,\n onClick,\n}: {\n disabled: boolean;\n onClick: () => void;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onClick}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:h-9 clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:rounded-full',\n 'clcosdk:border clcosdk:border-border clcosdk:px-5',\n 'clcosdk:font-medium clcosdk:text-text-primary',\n 'clcosdk:transition-colors clcosdk:hover:bg-surface',\n 'clcosdk:disabled:cursor-not-allowed clcosdk:disabled:opacity-40'\n )}\n >\n Max\n </button>\n );\n}\n","'use client';\n\nimport { Check, ExternalLink } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutConfirmationDialog } from '@/client/components/checkout/shared/confirmation/CheckoutConfirmationDialog';\nimport { AssetSummaryRow } from '@/client/components/checkout/shared/summary/AssetSummaryRow';\nimport type { CheckoutDetailRowUi } from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoSellOrderConfirmedUiEvent,\n OndoSellOrderConfirmedUiState,\n} from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel.types';\nimport type { AssetSymbol } from '@/universal/types/blockchain/core';\n\nconst TITLE = 'Order confirmed';\nconst SHARES_SOLD_LABEL = 'Shares sold';\nconst RECEIVED_LABEL = 'Received';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst DELIVERED_TO_LABEL = 'Delivered to';\nconst DONE_LABEL = 'Done';\nconst VIEW_TRANSACTION_LABEL = 'View transaction onchain';\n\nconst subtitle = (\n soldSymbol: AssetSymbol,\n proceedsSymbol: AssetSymbol\n): string =>\n `Your ${soldSymbol} shares have been sold and ${proceedsSymbol} was delivered to your wallet.`;\n\nexport interface OndoSellOrderConfirmedProps {\n state: OndoSellOrderConfirmedUiState;\n onEvent: (event: OndoSellOrderConfirmedUiEvent) => void;\n className?: string;\n}\n\n/**\n * The dialog that closes the Ondo sell checkout: what went, what came back,\n * and where it landed.\n *\n * Pure: every figure is handed over formatted, and the explorer link is\n * rendered from the URL the viewmodel built rather than raised as an event.\n *\n * Self-scoped: renders fully styled on its own. It bails before the scope while\n * hidden, so a closed dialog leaves nothing in the DOM.\n */\nexport function OndoSellOrderConfirmed({\n state,\n onEvent,\n className,\n}: OndoSellOrderConfirmedProps): ReactNode {\n if (state.type === 'hidden') {\n return null;\n }\n\n const onClose = () => onEvent({ type: 'ON_CLOSE_SELL_ORDER_CONFIRMED' });\n\n return (\n <CoinListStyleScope>\n <CheckoutConfirmationDialog\n icon={<SuccessGlyph />}\n title={TITLE}\n subtitle={subtitle(state.soldAsset.symbol, state.proceedsSymbol)}\n header={\n // The header names what was sold. The quantity is a detail row, so a\n // long fund name and a long share count each get the full width.\n <AssetSummaryRow asset={state.soldAsset} wrapIdentity />\n }\n rows={detailRows(state)}\n actions={\n <>\n <ClButton variant=\"gradient\" fullWidth onClick={onClose}>\n {DONE_LABEL}\n </ClButton>\n <ExplorerLink url={state.txExplorerUrl} />\n </>\n }\n onClose={onClose}\n className={className}\n />\n </CoinListStyleScope>\n );\n}\n\nfunction detailRows(\n state: Extract<OndoSellOrderConfirmedUiState, { type: 'visible' }>\n): CheckoutDetailRowUi[] {\n return [\n { label: SHARES_SOLD_LABEL, value: state.soldAmount },\n { label: RECEIVED_LABEL, value: state.proceeds },\n { label: PRICE_PER_SHARE_LABEL, value: state.pricePerShare },\n { label: DELIVERED_TO_LABEL, value: state.recipientAddress },\n ];\n}\n\nfunction SuccessGlyph(): ReactNode {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:size-10 clcosdk:shrink-0 clcosdk:items-center clcosdk:justify-center',\n 'clcosdk:rounded-full clcosdk:bg-positive-subtle'\n )}\n >\n <Check\n className=\"clcosdk:size-5 clcosdk:text-positive\"\n strokeWidth={2.5}\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n\n/**\n * An anchor rather than a button: the URL is known, so middle-click, copy-link\n * and the host's own link handling all keep working.\n */\nfunction ExplorerLink({ url }: { url: string }): ReactNode {\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n typeClasses.label,\n 'clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:items-center clcosdk:justify-center clcosdk:gap-1.5',\n 'clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:px-4',\n 'clcosdk:text-text-primary clcosdk:no-underline',\n 'clcosdk:transition-colors clcosdk:hover:bg-section'\n )}\n >\n {VIEW_TRANSACTION_LABEL}\n <ExternalLink\n className=\"clcosdk:size-3.5 clcosdk:shrink-0\"\n strokeWidth={1.5}\n aria-hidden=\"true\"\n />\n </a>\n );\n}\n","'use client';\n\nimport { Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { ONDO_TOS_URL } from '@/client/components/checkout/ondo/shared/constants';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { DetailRow } from '@/client/components/checkout/shared/common/DetailRow';\nimport {\n COINLIST_PRIVACY_URL,\n COINLIST_TOS_URL,\n} from '@/client/components/checkout/shared/constants';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { Tooltip } from '@/client/components/design-system/Tooltip';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoSellQuoteStatusUi,\n OndoSellReviewUiEvent,\n OndoSellReviewUiState,\n} from '@/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel.types';\n\nconst TITLE = 'Review and confirm';\nconst YOU_RECEIVE_LABEL = 'You receive';\nconst RECEIVING_WALLET_LABEL = 'Receiving wallet';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst PRICE_PER_SHARE_TOOLTIP =\n 'The price of one whole token at the time of this quote. It is what the order is expected to fill at; the minimum below is what it is guaranteed to settle for.';\nconst MINIMUM_RECEIVED_LABEL = 'Minimum received';\nconst MINIMUM_RECEIVED_TOOLTIP =\n 'The least this order will settle for, after fees. Ondo converts through USDon before delivering, so the amount above is expected rather than guaranteed; below this floor the order does not go through and nothing is sold.';\nconst COINLIST_FEE_LABEL = 'Expected CoinList fee';\nconst COINLIST_FEE_TOOLTIP =\n \"CoinList's fee at the amount you're expected to receive. It comes out of your proceeds; at the minimum it is slightly smaller.\";\nconst REFRESH_QUOTE_LABEL = 'Refresh quote';\nconst LOADING_STATUS = 'Loading your order details…';\nconst ERROR_TITLE = 'Something went wrong';\nconst ERROR_DESCRIPTION =\n \"We couldn't load your order details. Please try again.\";\n\nexport interface OndoSellReviewViewProps {\n state: OndoSellReviewUiState;\n onEvent: (event: OndoSellReviewUiEvent) => void;\n /** Where this card sits in the flow: 3 normally, 2 when the wallet step was skipped. */\n stepNumber: number;\n className?: string;\n}\n\n/**\n * The review step of the Ondo sell checkout. Pure: every number arrives\n * formatted, and whether the order can be placed is decided by\n * `placeOrderCta` rather than re-derived here from the quote's status.\n *\n * It carries no total. A sell has nothing for the user to pay - the proceeds\n * are the headline, and the fee comes out of them - so the buy step's\n * gross/fee/total ladder has no counterpart here. What it carries instead is\n * the floor: the proceeds above are what Ondo expects to deliver, and only the\n * minimum is what the calldata enforces.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoSellReviewView(props: OndoSellReviewViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoSellReviewViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoSellReviewViewBody({\n state,\n onEvent,\n stepNumber,\n className,\n}: OndoSellReviewViewProps): ReactNode {\n const title = `${stepNumber}. ${TITLE}`;\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={title}\n className={className}\n />\n );\n case 'loading':\n return <LoadingView title={title} className={className} />;\n case 'error':\n return (\n <ErrorView onEvent={onEvent} title={title} className={className} />\n );\n case 'active':\n return (\n <ActiveView\n state={state}\n onEvent={onEvent}\n title={title}\n className={className}\n />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n title,\n className,\n}: {\n state: Extract<OndoSellReviewUiState, { type: 'active' }>;\n onEvent: (event: OndoSellReviewUiEvent) => void;\n title: string;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={title} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {YOU_RECEIVE_LABEL}\n </span>\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n <AssetIcon asset={state.outputAsset} size={40} />\n <span className=\"clcosdk:min-w-0 clcosdk:break-words clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium clcosdk:text-text-primary\">\n {state.expected.amount}\n </span>\n </div>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n <DetailRow\n label={RECEIVING_WALLET_LABEL}\n value={state.recipientAddress}\n />\n <DetailRow\n label={PRICE_PER_SHARE_LABEL}\n tooltip={\n <Tooltip content={PRICE_PER_SHARE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.pricePerShare}\n />\n {/* Above the floor, not below it: the fee is the cut at the expected\n amount, and a row sitting under \"Minimum received\" reads as the cut\n at that one - a different number the day one lands. The guarantee\n closes the list instead. */}\n {state.expected.fee !== null && (\n <DetailRow\n label={COINLIST_FEE_LABEL}\n tooltip={\n <Tooltip content={COINLIST_FEE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.expected.fee}\n />\n )}\n <DetailRow\n label={MINIMUM_RECEIVED_LABEL}\n tooltip={\n <Tooltip content={MINIMUM_RECEIVED_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.minimum.amount}\n />\n </div>\n\n {/* Both lines, never one or the other. Placing an order takes longer\n than a quote lives, so a failure usually arrives on a quote that has\n already expired - and the quote line carries the only refresh link. */}\n {state.error !== null && (\n <QuoteLine tone=\"error\">{state.error}</QuoteLine>\n )}\n <QuoteStatusLine quote={state.quote} onEvent={onEvent} />\n\n <ClButton\n variant=\"gradient\"\n size=\"cta\"\n fullWidth\n disabled={state.placeOrderCta.type === 'disabled'}\n isLoading={state.placeOrderCta.type === 'loading'}\n loadingText={\n state.placeOrderCta.type === 'loading'\n ? state.placeOrderCta.message\n : undefined\n }\n onClick={() => onEvent({ type: 'ON_PLACE_SELL_ORDER' })}\n >\n Place order\n </ClButton>\n\n <Disclaimer />\n </CheckoutStepCard>\n );\n}\n\n/**\n * The line above the CTA saying whether the numbers can still be traded on.\n *\n * Every arm but `refreshing` offers the refresh action, because in every one of\n * them refreshing is the thing that helps.\n */\nfunction QuoteStatusLine({\n quote,\n onEvent,\n}: {\n quote: OndoSellQuoteStatusUi;\n onEvent: (event: OndoSellReviewUiEvent) => void;\n}): ReactNode {\n const refreshLink = (\n <button\n type=\"button\"\n onClick={() => onEvent({ type: 'ON_REFRESH_SELL_QUOTE' })}\n className=\"clcosdk:cursor-pointer clcosdk:underline clcosdk:transition-opacity clcosdk:hover:opacity-80\"\n >\n {REFRESH_QUOTE_LABEL}\n </button>\n );\n\n switch (quote.type) {\n case 'valid':\n return (\n <QuoteLine tone=\"muted\">\n {quote.expiresInLabel} {refreshLink}\n </QuoteLine>\n );\n case 'refreshing':\n return <QuoteLine tone=\"muted\">Refreshing quote…</QuoteLine>;\n case 'expired':\n return <QuoteLine tone=\"warning\">Quote expired. {refreshLink}</QuoteLine>;\n case 'refresh-failed':\n return (\n <QuoteLine tone=\"warning\">\n {quote.message} {refreshLink}\n </QuoteLine>\n );\n default: {\n const exhaustive: never = quote;\n return exhaustive;\n }\n }\n}\n\nfunction QuoteLine({\n tone,\n children,\n}: {\n tone: 'muted' | 'warning' | 'error';\n children: ReactNode;\n}): ReactNode {\n const toneClass = {\n muted: 'clcosdk:text-text-secondary',\n warning: 'clcosdk:text-warning',\n error: 'clcosdk:text-error',\n }[tone];\n\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:md:px-6',\n toneClass\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction LoadingView({\n title,\n className,\n}: {\n title: string;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={title} className={className}>\n {/* Every skeleton below is aria-hidden, so this line is the only thing a\n screen reader has to go on while the order details load. */}\n <output className=\"clcosdk:sr-only\">{LOADING_STATUS}</output>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-20\" />\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-3\">\n <Skeleton\n variant=\"circular\"\n className=\"clcosdk:size-10 clcosdk:shrink-0\"\n />\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <Skeleton className=\"clcosdk:h-5 clcosdk:w-32\" />\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-24\" />\n </div>\n </div>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n {['wallet', 'price', 'minimum'].map((row) => (\n <div\n key={row}\n className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\"\n >\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-28\" />\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-24\" />\n </div>\n ))}\n </div>\n\n <Skeleton\n variant=\"rectangular\"\n className=\"clcosdk:h-[54px] clcosdk:w-full clcosdk:rounded-full\"\n />\n </CheckoutStepCard>\n );\n}\n\nfunction ErrorView({\n onEvent,\n title,\n className,\n}: {\n onEvent: (event: OndoSellReviewUiEvent) => void;\n title: string;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={title} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-4 clcosdk:py-8 clcosdk:text-center\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-2\">\n <h3\n className={cn(\n typeClasses.h4,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {ERROR_TITLE}\n </h3>\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:max-w-md clcosdk:text-text-secondary'\n )}\n >\n {ERROR_DESCRIPTION}\n </p>\n </div>\n <ClButton\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_SELL_RETRY' })}\n >\n Try again\n </ClButton>\n </div>\n </CheckoutStepCard>\n );\n}\n\nfunction Disclaimer(): ReactNode {\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:text-text-secondary clcosdk:md:px-6'\n )}\n >\n By placing this order, you agree to CoinList's{' '}\n <DisclaimerLink href={COINLIST_TOS_URL}>Terms of Service</DisclaimerLink>{' '}\n and{' '}\n <DisclaimerLink href={COINLIST_PRIVACY_URL}>\n Privacy Policy\n </DisclaimerLink>\n , and <DisclaimerLink href={ONDO_TOS_URL}>Ondo's Terms</DisclaimerLink>.\n </p>\n );\n}\n\nfunction DisclaimerLink({\n href,\n children,\n}: {\n href: string;\n children: ReactNode;\n}): ReactNode {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"clcosdk:underline clcosdk:transition-colors clcosdk:hover:text-text-primary\"\n >\n {children}\n </a>\n );\n}\n\nfunction InfoIcon(): ReactNode {\n return (\n <Info\n className=\"clcosdk:size-4 clcosdk:text-text-secondary\"\n aria-hidden=\"true\"\n />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { OndoSellAmountView } from '@/client/components/checkout/ondo/sell/amount/OndoSellAmountView';\nimport { OndoSellOrderConfirmed } from '@/client/components/checkout/ondo/sell/confirmation/OndoSellOrderConfirmed';\nimport { OndoSellReviewView } from '@/client/components/checkout/ondo/sell/review/OndoSellReviewView';\nimport { OndoCheckoutError } from '@/client/components/checkout/ondo/shared/error/OndoCheckoutError';\nimport { OndoSidebarView } from '@/client/components/checkout/ondo/shared/sidebar/OndoSidebarView';\nimport { OndoWalletSelectView } from '@/client/components/checkout/ondo/shared/wallet/OndoWalletSelectView';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n OndoSellCheckoutUiEvent,\n OndoSellCheckoutUiState,\n} from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel.types';\n\nconst WALLET_DESCRIPTION = \"Choose which wallet you're selling from.\";\n\nexport interface OndoSellCheckoutViewProps {\n state: OndoSellCheckoutUiState;\n onEvent: (event: OndoSellCheckoutUiEvent) => void;\n className?: string;\n}\n\n/**\n * The whole Ondo sell checkout: the step cards, the asset panel beside them,\n * and the dialog that closes the flow.\n *\n * **Two or three cards, depending on `state.wallet`.** A host that already\n * knows which wallet holds the position preselects it, and the flow opens on\n * the amount. That one nullable field is where both remaining step numbers\n * come from, so a two-step flow reading `1, 2` and a three-step flow reading\n * `1, 2, 3` cannot disagree - a second source for \"is there a wallet step\"\n * would be the way they could.\n *\n * `onEvent` is handed to each step unwrapped. A handler that accepts the wider\n * union is assignable where a step's narrower one is expected, so there is no\n * per-step lambda here and no re-dispatch on the way back up.\n *\n * The panel leads on a phone and moves to the right column from `md` up, where\n * it is reference material rather than the first thing to read. No page heading\n * is rendered — the host titles its own page.\n *\n * An `error` state replaces the whole layout rather than appearing inside it:\n * it means there is no checkout, so there is nothing for the cards and the\n * panel to be laid out around.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it. The steps scope themselves too, and the scope is\n * idempotent, so nesting costs nothing.\n */\nexport function OndoSellCheckoutView({\n state,\n onEvent,\n className,\n}: OndoSellCheckoutViewProps): ReactNode {\n switch (state.type) {\n case 'error':\n return <OndoCheckoutError reason={state.reason} className={className} />;\n case 'content':\n return (\n <ContentView state={state} onEvent={onEvent} className={className} />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\n/**\n * The step cards and the panel, split out only so `hasWalletStep` has a scope\n * to be computed in: a `case` arm cannot hold a declaration, and the number\n * every step below reads comes from that one nullable field.\n */\nfunction ContentView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<OndoSellCheckoutUiState, { type: 'content' }>;\n onEvent: (event: OndoSellCheckoutUiEvent) => void;\n className?: string;\n}): ReactNode {\n const hasWalletStep = state.wallet !== null;\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-6',\n 'clcosdk:md:grid-cols-[minmax(0,11fr)_minmax(0,8fr)] clcosdk:md:gap-x-12',\n className\n )}\n >\n <div className=\"clcosdk:order-2 clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-4 clcosdk:md:order-1\">\n {state.wallet !== null && (\n <OndoWalletSelectView\n state={state.wallet}\n onEvent={onEvent}\n description={WALLET_DESCRIPTION}\n />\n )}\n <OndoSellAmountView\n state={state.amount}\n onEvent={onEvent}\n stepNumber={hasWalletStep ? 2 : 1}\n />\n <OndoSellReviewView\n state={state.review}\n onEvent={onEvent}\n stepNumber={hasWalletStep ? 3 : 2}\n />\n </div>\n\n <aside className=\"clcosdk:order-1 clcosdk:min-w-0 clcosdk:md:order-2\">\n <OndoSidebarView state={state.sidebar} />\n </aside>\n </div>\n\n <OndoSellOrderConfirmed state={state.orderConfirmed} onEvent={onEvent} />\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport {\n type OndoSellAmountStepInput,\n type OndoSellAsset,\n useOndoSellAmountViewModel,\n} from '@/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel';\nimport {\n type OndoSellReviewStepInput,\n useOndoSellReviewViewModel,\n} from '@/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel';\nimport type {\n OndoSellCheckoutUiEvent,\n OndoSellCheckoutUiState,\n OndoSellOrderConfirmedUiState,\n} from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel.types';\nimport { useOndoPrice } from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nimport {\n isNotTradable,\n useOndoTradingStatus,\n} from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\nimport { OndoCheckoutErrorReason } from '@/client/hooks/checkout/ondo/shared/ondo-checkout-error.types';\nimport type {\n OndoOrderPlaced,\n OndoSellOrderPlaced,\n} from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport { useOndoSidebarViewModel } from '@/client/hooks/checkout/ondo/shared/sidebar/useOndoSidebarViewModel';\nimport {\n type OndoWalletSelectStepInput,\n useOndoWalletSelectViewModel,\n} from '@/client/hooks/checkout/ondo/shared/wallet/useOndoWalletSelectViewModel';\nimport { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport {\n tokenMetadataOf,\n useCheckoutOfferTokenMetadata,\n} from '@/client/hooks/checkout/shared/data/useCheckoutOfferTokenMetadata';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport {\n DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE,\n ONDO_POLL_INTERVAL_MS,\n ONDO_SETTLEMENT_ASSET,\n} from '@/universal/core/checkout/ondo/constants';\nimport { computeOndoSellPrice } from '@/universal/core/checkout/ondo/math';\nimport type { OndoQuoteSize } from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport { swapSpender } from '@/universal/core/offers/swap-contracts';\nimport {\n getNetworkName,\n txExplorerUrl,\n} from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatShareAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\nimport type {\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Which step is being filled in, carrying everything the ones before it\n * settled.\n *\n * A union rather than a step index plus nullable fields: the amount step cannot\n * run without a wallet, and the review step cannot run without a built\n * transaction, so neither is representable here.\n *\n * The `wallet` arm is only ever entered when the host preselected nothing. A\n * skipped wallet step is not a fourth arm: it is the flow *opening* on\n * `amount`, which is why `wallets.preselected` is read once to seed the state\n * and never again.\n */\nexport type OndoSellStep =\n | { type: 'wallet' }\n | { type: 'amount'; wallet: EvmWallet }\n | {\n type: 'review';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: AssetSymbol;\n /** Built by `prepareSell` when the amount was confirmed. */\n transaction: OndoSellTransaction;\n };\n\nexport interface UseOndoSellCheckoutViewModelOptions {\n /**\n * The offer being sold: names the asset and supplies its logo.\n *\n * Fixed for the lifetime of the hook — see the note on\n * {@link useOndoSellCheckoutViewModel} about switching offers.\n */\n offer: OndoSwapOfferDetail;\n /**\n * Ondo's API symbol for the asset, e.g. `TSLAon`.\n *\n * Explicit rather than derived from `offer.asset.code`: Ondo's symbol tracks\n * the underlying ticker and changes on a rebrand, and the two already\n * disagree on Sepolia, where a mock asset stands in.\n */\n ondoSymbol: AssetSymbol;\n /**\n * The chain the order executes on: the balance read, the approval and the\n * broadcast. Quotes are priced against Ondo production whatever this says,\n * since Ondo runs no sandbox, so on a testnet the price is real and the\n * money is not.\n *\n * Fixed for the lifetime of the hook, as `offer` is.\n */\n chain: EthereumChain;\n /**\n * The host's wallets, the lambdas that connect and disconnect one, and\n * optionally the wallet it has already settled on.\n *\n * `wallets.preselected` is read **once**, to seed the step machine. A host\n * that changes it mid-flow is ignored: the approval that follows the amount\n * step is granted by one specific wallet, and moving the flow onto another\n * one under it would strand that approval and build calldata the new wallet\n * cannot broadcast.\n */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. When `false` nothing is fetched and no timer runs, for a\n * checkout that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /**\n * Fired once the swap has mined. The confirmation dialog shows either way;\n * this is for a host that wants to navigate, refresh a portfolio, or log.\n */\n onOrderConfirmed?: (order: OndoOrderPlaced) => void;\n}\n\nexport interface UseOndoSellCheckoutViewModelResult {\n state: OndoSellCheckoutUiState;\n onEvent: (event: OndoSellCheckoutUiEvent) => void;\n}\n\n/**\n * Drives the whole Ondo sell checkout: the steps, the reference panel beside\n * them, and the dialog that closes the flow.\n *\n * It owns the step machine and the two polls; each step's own viewmodel owns\n * its screen. The polls live here because they are shared - the sidebar shows\n * the price and the amount step gates on the market - and because the price is\n * sized by whatever the flow has settled on so far.\n *\n * The sell price poll is what names the asset being sold. `TOKEN_REGISTRY`\n * knows the stablecoins swaps are funded with and no provider's asset, so the\n * contract address the balance is read on and the approval is granted for, and\n * the decimals the typed amount is parsed at, both come off that quote and\n * nowhere else.\n *\n * Every failure a step can cause belongs to that step: a price that will not\n * load leaves the panel's corner unavailable, and an order that will not go\n * through is reported on the review step, next to the button that caused it.\n *\n * The one exception is the flow-level `error` state, and it is an exception\n * about whether there is a flow rather than about how one went. A chain with\n * no Ondo integration contract is known before any step runs, and there is no\n * region to report it in that would not first have to render something untrue.\n * A market known to be closed while the user is still on the first step is the\n * same kind of answer for as long as it lasts. See\n * {@link OndoCheckoutErrorReason}.\n *\n * `offer` and `chain` are read as fixed for the lifetime of the hook, and so is\n * the wallet the flow opened on. The step machine holds a committed quote and\n * an approval granted on one chain by one wallet for one order, so changing any\n * of them in place would carry them onto an order they were never priced for.\n * Remount instead: give the component holding this hook a `key` that changes\n * with the offer, the chain and the side, as {@link CheckoutContainer}\n * documents.\n */\nexport function useOndoSellCheckoutViewModel({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled = true,\n onOrderConfirmed,\n}: UseOndoSellCheckoutViewModelOptions): UseOndoSellCheckoutViewModelResult {\n const locale = useLocale();\n\n // The initializer runs once, which is exactly the read `preselected` wants:\n // whether this flow has a wallet step is settled at mount and cannot change\n // under an approval that has already been granted.\n const [initialStep] = useState<OndoSellStep>(() =>\n wallets.preselected === null\n ? { type: 'wallet' }\n : { type: 'amount', wallet: wallets.preselected }\n );\n const [step, setStep] = useState<OndoSellStep>(initialStep);\n const hasWalletStep = initialStep.type === 'wallet';\n // The placed order, not its rendering: the dialog's asset is derived during\n // render (see `uiState`), so a registry lookup that settles while the order\n // is being placed still reaches the dialog instead of the fallback logo the\n // completion callback captured.\n const [orderConfirmed, setOrderConfirmed] =\n useState<OndoSellOrderPlaced | null>(null);\n\n // An offer that cannot be swapped on this chain has no checkout, so every\n // hook below is turned off as surely as `enabled: false` would - no price\n // poll, no market poll, and no balance read against a token this flow will\n // never spend. `offer` and `chain` are both fixed for the lifetime of the\n // hook, so this cannot flip.\n const swappableHere = swapSpender(offer.swapContracts, chain) !== null;\n const live = enabled && swappableHere;\n\n const { state: tradingStatusState } = useOndoTradingStatus({\n symbol: ondoSymbol,\n side: 'sell',\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled: live,\n });\n const notTradable = isNotTradable(tradingStatusState);\n\n // Paused while the market is known to be closed: Ondo refuses every quote\n // then, so each tick would only fail. The last price stays on screen, and\n // the poll resumes once the trading-status poll above says it may.\n const { state: priceState } = useOndoPrice({\n symbol: ondoSymbol,\n side: 'sell',\n size: priceSize(step),\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled: live && !notTradable,\n });\n\n // One registry lookup for the flow: the sidebar, the amount card and the\n // confirmation dialog all show the same asset, so they share one answer\n // rather than tripling the request. Fetched once - registry content is\n // immutable per version - and passed down as a value so the steps stay\n // pure renderers of what they were given.\n const { state: inputTokenMetadataState } = useCheckoutOfferTokenMetadata({\n offer,\n chain,\n enabled: live,\n });\n const inputTokenMetadata = tokenMetadataOf(inputTokenMetadataState);\n\n /**\n * The confirmation dialog, derived at render from the placed order and the\n * *latest* metadata. Building it inside the review completion callback\n * would bake in whichever metadata that closure captured, so a lookup that\n * settles while the order is being placed would leave the dialog on the\n * fallback logo forever.\n */\n const orderConfirmedUi = (\n order: OndoSellOrderPlaced | null\n ): OndoSellOrderConfirmedUiState =>\n order === null\n ? { type: 'hidden' }\n : toOrderConfirmedUi({\n order,\n chain,\n locale,\n offer,\n ondoSymbol,\n inputTokenMetadata,\n });\n\n const { state: walletState, onEvent: onWalletEvent } =\n useOndoWalletSelectViewModel({\n stepInput: walletStepInput(step),\n wallets,\n chain,\n onComplete: (wallet) => setStep({ type: 'amount', wallet }),\n onEdit: () => setStep({ type: 'wallet' }),\n });\n\n const { state: amountState, onEvent: onAmountEvent } =\n useOndoSellAmountViewModel({\n stepInput: amountStepInput(step, {\n sellAsset:\n priceState.type === 'CONTENT' ? sellAsset(priceState.quote) : null,\n tradingStatus:\n tradingStatusState.type === 'CONTENT'\n ? tradingStatusState.status\n : null,\n walletIsEmbedded: (wallet: EvmWallet) => isEmbedded(wallets, wallet),\n }),\n ondoSymbol,\n chain,\n offer,\n inputTokenMetadata,\n enabled: live,\n // Both transitions read the step through the updater rather than the one\n // this render closed over. Preparing an amount takes an approval to mine,\n // and the wallet step's Edit stays live throughout, so a preparation can\n // succeed after the user has walked back to a step it knows nothing\n // about. Reading the step as it is when the result lands is what makes\n // these guards hold: reopening a step abandons the order, and the built\n // transaction goes with it. The approval does not, since the allowance\n // it left behind is what a retry finds.\n onComplete: ({ amount, inputAsset, transaction }) => {\n setStep((current) =>\n current.type === 'amount'\n ? {\n type: 'review',\n wallet: current.wallet,\n amount,\n inputAsset,\n transaction,\n }\n : current\n );\n },\n onEdit: () => {\n setStep((current) =>\n current.type === 'review'\n ? { type: 'amount', wallet: current.wallet }\n : current\n );\n },\n });\n\n const { state: reviewState, onEvent: onReviewEvent } =\n useOndoSellReviewViewModel({\n stepInput: reviewStepInput(step),\n ondoSymbol,\n chain,\n enabled: live,\n onComplete: (order) => {\n setOrderConfirmed(order);\n // The quote is spent and the allowance with it, so what is left behind\n // the dialog is a fresh checkout rather than a filled-in one - back to\n // whichever step this flow opened on, which for a preselected wallet\n // is the amount rather than a wallet step it never had.\n setStep(initialStep);\n onOrderConfirmed?.(order);\n },\n });\n\n const { state: sidebarState } = useOndoSidebarViewModel({\n offer,\n ondoSymbol,\n chain,\n tokenMetadata: inputTokenMetadata,\n priceState,\n tradingStatusState,\n });\n\n const errorReason = OndoCheckoutErrorReason.of({\n swappableHere,\n notTradable,\n // The step the flow opened on, which for a preselected wallet is the\n // amount rather than a wallet step it never had.\n atEntry: step.type === initialStep.type && orderConfirmed === null,\n });\n const state: OndoSellCheckoutUiState =\n errorReason !== null\n ? { type: 'error', reason: errorReason }\n : {\n type: 'content',\n wallet: hasWalletStep ? walletState : null,\n amount: amountState,\n review: reviewState,\n sidebar: sidebarState,\n orderConfirmed: orderConfirmedUi(orderConfirmed),\n };\n\n // The event union is flat, so this is one switch rather than a nested one.\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over each step's own handler for this render, so a memo could\n // only ever hand back a stale one.\n const onEvent = (event: OndoSellCheckoutUiEvent) => {\n switch (event.type) {\n case 'ON_SELECT_WALLET':\n case 'ON_CONNECT_WALLET':\n case 'ON_DISCONNECT_WALLET':\n case 'ON_CONFIRM_WALLET':\n case 'ON_EDIT_WALLET':\n // A skipped wallet step raises nothing - its View is not rendered -\n // but a host driving this viewmodel itself can still dispatch one, and\n // honouring it would reopen a step this flow does not have.\n if (!hasWalletStep) return;\n onWalletEvent(event);\n return;\n case 'ON_SELL_AMOUNT_CHANGE':\n case 'ON_SELL_MAX_AMOUNT_CLICK':\n case 'ON_CONFIRM_SELL_AMOUNT':\n case 'ON_EDIT_SELL_AMOUNT':\n onAmountEvent(event);\n return;\n case 'ON_REFRESH_SELL_QUOTE':\n case 'ON_SELL_RETRY':\n case 'ON_PLACE_SELL_ORDER':\n onReviewEvent(event);\n return;\n case 'ON_CLOSE_SELL_ORDER_CONFIRMED':\n setOrderConfirmed(null);\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state, onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Step inputs\n// ---------------------------------------------------------------------------\n\nfunction walletStepInput(step: OndoSellStep): OndoWalletSelectStepInput {\n return step.type === 'wallet'\n ? { type: 'active' }\n : { type: 'completed', wallet: step.wallet };\n}\n\nfunction amountStepInput(\n step: OndoSellStep,\n context: {\n sellAsset: OndoSellAsset | null;\n tradingStatus: OndoTradingStatus | null;\n walletIsEmbedded: (wallet: EvmWallet) => boolean;\n }\n): OndoSellAmountStepInput {\n switch (step.type) {\n case 'wallet':\n return { type: 'incomplete' };\n case 'amount':\n return {\n type: 'active',\n wallet: step.wallet,\n walletIsEmbedded: context.walletIsEmbedded(step.wallet),\n sellAsset: context.sellAsset,\n tradingStatus: context.tradingStatus,\n };\n case 'review':\n return {\n type: 'complete',\n wallet: step.wallet,\n amount: step.amount,\n inputAsset: step.inputAsset,\n };\n default: {\n const exhaustive: never = step;\n return exhaustive;\n }\n }\n}\n\nfunction reviewStepInput(step: OndoSellStep): OndoSellReviewStepInput {\n return step.type === 'review'\n ? {\n type: 'active',\n wallet: step.wallet,\n amount: step.amount,\n inputAsset: step.inputAsset,\n transaction: step.transaction,\n }\n : { type: 'incomplete' };\n}\n\n/**\n * The asset a sell spends, as the sell quote resolves it.\n *\n * The quote is the SDK's only source for either half. Its `asset.decimals`\n * scale `tokenBaseUnits` and are the scale the *request* is sized in, which is\n * what the amount step needs; the built transaction reports its own\n * `pay_input_decimals` separately, and the api layer refuses a response where\n * the two disagree.\n */\nfunction sellAsset(quote: OndoQuote): OndoSellAsset {\n return { address: quote.assetAddress, asset: quote.asset };\n}\n\n/** Whether a wallet is one of the user's CoinList wallets. */\nfunction isEmbedded(\n wallets: CheckoutWalletSelection,\n wallet: EvmWallet\n): boolean {\n return wallets.embedded.some(\n (candidate) => candidate.address === wallet.address\n );\n}\n\n/**\n * What size the indicative price is quoted for.\n *\n * Ondo prices by size, so something has to be sent, and a sell is quoted by\n * token amount rather than by notional - frontline's own expectation, since a\n * sell is sized by what the user already holds. Until they have committed an\n * amount that is a default: quoting each keystroke would fire a request per\n * character and make the panel's price jump while they type.\n */\nfunction priceSize(step: OndoSellStep): OndoQuoteSize {\n return step.type === 'review'\n ? { tokenAmount: step.amount }\n : {\n tokenAmount: BlockchainAmount({\n raw: BigInt(DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE),\n decimals: AssetDecimals(0),\n }),\n };\n}\n\n// ---------------------------------------------------------------------------\n// The confirmation dialog\n// ---------------------------------------------------------------------------\n\n/**\n * The dialog is a projection of the order that just filled: every figure comes\n * from the transaction that was broadcast, so nothing here can disagree with\n * what the user approved on the review step. `pricePerShare` is derived from\n * the same amounts the review step derived it from, so the two screens cannot\n * drift either.\n */\nfunction toOrderConfirmedUi({\n order,\n chain,\n locale,\n offer,\n ondoSymbol,\n inputTokenMetadata,\n}: {\n order: OndoSellOrderPlaced;\n chain: EthereumChain;\n locale: string;\n offer: OndoSwapOfferDetail;\n ondoSymbol: AssetSymbol;\n inputTokenMetadata: TokenMetadata | null;\n}): OndoSellOrderConfirmedUiState {\n const settlementSymbol = TOKEN_REGISTRY.erc20(ONDO_SETTLEMENT_ASSET).symbol;\n return {\n type: 'visible',\n soldAsset: CheckoutAssetUi.fromOffer(offer, {\n symbol: ondoSymbol,\n networkName: getNetworkName(chain),\n tokenMetadata: inputTokenMetadata,\n }),\n soldAmount: assetAmount(\n formatShareAmount(order.transaction.spendInputAmount, locale),\n ondoSymbol\n ),\n // The expected proceeds rather than the floor: this dialog reports a sale\n // that has already mined, so the range it was signed against is settled and\n // `expected` is what the review step showed as the headline.\n proceeds: assetAmount(\n formatAmount(order.transaction.expected.quantity, locale),\n settlementSymbol\n ),\n proceedsSymbol: settlementSymbol,\n pricePerShare: formattedUsdPrice(\n computeOndoSellPrice(order.transaction),\n locale\n ),\n recipientAddress: shortenAddress(order.wallet.address),\n txExplorerUrl: txExplorerUrl(chain, order.txHash),\n };\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport type {\n OndoSwapPreparationError,\n OndoSwapPreparationPhase,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport type {\n OndoSellAmountUiEvent,\n OndoSellAmountUiState,\n OndoSellBalanceUi,\n OndoSellSourceWalletUi,\n} from '@/client/hooks/checkout/ondo/sell/amount/useOndoSellAmountViewModel.types';\nimport {\n CheckoutAssetUi,\n type CheckoutCtaUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport { useErc20Balance } from '@/client/hooks/shared/erc20/useErc20Balance';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/universal/core/shared/blockchain/math';\nimport {\n type AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type DecimalString,\n type Erc20Asset,\n type EthereumChain,\n type EvmContractAddress,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\nimport type {\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/** Stands in for a wallet address while the step is not active and nothing is read. */\nconst NO_WALLET = EvmWalletAddress(\n '0x0000000000000000000000000000000000000000'\n);\n\nconst MARKET_CLOSED = 'This market is closed right now.';\nconst INVALID_AMOUNT = 'Enter a valid amount.';\nconst AMOUNT_ZERO = 'Enter an amount greater than 0.';\n\n/**\n * How much of the asset the user is selling, and the transaction built for it.\n *\n * It carries `inputAsset` where the buy step's counterpart carries a\n * stablecoin: the asset being sold is in no registry, so the symbol has to\n * travel with the amount for anything downstream to name it.\n */\nexport type OndoSellAmountConfirmed = {\n amount: BlockchainAmount;\n inputAsset: AssetSymbol;\n transaction: OndoSellTransaction;\n};\n\n/**\n * The asset a sell spends, as the quote resolves it.\n *\n * Both halves come off `GET /v1/ondo/swap/quote`, which is the SDK's only\n * source for either: `TOKEN_REGISTRY` knows the stablecoins swaps are funded\n * with and no provider's asset. The address is what the balance is read on and\n * what the swap contract is approved for; the decimals are what the typed\n * amount is parsed at.\n */\nexport type OndoSellAsset = {\n address: EvmContractAddress;\n asset: Erc20Asset;\n};\n\nexport type OndoSellAmountStepInput =\n | { type: 'incomplete' }\n | {\n type: 'active';\n /** The wallet holding the asset, and the one that signs. */\n wallet: EvmWallet;\n /**\n * Whether that wallet is one of the user's CoinList wallets, which\n * decides how the balance card names it: an embedded wallet reads\n * `from CoinList Wallet`, an external one `from 0x…`.\n *\n * Decided by the parent, which holds `wallets.embedded`. A preselected\n * wallet need not appear in that list at all, so this cannot be inferred\n * from how the step was reached.\n */\n walletIsEmbedded: boolean;\n /**\n * The asset as the sell quote resolves it, or `null` while the poll has\n * not answered. Without it there is no balance to read and no scale to\n * parse the field at, so the step renders but cannot be confirmed.\n */\n sellAsset: OndoSellAsset | null;\n /**\n * The market as last read, or `null` while it is unknown. Unknown does\n * not block: a dropped poll is not evidence the market is closed, and\n * building will fail with a real reason if it is.\n */\n tradingStatus: OndoTradingStatus | null;\n }\n | {\n type: 'complete';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: AssetSymbol;\n };\n\nexport interface UseOndoSellAmountViewModelOptions {\n stepInput: OndoSellAmountStepInput;\n /** Ondo's API symbol, e.g. `TSLAon`. */\n ondoSymbol: AssetSymbol;\n /** The chain the order executes on: the balance read, the approval and the broadcast. */\n chain: EthereumChain;\n /**\n * The offer being sold: supplies the asset's display name and its fallback\n * artwork.\n */\n offer: OndoSwapOfferDetail;\n /**\n * Registry metadata for the sold asset; `null` falls back to the offer's\n * logo.\n */\n inputTokenMetadata: TokenMetadata | null;\n /**\n * When false, the step neither fetches nor polls. Defaults to true.\n *\n * The step being `incomplete` is not the same thing and does not stand in\n * for it: a checkout switched off mid-flow leaves this step `active`, and\n * the parent's own data hooks hold their last `CONTENT` rather than\n * forgetting it - so the sell asset is still here to read a balance\n * against, and the poll would run on behind a screen nobody is looking at.\n */\n enabled?: boolean;\n /** Called once the approval has mined and the transaction has been built. */\n onComplete: (confirmed: OndoSellAmountConfirmed) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n}\n\nexport interface UseOndoSellAmountViewModelResult {\n state: OndoSellAmountUiState;\n onEvent: (event: OndoSellAmountUiEvent) => void;\n}\n\n/**\n * Drives the amount step of the Ondo sell checkout: how much of the asset to\n * sell, and getting the order ready to place.\n *\n * Confirming does real work - it approves the swap contract to pull the asset,\n * then builds the transaction that spends it - so the CTA reports the on-chain\n * phase as loading copy and every failure comes back as copy under the field.\n * The approval is on the *asset*, not on a stablecoin, which is the one thing\n * that makes this materially different from the buy step rather than a mirror\n * of it: the token's address and decimals are not the SDK's to look up, so\n * everything here waits on the sell quote.\n *\n * Everything checkable locally is checked before the wallet is asked to sign:\n * the balance and Ondo's own token cap. There is no minimum - `minimumPurchaseUsd`\n * is an offer's minimum *purchase* and frontline enforces no floor on a sell\n * beyond a non-zero amount - and the USD caps are deliberately not converted,\n * because doing it through a price that moves between the check and the build\n * would reject fillable orders and pass unfillable ones.\n */\nexport function useOndoSellAmountViewModel({\n stepInput,\n ondoSymbol,\n chain,\n offer,\n inputTokenMetadata,\n enabled = true,\n onComplete,\n onEdit,\n}: UseOndoSellAmountViewModelOptions): UseOndoSellAmountViewModelResult {\n const { coinlist } = useCoinList();\n const locale = useLocale();\n\n const [amountInput, setAmountInput] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [phase, setPhase] = useState<OndoSwapPreparationPhase | null>(null);\n\n /**\n * Which preparation the state below belongs to.\n *\n * Same guard, and same reason, as the buy step's: an approval takes most of\n * a minute to mine and the wallet step's Edit stays live throughout, so a\n * result can land against an order the user has walked away from. The\n * transaction was built for the *old* wallet, and nothing downstream can\n * tell - `OndoSellTransaction` does not carry the address it was built for -\n * so `executeSwap` would broadcast it from the new one and pay for the\n * revert.\n */\n const preparationIdRef = useRef(0);\n\n const isActive = stepInput.type === 'active';\n const networkName = getNetworkName(chain);\n const sellAsset = isActive ? stepInput.sellAsset : null;\n const marketClosed =\n isActive && stepInput.tradingStatus?.type === 'not-tradable';\n\n const { balance, isLoading: balanceLoading } = useErc20Balance({\n tokenAddress: sellAsset?.address ?? null,\n owner:\n stepInput.type === 'incomplete' ? NO_WALLET : stepInput.wallet.address,\n chain,\n enabled: enabled && isActive && sellAsset !== null,\n });\n\n // Start over when the user leaves the step, so reopening it does not restore\n // an amount they have since abandoned. A preparation still in flight is\n // abandoned with it: the order it belongs to is gone.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n ++preparationIdRef.current;\n setAmountInput('');\n setError(null);\n setPhase(null);\n }\n }, [stepInput.type]);\n\n const uiState = (): OndoSellAmountUiState => {\n switch (stepInput.type) {\n case 'incomplete':\n return { type: 'incomplete' };\n case 'active':\n return {\n type: 'active',\n amountInput,\n balance: toBalanceUi(),\n wallet: toSourceWalletUi(stepInput),\n confirmCta: confirmCta(),\n error: marketClosed ? MARKET_CLOSED : error,\n };\n case 'complete':\n return {\n type: 'complete',\n asset: CheckoutAssetUi.fromOffer(offer, {\n symbol: stepInput.inputAsset,\n networkName,\n tokenMetadata: inputTokenMetadata,\n }),\n amountFormatted: assetAmount(\n formatAmount(stepInput.amount, locale),\n stepInput.inputAsset\n ),\n };\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n /**\n * `null` until the quote has named the asset *and* a balance has been read.\n * A card that showed the asset with no holding beneath it would read as a\n * zero balance, which is a different claim from \"not known yet\".\n */\n const toBalanceUi = (): OndoSellBalanceUi | null => {\n if (sellAsset === null || balance === null) return null;\n const amount = BlockchainAmount({\n raw: balance,\n decimals: sellAsset.asset.decimals,\n });\n return {\n asset: CheckoutAssetUi.fromOffer(offer, {\n symbol: ondoSymbol,\n networkName,\n tokenMetadata: inputTokenMetadata,\n }),\n balance: assetAmount(formatAmount(amount, locale), ondoSymbol),\n rawBalance: balance,\n };\n };\n\n const confirmCta = (): CheckoutCtaUi => {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n // The asset is what the amount is parsed at and the balance is what it is\n // validated against, so confirming before either has arrived could only\n // guess.\n const blocked =\n marketClosed ||\n sellAsset === null ||\n balanceLoading ||\n balance === null ||\n amountInput.trim() === '';\n return blocked ? { type: 'disabled' } : { type: 'enabled' };\n };\n\n const confirmAmount = async () => {\n if (stepInput.type !== 'active' || phase !== null || marketClosed) return;\n const asset = stepInput.sellAsset;\n if (asset === null) return;\n\n const validated = validateSellAmount({\n input: amountInput,\n decimals: asset.asset.decimals,\n balance,\n symbol: ondoSymbol,\n tradingStatus: stepInput.tradingStatus,\n locale,\n });\n if (!validated.valid) {\n setError(validated.error);\n return;\n }\n\n setError(null);\n setPhase('checking-allowance');\n const preparationId = ++preparationIdRef.current;\n const result = await coinlist.ondo.prepareSell({\n wallet: stepInput.wallet,\n symbol: ondoSymbol,\n chain,\n swapContracts: offer.swapContracts,\n // The asset, not a stablecoin: a sell spends what it is selling, so this\n // is the contract the swap contract has to be allowed to pull from.\n tokenAddress: asset.address,\n amount: validated.amount,\n onProgress: (nextPhase) => {\n if (preparationId !== preparationIdRef.current) return;\n setPhase(nextPhase);\n },\n });\n if (preparationId !== preparationIdRef.current) return;\n setPhase(null);\n\n if (result.type === 'error') {\n setError(preparationErrorMessage(result.error));\n return;\n }\n onComplete({\n amount: validated.amount,\n inputAsset: ondoSymbol,\n transaction: result.transaction,\n });\n };\n\n const fillMaxAmount = () => {\n if (balance === null || sellAsset === null) return;\n setAmountInput(\n formatRawAmount(\n BlockchainAmount({ raw: balance, decimals: sellAsset.asset.decimals })\n )\n );\n setError(null);\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step, the typed amount and the balance this render was\n // given, so a memo could only ever hand back a stale one.\n const onEvent = (event: OndoSellAmountUiEvent) => {\n switch (event.type) {\n case 'ON_SELL_AMOUNT_CHANGE':\n setAmountInput(event.value);\n setError(null);\n return;\n case 'ON_SELL_MAX_AMOUNT_CLICK':\n fillMaxAmount();\n return;\n case 'ON_CONFIRM_SELL_AMOUNT':\n void confirmAmount();\n return;\n case 'ON_EDIT_SELL_AMOUNT':\n onEdit();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\nfunction toSourceWalletUi(\n stepInput: Extract<OndoSellAmountStepInput, { type: 'active' }>\n): OndoSellSourceWalletUi {\n return stepInput.walletIsEmbedded\n ? { type: 'embedded' }\n : { type: 'external', address: shortenAddress(stepInput.wallet.address) };\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nexport type OndoSellAmountValidation =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; error: string };\n\n/**\n * The checks that can be made without asking the wallet for anything, in the\n * order a user would hit them: is it a number, is it more than nothing, do they\n * hold that much, will Ondo fill it.\n *\n * Shorter than the buy ladder by two rungs, and deliberately so. There is no\n * offer minimum on a sell - `minimumPurchaseUsd` is a *purchase* minimum, and\n * frontline enforces nothing below a non-zero amount - and Ondo's two USD caps\n * are left to the server, because converting them into tokens needs a price\n * that has moved by the time the order is built. What survives is\n * `grossMaxTokens`, which is already in whole tokens and needs no conversion at\n * all.\n *\n * Exported for the property tests: the ladder is money logic, and the property\n * that matters (nothing above the balance or the cap is ever accepted) is about\n * the whole ladder rather than any one rung.\n */\nexport function validateSellAmount({\n input,\n decimals,\n balance,\n symbol,\n tradingStatus,\n locale,\n}: {\n input: string;\n decimals: AssetDecimals;\n /** `null` while no balance has been read; the check is then skipped. */\n balance: bigint | null;\n symbol: AssetSymbol;\n tradingStatus: OndoTradingStatus | null;\n locale: string;\n}): OndoSellAmountValidation {\n const parsed = parseBlockchainAmount(input, decimals);\n if (!parsed.valid) return { valid: false, error: INVALID_AMOUNT };\n const amount = parsed.amount;\n if (amount.raw === 0n) return { valid: false, error: AMOUNT_ZERO };\n\n if (balance !== null && amount.raw > balance) {\n return { valid: false, error: `Insufficient ${symbol}.` };\n }\n\n const cap = tokenCap(tradingStatus, decimals);\n if (cap !== null && amount.raw > cap.raw) {\n return {\n valid: false,\n error: `The maximum order size right now is ${assetAmount(formatAmount(cap, locale), symbol)}.`,\n };\n }\n\n return { valid: true, amount };\n}\n\n/**\n * Ondo's cap on a single sell in whole tokens, or `null` when the market is\n * closed, unknown, or publishes none.\n *\n * A closed market is not a cap of zero: the CTA is already disabled for it, and\n * reporting \"maximum order size 0\" would be a worse explanation than the one\n * the step already shows.\n */\nfunction tokenCap(\n status: OndoTradingStatus | null,\n decimals: AssetDecimals\n): BlockchainAmount | null {\n if (status === null || status.type !== 'tradable') return null;\n return capAmount(status.grossMaxTokens, decimals);\n}\n\n/**\n * A cap as an amount in the asset's decimals.\n *\n * Ondo publishes caps with 18 fractional digits, which may be more than the\n * asset has, so the surplus is truncated rather than rounded: rounding up would\n * raise the cap above what Ondo will actually fill.\n *\n * The point goes with the digits it separated. An asset with no fractional\n * units keeps none of them, and a trailing `\"50.\"` is not a number\n * `parseBlockchainAmount` accepts - which would drop the cap rather than\n * tighten it, and let an order through above what Ondo will fill.\n */\nfunction capAmount(\n cap: DecimalString | null,\n decimals: AssetDecimals\n): BlockchainAmount | null {\n if (cap === null) return null;\n const [whole, fraction = ''] = cap.split('.');\n const kept = fraction.slice(0, decimals);\n const truncated = kept === '' ? whole : `${whole}.${kept}`;\n const parsed = parseBlockchainAmount(truncated, decimals);\n return parsed.valid ? parsed.amount : null;\n}\n\n// ---------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------\n\nfunction phaseMessage(phase: OndoSwapPreparationPhase): string {\n switch (phase) {\n case 'checking-allowance':\n return 'Checking your approval...';\n case 'resetting-allowance':\n return 'Resetting your approval...';\n case 'confirming-allowance-reset':\n return 'Confirming the reset...';\n case 'approving':\n return 'Approving in your wallet...';\n case 'confirming-approval':\n return 'Confirming the approval...';\n case 'building-transaction':\n return 'Getting your quote...';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\nfunction preparationErrorMessage(error: OndoSwapPreparationError): string {\n switch (error.step) {\n case 'unsupported-chain':\n return 'Ondo orders are not available on this network yet.';\n case 'allowance-check':\n return 'Could not check your approval. Please try again.';\n case 'approval':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Approval declined. Approve it in your wallet to continue.';\n case 'insufficient_funds':\n return 'Not enough ETH to cover the gas for the approval.';\n case 'timeout':\n return 'The approval is taking too long to confirm. Please try again.';\n default:\n return 'Could not approve the spend. Please try again.';\n }\n case 'approval-reverted':\n return 'The approval transaction failed. Please try again.';\n // Frontline read the allowance itself and found it short of the order.\n // The remedy is to try again, not to approve again: the approval is mined\n // by the time this can fire, so the usual cause is frontline's node being\n // a block behind it.\n case 'insufficient-allowance':\n return 'Your approval has not landed yet. Please try again in a moment.';\n // Also where Ondo's own floor lands: it rejects an order whose expected\n // output is below its minimum-quantity tolerance, with no error code of its\n // own, so the remedy this offers - a different amount - is the right one.\n case 'build-transaction':\n return 'Could not get a quote for that amount. Please try again.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { ERC20_BALANCE_POLL_INTERVAL_MS } from '@/client/hooks/shared/erc20/useErc20TokenBalances';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type {\n EthereumChain,\n EvmContractAddress,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\n\nexport interface UseErc20BalanceOptions {\n /**\n * The token to read, by contract address.\n *\n * `null` when the caller does not know it yet, which fetches nothing. That is\n * the normal state for a token the SDK ships no registry entry for: an Ondo\n * asset's address arrives with its quote, so a sell screen renders before it\n * has one.\n */\n tokenAddress: EvmContractAddress | null;\n owner: EvmWalletAddress;\n chain: EthereumChain;\n /** How often to refresh. Defaults to {@link ERC20_BALANCE_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseErc20BalanceResult {\n /**\n * Raw base units of the token currently named by the options, or `null`.\n *\n * `null` covers every state that is not a settled read of *this* request:\n * before the first one settles, after one fails, while disabled, and from\n * the moment the token, owner or chain changes until the read for the new\n * one lands. A caller cannot tell those apart on purpose - none of them is a\n * number to size an order against - and `isLoading` is what says whether to\n * wait.\n */\n balance: bigint | null;\n isLoading: boolean;\n}\n\n/**\n * Polls one wallet's balance of one ERC-20, named by contract address.\n *\n * The address-keyed counterpart to `useErc20TokenBalances`, which reads a list\n * of tokens by symbol through `TOKEN_REGISTRY`. That registry knows the\n * stablecoins the SDK funds swaps with and nothing else, so a token whose\n * address arrives at runtime - a provider's asset, resolved from a quote - has\n * no symbol to look up and needs this instead. Two hooks rather than one\n * widened hook: the plural one exists to read a *set* concurrently and settle\n * each independently, which is a different job from following a single token\n * whose address may not be known yet.\n *\n * A poll tick is skipped while the previous read is in flight, so a slow one\n * cannot resolve last and overwrite a fresher balance. `isLoading` is true only\n * until the first read settles; background polls do not toggle it. Disabled, or\n * with no `tokenAddress`, it neither fetches nor holds a timer.\n */\nexport function useErc20Balance(\n options: UseErc20BalanceOptions\n): UseErc20BalanceResult {\n const {\n tokenAddress,\n owner,\n chain,\n pollIntervalMs = ERC20_BALANCE_POLL_INTERVAL_MS,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useErc20Balance');\n\n const [balance, setBalance] = useState<bigint | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n\n const fetchIdRef = useRef(0);\n const isFetchingRef = useRef(false);\n // Whether this hook has ever answered with a balance, for deciding at what\n // level a failed read is reported. A ref rather than `balance`, which the\n // poll loop closes over once and would read stale for the life of the\n // effect.\n const hasReadRef = useRef(false);\n\n useEffect(() => {\n if (!isReady) return;\n // A balance answers for one token, one owner and one chain, and nothing in\n // the result says which. Carrying the last one across a change of any of\n // them - or past being switched off - would hand a caller a number read\n // for something else, indistinguishable from a fresh one.\n setBalance(null);\n hasReadRef.current = false;\n if (!enabled || tokenAddress === null) {\n setIsLoading(false);\n return;\n }\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n let isFirstFetch = true;\n\n async function fetchBalance() {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n if (isFirstFetch) setIsLoading(true);\n\n try {\n const result = await coinlist.erc20.getBalance({\n tokenAddress: tokenAddress as EvmContractAddress,\n owner,\n chain,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n hasReadRef.current = true;\n setBalance(result);\n } catch (error) {\n // A failed read is not a zero balance, and the next tick is seconds\n // away. Reporting `null` keeps the amount step's CTA disabled rather\n // than letting an order be sized against a number nobody read.\n if (currentFetchId !== fetchIdRef.current) return;\n // Reported at the level the outcome actually has, the same split\n // `useOndoPrice` makes: a tick that fails after this hook has already\n // answered once is recoverable and the next one retries within\n // seconds, so an `error` per tick would flood a host's tracker through\n // an outage. Only never having read a balance leaves the step with\n // nothing, and that is the failure.\n //\n // The dropped value is what makes the recoverable case still worth a\n // line: unlike a price, a stale balance is not offered to the user, so\n // a host watching a CTA that will not enable sees why here and nowhere\n // else.\n if (hasReadRef.current) {\n log.warning(\n () => ({ msg: 'poll failed; dropping the last balance' }),\n error\n );\n } else {\n log.failure(\n () => ({ msg: 'settled', fields: { read: false } }),\n error\n );\n }\n setBalance(null);\n } finally {\n if (currentFetchId === fetchIdRef.current) {\n isFetchingRef.current = false;\n setIsLoading(false);\n isFirstFetch = false;\n }\n }\n }\n\n fetchBalance();\n const interval = setInterval(fetchBalance, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n };\n }, [\n coinlist,\n isReady,\n enabled,\n tokenAddress,\n owner,\n chain,\n pollIntervalMs,\n log,\n ]);\n\n return { balance, isLoading };\n}\n","'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n OndoSwapExecutionError,\n OndoSwapExecutionPhase,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport {\n type LoadOndoSellTransactionState,\n useOndoSellTransaction,\n} from '@/client/hooks/checkout/ondo/sell/data/useOndoSellTransaction';\nimport type {\n OndoSellOutcomeUi,\n OndoSellQuoteStatusUi,\n OndoSellReviewUiEvent,\n OndoSellReviewUiState,\n} from '@/client/hooks/checkout/ondo/sell/review/useOndoSellReviewViewModel.types';\nimport type { OndoLoadErrorReason } from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport type { OndoSellOrderPlaced } from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport {\n CheckoutAssetUi,\n type CheckoutCtaUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { stablecoinIconUrl } from '@/client/ui/format/asset-icon';\nimport { useCountdown } from '@/client/ui/hooks/useCountdown';\nimport { ONDO_SETTLEMENT_ASSET } from '@/universal/core/checkout/ondo/constants';\nimport {\n computeOndoSellPrice,\n ondoQuoteOfferDeadline,\n} from '@/universal/core/checkout/ondo/math';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type {\n OndoSellOutcome,\n OndoSellTransaction,\n} from '@/universal/types/providers/ondo/ondo';\n\nexport type OndoSellReviewStepInput =\n | { type: 'incomplete' }\n | {\n type: 'active';\n /** The wallet that signs, sends the asset, and receives the proceeds. */\n wallet: EvmWallet;\n /** What the user is selling, in the asset's base units. */\n amount: BlockchainAmount;\n inputAsset: AssetSymbol;\n /**\n * The sale `prepareSell` already built for this order. Omitting it makes\n * this step build one itself, which is the path a partner driving the\n * review on its own takes - and the only way its `loading` and `error`\n * states are reached.\n */\n transaction?: OndoSellTransaction;\n };\n\nexport interface UseOndoSellReviewViewModelOptions {\n stepInput: OndoSellReviewStepInput;\n /** Ondo's API symbol, e.g. `TSLAon`. Rebuilds the transaction. */\n ondoSymbol: AssetSymbol;\n /** The chain the order executes on. */\n chain: EthereumChain;\n /**\n * When false, the step neither builds a transaction nor counts down, and\n * neither refreshing the quote nor placing an order does anything. Defaults\n * to true.\n *\n * The step being `incomplete` is not the same thing and does not stand in\n * for it: a checkout switched off mid-flow leaves this step `active`, so the\n * committed quote is still here to render and its clock would tick on behind\n * a screen nobody is looking at.\n */\n enabled?: boolean;\n /** Called once the swap has mined. */\n /** Always a sell: this step only ever places one. */\n onComplete: (order: OndoSellOrderPlaced) => void;\n}\n\nexport interface UseOndoSellReviewViewModelResult {\n state: OndoSellReviewUiState;\n onEvent: (event: OndoSellReviewUiEvent) => void;\n}\n\n/**\n * Drives the review step of the Ondo sell checkout: what the sale comes to, how\n * long the price holds, and placing it.\n *\n * The same shape as its buy counterpart, and the same reasoning about time: the\n * SDK offers the quote for at most {@link ONDO_QUOTE_MAX_TTL_MS}, and\n * refreshing is always something the user asks for because each refresh spends\n * an attestation.\n *\n * What differs is what it reads off the transaction. A sale has no\n * `notionalValue` and therefore no total to render; it publishes an expected\n * outcome and a floor beneath it where the buy publishes one attested\n * quantity; and its fee, if one ever lands, is denominated in the proceeds\n * rather than in what was spent, and comes in two - one per outcome. Those\n * facts are why this is a second viewmodel rather than a flag on the first,\n * and why the endpoint behind it is a second endpoint.\n */\nexport function useOndoSellReviewViewModel({\n stepInput,\n ondoSymbol,\n chain,\n enabled = true,\n onComplete,\n}: UseOndoSellReviewViewModelOptions): UseOndoSellReviewViewModelResult {\n const { coinlist } = useCoinList();\n const locale = useLocale();\n\n const [phase, setPhase] = useState<OndoSwapExecutionPhase | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const isActive = stepInput.type === 'active';\n const { state: transactionState, refetch } = useOndoSellTransaction({\n request: isActive\n ? {\n symbol: ondoSymbol,\n chain,\n walletAddress: stepInput.wallet.address,\n amount: stepInput.amount,\n }\n : null,\n data: isActive ? stepInput.transaction : undefined,\n enabled: enabled && isActive,\n });\n\n /**\n * Which order the error above belongs to.\n *\n * Same guard, and same reason, as the amount step's `preparationIdRef`: an\n * execution outlives the step being reopened, so a rejection can land after\n * the user has walked back to edit the amount. Clearing the message on the\n * way out is not enough on its own - the effect below has already run by\n * then, and the late `setError` would write it back and hold it there until\n * the next order arrives to be blamed for it.\n *\n * It guards the failure only. A fill is reported whatever step the user is\n * on, because the sale happened: an order that reached the chain is not the\n * viewmodel's to discard.\n */\n const executionIdRef = useRef(0);\n\n // A failure belongs to the order that caused it. Leaving the step abandons\n // that order, so its message goes too. `phase` deliberately survives: it is\n // the only guard `placeOrder` has, and an execution in flight outlives the\n // step being reopened.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n ++executionIdRef.current;\n setError(null);\n }\n }, [stepInput.type]);\n\n const transaction =\n transactionState.type === 'CONTENT' ? transactionState.transaction : null;\n const offerUntil = useMemo(\n () =>\n transaction === null\n ? null\n : ondoQuoteOfferDeadline(transaction.expiresAt),\n [transaction]\n );\n const secondsLeft = useCountdown({\n until: offerUntil,\n enabled,\n });\n const quoteStatus = toQuoteStatusUi(transactionState, secondsLeft);\n\n const uiState = (): OndoSellReviewUiState => {\n if (stepInput.type === 'incomplete') return { type: 'incomplete' };\n switch (transactionState.type) {\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR':\n return { type: 'error' };\n case 'CONTENT':\n return sellState(stepInput, transactionState.transaction);\n default: {\n const exhaustive: never = transactionState;\n return exhaustive;\n }\n }\n };\n\n // No narrowing on the way in. `useOndoSellTransaction` calls\n // `POST /v1/ondo/swap/sell` and can only answer with a sale, so the check\n // that used to stand here - and the `error` state it fell back on - is now\n // the endpoint's rather than this screen's.\n function sellState(\n active: Extract<OndoSellReviewStepInput, { type: 'active' }>,\n built: OndoSellTransaction\n ): Extract<OndoSellReviewUiState, { type: 'active' }> {\n const settlement = TOKEN_REGISTRY.erc20(ONDO_SETTLEMENT_ASSET);\n const settlementSymbol = settlement.symbol;\n return {\n type: 'active',\n outputAsset: CheckoutAssetUi.fromErc20(settlement, {\n networkName: getNetworkName(chain),\n iconUrl: stablecoinIconUrl(ONDO_SETTLEMENT_ASSET),\n }),\n // The server's echo, not a figure derived from the amount the user typed:\n // showing the one that was actually signed for is what makes it visible\n // when the two disagree.\n //\n // One mapper for both outcomes, so neither can be built from the other's\n // half. The screen renders `expected.fee` beside the figure it annotates\n // and leaves `minimum.fee` unrendered - a host that wants to disclose\n // worst-case cost reads it off this state, or off the\n // `OndoSellTransaction` that `useOndoSellTransaction` hands it directly.\n expected: outcomeUi(built.expected, settlementSymbol),\n minimum: outcomeUi(built.minimum, settlementSymbol),\n recipientAddress: shortenAddress(active.wallet.address),\n // Derived, because the endpoint publishes no price. This is what the\n // order actually fills at rather than the sidebar's polled figure, which\n // has moved since and is struck against a different size.\n pricePerShare: formattedUsdPrice(computeOndoSellPrice(built), locale),\n quote: quoteStatus,\n placeOrderCta: placeOrderCta(),\n error,\n };\n }\n\n // A zero fee is not a fee: the row is hidden rather than reading \"0.00 USDC\",\n // which would imply a fee exists and happens to round away. Both halves are\n // in the proceeds' decimals, which is the scale a sale carries both of its\n // fees in.\n function outcomeUi(\n outcome: OndoSellOutcome,\n settlementSymbol: AssetSymbol\n ): OndoSellOutcomeUi {\n return {\n amount: assetAmount(\n formatAmount(outcome.quantity, locale),\n settlementSymbol\n ),\n fee:\n outcome.fee.raw === 0n\n ? null\n : assetAmount(formatAmount(outcome.fee, locale), settlementSymbol),\n };\n }\n\n function placeOrderCta(): CheckoutCtaUi {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n // The CTA, not the View, decides whether an order can be placed - and a\n // quote that is not `valid` is one the contract would reject.\n return quoteStatus.type === 'valid'\n ? { type: 'enabled' }\n : { type: 'disabled' };\n }\n\n const placeOrder = async () => {\n // A switched-off checkout starts no order. The View that would raise this\n // event is one the host has stopped rendering, so this is the guard that\n // says so to a partner driving the viewmodel directly.\n if (!enabled) return;\n // No side to guard any more: `useOndoSellTransaction` calls\n // `POST /v1/ondo/swap/sell`, so a sale is the only thing `transaction` can\n // be, and the filled order carries the matching arm by construction.\n if (stepInput.type !== 'active' || transaction === null || phase !== null) {\n return;\n }\n if (quoteStatus.type !== 'valid') return;\n\n const executionId = ++executionIdRef.current;\n setError(null);\n setPhase('broadcasting-swap');\n const result = await coinlist.ondo.executeSwap({\n wallet: stepInput.wallet,\n transaction,\n chain,\n onProgress: setPhase,\n });\n setPhase(null);\n\n if (result.type === 'error') {\n // Silence rather than a message when the order has been abandoned: the\n // step it would be reported on belongs to a different one now.\n if (executionId !== executionIdRef.current) return;\n setError(executionErrorMessage(result.error));\n return;\n }\n onComplete({\n side: 'sell',\n txHash: result.txHash,\n // The narrowed local rather than the echo: they are the same object -\n // `executeOndoSwap` returns what it was handed - and only this one\n // carries the arm.\n transaction,\n amount: stepInput.amount,\n inputAsset: stepInput.inputAsset,\n wallet: stepInput.wallet,\n });\n };\n\n const refreshQuote = () => {\n // Same reason as `placeOrder`, and doubly so here: a build spends an\n // attestation, so a switched-off checkout must not be able to spend one.\n if (!enabled) return;\n // An order in flight is signed against the quote on screen. Replacing it\n // now would spend an attestation and rewrite the numbers under a\n // transaction the user has already approved in their wallet.\n if (phase !== null) return;\n // A failed order and a stale quote are different problems; clear the first\n // so a fresh quote does not arrive under an old error message.\n setError(null);\n refetch();\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step, the quote and the phase this render was given, so\n // a memo could only ever hand back a stale one.\n const onEvent = (event: OndoSellReviewUiEvent) => {\n switch (event.type) {\n case 'ON_REFRESH_SELL_QUOTE':\n case 'ON_SELL_RETRY':\n refreshQuote();\n return;\n case 'ON_PLACE_SELL_ORDER':\n void placeOrder();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Quote status\n// ---------------------------------------------------------------------------\n\n/**\n * Whether the numbers on screen can still be traded on.\n *\n * Order matters. A refresh in flight outranks everything, because the answer\n * is about to change. A failed refresh outranks expiry, because refreshing\n * again is the remedy for both and the failure is the more useful thing to\n * say. Only then does the clock decide.\n */\nfunction toQuoteStatusUi(\n state: LoadOndoSellTransactionState,\n secondsLeft: number | null\n): OndoSellQuoteStatusUi {\n if (state.type !== 'CONTENT') return { type: 'expired' };\n if (state.isRefreshing) return { type: 'refreshing' };\n if (state.refreshError !== null) {\n return {\n type: 'refresh-failed',\n message: refreshErrorMessage(state.refreshError),\n };\n }\n if (secondsLeft === null || secondsLeft === 0) {\n return { type: 'expired' };\n }\n return { type: 'valid', expiresInLabel: expiresInLabel(secondsLeft) };\n}\n\nfunction expiresInLabel(secondsLeft: number): string {\n const unit = secondsLeft === 1 ? 'second' : 'seconds';\n return `Quote expires in ${secondsLeft} ${unit}`;\n}\n\n// ---------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------\n\nfunction phaseMessage(phase: OndoSwapExecutionPhase): string {\n switch (phase) {\n case 'broadcasting-swap':\n return 'Confirm in your wallet...';\n case 'confirming-swap':\n return 'Placing your order...';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\nfunction refreshErrorMessage(reason: OndoLoadErrorReason): string {\n switch (reason) {\n case 'not-authenticated':\n return 'Sign in to refresh this quote.';\n case 'not-tradable':\n return 'Trading is paused for this asset. Try again when the market opens.';\n case 'generic-error':\n return 'Could not refresh the quote.';\n default: {\n const exhaustive: never = reason;\n return exhaustive;\n }\n }\n}\n\nfunction executionErrorMessage(error: OndoSwapExecutionError): string {\n switch (error.step) {\n case 'quote-expired':\n return 'That quote expired. Get a new one to place your order.';\n case 'swap':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Order declined. Confirm it in your wallet to continue.';\n case 'insufficient_funds':\n return 'Not enough ETH to cover the gas for this order.';\n case 'timeout':\n return 'Your order is taking a while to confirm. Check your wallet before retrying.';\n default:\n return 'Could not place your order. Please try again.';\n }\n // Also where a sale that slipped below its floor lands: the calldata\n // enforces `minimumReceiveOutputAmount`, so an outcome under it reverts\n // rather than settling short.\n case 'swap-reverted':\n return 'Your order did not go through and nothing was sold. Get a new quote and try again.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n type OndoLoadErrorReason,\n ondoLoadErrorReason,\n} from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { BuildOndoSellParams } from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport type { OndoSellTransaction } from '@/universal/types/providers/ondo/ondo';\n\n/**\n * The state of the built sale a review step acts on.\n *\n * `isRefreshing` rides on `CONTENT` rather than replacing it, so a refresh in\n * flight never blanks the numbers the user is reading. A refresh that fails\n * keeps them too, and reports why alongside - the previous sale may still\n * be good, and a failed refresh is fixed by refreshing again.\n */\nexport type LoadOndoSellTransactionState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: OndoLoadErrorReason }\n | {\n type: 'CONTENT';\n transaction: OndoSellTransaction;\n isRefreshing: boolean;\n /** Why the last refresh failed; `null` when the sale is fresh. */\n refreshError: OndoLoadErrorReason | null;\n };\n\nexport interface UseOndoSellTransactionOptions {\n /**\n * The order to build, or `null` while there is not one yet - before the\n * amount step is confirmed. A `null` request fetches nothing.\n */\n request: BuildOndoSellParams | null;\n /**\n * A sale the caller already holds, typically the one `prepareSell`\n * returned with the approval. When present the hook adopts it and skips the\n * initial fetch; `refetch` still fetches. This is what keeps the flow to one\n * attestation per order.\n */\n data?: OndoSellTransaction;\n /** When false, the hook does not fetch. */\n enabled: boolean;\n}\n\nexport interface UseOndoSellTransactionResult {\n state: LoadOndoSellTransactionState;\n /** Builds a fresh sale for the same order. Spends an attestation. */\n refetch: () => void;\n}\n\n/**\n * Holds the firm, expiring sale the sell review step places an order\n * against, and rebuilds it on demand.\n *\n * **Never polls.** Building spends an attestation, so a new one is only ever\n * obtained when the caller asks - on `refetch`, or on the first render if no\n * `data` was supplied. That is also why an expired sale is left expired\n * here: whether to replace it is the user's call, not a timer's.\n *\n * Disabled it fetches nothing and stays on whatever state it opened with. That\n * is `LOADING` and not an empty `CONTENT` because there is no empty\n * sale: firm calldata for an order that does not exist is not\n * representable. A caller that switches this hook off should switch its own\n * rendering off with it - which is what the review step does, since a step\n * that is not active is `incomplete` and never reads this state at all.\n *\n * The sell half of the pair `useOndoBuyTransaction` opens - see there for why\n * the two are not one hook. What differs is entirely in what `CONTENT` carries:\n * an {@link OndoSellTransaction} publishes an expected outcome and a floor\n * beneath it rather than one attested quantity, and the review step renders\n * both.\n */\nexport function useOndoSellTransaction(\n options: UseOndoSellTransactionOptions\n): UseOndoSellTransactionResult {\n const { request, data, enabled } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOndoSellTransaction');\n\n const [state, setState] = useState<LoadOndoSellTransactionState>(() =>\n data === undefined\n ? { type: 'LOADING' }\n : {\n type: 'CONTENT',\n transaction: data,\n isRefreshing: false,\n refreshError: null,\n }\n );\n\n const fetchIdRef = useRef(0);\n // `fetchIdRef` decides which *response* wins; this decides which *request*\n // leaves at all. Both are needed, and this one more than in the polling\n // hooks: a build spends an attestation, so two overlapping calls cost two\n // of them however carefully the answers are then discarded. `refetch` is\n // part of the Level-2 surface, so the guard belongs here rather than in a\n // View that happens to hide its refresh link while one is in flight.\n const isFetchingRef = useRef(false);\n // The request keys the effect by value: the same order re-created on a\n // render must not spend a second attestation.\n const requestKey = request === null ? null : stableKey(request);\n const requestRef = useRef(request);\n requestRef.current = request;\n\n const build = useCallback(async () => {\n const params = requestRef.current;\n if (!isReady || !enabled || params === null) return;\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n const currentFetchId = ++fetchIdRef.current;\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: true, refreshError: null }\n : { type: 'LOADING' }\n );\n\n try {\n const transaction = await coinlist.ondo.buildSellTransaction(params);\n if (currentFetchId !== fetchIdRef.current) return;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT' },\n }));\n setState({\n type: 'CONTENT',\n transaction,\n isRefreshing: false,\n refreshError: null,\n });\n } catch (error) {\n if (currentFetchId !== fetchIdRef.current) return;\n const reason = ondoLoadErrorReason(error);\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setState((previous) =>\n previous.type === 'CONTENT'\n ? { ...previous, isRefreshing: false, refreshError: reason }\n : { type: 'ERROR', reason }\n );\n } finally {\n isFetchingRef.current = false;\n }\n }, [coinlist, isReady, enabled, log]);\n\n // Adopt a transaction the caller supplies, whenever it arrives. It usually\n // arrives after mount: the review step is rendered (collapsed) from the first\n // frame, and `prepareSell` only hands one over when the amount is confirmed.\n // A later `refetch` replaces it without this firing again, because the\n // caller's own `data` has not changed.\n useEffect(() => {\n if (data === undefined) return;\n ++fetchIdRef.current;\n setState({\n type: 'CONTENT',\n transaction: data,\n isRefreshing: false,\n refreshError: null,\n });\n }, [data]);\n\n // Fetch only what the caller did not provide. A seeded transaction is the\n // normal path - `prepareSell` built one moments ago, as part of approving -\n // so this branch belongs to a partner driving the review step themselves.\n const hasSeed = data !== undefined;\n useEffect(() => {\n if (hasSeed || requestKey === null) return;\n build();\n return () => {\n ++fetchIdRef.current;\n };\n }, [build, requestKey, hasSeed]);\n\n const refetch = useCallback(() => {\n build();\n }, [build]);\n\n return { state, refetch };\n}\n\n/** Key-order-independent identity for a request, for effect comparison. */\nfunction stableKey(request: BuildOndoSellParams): string {\n return [\n request.symbol,\n request.chain,\n request.walletAddress,\n request.amount.raw.toString(),\n request.amount.decimals,\n ].join('|');\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { OndoSellCheckoutView } from '@/client/components/checkout/ondo/sell/OndoSellCheckoutView';\nimport { useOndoSellCheckoutViewModel } from '@/client/hooks/checkout/ondo/sell/useOndoSellCheckoutViewModel';\nimport type { OndoOrderPlaced } from '@/client/hooks/checkout/ondo/shared/ondo-order.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type {\n AssetSymbol,\n EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type { OndoSwapOfferDetail } from '@/universal/types/offer-detail';\n\nexport interface OndoSellCheckoutContainerProps {\n /** The offer being sold: names the asset and supplies its logo. */\n offer: OndoSwapOfferDetail;\n /**\n * Ondo's API symbol for the asset, e.g. `TSLAon`.\n *\n * Explicit rather than derived from the offer: Ondo's symbol tracks the\n * underlying ticker and changes on a rebrand, and on Sepolia the two already\n * disagree, where a mock asset stands in.\n */\n ondoSymbol: AssetSymbol;\n /**\n * The chain the order executes on: the balance read, the approval and the\n * broadcast. Ondo prices against production whatever this says, since it\n * runs no sandbox.\n */\n chain: EthereumChain;\n /**\n * The wallets the seller can sell from, the lambdas that connect and\n * disconnect an external one, and optionally the one the host has already\n * settled on.\n *\n * Setting `wallets.preselected` skips the wallet step and opens the flow on\n * the amount, with the two remaining cards renumbered. It is read once, at\n * mount: the approval that follows the amount step is granted by one\n * specific wallet.\n */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. `false` turns off every request and timer, for a checkout\n * that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /** Fired once the swap has mined. The dialog shows either way. */\n onOrderConfirmed?: (order: OndoOrderPlaced) => void;\n className?: string;\n}\n\n/**\n * The Ondo sell checkout, ready to drop in: the steps, the asset panel beside\n * them, and the dialog that closes the flow.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function OndoSellCheckoutContainer({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n className,\n}: OndoSellCheckoutContainerProps): ReactNode {\n const { state, onEvent } = useOndoSellCheckoutViewModel({\n offer,\n ondoSymbol,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n });\n\n return (\n <OndoSellCheckoutView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutAmountInput } from '@/client/components/checkout/shared/amount/CheckoutAmountInput';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { PayWithAssetCard } from '@/client/components/checkout/shared/selection/PayWithAssetCard';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { CheckoutStepFooter } from '@/client/components/checkout/shared/step/CheckoutStepFooter';\nimport { CompletedStepSummary } from '@/client/components/checkout/shared/step/CompletedStepSummary';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutSelectableInputAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateAmountUiEvent,\n SuperstateAmountUiState,\n} from '@/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel.types';\n\nconst TITLE = '2. Enter amount';\nconst AMOUNT_LABEL = 'Amount';\nconst AMOUNT_PLACEHOLDER = '0.00';\nconst PAY_WITH_LABEL = 'Pay with';\nconst REVIEW_NOTE = \"You'll review your order details before confirming.\";\n\nexport interface SuperstateAmountViewProps {\n state: SuperstateAmountUiState;\n onEvent: (event: SuperstateAmountUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 2 of the Superstate checkout. Pure: amounts arrive already formatted,\n * and every interaction leaves through `onEvent`.\n *\n * The field is dollar-denominated, so the `$` leads the number via\n * `CheckoutAmountInput`'s `prefix` slot. Nothing here is submitted: confirming\n * only moves the flow to the review step.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SuperstateAmountView(\n props: SuperstateAmountViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <SuperstateAmountViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction SuperstateAmountViewBody({\n state,\n onEvent,\n className,\n}: SuperstateAmountViewProps): ReactNode {\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={TITLE}\n className={className}\n />\n );\n case 'active':\n return (\n <ActiveView state={state} onEvent={onEvent} className={className} />\n );\n case 'complete':\n return (\n <CompletedView state={state} onEvent={onEvent} className={className} />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<SuperstateAmountUiState, { type: 'active' }>;\n onEvent: (event: SuperstateAmountUiEvent) => void;\n className?: string;\n}): ReactNode {\n const selectedAsset =\n state.inputAssets.find((asset) => asset.selected) ?? null;\n\n return (\n <CheckoutStepCard\n state=\"active\"\n title={TITLE}\n className={className}\n footer={\n <CheckoutStepFooter\n message={REVIEW_NOTE}\n error={state.error}\n cta={\n <ClButton\n variant=\"primary\"\n disabled={!state.confirmEnabled}\n onClick={() => onEvent({ type: 'ON_PREVIEW_ORDER' })}\n className=\"clcosdk:h-12 clcosdk:max-md:w-full\"\n >\n Review order\n </ClButton>\n }\n />\n }\n >\n <CheckoutAmountInput\n label={AMOUNT_LABEL}\n value={state.amountInput}\n onChange={(value) => onEvent({ type: 'ON_AMOUNT_CHANGE', value })}\n placeholder={AMOUNT_PLACEHOLDER}\n invalid={state.error !== null}\n prefix=\"$\"\n action={\n selectedAsset && (\n <MaxButton\n onClick={() => onEvent({ type: 'ON_MAX_AMOUNT_CLICK' })}\n />\n )\n }\n />\n\n {state.inputAssets.length > 0 && (\n <PayWithSection\n inputAssets={state.inputAssets}\n walletAddress={state.walletAddress}\n onEvent={onEvent}\n />\n )}\n </CheckoutStepCard>\n );\n}\n\nfunction PayWithSection({\n inputAssets,\n walletAddress,\n onEvent,\n}: {\n inputAssets: CheckoutSelectableInputAssetUi[];\n walletAddress: string;\n onEvent: (event: SuperstateAmountUiEvent) => void;\n}): ReactNode {\n // One fundable asset is a statement, not a choice: render it as a plain card.\n const isChoice = inputAssets.length >= 2;\n\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {PAY_WITH_LABEL}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n from {walletAddress}\n </span>\n </div>\n\n <div\n className={cn(\n isChoice\n ? 'clcosdk:grid clcosdk:grid-cols-1 clcosdk:gap-2 clcosdk:sm:grid-cols-2'\n : 'clcosdk:flex clcosdk:flex-col'\n )}\n >\n {inputAssets.map((inputAsset) =>\n isChoice ? (\n <PayWithAssetCard\n key={inputAsset.symbol}\n variant=\"selectable\"\n asset={inputAsset.asset}\n balance={inputAsset.balance}\n selected={inputAsset.selected}\n onSelect={() =>\n onEvent({\n type: 'ON_SELECT_PAY_WITH',\n value: inputAsset.symbol,\n })\n }\n />\n ) : (\n <PayWithAssetCard\n key={inputAsset.symbol}\n variant=\"static\"\n asset={inputAsset.asset}\n balance={inputAsset.balance}\n />\n )\n )}\n </div>\n </div>\n );\n}\n\nfunction CompletedView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<SuperstateAmountUiState, { type: 'complete' }>;\n onEvent: (event: SuperstateAmountUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"completed\" title={TITLE} className={className}>\n <CompletedStepSummary\n icon={<AssetIcon asset={state.inputAsset} size={40} />}\n title={state.amountFormatted}\n subtitle={state.inputAmountFormatted}\n editLabel=\"Edit\"\n onEdit={() => onEvent({ type: 'ON_EDIT_AMOUNT' })}\n />\n </CheckoutStepCard>\n );\n}\n\nfunction MaxButton({ onClick }: { onClick: () => void }): ReactNode {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:h-9 clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:rounded-full',\n 'clcosdk:border clcosdk:border-border clcosdk:px-5',\n 'clcosdk:font-medium clcosdk:text-text-primary',\n 'clcosdk:transition-colors clcosdk:hover:bg-surface'\n )}\n >\n Max\n </button>\n );\n}\n","'use client';\n\nimport { Check, ExternalLink } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutConfirmationDialog } from '@/client/components/checkout/shared/confirmation/CheckoutConfirmationDialog';\nimport { AssetSummaryRow } from '@/client/components/checkout/shared/summary/AssetSummaryRow';\nimport type { CheckoutDetailRowUi } from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n SuperstateOrderConfirmedUiEvent,\n SuperstateOrderConfirmedUiState,\n} from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel.types';\nimport type { AssetSymbol } from '@/universal/types/blockchain/core';\n\nconst TITLE = 'Order confirmed';\nconst TOTAL_COST_LABEL = 'Total cost';\nconst SHARES_RECEIVED_LABEL = 'Shares received';\n/**\n * Shown instead when the swap's `Swapped` event would not decode and the\n * figures fall back to the quote. The swap mined and the shares are in the\n * wallet; how many is what the SDK could not confirm, and captioning an\n * estimate `Shares received` would state as fact something it does not know.\n */\nconst SHARES_RECEIVED_ESTIMATED_LABEL = 'Shares received (estimated)';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst PRICE_PER_SHARE_ESTIMATED_LABEL = 'Price per share (estimated)';\nconst DELIVERED_TO_LABEL = 'Delivered to';\nconst DONE_LABEL = 'Done';\nconst VIEW_TRANSACTION_LABEL = 'View transaction onchain';\n\nconst subtitle = (symbol: AssetSymbol): string =>\n `Your ${symbol} shares have been delivered to your wallet.`;\n\nexport interface SuperstateOrderConfirmedProps {\n state: SuperstateOrderConfirmedUiState;\n onEvent: (event: SuperstateOrderConfirmedUiEvent) => void;\n className?: string;\n}\n\n/**\n * The dialog that closes the Superstate checkout: what arrived, what it cost,\n * and where it went.\n *\n * Pure: every figure is handed over formatted, and the explorer link is\n * rendered from the URL the viewmodel built rather than raised as an event.\n *\n * Self-scoped: renders fully styled on its own. It bails before the scope while\n * hidden, so a closed dialog leaves nothing in the DOM.\n */\nexport function SuperstateOrderConfirmed({\n state,\n onEvent,\n className,\n}: SuperstateOrderConfirmedProps): ReactNode {\n if (state.type === 'hidden') {\n return null;\n }\n\n const onClose = () => onEvent({ type: 'ON_CLOSE_ORDER_CONFIRMED' });\n\n return (\n <CoinListStyleScope>\n <CheckoutConfirmationDialog\n icon={<SuccessGlyph />}\n title={TITLE}\n subtitle={subtitle(state.asset.symbol)}\n header={<AssetSummaryRow asset={state.asset} wrapIdentity />}\n rows={detailRows(state)}\n actions={\n <>\n <ClButton variant=\"gradient\" fullWidth onClick={onClose}>\n {DONE_LABEL}\n </ClButton>\n <ExplorerLink url={state.txExplorerUrl} />\n </>\n }\n onClose={onClose}\n className={className}\n />\n </CoinListStyleScope>\n );\n}\n\nfunction detailRows(\n state: Extract<SuperstateOrderConfirmedUiState, { type: 'visible' }>\n): CheckoutDetailRowUi[] {\n // The cost and the recipient are read off the transaction the user signed, so\n // they are certain whichever path the output came down. Only the two figures\n // derived from the fill are hedged.\n const confirmed = state.outputAmountConfirmed;\n return [\n { label: TOTAL_COST_LABEL, value: state.totalCost },\n {\n label: confirmed\n ? SHARES_RECEIVED_LABEL\n : SHARES_RECEIVED_ESTIMATED_LABEL,\n value: state.outputAmount,\n },\n {\n label: confirmed\n ? PRICE_PER_SHARE_LABEL\n : PRICE_PER_SHARE_ESTIMATED_LABEL,\n value: state.pricePerShare,\n },\n { label: DELIVERED_TO_LABEL, value: state.recipientAddress },\n ];\n}\n\nfunction SuccessGlyph(): ReactNode {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:size-10 clcosdk:shrink-0 clcosdk:items-center clcosdk:justify-center',\n 'clcosdk:rounded-full clcosdk:bg-positive-subtle'\n )}\n >\n <Check\n className=\"clcosdk:size-5 clcosdk:text-positive\"\n strokeWidth={2.5}\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n\n/**\n * An anchor rather than a button: the URL is known, so middle-click, copy-link\n * and the host's own link handling all keep working.\n */\nfunction ExplorerLink({ url }: { url: string }): ReactNode {\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n typeClasses.label,\n 'clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:items-center clcosdk:justify-center clcosdk:gap-1.5',\n 'clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:px-4',\n 'clcosdk:text-text-primary clcosdk:no-underline',\n 'clcosdk:transition-colors clcosdk:hover:bg-section'\n )}\n >\n {VIEW_TRANSACTION_LABEL}\n <ExternalLink\n className=\"clcosdk:size-3.5 clcosdk:shrink-0\"\n strokeWidth={1.5}\n aria-hidden=\"true\"\n />\n </a>\n );\n}\n","'use client';\n\nimport { Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AssetIcon } from '@/client/components/checkout/shared/common/AssetIcon';\nimport { DetailRow } from '@/client/components/checkout/shared/common/DetailRow';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { SUPERSTATE_TOS_URL } from '@/client/components/checkout/superstate/shared/constants';\nimport { SlippagePicker } from '@/client/components/checkout/superstate/swap/review/SlippagePicker';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { Tooltip } from '@/client/components/design-system/Tooltip';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n SuperstateReviewUiEvent,\n SuperstateReviewUiState,\n} from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel.types';\n\nconst TITLE = '3. Review and confirm';\nconst YOU_RECEIVE_LABEL = 'You receive';\nconst MINIMUM_RECEIVE_TOOLTIP =\n \"The minimum amount of shares you're guaranteed to receive based on your slippage\";\nconst RECEIVING_WALLET_LABEL = 'Receiving wallet';\nconst PRICE_PER_SHARE_LABEL = 'Price per share';\nconst PRICE_PER_SHARE_TOOLTIP = 'The current token price per share';\nconst COINLIST_FEE_LABEL = 'CoinList fee';\nconst COINLIST_FEE_TOOLTIP = 'Transaction fee charged by CoinList';\nconst TOTAL_LABEL = 'Total';\nconst PROCESSING_NOTICE =\n \"Processing onchain. Don't close or refresh this page.\";\nconst LOADING_STATUS = 'Loading your order details…';\nconst ERROR_TITLE = 'Unable to load quote';\nconst ERROR_DESCRIPTION =\n \"We're having trouble fetching a price right now. Please try again.\";\n\nexport interface SuperstateReviewViewProps {\n state: SuperstateReviewUiState;\n onEvent: (event: SuperstateReviewUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 3 of the Superstate checkout. Pure: every number arrives formatted, and\n * whether the order can be placed is decided by `placeOrderCta` rather than\n * re-derived here.\n *\n * The CTA covers a status check, an approval and the swap, which is why the\n * \"don't close this page\" notice appears only while it runs — a Superstate\n * order is several wallet prompts long, and leaving mid-flight strands the\n * approval.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SuperstateReviewView(\n props: SuperstateReviewViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <SuperstateReviewViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction SuperstateReviewViewBody({\n state,\n onEvent,\n className,\n}: SuperstateReviewViewProps): ReactNode {\n switch (state.type) {\n case 'incomplete':\n return (\n <CheckoutStepCard\n state=\"inactive\"\n title={TITLE}\n className={className}\n />\n );\n case 'loading':\n return <LoadingView className={className} />;\n case 'error':\n return <ErrorView className={className} />;\n case 'active':\n return (\n <ActiveView state={state} onEvent={onEvent} className={className} />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<SuperstateReviewUiState, { type: 'active' }>;\n onEvent: (event: SuperstateReviewUiEvent) => void;\n className?: string;\n}): ReactNode {\n const { placeOrderCta } = state;\n\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <span className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {YOU_RECEIVE_LABEL}\n </span>\n\n {/* The picker lays out this summary and its own toggle side by side,\n so that its options can span the full card beneath them rather than\n being confined to the toggle's column. */}\n <SlippagePicker\n slippage={state.slippage}\n onToggle={() => onEvent({ type: 'ON_SLIPPAGE_CLICK' })}\n onSelect={(bps) => onEvent({ type: 'ON_SLIPPAGE_SELECT', bps })}\n summary={\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-3\">\n <AssetIcon asset={state.outputAsset} size={40} />\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col\">\n <span\n className={cn(\n typeClasses.h3,\n 'clcosdk:min-w-0 clcosdk:break-words clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {state.outputAmount}\n </span>\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-1.5\">\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n Minimum: {state.minOutputAmount}\n </span>\n <Tooltip content={MINIMUM_RECEIVE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n </div>\n </div>\n </div>\n }\n />\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n <DetailRow\n label={RECEIVING_WALLET_LABEL}\n value={state.recipientAddress}\n />\n <DetailRow\n label={PRICE_PER_SHARE_LABEL}\n tooltip={\n <Tooltip content={PRICE_PER_SHARE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.pricePerShare}\n />\n <DetailRow\n label={COINLIST_FEE_LABEL}\n tooltip={\n <Tooltip content={COINLIST_FEE_TOOLTIP}>\n <InfoIcon />\n </Tooltip>\n }\n value={state.coinlistFee}\n />\n </div>\n\n <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />\n\n <DetailRow\n label={TOTAL_LABEL}\n value={state.total}\n emphasis\n className=\"clcosdk:px-2\"\n />\n </div>\n\n {state.error && <Note tone=\"error\">{state.error}</Note>}\n\n {placeOrderCta.type === 'loading' && (\n <Note tone=\"muted\">{PROCESSING_NOTICE}</Note>\n )}\n\n <ClButton\n variant=\"gradient\"\n size=\"cta\"\n fullWidth\n disabled={placeOrderCta.type === 'disabled'}\n isLoading={placeOrderCta.type === 'loading'}\n loadingText={\n placeOrderCta.type === 'loading' ? placeOrderCta.message : undefined\n }\n onClick={() => onEvent({ type: 'ON_PLACE_ORDER' })}\n >\n Place order\n </ClButton>\n\n <Disclaimer />\n </CheckoutStepCard>\n );\n}\n\nfunction Note({\n tone,\n children,\n}: {\n tone: 'muted' | 'error';\n children: ReactNode;\n}): ReactNode {\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:md:px-6',\n tone === 'error' ? 'clcosdk:text-error' : 'clcosdk:text-text-secondary'\n )}\n >\n {children}\n </p>\n );\n}\n\nfunction LoadingView({ className }: { className?: string }): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n {/* Every skeleton below is aria-hidden, so this line is the only thing a\n screen reader has to go on while the order details load. */}\n <output className=\"clcosdk:sr-only\">{LOADING_STATUS}</output>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:p-4\">\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-20\" />\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-3\">\n <Skeleton\n variant=\"circular\"\n className=\"clcosdk:size-10 clcosdk:shrink-0\"\n />\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <Skeleton className=\"clcosdk:h-5 clcosdk:w-32\" />\n <Skeleton className=\"clcosdk:h-3 clcosdk:w-24\" />\n </div>\n </div>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3 clcosdk:px-2\">\n {['wallet', 'price', 'fee'].map((row) => (\n <div\n key={row}\n className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4\"\n >\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-28\" />\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-24\" />\n </div>\n ))}\n </div>\n\n <div className=\"clcosdk:h-px clcosdk:shrink-0 clcosdk:bg-divider\" />\n\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:justify-between clcosdk:gap-4 clcosdk:px-2\">\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-16\" />\n <Skeleton className=\"clcosdk:h-4 clcosdk:w-20\" />\n </div>\n\n <Skeleton\n variant=\"rectangular\"\n className=\"clcosdk:h-[54px] clcosdk:w-full clcosdk:rounded-full\"\n />\n </CheckoutStepCard>\n );\n}\n\n/**\n * No quote could be produced for this amount, or the one produced asks for more\n * than the user offered.\n *\n * There is no retry here: the quote is on a poll, so the next tick is the\n * retry, and a button that raced it would only invite a double request. The\n * copy says as much.\n */\nfunction ErrorView({ className }: { className?: string }): ReactNode {\n return (\n <CheckoutStepCard state=\"active\" title={TITLE} className={className}>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-2 clcosdk:py-8 clcosdk:text-center\">\n <h3\n className={cn(\n typeClasses.h4,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {ERROR_TITLE}\n </h3>\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:max-w-md clcosdk:text-text-secondary'\n )}\n >\n {ERROR_DESCRIPTION}\n </p>\n </div>\n </CheckoutStepCard>\n );\n}\n\nfunction Disclaimer(): ReactNode {\n return (\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:px-2 clcosdk:text-center clcosdk:text-text-secondary clcosdk:md:px-6'\n )}\n >\n Final amounts may vary based on price at time of settlement. By placing\n this order, you agree to Superstate's{' '}\n <a\n href={SUPERSTATE_TOS_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"clcosdk:underline clcosdk:transition-colors clcosdk:hover:text-text-primary\"\n >\n Terms of Service\n </a>\n .\n </p>\n );\n}\n\nfunction InfoIcon(): ReactNode {\n return (\n <Info\n className=\"clcosdk:size-4 clcosdk:text-text-secondary\"\n aria-hidden=\"true\"\n />\n );\n}\n","/**\n * Superstate's own terms, which a user accepts by placing a Superstate order.\n *\n * Hardcoded rather than taken as a prop: the disclaimer names Superstate\n * specifically, so a partner substituting their own link would be misstating\n * whose terms apply.\n *\n * At the provider level rather than under `swap/`, because whose terms these\n * are is a fact about Superstate rather than about the product being bought:\n * a second Superstate product would link the same document.\n */\nexport const SUPERSTATE_TOS_URL = 'https://superstate.com/terms';\n","'use client';\n\nimport { ChevronDown } from 'lucide-react';\nimport { type ReactNode, useId } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n SuperstateSlippageOptionUi,\n SuperstateSlippageUi,\n} from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel.types';\nimport type { Bps } from '@/universal/types/blockchain/core';\n\nexport interface SlippagePickerProps {\n slippage: SuperstateSlippageUi;\n /**\n * What the tolerance applies to, rendered to the left of the toggle: the\n * amount the user receives, in practice.\n *\n * A slot, and the reason this component owns a row at all. The toggle has to\n * sit beside the summary while the options have to span the full width\n * beneath both - a picker that rendered only itself would put the options in\n * whatever narrow column the toggle landed in. Taking the summary is what\n * lets one component place both, and keeps `aria-controls` pointing at a\n * panel it still owns.\n */\n summary: ReactNode;\n /** Toggles the disclosure. Open/closed is viewmodel state, not View state. */\n onToggle: () => void;\n onSelect: (bps: Bps) => void;\n className?: string;\n}\n\n/**\n * The slippage tolerance, and the disclosure that changes it: a pill showing\n * the tolerance in force beside {@link SlippagePickerProps.summary}, and - once\n * opened - the options and what they mean, on their own line below both.\n *\n * Superstate-only, so it lives beside the review step rather than in\n * `checkout/shared`. Ondo quotes firm prices and has no tolerance to set, and a\n * shared component shaped entirely by one provider's `SLIPPAGE_OPTIONS_BPS`\n * would be that provider's component in a shared directory.\n *\n * Pure: it renders the options it is handed and reports which was picked. It\n * does not know what a basis point is.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SlippagePicker({\n slippage,\n summary,\n onToggle,\n onSelect,\n className,\n}: SlippagePickerProps): ReactNode {\n const optionsId = useId();\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-2',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-3 clcosdk:md:flex-row clcosdk:md:items-end clcosdk:md:justify-between\">\n {summary}\n\n <button\n type=\"button\"\n aria-expanded={slippage.expanded}\n aria-controls={optionsId}\n onClick={onToggle}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:flex clcosdk:shrink-0 clcosdk:items-center clcosdk:gap-2',\n 'clcosdk:self-start clcosdk:md:self-end',\n 'clcosdk:cursor-pointer clcosdk:rounded-full clcosdk:border',\n 'clcosdk:border-border clcosdk:px-3 clcosdk:py-1.5',\n 'clcosdk:font-medium clcosdk:text-text-secondary',\n 'clcosdk:transition-colors clcosdk:hover:bg-surface'\n )}\n >\n {slippage.percent} slippage\n <ChevronDown\n className={cn(\n 'clcosdk:size-3 clcosdk:shrink-0 clcosdk:transition-transform clcosdk:duration-200',\n slippage.expanded && 'clcosdk:rotate-180'\n )}\n strokeWidth={1.5}\n aria-hidden=\"true\"\n />\n </button>\n </div>\n\n {slippage.expanded && (\n <div\n id={optionsId}\n className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-3 clcosdk:pt-1\"\n >\n <div className=\"clcosdk:flex clcosdk:flex-wrap clcosdk:gap-2\">\n {slippage.options.map((option) => (\n <SlippageOption\n key={String(option.bps)}\n option={option}\n onSelect={() => onSelect(option.bps)}\n />\n ))}\n </div>\n <p\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n {slippage.description}\n </p>\n </div>\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction SlippageOption({\n option,\n onSelect,\n}: {\n option: SuperstateSlippageOptionUi;\n onSelect: () => void;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n aria-pressed={option.selected}\n onClick={onSelect}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:flex clcosdk:w-16 clcosdk:cursor-pointer clcosdk:items-center clcosdk:justify-center',\n 'clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:py-1.5',\n 'clcosdk:font-medium clcosdk:text-text-primary clcosdk:transition-colors',\n option.selected ? 'clcosdk:bg-section' : 'clcosdk:hover:bg-surface'\n )}\n >\n {option.percent}\n </button>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CheckoutSidebarCard } from '@/client/components/checkout/shared/sidebar/CheckoutSidebarCard';\nimport { AssetSummaryRow } from '@/client/components/checkout/shared/summary/AssetSummaryRow';\nimport type { CheckoutDetailRowUi } from '@/client/components/checkout/shared/summary/CheckoutDetailList';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { CheckoutStatusUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateSidebarPriceUi,\n SuperstateSidebarUiState,\n} from '@/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel.types';\n\nconst TITLE = 'Sale details';\nconst SHOW_DETAILS_LABEL = 'View details';\nconst HIDE_DETAILS_LABEL = 'Hide details';\nconst PRICE_PER_SHARE_CAPTION = 'Price per share';\nconst ISSUER_LABEL = 'Issuer';\nconst NETWORK_LABEL = 'Network';\nconst PURCHASE_OPTIONS_LABEL = 'Purchase options';\nconst PURCHASE_LIMITS_LABEL = 'Purchase limits';\n\nexport interface SuperstateSidebarViewProps {\n state: SuperstateSidebarUiState;\n className?: string;\n}\n\n/**\n * The panel beside the Superstate checkout: whether the sale is still running,\n * what is being bought, what one share costs, and the terms of the sale.\n *\n * Read-only, so it takes no `onEvent`. The sale banner sits above the card\n * rather than inside it — it is the first thing to read on a phone, where the\n * card's own contents fold away behind a disclosure.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SuperstateSidebarView({\n state,\n className,\n}: SuperstateSidebarViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:min-w-0 clcosdk:flex-col',\n 'clcosdk:gap-6 clcosdk:max-md:gap-4',\n className\n )}\n >\n <SaleBanner sale={state.sale} />\n <CheckoutSidebarCard\n title={TITLE}\n header={\n <AssetSummaryRow\n asset={state.asset}\n value={<PriceValue price={state.price} />}\n caption={PRICE_PER_SHARE_CAPTION}\n />\n }\n rows={detailRows(state)}\n showDetailsLabel={SHOW_DETAILS_LABEL}\n hideDetailsLabel={HIDE_DETAILS_LABEL}\n />\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction detailRows(state: SuperstateSidebarUiState): CheckoutDetailRowUi[] {\n return [\n { label: ISSUER_LABEL, value: state.issuer },\n { label: NETWORK_LABEL, value: state.networkName },\n { label: PURCHASE_OPTIONS_LABEL, value: state.purchaseOptionsLabel },\n { label: PURCHASE_LIMITS_LABEL, value: `Minimum: ${state.minPurchase}` },\n ];\n}\n\n/**\n * Whether the sale is still running. A live sale gets a pulsing dot; an ended\n * one gets the label alone, because there is nothing to watch.\n *\n * Below `md` it drops its card chrome, matching `CheckoutSidebarCard` beneath\n * it, so the panel reads as one column on a phone rather than two stacked\n * boxes.\n */\nfunction SaleBanner({ sale }: { sale: CheckoutStatusUi }): ReactNode {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:gap-3',\n 'clcosdk:justify-center clcosdk:max-md:justify-start',\n 'clcosdk:p-3.5 clcosdk:max-md:p-0',\n 'clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background',\n 'clcosdk:max-md:rounded-none clcosdk:max-md:border-0 clcosdk:max-md:bg-transparent'\n )}\n >\n {sale.type === 'active' && <LiveDot />}\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:tabular-nums clcosdk:text-text-primary'\n )}\n >\n {sale.label}\n </span>\n </div>\n );\n}\n\nfunction LiveDot(): ReactNode {\n return (\n <span\n className=\"clcosdk:size-2 clcosdk:shrink-0 clcosdk:animate-pulse clcosdk:rounded-full clcosdk:bg-positive\"\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction PriceValue({ price }: { price: SuperstateSidebarPriceUi }): ReactNode {\n switch (price.type) {\n case 'loading':\n return <Skeleton className=\"clcosdk:h-[1em] clcosdk:w-24\" />;\n case 'known':\n return price.price;\n default: {\n // A new price arm without a case here is a compile error.\n const exhaustive: never = price;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { Wallet } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport {\n OptionMetaRow,\n SelectableOptionRow,\n} from '@/client/components/checkout/shared/selection/SelectableOptionRow';\nimport { CheckoutStepCard } from '@/client/components/checkout/shared/step/CheckoutStepCard';\nimport { CheckoutStepFooter } from '@/client/components/checkout/shared/step/CheckoutStepFooter';\nimport { CompletedStepSummary } from '@/client/components/checkout/shared/step/CompletedStepSummary';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n CheckoutConfirmedWalletUi,\n CheckoutEmbeddedWalletUi,\n CheckoutWalletUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateWalletUiEvent,\n SuperstateWalletUiState,\n} from '@/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel.types';\n\nconst TITLE = '1. Choose your wallet';\nconst DESCRIPTION =\n 'Choose your wallet to fund your purchase and receive your assets.';\nconst EMBEDDED_WALLET_LABEL = 'CoinList Wallet';\nconst EXTERNAL_WALLET_LABEL = 'External wallet';\nconst ALLOWLISTED_LABEL = 'Allowlisted';\n\nexport interface SuperstateWalletViewProps {\n state: SuperstateWalletUiState;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 1 of the Superstate checkout. Pure: the wallets arrive already shaped,\n * and every interaction leaves through `onEvent`.\n *\n * Confirming allow-lists the wallet on-chain, which is why the CTA renders a\n * loading message rather than a spinner alone — the copy is what tells the user\n * their wallet is about to ask them to sign. The completed step says\n * `Allowlisted`, the only place the flow admits that anything happened.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SuperstateWalletView(\n props: SuperstateWalletViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <SuperstateWalletViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction SuperstateWalletViewBody({\n state,\n onEvent,\n className,\n}: SuperstateWalletViewProps): ReactNode {\n switch (state.type) {\n case 'active':\n return (\n <ActiveView state={state} onEvent={onEvent} className={className} />\n );\n case 'completed':\n return (\n <CompletedView\n wallet={state.wallet}\n onEvent={onEvent}\n className={className}\n />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction ActiveView({\n state,\n onEvent,\n className,\n}: {\n state: Extract<SuperstateWalletUiState, { type: 'active' }>;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n className?: string;\n}): ReactNode {\n const { confirmCta } = state;\n const isLoading = confirmCta.type === 'loading';\n\n return (\n <CheckoutStepCard\n state=\"active\"\n title={TITLE}\n description={\n <p className={cn(typeClasses.bodySm, 'clcosdk:text-text-secondary')}>\n {DESCRIPTION}\n </p>\n }\n className={className}\n footer={\n <CheckoutStepFooter\n message={\n confirmCta.type === 'loading' ? confirmCta.message : undefined\n }\n error={state.error}\n cta={\n <ClButton\n variant=\"primary\"\n disabled={confirmCta.type === 'disabled'}\n isLoading={isLoading}\n loadingText=\"Confirming\"\n onClick={() => onEvent({ type: 'ON_CONFIRM_WALLET' })}\n className=\"clcosdk:h-12 clcosdk:max-md:w-full\"\n >\n Confirm wallet\n </ClButton>\n }\n />\n }\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\">\n <ExternalWalletRow\n wallet={state.externalWallet}\n canDisconnect={state.canDisconnect}\n disabled={isLoading}\n onEvent={onEvent}\n />\n {state.embeddedWallets.map((wallet) => (\n <EmbeddedWalletRow\n key={wallet.walletAddress}\n wallet={wallet}\n disabled={isLoading}\n onEvent={onEvent}\n />\n ))}\n </div>\n </CheckoutStepCard>\n );\n}\n\n/**\n * The external-wallet row is always rendered, connected or not: disconnected it\n * is the invitation to connect one, connected it is a wallet like any other.\n */\nfunction ExternalWalletRow({\n wallet,\n canDisconnect,\n disabled,\n onEvent,\n}: {\n wallet: CheckoutWalletUi | null;\n canDisconnect: boolean;\n /** Frozen while an authorization runs: that wallet is mid-signature. */\n disabled: boolean;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n}): ReactNode {\n if (wallet === null) {\n return (\n <SelectableOptionRow\n selected={false}\n disabled={disabled}\n onSelect={() => onEvent({ type: 'ON_CONNECT_WALLET' })}\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {EXTERNAL_WALLET_LABEL}\n </span>\n </SelectableOptionRow>\n );\n }\n\n return (\n <SelectableOptionRow\n selected={wallet.selected}\n disabled={disabled}\n onSelect={() =>\n onEvent({ type: 'ON_SELECT_WALLET', value: { type: 'external' } })\n }\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {wallet.address}\n </span>\n {/*\n Below `md` the chain is omitted, so this cannot share `OptionMetaRow`\n with the desktop line: that helper inserts a dot for every child, even\n one that is only CSS-hidden, and the bullet would dangle after the\n address. Disconnect sits on its own here; the desktop meta row below\n keeps `Ethereum • Disconnect`.\n */}\n {canDisconnect && (\n <DisconnectControl\n onDisconnect={() => onEvent({ type: 'ON_DISCONNECT_WALLET' })}\n className=\"clcosdk:md:hidden\"\n />\n )}\n <div className=\"clcosdk:max-md:hidden\">\n <OptionMetaRow>\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n {wallet.network}\n </span>\n {canDisconnect && (\n <DisconnectControl\n onDisconnect={() => onEvent({ type: 'ON_DISCONNECT_WALLET' })}\n />\n )}\n </OptionMetaRow>\n </div>\n </SelectableOptionRow>\n );\n}\n\nfunction EmbeddedWalletRow({\n wallet,\n disabled,\n onEvent,\n}: {\n wallet: CheckoutEmbeddedWalletUi;\n disabled: boolean;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n}): ReactNode {\n return (\n <SelectableOptionRow\n selected={wallet.selected}\n disabled={disabled}\n onSelect={() =>\n onEvent({\n type: 'ON_SELECT_WALLET',\n value: { type: 'embedded', address: wallet.walletAddress },\n })\n }\n icon={<WalletGlyph />}\n >\n <span\n className={cn(\n typeClasses.bodyMedium,\n 'clcosdk:truncate clcosdk:text-text-primary'\n )}\n >\n {EMBEDDED_WALLET_LABEL}\n </span>\n {/* Address only below `md`. Same reason as the external row: hiding the\n chain with CSS still leaves OptionMetaRow's separator in the markup. */}\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary clcosdk:md:hidden'\n )}\n >\n {wallet.address}\n </span>\n <div className=\"clcosdk:max-md:hidden\">\n <OptionMetaRow>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:truncate clcosdk:text-text-secondary'\n )}\n >\n {wallet.address}\n </span>\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:shrink-0 clcosdk:text-text-secondary'\n )}\n >\n {wallet.network}\n </span>\n </OptionMetaRow>\n </div>\n </SelectableOptionRow>\n );\n}\n\nfunction CompletedView({\n wallet,\n onEvent,\n className,\n}: {\n wallet: CheckoutConfirmedWalletUi;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n className?: string;\n}): ReactNode {\n return (\n <CheckoutStepCard state=\"completed\" title={TITLE} className={className}>\n <CompletedStepSummary\n icon={<WalletGlyph />}\n title={\n wallet.type === 'embedded' ? EMBEDDED_WALLET_LABEL : wallet.address\n }\n subtitle={\n <OptionMetaRow>\n {wallet.type === 'embedded' ? wallet.address : null}\n <AllowlistedBadge />\n </OptionMetaRow>\n }\n editLabel=\"Edit\"\n onEdit={() => onEvent({ type: 'ON_EDIT_WALLET' })}\n />\n </CheckoutStepCard>\n );\n}\n\n/**\n * The only trace the flow leaves of the allow-listing that step 1 performs.\n * Rendered from the state's shape rather than a flag: reaching `completed` is\n * what allow-listed means here, since `authorizeWallet` is what completes it.\n */\nfunction AllowlistedBadge(): ReactNode {\n return (\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:shrink-0 clcosdk:text-positive'\n )}\n >\n {ALLOWLISTED_LABEL}\n </span>\n );\n}\n\nfunction DisconnectControl({\n onDisconnect,\n className,\n}: {\n onDisconnect: () => void;\n className?: string;\n}): ReactNode {\n return (\n <button\n type=\"button\"\n onClick={(event) => {\n // The row behind it would otherwise take this as a selection.\n event.stopPropagation();\n onDisconnect();\n }}\n className={cn(\n typeClasses.subhead,\n 'clcosdk:w-fit clcosdk:shrink-0 clcosdk:cursor-pointer clcosdk:self-start clcosdk:underline',\n 'clcosdk:text-text-secondary clcosdk:transition-colors clcosdk:hover:text-text-primary',\n className\n )}\n >\n Disconnect\n </button>\n );\n}\n\nfunction WalletGlyph(): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:size-10 clcosdk:shrink-0 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-xl clcosdk:bg-section\">\n <Wallet\n className=\"clcosdk:size-5 clcosdk:text-text-primary\"\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { SuperstateAmountView } from '@/client/components/checkout/superstate/swap/amount/SuperstateAmountView';\nimport { SuperstateOrderConfirmed } from '@/client/components/checkout/superstate/swap/confirmation/SuperstateOrderConfirmed';\nimport { SuperstateReviewView } from '@/client/components/checkout/superstate/swap/review/SuperstateReviewView';\nimport { SuperstateSidebarView } from '@/client/components/checkout/superstate/swap/sidebar/SuperstateSidebarView';\nimport { SuperstateWalletView } from '@/client/components/checkout/superstate/swap/wallet/SuperstateWalletView';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n SuperstateSwapCheckoutUiEvent,\n SuperstateSwapCheckoutUiState,\n SuperstateSwapLoadErrorReason,\n} from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel.types';\n\nconst ERROR_TITLE = 'Failed to load';\nconst ERROR_DESCRIPTION =\n 'Something went wrong while loading this sale. Please try again.';\nconst UNSUPPORTED_CHAIN_TITLE = 'Not available on this network';\nconst UNSUPPORTED_CHAIN_DESCRIPTION =\n 'This sale cannot be traded on the selected network.';\nconst RETRY_LABEL = 'Try again';\n\nexport interface SuperstateSwapCheckoutViewProps {\n state: SuperstateSwapCheckoutUiState;\n onEvent: (event: SuperstateSwapCheckoutUiEvent) => void;\n className?: string;\n}\n\n/**\n * The whole Superstate swap checkout: the three step cards, the sale panel\n * beside them, and the dialog that closes the flow.\n *\n * `onEvent` is handed to each step unwrapped. A handler that accepts the wider\n * union is assignable where a step's narrower one is expected, so there is no\n * per-step lambda here and no re-dispatch on the way back up.\n *\n * The panel leads on a phone and moves to the right column from `md` up, where\n * it is reference material rather than the first thing to read. No page heading\n * and no back button — the host titles and navigates its own page.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it. The steps scope themselves too, and the scope is\n * idempotent, so nesting costs nothing.\n */\nexport function SuperstateSwapCheckoutView({\n state,\n onEvent,\n className,\n}: SuperstateSwapCheckoutViewProps): ReactNode {\n switch (state.type) {\n case 'content':\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-6',\n 'clcosdk:md:grid-cols-[minmax(0,11fr)_minmax(0,8fr)] clcosdk:md:gap-x-12',\n className\n )}\n >\n <div className=\"clcosdk:order-2 clcosdk:flex clcosdk:min-w-0 clcosdk:flex-col clcosdk:gap-4 clcosdk:md:order-1\">\n <SuperstateWalletView state={state.wallet} onEvent={onEvent} />\n <SuperstateAmountView state={state.amount} onEvent={onEvent} />\n <SuperstateReviewView state={state.review} onEvent={onEvent} />\n </div>\n\n <aside className=\"clcosdk:order-1 clcosdk:min-w-0 clcosdk:md:order-2\">\n <SuperstateSidebarView state={state.sidebar} />\n </aside>\n </div>\n\n <SuperstateOrderConfirmed\n state={state.orderConfirmed}\n onEvent={onEvent}\n />\n </CoinListStyleScope>\n );\n case 'error':\n return (\n <ErrorView\n reason={state.reason}\n onEvent={onEvent}\n className={className}\n />\n );\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\n/**\n * The whole flow failed to load, so there is nothing to lay out beside.\n *\n * The retry is offered only where it can help. `ON_RETRY_LOAD` re-runs the\n * fetch rather than reloading the document — the SDK owns the request, not the\n * page it is mounted in — and there is no fetch to re-run on a chain with no\n * contract deployed, so that arm gets copy and no button.\n */\nfunction ErrorView({\n reason,\n onEvent,\n className,\n}: {\n reason: SuperstateSwapLoadErrorReason;\n onEvent: (event: SuperstateSwapCheckoutUiEvent) => void;\n className?: string;\n}): ReactNode {\n const canRetry = reason === 'load-failed';\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:min-w-0 clcosdk:flex-col',\n 'clcosdk:items-center clcosdk:gap-4 clcosdk:py-12 clcosdk:text-center',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:items-center clcosdk:gap-2\">\n <h2\n className={cn(\n typeClasses.h3,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {canRetry ? ERROR_TITLE : UNSUPPORTED_CHAIN_TITLE}\n </h2>\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:max-w-md clcosdk:text-text-secondary'\n )}\n >\n {canRetry ? ERROR_DESCRIPTION : UNSUPPORTED_CHAIN_DESCRIPTION}\n </p>\n </div>\n {canRetry && (\n <ClButton\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_RETRY_LOAD' })}\n >\n {RETRY_LABEL}\n </ClButton>\n )}\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport {\n tokenMetadataOf,\n useCheckoutOfferTokenMetadata,\n} from '@/client/hooks/checkout/shared/data/useCheckoutOfferTokenMetadata';\nimport {\n type SuperstateAmountStepInput,\n useSuperstateAmountViewModel,\n} from '@/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel';\nimport { useSwapOutputToken } from '@/client/hooks/checkout/superstate/swap/data/useSwapOutputToken';\nimport { useSwapQuote } from '@/client/hooks/checkout/superstate/swap/data/useSwapQuote';\nimport {\n type SuperstateOrderPlaced,\n type SuperstateReviewStepInput,\n useSuperstateReviewViewModel,\n} from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel';\nimport { useSuperstateSidebarViewModel } from '@/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel';\nimport type {\n SuperstateOrderConfirmedUiState,\n SuperstateSwapCheckoutUiEvent,\n SuperstateSwapCheckoutUiState,\n} from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel.types';\nimport {\n type SuperstateWalletStepInput,\n useSuperstateWalletViewModel,\n} from '@/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { offerAssetIconUrl } from '@/client/ui/format/asset-icon';\nimport type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport {\n DEFAULT_AMOUNT_TO_COMPUTE_PRICE,\n SWAP_POLL_INTERVAL_MS,\n superstateSwapContractAddress,\n} from '@/universal/core/checkout/superstate/constants';\nimport {\n getNetworkName,\n txExplorerUrl,\n} from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formattedUsdPrice,\n shortenAddress,\n usdAmount,\n} from '@/universal/core/shared/blockchain/formatters';\nimport {\n TOKEN_REGISTRY,\n USDC,\n} from '@/universal/core/shared/blockchain/token-registry';\nimport {\n BlockchainAmount,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { AssetIconUrl } from '@/universal/types/blockchain/ui';\nimport type { SuperstateSwapOfferDetail } from '@/universal/types/offer-detail';\n\n/**\n * Which step is being filled in, carrying everything the ones before it\n * settled.\n *\n * A union rather than a step index plus nullable fields: the amount step cannot\n * run without an authorized wallet, and the review step cannot run without an\n * amount, so neither is representable here.\n */\nexport type SuperstateSwapStep =\n | { type: 'wallet' }\n | { type: 'amount'; wallet: EvmWallet }\n | {\n type: 'review';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n };\n\nexport interface UseSuperstateSwapCheckoutViewModelOptions {\n /**\n * The offer being bought: names the asset, the window and the minimum.\n *\n * Fixed for the lifetime of the hook — see the note on\n * {@link useSuperstateSwapCheckoutViewModel} about switching offers.\n */\n offer: SuperstateSwapOfferDetail;\n /**\n * The chain the order executes on: the balance reads, the approval and the\n * swap. The swap contract is looked up from it; a chain with none deployed\n * puts the whole flow in its `error` arm.\n *\n * Fixed for the lifetime of the hook, as `offer` is.\n */\n chain: EthereumChain;\n /** The host's wallets, and the lambdas that connect and disconnect one. */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. When `false` nothing is fetched and no timer runs, for a\n * checkout that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /**\n * Fired once the swap has mined. The confirmation dialog shows either way;\n * this is for a host that wants to navigate, refresh a portfolio, or log.\n */\n onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;\n}\n\nexport interface UseSuperstateSwapCheckoutViewModelResult {\n state: SuperstateSwapCheckoutUiState;\n onEvent: (event: SuperstateSwapCheckoutUiEvent) => void;\n}\n\n/**\n * Drives the whole Superstate swap checkout: the three steps, the sale panel\n * beside them, and the dialog that closes the flow.\n *\n * It owns the step machine and both polls. The quote poll lives here because it\n * is shared — the panel prices from it and the review step trades on it — and\n * because what it quotes for depends on how far the flow has got: a nominal\n * dollar until an amount is confirmed, and the confirmed amount after that.\n * Quoting each keystroke would fire a request per character and make the\n * panel's price jump while the user types.\n *\n * Unlike Ondo's checkout there is a flow-level `error`. The swap's output token\n * is read once and everything else is derived from it, so a failure there is\n * not localisable to one region: the panel, the review step and the\n * confirmation dialog would each have to invent an asset.\n *\n * `offer` and `chain` are read as fixed for the lifetime of the hook. The step\n * machine holds progress that is bound to both — a Superstate wallet\n * authorization is allow-listed per offer, and the ERC-20 approval the swap\n * spends is granted per chain — so changing either in place would carry a\n * completed step onto an offer it was never made against. Remount instead: give\n * the component holding this hook a `key` that changes with the offer and the\n * chain, as {@link CheckoutContainer} documents. That discards the flow with\n * its component instance, which is the only reset that cannot land between an\n * approval and the broadcast it was granted for.\n */\nexport function useSuperstateSwapCheckoutViewModel({\n offer,\n chain,\n wallets,\n enabled = true,\n onOrderConfirmed,\n}: UseSuperstateSwapCheckoutViewModelOptions): UseSuperstateSwapCheckoutViewModelResult {\n const locale = useLocale();\n\n const contractAddress = superstateSwapContractAddress(chain);\n\n const [step, setStep] = useState<SuperstateSwapStep>({ type: 'wallet' });\n // The placed order, not its rendering: the dialog's asset is derived during\n // render (see `uiState`), so a registry lookup that settles while the order\n // is being placed still reaches the dialog instead of the fallback icon the\n // completion callback captured.\n const [orderConfirmed, setOrderConfirmed] =\n useState<SuperstateOrderPlaced | null>(null);\n\n const { inputAmount, inputTokenAddress } = quoteInput(step, chain);\n\n // A chain with no contract has nothing to read, quote or trade against, so\n // every hook below is turned off as surely as `enabled: false` would.\n const live = enabled && contractAddress !== null;\n // Stands in only while `live` is false, when nothing is fetched with it.\n const contract = contractAddress ?? NO_CONTRACT;\n\n // The output asset's icon, registry-first: the offer's `tokens` entry for\n // this chain keys the lookup, and the offer's own logo covers an unlisted\n // token and the time before the answer arrives.\n const { state: offerTokenMetadataState } = useCheckoutOfferTokenMetadata({\n offer,\n chain,\n enabled: live,\n });\n const assetIconUrl = offerAssetIconUrl(\n offer,\n tokenMetadataOf(offerTokenMetadataState)\n );\n\n const { outputTokenState, refetch: refetchOutputToken } = useSwapOutputToken({\n contractAddress: contract,\n chain,\n enabled: live,\n });\n const outputToken =\n outputTokenState.type === 'CONTENT' ? outputTokenState.outputToken : null;\n\n const { quote, isRefreshing: isQuoteRefreshing } = useSwapQuote({\n contractAddress: contract,\n chain,\n inputAmount,\n inputTokenAddress,\n outputTokenDecimals: outputToken?.decimals ?? null,\n pollIntervalMs: SWAP_POLL_INTERVAL_MS,\n enabled: live,\n });\n\n const { state: walletState, onEvent: onWalletEvent } =\n useSuperstateWalletViewModel({\n stepInput: walletStepInput(step),\n wallets,\n offerId: offer.id,\n contractAddress: contract,\n chain,\n onComplete: (wallet) => setStep({ type: 'amount', wallet }),\n onEdit: () => setStep({ type: 'wallet' }),\n });\n\n const { state: amountState, onEvent: onAmountEvent } =\n useSuperstateAmountViewModel({\n stepInput: amountStepInput(\n step,\n offer.options[0]?.minimumPurchaseUsd ?? null\n ),\n chain,\n // Both transitions read the step through the updater rather than the one\n // this render closed over. Confirming an amount is synchronous here, but\n // the wallet step's Edit stays live, so a reopened step must not be\n // overwritten by a transition the user has already walked away from.\n onComplete: ({ amount, inputAsset }) => {\n setStep((current) =>\n current.type === 'amount'\n ? { type: 'review', wallet: current.wallet, amount, inputAsset }\n : current\n );\n },\n onEdit: () => {\n setStep((current) =>\n current.type === 'review'\n ? { type: 'amount', wallet: current.wallet }\n : current\n );\n },\n enabled: live,\n });\n\n const { state: reviewState, onEvent: onReviewEvent } =\n useSuperstateReviewViewModel({\n stepInput: reviewStepInput(step, {\n outputToken,\n quote,\n isQuoteRefreshing,\n }),\n contractAddress: contract,\n chain,\n assetIconUrl,\n onComplete: (order) => {\n setOrderConfirmed(order);\n // The quote is spent and the allowance with it, so what is left behind\n // the dialog is a fresh checkout rather than a filled-in one. The\n // wallet stays allow-listed on-chain, so choosing it again is quick.\n setStep({ type: 'wallet' });\n onOrderConfirmed?.(order);\n },\n });\n\n const { state: sidebarState } = useSuperstateSidebarViewModel({\n offer,\n chain,\n assetIconUrl,\n outputToken,\n quote,\n enabled: live,\n });\n\n const uiState = (): SuperstateSwapCheckoutUiState => {\n if (contractAddress === null) {\n return { type: 'error', reason: 'unsupported-chain' };\n }\n if (outputTokenState.type === 'ERROR') {\n return { type: 'error', reason: 'load-failed' };\n }\n return {\n type: 'content',\n wallet: walletState,\n amount: amountState,\n review: reviewState,\n sidebar: sidebarState,\n // Derived here rather than in the review completion callback, so a\n // registry lookup that settles while the order is being placed still\n // reaches the dialog instead of the fallback icon that closure captured.\n orderConfirmed:\n orderConfirmed === null\n ? { type: 'hidden' }\n : toOrderConfirmedUi({\n order: orderConfirmed,\n chain,\n locale,\n assetIconUrl,\n }),\n };\n };\n\n // The event union is flat, so this is one switch rather than a nested one.\n // Every tag belongs to exactly one step, which is why the edit events are\n // `ON_EDIT_WALLET` and `ON_EDIT_AMOUNT` rather than a shared `ON_EDIT`.\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over each step's own handler for this render, so a memo could\n // only ever hand back a stale one.\n const onEvent = (event: SuperstateSwapCheckoutUiEvent) => {\n switch (event.type) {\n case 'ON_SELECT_WALLET':\n case 'ON_CONNECT_WALLET':\n case 'ON_DISCONNECT_WALLET':\n case 'ON_CONFIRM_WALLET':\n case 'ON_EDIT_WALLET':\n onWalletEvent(event);\n return;\n case 'ON_AMOUNT_CHANGE':\n case 'ON_MAX_AMOUNT_CLICK':\n case 'ON_SELECT_PAY_WITH':\n case 'ON_PREVIEW_ORDER':\n case 'ON_EDIT_AMOUNT':\n onAmountEvent(event);\n return;\n case 'ON_SLIPPAGE_CLICK':\n case 'ON_SLIPPAGE_SELECT':\n case 'ON_PLACE_ORDER':\n onReviewEvent(event);\n return;\n case 'ON_CLOSE_ORDER_CONFIRMED':\n setOrderConfirmed(null);\n return;\n case 'ON_RETRY_LOAD':\n refetchOutputToken();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n/**\n * Stands in for the swap contract on a chain that has none.\n *\n * Never sent anywhere: `live` is false whenever this is in play, so no hook\n * below fetches with it, and the flow renders its `error` arm. React hooks must\n * render unconditionally, which is why a placeholder is needed at all.\n */\nconst NO_CONTRACT = EvmContractAddress(\n '0x0000000000000000000000000000000000000000'\n);\n\n// ---------------------------------------------------------------------------\n// The quote's input\n// ---------------------------------------------------------------------------\n\n/**\n * What the quote is priced for.\n *\n * Before an amount is confirmed there is nothing to quote but a nominal one\n * dollar, which is enough to derive a price per share for the panel. From the\n * review step on it is the real amount, because that quote is the one the user\n * trades on.\n */\nfunction quoteInput(\n step: SuperstateSwapStep,\n chain: EthereumChain\n): { inputAmount: BlockchainAmount; inputTokenAddress: EvmContractAddress } {\n // The input asset is USDC on every chain the SDK models: it is the only\n // member of `SUPERSTATE_SUPPORTED_INPUT_ASSETS`, and its registry table is\n // total, so the address is never null.\n const inputTokenAddress = TOKEN_REGISTRY.usdcAddress(chain);\n switch (step.type) {\n case 'wallet':\n case 'amount':\n return {\n inputAmount: BlockchainAmount({\n raw: DEFAULT_AMOUNT_TO_COMPUTE_PRICE,\n decimals: USDC.decimals,\n }),\n inputTokenAddress,\n };\n case 'review':\n return {\n inputAmount: step.amount,\n inputTokenAddress,\n };\n default: {\n const exhaustive: never = step;\n return exhaustive;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Step inputs\n// ---------------------------------------------------------------------------\n\nfunction walletStepInput(step: SuperstateSwapStep): SuperstateWalletStepInput {\n return step.type === 'wallet'\n ? { type: 'active' }\n : { type: 'completed', wallet: step.wallet };\n}\n\nfunction amountStepInput(\n step: SuperstateSwapStep,\n minimumPurchaseUsd: number | null\n): SuperstateAmountStepInput {\n switch (step.type) {\n case 'wallet':\n return { type: 'incomplete' };\n case 'amount':\n return { type: 'active', wallet: step.wallet, minimumPurchaseUsd };\n case 'review':\n return {\n type: 'complete',\n wallet: step.wallet,\n amount: step.amount,\n inputAsset: step.inputAsset,\n };\n default: {\n const exhaustive: never = step;\n return exhaustive;\n }\n }\n}\n\n/**\n * The review step waits on two things the flow polls for it. Until both have\n * landed it is `loading` rather than `active`: a review screen with no quote\n * has no figures on it at all.\n */\nfunction reviewStepInput(\n step: SuperstateSwapStep,\n quoteContext: {\n outputToken: Erc20Asset | null;\n quote: SwapQuote | null;\n isQuoteRefreshing: boolean;\n }\n): SuperstateReviewStepInput {\n if (step.type !== 'review') return { type: 'incomplete' };\n\n const { outputToken, quote, isQuoteRefreshing } = quoteContext;\n if (outputToken === null || quote === null) return { type: 'loading' };\n\n return {\n type: 'active',\n wallet: step.wallet,\n inputAsset: step.inputAsset,\n inputAmount: step.amount,\n outputAsset: outputToken,\n quote,\n isQuoteRefreshing,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The confirmation dialog\n// ---------------------------------------------------------------------------\n\n/**\n * The dialog is a projection of the swap that just settled: every figure comes\n * from the mined transaction, so nothing here can disagree with what actually\n * happened — the output amount is decoded from the `Swapped` event rather than\n * taken from the quote the user approved.\n *\n * With one exception, which travels with the order rather than being smoothed\n * over here: a receipt whose event will not decode leaves `executeSwap` no\n * choice but the quote's estimate, and `outputAmountConfirmed` says so. It is\n * passed through unchanged for the dialog to caption, because the difference\n * between what arrived and what was predicted to is the user's to know.\n */\nfunction toOrderConfirmedUi({\n order,\n chain,\n locale,\n assetIconUrl,\n}: {\n order: SuperstateOrderPlaced;\n chain: EthereumChain;\n locale: string;\n assetIconUrl: AssetIconUrl | null;\n}): SuperstateOrderConfirmedUiState {\n return {\n type: 'visible',\n asset: CheckoutAssetUi.fromErc20(order.outputAsset, {\n networkName: getNetworkName(chain),\n iconUrl: assetIconUrl,\n }),\n outputAmount: assetAmount(\n formatAmount(order.outputAmount, locale),\n order.outputAsset.symbol\n ),\n outputAmountConfirmed: order.outputAmountConfirmed,\n totalCost: usdAmount(\n formatAmount(BlockchainAmount.add(order.inputAmount, order.fee), locale)\n ),\n pricePerShare: formattedUsdPrice(order.pricePerShare, locale),\n recipientAddress: shortenAddress(order.recipientAddress),\n txExplorerUrl: txExplorerUrl(chain, order.swapTxHash),\n };\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport {\n CheckoutAssetUi,\n type CheckoutSelectableInputAssetUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateAmountUiEvent,\n SuperstateAmountUiState,\n} from '@/client/hooks/checkout/superstate/swap/amount/useSuperstateAmountViewModel.types';\nimport { useErc20TokenBalances } from '@/client/hooks/shared/erc20/useErc20TokenBalances';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { stablecoinIconUrl } from '@/client/ui/format/asset-icon';\nimport {\n SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n SWAP_POLL_INTERVAL_MS,\n} from '@/universal/core/checkout/superstate/constants';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n shortenAddress,\n usdAmount,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/universal/core/shared/blockchain/math';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n type AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type EthereumChain,\n EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\n\n/** Stands in for a wallet address while the step is not active and nothing is read. */\nconst NO_WALLET = EvmWalletAddress(\n '0x0000000000000000000000000000000000000000'\n);\n\nconst INVALID_AMOUNT = 'Invalid amount';\nconst AMOUNT_ZERO = 'Amount must be greater than 0.';\n\n/** How much the user is spending, and what they are spending it in. */\nexport type SuperstateAmountConfirmed = {\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n};\n\nexport type SuperstateAmountStepInput =\n | { type: 'incomplete' }\n | {\n type: 'active';\n /** The wallet confirmed in step 1: it holds the funds and signs. */\n wallet: EvmWallet;\n /** The offer's minimum, in whole USD. `null` when it publishes none. */\n minimumPurchaseUsd: number | null;\n }\n | {\n type: 'complete';\n wallet: EvmWallet;\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n };\n\nexport interface UseSuperstateAmountViewModelOptions {\n stepInput: SuperstateAmountStepInput;\n /** The chain the order executes on: balances, and the token addresses. */\n chain: EthereumChain;\n /** Called with the amount the user settled on. */\n onComplete: (confirmed: SuperstateAmountConfirmed) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n /**\n * Default `true`. `false` stops the balance poll outright, for a step that is\n * mounted beside another provider's checkout and not on screen.\n *\n * Separate from the step being active: a checkout can be turned off while\n * sitting on this step, and the poll has to stop for that too.\n */\n enabled?: boolean;\n}\n\nexport interface UseSuperstateAmountViewModelResult {\n state: SuperstateAmountUiState;\n onEvent: (event: SuperstateAmountUiEvent) => void;\n}\n\n/**\n * Drives step 2 of the Superstate checkout: how much to spend, and which asset\n * to spend it in.\n *\n * Everything is local. No approval is submitted and no quote is committed —\n * `executeSwap` on the review step does both together — so confirming is\n * synchronous and every failure is a validation message under the field.\n *\n * The checks run in the order that costs the user least to correct: the shape\n * of what they typed, then zero, then the offer's minimum, then their balance.\n * The balance is checked last because it is the one that depends on a network\n * read, and a mistyped amount should not wait on it.\n */\nexport function useSuperstateAmountViewModel({\n stepInput,\n chain,\n onComplete,\n onEdit,\n enabled = true,\n}: UseSuperstateAmountViewModelOptions): UseSuperstateAmountViewModelResult {\n const locale = useLocale();\n\n const [amountInput, setAmountInput] = useState('');\n const [selectedAsset, setSelectedAsset] = useState<StablecoinSymbol>(\n SUPERSTATE_SUPPORTED_INPUT_ASSETS[0]\n );\n const [error, setError] = useState<string | null>(null);\n\n const isActive = stepInput.type === 'active';\n const networkName = getNetworkName(chain);\n\n const { balances, isLoading: balancesLoading } = useErc20TokenBalances({\n address:\n stepInput.type === 'incomplete' ? NO_WALLET : stepInput.wallet.address,\n chain,\n assets: SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n pollIntervalMs: SWAP_POLL_INTERVAL_MS,\n // Both conditions: the step being active says the balance is worth reading,\n // and `enabled` says anyone is looking. A checkout turned off while parked\n // on this step satisfies the first and not the second.\n enabled: enabled && isActive,\n });\n\n // Start over when the user leaves the step, so reopening it does not restore\n // an amount they have since abandoned.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n setAmountInput('');\n setSelectedAsset(SUPERSTATE_SUPPORTED_INPUT_ASSETS[0]);\n setError(null);\n }\n }, [stepInput.type]);\n\n const selectedBalance = balances.get(selectedAsset) ?? null;\n const selectedErc20 = TOKEN_REGISTRY.erc20(selectedAsset);\n\n const uiState = (): SuperstateAmountUiState => {\n switch (stepInput.type) {\n case 'incomplete':\n return { type: 'incomplete' };\n case 'active':\n return {\n type: 'active',\n amountInput,\n walletAddress: shortenAddress(stepInput.wallet.address),\n inputAssets: SUPERSTATE_SUPPORTED_INPUT_ASSETS.map((symbol) =>\n toInputAssetUi({\n symbol,\n balance: balances.get(symbol) ?? null,\n selected: symbol === selectedAsset,\n networkName,\n locale,\n })\n ),\n // A balance is what the amount is validated against, so previewing\n // before one has arrived could only guess.\n confirmEnabled: amountInput.trim() !== '' && !balancesLoading,\n error,\n };\n case 'complete': {\n const formatted = formatAmount(stepInput.amount, locale);\n return {\n type: 'complete',\n inputAsset: CheckoutAssetUi.fromErc20(\n TOKEN_REGISTRY.erc20(stepInput.inputAsset),\n {\n networkName,\n iconUrl: stablecoinIconUrl(stepInput.inputAsset),\n }\n ),\n amountFormatted: usdAmount(formatted),\n inputAmountFormatted: assetAmount(\n formatted,\n TOKEN_REGISTRY.erc20(stepInput.inputAsset).symbol\n ),\n };\n }\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n const previewOrder = () => {\n if (stepInput.type !== 'active') return;\n\n const validated = validateSuperstateAmount({\n input: amountInput,\n decimals: selectedErc20.decimals,\n balance: selectedBalance,\n symbol: selectedErc20.symbol,\n minimumPurchaseUsd: stepInput.minimumPurchaseUsd,\n });\n if (!validated.valid) {\n setError(validated.error);\n return;\n }\n\n setError(null);\n onComplete({ amount: validated.amount, inputAsset: selectedAsset });\n };\n\n /**\n * Ignores a symbol the checkout does not fund. The event carries a plain\n * `AssetSymbol` (the View knows nothing of stablecoins), so this is the seam\n * where it becomes one of the assets actually on offer.\n */\n const selectInputAsset = (symbol: AssetSymbol) => {\n const supported = SUPERSTATE_SUPPORTED_INPUT_ASSETS.find(\n (candidate) => candidate === symbol\n );\n if (supported === undefined) return;\n setSelectedAsset(supported);\n setError(null);\n };\n\n const fillMaxAmount = () => {\n if (selectedBalance === null) return;\n setAmountInput(\n formatRawAmount(\n BlockchainAmount({\n raw: selectedBalance,\n decimals: selectedErc20.decimals,\n })\n )\n );\n setError(null);\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step, the typed amount and the balances this render was\n // given, so a memo could only ever hand back a stale one.\n const onEvent = (event: SuperstateAmountUiEvent) => {\n switch (event.type) {\n case 'ON_AMOUNT_CHANGE':\n setAmountInput(event.value);\n setError(null);\n return;\n case 'ON_MAX_AMOUNT_CLICK':\n fillMaxAmount();\n return;\n case 'ON_SELECT_PAY_WITH':\n selectInputAsset(event.value);\n return;\n case 'ON_PREVIEW_ORDER':\n previewOrder();\n return;\n case 'ON_EDIT_AMOUNT':\n onEdit();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nexport type SuperstateAmountValidation =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; error: string };\n\n/**\n * Whether the typed amount is one the swap could actually be made for.\n *\n * A free function rather than a closure, so it can be unit-tested against every\n * boundary — empty, zero, one wei under the minimum, exactly the balance —\n * without mounting a hook.\n *\n * Provider-qualified where the rest of this step is not, because\n * `src/client/index.ts` is a flat `export *` barrel and Ondo's amount step\n * already publishes a `validateAmount` with different rules.\n *\n * An unknown balance passes. A dropped balance read is not evidence the user\n * cannot afford the swap, and the contract will reject a genuine shortfall\n * anyway; blocking on it would strand a user whose node is having a bad minute.\n */\nexport function validateSuperstateAmount({\n input,\n decimals,\n balance,\n symbol,\n minimumPurchaseUsd,\n}: {\n input: string;\n decimals: AssetDecimals;\n balance: bigint | null;\n symbol: AssetSymbol;\n minimumPurchaseUsd: number | null;\n}): SuperstateAmountValidation {\n const parsed = parseBlockchainAmount(input, decimals);\n if (!parsed.valid) return { valid: false, error: INVALID_AMOUNT };\n\n const amount = parsed.amount;\n if (amount.raw === 0n) return { valid: false, error: AMOUNT_ZERO };\n\n if (minimumPurchaseUsd !== null) {\n const minimum = parseBlockchainAmount(String(minimumPurchaseUsd), decimals);\n if (minimum.valid && amount.raw < minimum.amount.raw) {\n return {\n valid: false,\n error: `Minimum purchase is $${minimumPurchaseUsd}.`,\n };\n }\n }\n\n if (balance !== null && amount.raw > balance) {\n return {\n valid: false,\n error: `Insufficient funds. Add more ${symbol} to your wallet to continue.`,\n };\n }\n\n return { valid: true, amount };\n}\n\n// ---------------------------------------------------------------------------\n// Assets, as cards\n// ---------------------------------------------------------------------------\n\nfunction toInputAssetUi({\n symbol,\n balance,\n selected,\n networkName,\n locale,\n}: {\n symbol: StablecoinSymbol;\n /** `null` before the first balance read settles, and after one that failed. */\n balance: bigint | null;\n selected: boolean;\n networkName: string;\n locale: string;\n}): CheckoutSelectableInputAssetUi {\n const erc20 = TOKEN_REGISTRY.erc20(symbol);\n const raw = balance ?? 0n;\n\n return {\n symbol: erc20.symbol,\n asset: CheckoutAssetUi.fromErc20(erc20, {\n networkName,\n iconUrl: stablecoinIconUrl(symbol),\n }),\n balance: assetAmount(\n formatAmount(BlockchainAmount({ raw, decimals: erc20.decimals }), locale),\n erc20.symbol\n ),\n rawBalance: raw,\n selected,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type {\n Erc20Asset,\n EthereumChain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\n\n/**\n * The state of the swap's output-token fetch.\n *\n * - `LOADING`: no result yet (initial, or provider still initializing).\n * - `ERROR`: the fetch failed.\n * - `CONTENT`: the output token was fetched successfully.\n *\n * A stale `CONTENT`/`ERROR` is preserved while a re-fetch (e.g. after a chain\n * change) is in flight, rather than flipping back to `LOADING`.\n */\nexport type SwapOutputTokenState =\n | { type: 'LOADING' }\n | { type: 'ERROR' }\n | { type: 'CONTENT'; outputToken: Erc20Asset };\n\nexport interface UseSwapOutputTokenOptions {\n /** The swap contract whose output token to read. */\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n /** When false, the hook does not fetch. */\n enabled: boolean;\n}\n\nexport interface UseSwapOutputTokenResult {\n outputTokenState: SwapOutputTokenState;\n /**\n * Runs the fetch again after a failure.\n *\n * The output token is read once and never polled, so `ERROR` is otherwise\n * terminal until a dependency changes — and without it there is no quote,\n * no price and no minimum received, which is why the Superstate checkout\n * surfaces it as a whole-flow failure with a retry rather than as one\n * unavailable corner.\n */\n refetch: () => void;\n}\n\nconst LOADING_STATE: SwapOutputTokenState = { type: 'LOADING' };\n\n/**\n * Fetches the ERC-20 output token a swap contract pays out. Re-fetches when the\n * contract or chain changes, and once when `enabled` flips to true.\n *\n * The fetch runs once (no polling); a failure resolves to `ERROR` and is not\n * retried until a dependency changes.\n */\nexport function useSwapOutputToken(\n options: UseSwapOutputTokenOptions\n): UseSwapOutputTokenResult {\n const { contractAddress, chain, enabled } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useSwapOutputToken');\n\n const [outputTokenState, setOutputTokenState] =\n useState<SwapOutputTokenState>(LOADING_STATE);\n /**\n * Bumped by `refetch` to re-run the effect below.\n *\n * A counter rather than a lambda that fetches directly, so a retry goes\n * through the same `fetchIdRef` guard as every other run and cannot race the\n * one it replaces. The effect never reads it — it is a dependency and nothing\n * else, which is why the lint rule below has to be silenced by hand.\n */\n const [retryCount, setRetryCount] = useState(0);\n\n const fetchIdRef = useRef(0);\n\n const refetch = useCallback(() => {\n setOutputTokenState(LOADING_STATE);\n setRetryCount((count) => count + 1);\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `retryCount` is the retry trigger. The body deliberately never reads it — bumping it is the whole mechanism — so the rule sees it as extraneous, and taking it out makes `refetch()` silently do nothing.\n useEffect(() => {\n if (!enabled || !isReady) return;\n const currentFetchId = ++fetchIdRef.current;\n\n const load = async () => {\n try {\n const outputToken = await coinlist.superstate.getOutputToken({\n contractAddress,\n chain,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', symbol: outputToken.symbol },\n }));\n setOutputTokenState({ type: 'CONTENT', outputToken });\n } catch (error) {\n if (currentFetchId !== fetchIdRef.current) return;\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR' } }),\n error\n );\n setOutputTokenState({ type: 'ERROR' });\n }\n };\n\n load();\n\n return () => {\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, contractAddress, chain, enabled, retryCount, log]);\n\n return { outputTokenState, refetch };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport { SWAP_POLL_INTERVAL_MS } from '@/universal/core/checkout/superstate/constants';\nimport type {\n AssetDecimals,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\n\nexport interface UseSwapQuoteOptions {\n /** The swap contract to quote against. */\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n /** The gross amount the user wants to swap, in the input token. */\n inputAmount: BlockchainAmount;\n inputTokenAddress: EvmContractAddress;\n /**\n * Decimals of the swap's output token. Quoting is skipped until this is\n * known (e.g. while {@link useSwapOutputToken} is still loading).\n */\n outputTokenDecimals: AssetDecimals | null;\n /** How often to refresh the quote. Defaults to {@link SWAP_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseSwapQuoteResult {\n /** The latest quote, or `null` until the first successful fetch. */\n quote: SwapQuote | null;\n /** True until the first quote arrives; false while the hook is disabled. */\n isLoading: boolean;\n /** True while a background poll refreshes an existing quote. */\n isRefreshing: boolean;\n}\n\n/**\n * Polls a read-only swap quote for `inputAmount` of `inputTokenAddress` against\n * the given swap contract, refreshing every `pollIntervalMs`.\n *\n * A failed fetch is swallowed: the last quote stays visible and the next poll\n * tick retries. Quoting is skipped while `outputTokenDecimals` is `null` or\n * `enabled` is false, and until the CoinList provider finishes initializing.\n */\nexport function useSwapQuote(options: UseSwapQuoteOptions): UseSwapQuoteResult {\n const {\n contractAddress,\n chain,\n inputAmount,\n inputTokenAddress,\n outputTokenDecimals,\n pollIntervalMs = SWAP_POLL_INTERVAL_MS,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useSwapQuote');\n\n const [quote, setQuote] = useState<SwapQuote | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefreshing, setIsRefreshing] = useState(false);\n\n const isFetchingRef = useRef(false);\n const hasQuoteRef = useRef(false);\n const fetchIdRef = useRef(0);\n\n useEffect(() => {\n if (!isReady) return;\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n\n const loadQuote = async () => {\n if (outputTokenDecimals === null) return;\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n if (hasQuoteRef.current) {\n setIsRefreshing(true);\n }\n\n try {\n const preview = await coinlist.superstate.getPreview({\n contractAddress,\n chain,\n inputToken: inputTokenAddress,\n amount: inputAmount.raw,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n\n setQuote(\n SwapQuote.fromPreview(\n preview,\n inputAmount.decimals,\n outputTokenDecimals\n )\n );\n if (!hasQuoteRef.current) {\n hasQuoteRef.current = true;\n setIsLoading(false);\n }\n } catch (error) {\n // Swallow: whatever quote is on screen stands and the next tick\n // retries, so this never reaches an error state and is never an\n // `error` line. The namespace already recorded the classified failure.\n log.warning(\n () => ({ msg: 'poll failed; retrying on the next tick' }),\n error\n );\n } finally {\n if (currentFetchId === fetchIdRef.current) {\n isFetchingRef.current = false;\n setIsRefreshing(false);\n }\n }\n };\n\n loadQuote();\n const interval = setInterval(loadQuote, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n setIsRefreshing(false);\n };\n }, [\n coinlist,\n isReady,\n contractAddress,\n chain,\n inputAmount.raw,\n inputAmount.decimals,\n inputTokenAddress,\n outputTokenDecimals,\n pollIntervalMs,\n enabled,\n log,\n ]);\n\n return { quote, isLoading, isRefreshing };\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport type { Hash } from 'viem';\nimport type {\n SwapExecutionError,\n SwapExecutionPhase,\n} from '@/client/core/checkout/superstate/swap-flows';\nimport {\n CheckoutAssetUi,\n type CheckoutCtaUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateReviewUiEvent,\n SuperstateReviewUiState,\n SuperstateSlippageUi,\n} from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { computeSlip } from '@/universal/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport {\n DEFAULT_SLIPPAGE_BPS,\n SLIPPAGE_OPTIONS_BPS,\n} from '@/universal/core/checkout/superstate/constants';\nimport { formattedPricePerShare } from '@/universal/core/checkout/superstate/formatters';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatBpsAsPercent,\n shortenAddress,\n usdAmount,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/universal/core/shared/blockchain/token-registry';\nimport {\n BlockchainAmount,\n type Bps,\n type Erc20Asset,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { AssetIconUrl } from '@/universal/types/blockchain/ui';\n\n/** What the swap actually filled at, once it has mined. */\nexport type SuperstateOrderPlaced = {\n swapTxHash: Hash;\n wallet: EvmWallet;\n inputAsset: StablecoinSymbol;\n /** The input the contract pulled, excluding the fee. */\n inputAmount: BlockchainAmount;\n fee: BlockchainAmount;\n outputAsset: Erc20Asset;\n /**\n * How much arrived. Decoded from the `Swapped` event, except on the fallback\n * path `outputAmountConfirmed` marks.\n */\n outputAmount: BlockchainAmount;\n /**\n * Whether `outputAmount` came from the receipt rather than from the quote.\n *\n * `false` means the swap mined but its `Swapped` event would not decode, so\n * the quote's estimate is standing in. A host that shows the number owes the\n * user that distinction; the SDK's own dialog labels the row as an estimate.\n * `pricePerShare` is computed from the same number and carries the same\n * caveat.\n */\n outputAmountConfirmed: boolean;\n /** `null` when the fill produced no output to divide by. */\n pricePerShare: BlockchainAmount | null;\n recipientAddress: EvmWalletAddress;\n};\n\nexport type SuperstateReviewStepInput =\n | { type: 'incomplete' }\n /** No quote at all yet for the amount the user confirmed. */\n | { type: 'loading' }\n | {\n type: 'active';\n /** The wallet authorized in step 1: it pays, signs and receives. */\n wallet: EvmWallet;\n inputAsset: StablecoinSymbol;\n /** What the user committed to spend, gross of the fee. */\n inputAmount: BlockchainAmount;\n outputAsset: Erc20Asset;\n quote: SwapQuote;\n /** True while a poll is repricing the quote on screen. */\n isQuoteRefreshing: boolean;\n };\n\nexport interface UseSuperstateReviewViewModelOptions {\n stepInput: SuperstateReviewStepInput;\n /** The swap contract the order is sent to. */\n contractAddress: EvmContractAddress;\n /** The chain the order executes on: the approval and the swap. */\n chain: EthereumChain;\n /**\n * The output asset's icon, resolved registry-first by the flow above:\n * the offer's logo covers an unlisted token.\n */\n assetIconUrl: AssetIconUrl | null;\n /** Called once the swap has mined. */\n onComplete: (order: SuperstateOrderPlaced) => void;\n}\n\nexport interface UseSuperstateReviewViewModelResult {\n state: SuperstateReviewUiState;\n onEvent: (event: SuperstateReviewUiEvent) => void;\n}\n\n/**\n * Drives step 3 of the Superstate checkout: what the swap comes to, and placing\n * it.\n *\n * Placing does everything at once — a status check, an ERC-20 approval and the\n * swap itself — so the CTA reports the on-chain phase as loading copy and every\n * failure comes back as copy above the button. Nothing was approved on the\n * amount step, which is why a Superstate order costs two wallet prompts here\n * rather than one on each of two steps.\n *\n * The quote on screen is a live one, repriced by the flow's poll. See\n * {@link quoteMismatch} for why a quote that asks for more than the user offered\n * is a failure rather than something to render.\n */\nexport function useSuperstateReviewViewModel({\n stepInput,\n contractAddress,\n chain,\n assetIconUrl,\n onComplete,\n}: UseSuperstateReviewViewModelOptions): UseSuperstateReviewViewModelResult {\n const { coinlist, isReady } = useCoinList();\n const locale = useLocale();\n\n const [slippageBps, setSlippageBps] = useState<Bps>(DEFAULT_SLIPPAGE_BPS);\n const [slippageExpanded, setSlippageExpanded] = useState(false);\n const [phase, setPhase] = useState<SwapExecutionPhase | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n // Start over when the user reopens an earlier step, so a stale failure or an\n // open picker does not greet them when they come back.\n useEffect(() => {\n if (stepInput.type === 'incomplete') {\n setSlippageBps(DEFAULT_SLIPPAGE_BPS);\n setSlippageExpanded(false);\n setPhase(null);\n setError(null);\n }\n }, [stepInput.type]);\n\n const uiState = (): SuperstateReviewUiState => {\n switch (stepInput.type) {\n case 'incomplete':\n return { type: 'incomplete' };\n case 'loading':\n return { type: 'loading' };\n case 'active': {\n const { quote, inputAmount, isQuoteRefreshing } = stepInput;\n const total = BlockchainAmount.add(quote.inputTokenAmount, quote.fee);\n\n if (quoteOverAsks({ total, inputAmount, isQuoteRefreshing })) {\n return { type: 'error' };\n }\n if (quoteIsStale({ total, inputAmount, isQuoteRefreshing })) {\n return { type: 'loading' };\n }\n\n const inputSymbol = TOKEN_REGISTRY.erc20(stepInput.inputAsset).symbol;\n const minOutput = computeSlip(quote.outputTokenAmount, slippageBps);\n\n return {\n type: 'active',\n outputAsset: CheckoutAssetUi.fromErc20(stepInput.outputAsset, {\n networkName: getNetworkName(chain),\n iconUrl: assetIconUrl,\n }),\n outputAmount: assetAmount(\n formatAmount(quote.outputTokenAmount, locale),\n stepInput.outputAsset.symbol\n ),\n minOutputAmount: assetAmount(\n formatAmount(minOutput, locale),\n stepInput.outputAsset.symbol\n ),\n recipientAddress: shortenAddress(stepInput.wallet.address),\n pricePerShare: formattedPricePerShare(quote, locale),\n coinlistFee: assetAmount(\n formatAmount(quote.fee, locale),\n inputSymbol\n ),\n total: usdAmount(formatAmount(total, locale)),\n slippage: slippageUi(),\n placeOrderCta: placeOrderCta(),\n error,\n };\n }\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n const slippageUi = (): SuperstateSlippageUi => {\n const percent = formatBpsAsPercent(slippageBps, locale);\n return {\n percent,\n expanded: slippageExpanded,\n description: `If the price moves more than ${percent} before your order fills, it will be cancelled.`,\n options: SLIPPAGE_OPTIONS_BPS.map((bps) => ({\n bps,\n percent: formatBpsAsPercent(bps, locale),\n selected: bps === slippageBps,\n })),\n };\n };\n\n const placeOrderCta = (): CheckoutCtaUi => {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n return isReady ? { type: 'enabled' } : { type: 'disabled' };\n };\n\n const placeOrder = async () => {\n if (stepInput.type !== 'active' || phase !== null || !isReady) return;\n\n setError(null);\n setPhase('checking-status');\n\n const result = await coinlist.superstate.execute({\n wallet: stepInput.wallet,\n contractAddress,\n chain,\n // The input asset is USDC on every chain the SDK models (it is the\n // only member of `SUPERSTATE_SUPPORTED_INPUT_ASSETS`), and its\n // registry table is total, so the address is never null.\n inputTokenAddress: TOKEN_REGISTRY.usdcAddress(chain),\n quote: stepInput.quote,\n slippageBps,\n onProgress: setPhase,\n });\n setPhase(null);\n\n if (result.type === 'error') {\n setError(executionErrorMessage(result.error));\n return;\n }\n\n onComplete({\n swapTxHash: result.swapTxHash,\n wallet: stepInput.wallet,\n inputAsset: stepInput.inputAsset,\n inputAmount: result.inputAmount,\n fee: result.fee,\n outputAsset: stepInput.outputAsset,\n outputAmount: result.outputAmount,\n outputAmountConfirmed: result.outputAmountConfirmed,\n pricePerShare: result.pricePerShare,\n recipientAddress: result.recipientAddress,\n });\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the step and the tolerance this render was given, so a memo\n // could only ever hand back a stale one.\n const onEvent = (event: SuperstateReviewUiEvent) => {\n switch (event.type) {\n case 'ON_SLIPPAGE_CLICK':\n setSlippageExpanded((expanded) => !expanded);\n return;\n case 'ON_SLIPPAGE_SELECT':\n setSlippageBps(event.bps);\n return;\n case 'ON_PLACE_ORDER':\n void placeOrder();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// The quote, against what the user offered\n// ---------------------------------------------------------------------------\n\n/**\n * What the two functions below are told about the quote on screen.\n *\n * `total` is the quote's input plus its fee — what the contract would actually\n * pull — and `inputAmount` is what the user confirmed on the amount step. The\n * two are compared rather than assumed equal because the quote is repriced on a\n * poll and the amount is not.\n */\ntype QuoteAgainstOffer = {\n total: BlockchainAmount;\n inputAmount: BlockchainAmount;\n /** True while a poll is repricing the quote. */\n isQuoteRefreshing: boolean;\n};\n\n/**\n * Whether the settled quote asks for more than the user agreed to spend.\n *\n * The contract may fill for *less* than the amount offered — a partial fill is\n * legitimate, and the difference simply stays in the wallet — but it must never\n * ask for more. A quote that does is either priced for a different order or a\n * bug, and either way there is no honest screen to render for it: the numbers\n * would say one thing and the transaction would pull another.\n *\n * Gated on `isQuoteRefreshing` because a poll in flight is the ordinary way to\n * observe a quote for the previous, larger amount. Only a settled quote is\n * evidence of a mismatch; one mid-refresh is evidence of nothing yet.\n */\nexport function quoteOverAsks({\n total,\n inputAmount,\n isQuoteRefreshing,\n}: QuoteAgainstOffer): boolean {\n return !isQuoteRefreshing && total.raw > inputAmount.raw;\n}\n\n/**\n * Whether the quote on screen still belongs to a previous amount.\n *\n * Only while a refresh is in flight: a settled quote for less than the offer is\n * a partial fill and is shown as-is, which is why this is not simply\n * `total !== inputAmount`. Rendering the skeleton here is more honest than\n * leaving the last order's figures up with a spinner beside them.\n */\nexport function quoteIsStale({\n total,\n inputAmount,\n isQuoteRefreshing,\n}: QuoteAgainstOffer): boolean {\n return isQuoteRefreshing && total.raw !== inputAmount.raw;\n}\n\n// ---------------------------------------------------------------------------\n// Execution copy\n// ---------------------------------------------------------------------------\n\n/** What the user reads while each step of the swap runs. */\nfunction phaseMessage(phase: SwapExecutionPhase): string {\n switch (phase) {\n case 'checking-status':\n return 'Checking swap availability…';\n case 'checking-allowance':\n return 'Checking token allowance…';\n case 'resetting-allowance':\n return 'Reset approval in your wallet…';\n case 'confirming-allowance-reset':\n return 'Resetting approval…';\n case 'approving':\n return 'Approve spending in your wallet…';\n case 'confirming-approval':\n return 'Confirming approval…';\n case 'swapping':\n return 'Confirm the swap in your wallet…';\n case 'confirming-swap':\n return 'Confirming swap…';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\n/**\n * Why the swap failed, in the user's terms.\n *\n * The two wallet-driven steps look at the classified cause as well as the step,\n * because a rejected prompt, an empty gas tank and a timeout are the same step\n * and completely different problems.\n */\nfunction executionErrorMessage(error: SwapExecutionError): string {\n switch (error.step) {\n case 'status-check':\n return \"Couldn't verify swap availability. Please try again.\";\n case 'swap-paused':\n return 'Swapping is currently paused. Please check back soon.';\n case 'swap-stopped':\n return 'This swap has been permanently closed.';\n case 'allowance-check':\n return 'Failed to check token allowance. Please try again.';\n case 'approval':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Approval rejected. Please try again.';\n case 'insufficient_funds':\n return 'Insufficient funds to complete this transaction. Please try again.';\n default:\n return 'Failed to approve token spending. Please try again.';\n }\n case 'approval-reverted':\n return 'Failed to approve token spending. Please try again.';\n case 'swap':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Swap rejected. Please try again.';\n case 'insufficient_funds':\n return 'Insufficient funds to complete this transaction. Please try again.';\n case 'timeout':\n return 'Swap timed out. Please check your wallet and try again.';\n default:\n return 'Failed to complete the swap. Please try again.';\n }\n case 'swap-reverted':\n return 'Failed to complete the swap. Please try again.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n","/**\n * How many units a countdown shows at once.\n *\n * Two: enough to be precise about what matters and short enough to fit a\n * sidebar row. `2d 3h` rather than `2d 3h 14m 7s`, which reads as a stopwatch\n * and changes every second for no one's benefit.\n */\nconst MAX_UNITS = 2;\n\nconst SECONDS_PER_MINUTE = 60;\nconst SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;\nconst SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;\n\n/** The units a countdown is built from, largest first. */\nconst UNITS: { suffix: string; seconds: number }[] = [\n { suffix: 'd', seconds: SECONDS_PER_DAY },\n { suffix: 'h', seconds: SECONDS_PER_HOUR },\n { suffix: 'm', seconds: SECONDS_PER_MINUTE },\n { suffix: 's', seconds: 1 },\n];\n\nconst ZERO = '0s';\n\n/**\n * A whole-second duration as a short countdown, e.g. `2d 3h`, `14m 7s`, `9s`.\n *\n * Takes seconds rather than a `Date` so it composes with `useCountdown`, which\n * re-reads the clock and hands back exactly this. Keeping the tick and the copy\n * apart is what lets one countdown serve a sale window, a quote expiry and a\n * resend timer without any of them having to agree on wording.\n *\n * Zero, negative and non-finite all render `0s`: a deadline that has passed is\n * not a negative countdown, and the caller decides what \"over\" means — the\n * Superstate sidebar switches to `Sale ended` rather than rendering this at\n * all.\n *\n * Leading zero units are dropped and trailing ones kept, so a two-minute\n * countdown reads `2m 0s` rather than `0d 0h`, and an hour reads `1h 0m` rather\n * than jumping between one unit and two as the clock runs down.\n *\n * Deliberately not localized: the unit letters are copy, and the SDK ships\n * hardcoded English until the i18n effort lands. `Intl.RelativeTimeFormat` is\n * not a substitute — it renders one unit (\"in 2 days\"), not two.\n */\nexport function formatCountdown(totalSeconds: number): string {\n if (!Number.isFinite(totalSeconds) || totalSeconds < 1) return ZERO;\n\n let remaining = Math.floor(totalSeconds);\n const counts = UNITS.map((unit) => {\n const count = Math.floor(remaining / unit.seconds);\n remaining -= count * unit.seconds;\n return count;\n });\n\n const firstSignificant = counts.findIndex((count) => count > 0);\n if (firstSignificant === -1) return ZERO;\n\n return counts\n .slice(firstSignificant, firstSignificant + MAX_UNITS)\n .map(\n (count, offset) => `${count}${UNITS[firstSignificant + offset].suffix}`\n )\n .join(' ');\n}\n\n/**\n * Live-sale chrome countdown, e.g. `3D 19H 42M`.\n *\n * Always three uppercase units and no seconds, matching Clay's sale card.\n * Distinct from {@link formatCountdown}, which stays two mixed-case units for\n * checkout sidebars.\n *\n * A positive remainder under a minute clamps to `0D 0H 1M`: the card shows the\n * live dot next to this string, and a live sale reading `0D 0H 0M` would\n * contradict the dot. That all-zero string is reserved for `ended` — and the\n * status label for that never calls this function.\n */\nexport function formatSaleCardCountdown(totalSeconds: number): string {\n if (!Number.isFinite(totalSeconds) || totalSeconds < 1) {\n return '0D 0H 0M';\n }\n\n const remaining = Math.max(Math.floor(totalSeconds), SECONDS_PER_MINUTE);\n const days = Math.floor(remaining / SECONDS_PER_DAY);\n const hours = Math.floor((remaining % SECONDS_PER_DAY) / SECONDS_PER_HOUR);\n const minutes = Math.floor(\n (remaining % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE\n );\n return `${days}D ${hours}H ${minutes}M`;\n}\n","'use client';\n\nimport {\n CheckoutAssetUi,\n type CheckoutStatusUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type {\n SuperstateSidebarPriceUi,\n SuperstateSidebarUiState,\n} from '@/client/hooks/checkout/superstate/swap/sidebar/useSuperstateSidebarViewModel.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { formatCountdown } from '@/client/ui/format/duration';\nimport { useCountdown } from '@/client/ui/hooks/useCountdown';\nimport type { SwapQuote } from '@/universal/core/checkout/superstate/blockchain/quote';\nimport {\n SUPERSTATE_ISSUER_NAME,\n SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n} from '@/universal/core/checkout/superstate/constants';\nimport { formattedPricePerShare } from '@/universal/core/checkout/superstate/formatters';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport {\n formatAmount,\n NA_AMOUNT_ASSET_UI,\n usdAmount,\n} from '@/universal/core/shared/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/universal/core/shared/blockchain/math';\nimport {\n TOKEN_REGISTRY,\n USDC,\n} from '@/universal/core/shared/blockchain/token-registry';\nimport {\n AssetSymbol,\n type Erc20Asset,\n type EthereumChain,\n} from '@/universal/types/blockchain/core';\nimport type {\n AssetIconUrl,\n FormattedAmountAssetUi,\n} from '@/universal/types/blockchain/ui';\nimport type { SuperstateSwapOfferDetail } from '@/universal/types/offer-detail';\n\nconst SALE_ENDED = 'Sale ended';\nconst SALE_OPEN = 'Sale open';\n\nexport interface UseSuperstateSidebarViewModelOptions {\n /** The offer being bought: names the asset, the window and the minimum. */\n offer: SuperstateSwapOfferDetail;\n /** The chain the token lives on, which names the network row. */\n chain: EthereumChain;\n /**\n * The output asset's icon, resolved by the flow above: registry-first,\n * with the offer's logo as the fallback.\n */\n assetIconUrl: AssetIconUrl | null;\n /**\n * The swap's output token, or `null` while it is still being read. It names\n * the asset, so the panel's headline waits on it.\n */\n outputToken: Erc20Asset | null;\n /** The latest quote, or `null` until the first one lands. Prices the corner. */\n quote: SwapQuote | null;\n /**\n * Default `true`. `false` stops the sale-window tick, for a panel that is\n * mounted beside another provider's checkout and not on screen. The window it\n * reports stays correct; only the second-by-second re-read stops.\n */\n enabled?: boolean;\n}\n\nexport interface UseSuperstateSidebarViewModelResult {\n state: SuperstateSidebarUiState;\n}\n\n/**\n * Drives the panel beside the Superstate checkout.\n *\n * Everything here is derived — it holds no state of its own and starts no\n * request. The quote and the output token are polled by the flow above it,\n * because the review step needs them too and two polls would disagree.\n *\n * The sale window is the one live thing, and it ticks locally: `useCountdown`\n * re-reads the clock rather than decrementing, so a tab that was backgrounded\n * comes back with the truth.\n */\nexport function useSuperstateSidebarViewModel({\n offer,\n chain,\n assetIconUrl,\n outputToken,\n quote,\n enabled = true,\n}: UseSuperstateSidebarViewModelOptions): UseSuperstateSidebarViewModelResult {\n const locale = useLocale();\n // Two ticks, because the window has two boundaries and the panel's copy\n // changes at both. Each stops on its own once its deadline has passed, since\n // `remainingSeconds` clamps at zero and the value stops moving.\n const secondsUntilStart = useCountdown({ until: offer.startsAt, enabled });\n const secondsLeft = useCountdown({ until: offer.endsAt, enabled });\n\n const state: SuperstateSidebarUiState = {\n asset: assetUi(offer, outputToken, chain, assetIconUrl),\n issuer: SUPERSTATE_ISSUER_NAME,\n sale: saleUi({\n endsAt: offer.endsAt,\n secondsUntilStart,\n secondsLeft,\n }),\n networkName: getNetworkName(chain),\n purchaseOptionsLabel: SUPERSTATE_SUPPORTED_INPUT_ASSETS.map(\n (symbol) => TOKEN_REGISTRY.erc20(symbol).symbol\n ).join(', '),\n minPurchase: minPurchaseUi(\n offer.options[0]?.minimumPurchaseUsd ?? null,\n locale\n ),\n price: priceUi(quote, outputToken, locale),\n };\n\n return { state };\n}\n\n/**\n * The asset headline.\n *\n * Named by the output token rather than by the offer, because the token is what\n * lands in the wallet and the offer's name is marketing copy. The icon is the\n * caller's to supply — an `Erc20Asset` carries none — and the flow above passes\n * in `offerAssetIconUrl`'s registry-first resolution.\n */\nfunction assetUi(\n offer: SuperstateSwapOfferDetail,\n outputToken: Erc20Asset | null,\n chain: EthereumChain,\n assetIconUrl: AssetIconUrl | null\n): CheckoutAssetUi {\n const networkName = getNetworkName(chain);\n if (outputToken === null) {\n return {\n name: offer.name,\n // The offer's asset code, not the token's symbol: they usually agree, but\n // the token is what settles the question and it has not been read yet.\n symbol: AssetSymbol(offer.asset.code),\n iconUrl: assetIconUrl,\n network: { name: networkName, iconUrl: null },\n };\n }\n return CheckoutAssetUi.fromErc20(outputToken, {\n networkName,\n iconUrl: assetIconUrl,\n });\n}\n\n/**\n * Whether the sale is running, and the copy for it.\n *\n * Three boundaries rather than one, in the order they occur. A sale whose\n * `startsAt` is still in the future has not begun, which a countdown to\n * `endsAt` cannot see — it would have reported a sale opening next week as\n * already running.\n *\n * Open-endedness is read off `endsAt` itself rather than off a `null`\n * countdown. `useCountdown` returns `null` both for a deadline it was given\n * none of and for one it is not watching, and neither means the sale is over:\n * an offer with no `endsAt` is running until someone says otherwise, and\n * treating it as ended would have shown `Sale ended` for a sale that never\n * ends.\n */\nfunction saleUi({\n endsAt,\n secondsUntilStart,\n secondsLeft,\n}: {\n endsAt: Date | null;\n /** Seconds until the window opens. Zero once it has. */\n secondsUntilStart: number | null;\n /** Seconds until it closes, or `null` for a sale with no close. */\n secondsLeft: number | null;\n}): CheckoutStatusUi {\n if (secondsUntilStart !== null && secondsUntilStart > 0) {\n return {\n type: 'inactive',\n label: `Starts in ${formatCountdown(secondsUntilStart)}`,\n };\n }\n if (endsAt === null) {\n return { type: 'active', label: SALE_OPEN };\n }\n if (secondsLeft === null || secondsLeft <= 0) {\n return { type: 'inactive', label: SALE_ENDED };\n }\n return { type: 'active', label: `Ends in ${formatCountdown(secondsLeft)}` };\n}\n\n/**\n * The offer's minimum as a USD amount.\n *\n * Parsed through `parseBlockchainAmount` at USDC's decimals rather than\n * formatted straight from the number, so the same rounding and grouping apply\n * here as to every other amount on the screen.\n */\nfunction minPurchaseUi(\n minimumPurchaseUsd: number | null,\n locale: string\n): FormattedAmountAssetUi {\n if (minimumPurchaseUsd === null) return NA_AMOUNT_ASSET_UI;\n\n const parsed = parseBlockchainAmount(\n String(minimumPurchaseUsd),\n USDC.decimals\n );\n return parsed.valid\n ? usdAmount(formatAmount(parsed.amount, locale))\n : NA_AMOUNT_ASSET_UI;\n}\n\n/**\n * The price corner: what one whole output token costs, derived from the quote.\n *\n * Both inputs are needed — the quote supplies the ratio and the output token\n * its decimals — so either one missing means there is nothing to price yet.\n */\nfunction priceUi(\n quote: SwapQuote | null,\n outputToken: Erc20Asset | null,\n locale: string\n): SuperstateSidebarPriceUi {\n if (quote === null || outputToken === null) return { type: 'loading' };\n return { type: 'known', price: formattedPricePerShare(quote, locale) };\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport type {\n WalletAuthorizationError,\n WalletAuthorizationPhase,\n} from '@/client/core/checkout/superstate/swap-flows';\nimport type {\n CheckoutConfirmedWalletUi,\n CheckoutCtaUi,\n CheckoutEmbeddedWalletUi,\n CheckoutWalletTypeUi,\n CheckoutWalletUi,\n} from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type {\n SuperstateWalletUiEvent,\n SuperstateWalletUiState,\n} from '@/client/hooks/checkout/superstate/swap/wallet/useSuperstateWalletViewModel.types';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { getNetworkName } from '@/universal/core/shared/blockchain/chain';\nimport { shortenAddress } from '@/universal/core/shared/blockchain/formatters';\nimport type {\n EthereumChain,\n EvmContractAddress,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type { EvmWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/universal/types/offer';\n\nconst CONNECT_FAILED = 'Could not connect that wallet. Please try again.';\n\n/**\n * Whether step 1 is being filled in or already answered.\n *\n * There is no `incomplete` arm: this is the first step, so it is never waiting\n * on one above it.\n */\nexport type SuperstateWalletStepInput =\n | { type: 'active' }\n | { type: 'completed'; wallet: EvmWallet };\n\nexport interface UseSuperstateWalletViewModelOptions {\n stepInput: SuperstateWalletStepInput;\n /** The host's wallets, and the lambdas that connect and disconnect one. */\n wallets: CheckoutWalletSelection;\n /**\n * The offer being bought. Allow-listing is per offer, not per contract, so\n * the challenge is bound to it.\n */\n offerId: OfferId;\n /** The swap contract the wallet is being authorized against. */\n contractAddress: EvmContractAddress;\n /** The chain the order executes on, which names the network on each row. */\n chain: EthereumChain;\n /** Called with the wallet once it is authorized to trade. */\n onComplete: (wallet: EvmWallet) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n}\n\nexport interface UseSuperstateWalletViewModelResult {\n state: SuperstateWalletUiState;\n onEvent: (event: SuperstateWalletUiEvent) => void;\n}\n\n/**\n * Drives step 1 of the Superstate checkout: which wallet funds the swap and\n * receives the asset.\n *\n * Unlike Ondo's equivalent, confirming does real work. A Superstate swap only\n * accepts allow-listed wallets, so the wallet has to prove ownership — a\n * signature, and a transaction where the contract needs one — before the flow\n * may move on. `authorizeWallet` is total, so every failure comes back as a\n * step tag this maps to copy under the rows, and a wallet that is already\n * allow-listed short-circuits to success without prompting at all.\n *\n * Connecting an external wallet stays the host's job: `connectExternal` opens\n * whatever connector it ships, and the result is read from `wallets.external`\n * on the next render rather than from a return value, so a connector that\n * redirects works as well as one that opens a modal.\n */\nexport function useSuperstateWalletViewModel({\n stepInput,\n wallets,\n offerId,\n contractAddress,\n chain,\n onComplete,\n onEdit,\n}: UseSuperstateWalletViewModelOptions): UseSuperstateWalletViewModelResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useSuperstateWalletViewModel');\n\n const [selected, setSelected] = useState<CheckoutWalletTypeUi | null>(null);\n const [phase, setPhase] = useState<WalletAuthorizationPhase | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const networkName = getNetworkName(chain);\n const selectedWallet = resolveWallet(wallets, selected);\n\n // Clear a stale failure once the step is answered, so reopening it later does\n // not greet the user with the error from an attempt that eventually worked.\n useEffect(() => {\n if (stepInput.type === 'completed') {\n setPhase(null);\n setError(null);\n }\n }, [stepInput.type]);\n\n const uiState = (): SuperstateWalletUiState => {\n switch (stepInput.type) {\n case 'active':\n return {\n type: 'active',\n embeddedWallets: wallets.embedded.map((wallet) =>\n toEmbeddedWalletUi(wallet, networkName, selected)\n ),\n externalWallet: toExternalWalletUi(\n wallets.external,\n networkName,\n selected\n ),\n // Disconnecting is offered whenever there is something to\n // disconnect: a user who connected the wrong account needs the way\n // out whether or not that row happens to be selected. Not while an\n // authorization runs, though — that wallet is mid-signature.\n canDisconnect: wallets.external !== null && phase === null,\n confirmCta: confirmCta(),\n error,\n };\n case 'completed':\n return {\n type: 'completed',\n wallet: toConfirmedWalletUi(wallets, stepInput.wallet),\n };\n default: {\n const exhaustive: never = stepInput;\n return exhaustive;\n }\n }\n };\n\n const confirmCta = (): CheckoutCtaUi => {\n if (phase !== null) {\n return { type: 'loading', message: phaseMessage(phase) };\n }\n // `isReady` gates as well as the selection: authorizing goes through the\n // client, and a client still initializing would throw rather than prompt.\n return selectedWallet !== null && isReady\n ? { type: 'enabled' }\n : { type: 'disabled' };\n };\n\n const confirmWallet = async () => {\n if (stepInput.type !== 'active' || phase !== null) return;\n const wallet = selectedWallet;\n if (wallet === null || !isReady) return;\n\n setError(null);\n setPhase('checking-authorization');\n\n // No guard is needed around the result: `phase` freezes selection,\n // connection and disconnection for as long as this runs, so the wallet this\n // resolves for is necessarily still the one the user chose. That freeze is\n // deliberate — an authorization waits on a signature and possibly on a\n // transaction being mined, and letting the choice move underneath it is how\n // a flow ends up funded from an address the user never picked.\n const result = await coinlist.superstate.authorizeWallet({\n wallet,\n offerId,\n contractAddress,\n chain,\n onProgress: setPhase,\n });\n setPhase(null);\n\n if (result.type === 'error') {\n setError(authorizationErrorMessage(result.error));\n return;\n }\n onComplete(wallet);\n };\n\n const selectWallet = (value: CheckoutWalletTypeUi) => {\n if (phase !== null) return;\n setError(null);\n // Ignore a selection the host cannot back with a wallet: the row it came\n // from has already gone.\n if (resolveWallet(wallets, value) === null) return;\n setSelected(value);\n };\n\n const connectWallet = async () => {\n if (phase !== null) return;\n setError(null);\n try {\n await wallets.connectExternal();\n } catch (error) {\n log.failure(\n () => ({ msg: 'the host connectExternal handler threw' }),\n error\n );\n setError(CONNECT_FAILED);\n return;\n }\n // The wallet itself arrives through `wallets.external` on the next render;\n // selecting the row is all this can do now.\n setSelected({ type: 'external' });\n };\n\n const disconnectWallet = async () => {\n if (phase !== null) return;\n setError(null);\n await wallets.disconnectExternal();\n setSelected((previous) =>\n previous?.type === 'external' ? null : previous\n );\n };\n\n // A plain function rather than a `useCallback`: every handler it dispatches\n // to closes over the wallets, the selection and the phase this render was\n // given, so a memo could only ever hand back a stale one.\n const onEvent = (event: SuperstateWalletUiEvent) => {\n switch (event.type) {\n case 'ON_SELECT_WALLET':\n selectWallet(event.value);\n return;\n case 'ON_CONNECT_WALLET':\n void connectWallet();\n return;\n case 'ON_DISCONNECT_WALLET':\n void disconnectWallet();\n return;\n case 'ON_CONFIRM_WALLET':\n void confirmWallet();\n return;\n case 'ON_EDIT_WALLET':\n onEdit();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n };\n\n return { state: uiState(), onEvent };\n}\n\n// ---------------------------------------------------------------------------\n// Authorization copy\n// ---------------------------------------------------------------------------\n\n/** What the user reads while each step of the authorization runs. */\nfunction phaseMessage(phase: WalletAuthorizationPhase): string {\n switch (phase) {\n case 'checking-authorization':\n return 'Verifying your wallet…';\n case 'requesting-challenge':\n return 'Requesting authorization challenge…';\n case 'signing-message':\n return 'Sign the message in your wallet…';\n case 'submitting-signature':\n return 'Submitting signature…';\n case 'broadcasting-transaction':\n return 'Broadcasting authorization transaction…';\n case 'awaiting-confirmation':\n return 'Waiting for transaction confirmation…';\n case 'verifying-authorization':\n return 'Verifying authorization on-chain…';\n default: {\n const exhaustive: never = phase;\n return exhaustive;\n }\n }\n}\n\n/**\n * Why the authorization failed, in the user's terms.\n *\n * Every arm names something the user can act on. The wallet-driven steps look\n * at the classified cause as well as the step, because a rejected prompt and a\n * failed broadcast are the same step and completely different problems.\n */\nfunction authorizationErrorMessage(error: WalletAuthorizationError): string {\n switch (error.step) {\n case 'authorization-check':\n return 'Failed to check wallet authorization. Please try again.';\n case 'challenge-request':\n return 'Failed to request authorization challenge. Please try again.';\n case 'signing':\n return error.cause.type === 'user_rejected'\n ? 'Signature rejected. Please try again.'\n : 'Failed to sign message. Please try again.';\n case 'allow-wallet':\n return 'Failed to submit signature. Please try again.';\n case 'broadcast':\n switch (error.cause.type) {\n case 'user_rejected':\n return 'Transaction rejected. Please try again.';\n case 'insufficient_funds':\n return 'Insufficient ETH for gas. Please add ETH to your wallet and try again.';\n case 'timeout':\n return 'Transaction timed out. Please check your wallet and try again.';\n default:\n return 'Failed to broadcast transaction. Please try again.';\n }\n case 'not-authorized':\n return 'Authorization not yet confirmed on-chain. Please try again shortly.';\n default: {\n const exhaustive: never = error;\n return exhaustive;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wallets, as rows\n// ---------------------------------------------------------------------------\n\n/**\n * The wallet a selection refers to, or `null` when the host no longer offers\n * it — an embedded wallet that disappeared, or an external row tapped before\n * anything is connected.\n */\nfunction resolveWallet(\n wallets: CheckoutWalletSelection,\n selected: CheckoutWalletTypeUi | null\n): EvmWallet | null {\n if (selected === null) return null;\n switch (selected.type) {\n case 'external':\n return wallets.external;\n case 'embedded':\n return findEmbedded(wallets, selected.address);\n default: {\n const exhaustive: never = selected;\n return exhaustive;\n }\n }\n}\n\nfunction findEmbedded(\n wallets: CheckoutWalletSelection,\n address: EvmWalletAddress\n): EvmWallet | null {\n return wallets.embedded.find((wallet) => wallet.address === address) ?? null;\n}\n\nfunction toEmbeddedWalletUi(\n wallet: EvmWallet,\n networkName: string,\n selected: CheckoutWalletTypeUi | null\n): CheckoutEmbeddedWalletUi {\n return {\n address: shortenAddress(wallet.address),\n network: networkName,\n selected:\n selected?.type === 'embedded' && selected.address === wallet.address,\n walletAddress: wallet.address,\n };\n}\n\nfunction toExternalWalletUi(\n wallet: EvmWallet | null,\n networkName: string,\n selected: CheckoutWalletTypeUi | null\n): CheckoutWalletUi | null {\n if (wallet === null) return null;\n return {\n address: shortenAddress(wallet.address),\n network: networkName,\n selected: selected?.type === 'external',\n };\n}\n\n/**\n * Which kind of wallet was confirmed, decided by whether the host lists it as\n * an embedded one. The two are shown differently: a CoinList wallet is named\n * as such, an external one is shown by address.\n */\nfunction toConfirmedWalletUi(\n wallets: CheckoutWalletSelection,\n wallet: EvmWallet\n): CheckoutConfirmedWalletUi {\n const isEmbedded = findEmbedded(wallets, wallet.address) !== null;\n return {\n type: isEmbedded ? 'embedded' : 'external',\n address: shortenAddress(wallet.address),\n };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { SuperstateSwapCheckoutView } from '@/client/components/checkout/superstate/swap/SuperstateSwapCheckoutView';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type { SuperstateOrderPlaced } from '@/client/hooks/checkout/superstate/swap/review/useSuperstateReviewViewModel';\nimport { useSuperstateSwapCheckoutViewModel } from '@/client/hooks/checkout/superstate/swap/useSuperstateSwapCheckoutViewModel';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport type { SuperstateSwapOfferDetail } from '@/universal/types/offer-detail';\n\nexport interface SuperstateSwapCheckoutContainerProps {\n /** The offer being bought: names the asset, the window and the minimum. */\n offer: SuperstateSwapOfferDetail;\n /**\n * The chain the order executes on: the balance reads, the approval and the\n * swap. The swap contract is looked up from it, so a chain with none\n * deployed renders the flow's error state rather than a broken checkout.\n */\n chain: EthereumChain;\n /**\n * The wallets the buyer can spend from, and the lambdas that connect and\n * disconnect an external one. The SDK ships no wallet stack, so this is how\n * a host plugs in Privy, AppKit, or its own.\n */\n wallets: CheckoutWalletSelection;\n /**\n * Default `true`. `false` turns off every request and timer, for a checkout\n * that is mounted but not on screen yet.\n */\n enabled?: boolean;\n /** Fired once the swap has mined. The dialog shows either way. */\n onOrderConfirmed?: (order: SuperstateOrderPlaced) => void;\n className?: string;\n}\n\n/**\n * The Superstate swap checkout, ready to drop in: three steps, the sale panel\n * beside them, and the dialog that closes the flow.\n *\n * Takes no contract address: it is looked up from `chain`, the way Ondo's is.\n * A partner who needs to point at a different deployment is below this rung and\n * calls `coinlist.superstate.execute` directly.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed around it.\n */\nexport function SuperstateSwapCheckoutContainer({\n offer,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n className,\n}: SuperstateSwapCheckoutContainerProps): ReactNode {\n const { state, onEvent } = useSuperstateSwapCheckoutViewModel({\n offer,\n chain,\n wallets,\n enabled,\n onOrderConfirmed,\n });\n\n return (\n <SuperstateSwapCheckoutView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","import type { CSSProperties } from 'react';\nimport { cn } from '@/client/components/design-system/utils';\n\n/** One image as an `<img>` takes it: a `src`, and `srcSet` candidates when it has any. */\nexport interface ThemedImageSource {\n src: string;\n srcSet?: string;\n}\n\nexport interface ThemedImageProps {\n /** The image for a light theme, and the only one when `dark` is absent. */\n light: ThemedImageSource;\n /** The image for a dark theme; omit it to render `light` on both. */\n dark?: ThemedImageSource;\n /**\n * The rendered width, as the `sizes` attribute spells it (`48px`,\n * `(min-width: 768px) 36px, 32px`). Only meaningful next to a `srcSet`, and\n * only forwarded when there is one.\n */\n sizes?: string;\n alt: string;\n width?: number;\n height?: number;\n /** Applied to each `<img>`. */\n className?: string;\n /** Applied to each `<img>`. */\n style?: CSSProperties;\n}\n\n/**\n * An image with an optional dark-theme counterpart.\n *\n * With a `dark` source it renders *both* `<img>`s, and only one is ever on\n * screen: `globals.css` sets `--display-on-light` / `--display-on-dark` to\n * `block` / `none` on the light theme and flips them on the dark one, and the\n * two classes here read those tokens. Rendering both and letting CSS choose\n * is deliberate: the SDK's theme is either the OS preference or\n * a `.dark` / `.light` ancestor, decided once in `globals.css` for every\n * colour token, and a `<picture>` with its own `prefers-color-scheme` media\n * query would disagree with a class-driven host. Two images cost one extra\n * request for a logo-sized file, which is cheaper than a theme that flips\n * the page and not the logo.\n *\n * Without a `dark` source it is a plain `<img>`, so a caller with one image\n * pays nothing for the option.\n */\nexport function ThemedImage({\n light,\n dark,\n sizes,\n alt,\n width,\n height,\n className,\n style,\n}: ThemedImageProps) {\n // `alt` stays explicit on each <img> rather than in the shared bag: the\n // a11y lint reads the attribute, not the spread.\n const shared = { width, height, style };\n\n if (!dark) {\n return (\n <img\n src={light.src}\n srcSet={light.srcSet}\n sizes={light.srcSet ? sizes : undefined}\n className={className}\n alt={alt}\n {...shared}\n />\n );\n }\n\n return (\n <>\n <img\n src={light.src}\n srcSet={light.srcSet}\n sizes={light.srcSet ? sizes : undefined}\n className={cn('clcosdk-on-light', className)}\n alt={alt}\n {...shared}\n />\n <img\n src={dark.src}\n srcSet={dark.srcSet}\n sizes={dark.srcSet ? sizes : undefined}\n className={cn('clcosdk-on-dark', className)}\n alt={alt}\n {...shared}\n />\n </>\n );\n}\n","import type { KeyboardEvent } from 'react';\n\n/** Enter / Space activate a whole-card hit target (`role=\"button\"`). */\nexport function onOfferCardKeyDown(\n event: KeyboardEvent<HTMLElement>,\n onClick: () => void\n): void {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n onClick();\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { ThemedImage } from '@/client/components/design-system/ThemedImage';\nimport { cn } from '@/client/components/design-system/utils';\nimport { onOfferCardKeyDown } from '@/client/components/offers/shared/offer-card-keyboard';\nimport type { OfferAssetCardUi } from '@/client/hooks/offers/shared/offer-asset-card.types';\n\n// The logo is 40px below `md` and 48px from it (`h-10` / `md:h-12`); `sizes`\n// tells the browser which `srcSet` candidate covers it at the screen's density.\nconst LOGO_SIZES = '(min-width: 768px) 48px, 40px';\n\nexport interface OfferAssetCardProps {\n offer: OfferAssetCardUi;\n /** When set, the whole card is the hit target. */\n onClick?: () => void;\n /** Optional className applied to the card root element. */\n className?: string;\n /** Optional className applied to an outer wrapper element. */\n containerClassName?: string;\n}\n\n/**\n * Light browse-row catalogue card. Self-scoped. Header is the offer's `logo`\n * (the token registry's where it lists the token, with its dark-theme\n * variant, the catalogue's otherwise) beside `name` (h2) and asset `symbol`\n * under it — not a wordmark.\n * Responsive hug: tighter pad / logo / type below `md`, desktop keeps the\n * H4 + 48px logo row. Hosts compose this beside {@link OfferSaleCard}; the\n * card does not pick a variant itself.\n */\nexport function OfferAssetCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: OfferAssetCardProps): ReactNode {\n const interactive = onClick !== undefined;\n\n const card = (\n <article\n className={cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:items-center clcosdk:rounded-[20px] clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-3 clcosdk:shadow-[0px_1px_1px_0px_rgba(10,10,10,0.04),0px_8px_12px_0px_rgba(10,10,10,0.08)]',\n 'clcosdk:md:rounded-card clcosdk:md:p-4',\n interactive &&\n 'clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100',\n className\n )}\n aria-label={interactive ? cardActionLabel(offer) : undefined}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n interactive ? (event) => onOfferCardKeyDown(event, onClick) : undefined\n }\n >\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:items-center clcosdk:gap-2.5 clcosdk:pr-3 clcosdk:md:gap-3 clcosdk:md:pr-4\">\n {offer.logo ? (\n <div className=\"clcosdk:h-10 clcosdk:w-10 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-12 clcosdk:md:w-12\">\n <ThemedImage\n light={offer.logo.light}\n dark={offer.logo.dark ?? undefined}\n sizes={LOGO_SIZES}\n alt=\"\"\n width={48}\n height={48}\n className=\"clcosdk:size-full clcosdk:object-cover\"\n style={{ maxWidth: 'none', width: '100%', height: '100%' }}\n />\n </div>\n ) : null}\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:flex-col clcosdk:items-start clcosdk:justify-center\">\n {offer.name ? (\n <h2\n className={cn(\n 'clcosdk:w-full clcosdk:truncate clcosdk:text-[16px] clcosdk:leading-[140%] clcosdk:font-medium clcosdk:text-text-primary clcosdk:md:text-[18px]'\n )}\n >\n {offer.name}\n </h2>\n ) : null}\n {offer.symbol ? (\n <p className=\"clcosdk:w-full clcosdk:truncate clcosdk:text-[13px] clcosdk:leading-[150%] clcosdk:font-normal clcosdk:text-text-secondary clcosdk:md:text-[14px]\">\n {offer.symbol}\n </p>\n ) : null}\n </div>\n </div>\n </article>\n );\n\n const wrapped = containerClassName ? (\n <div className={containerClassName}>{card}</div>\n ) : (\n card\n );\n\n return <CoinListStyleScope>{wrapped}</CoinListStyleScope>;\n}\n\nfunction cardActionLabel(offer: OfferAssetCardUi): string {\n const parts = [offer.name, offer.symbol].filter(Boolean);\n return parts.length > 0 ? parts.join(', ') : 'View offer';\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { cn } from '@/client/components/design-system/utils';\nimport { OfferAssetCard } from '@/client/components/offers/shared/OfferAssetCard';\nimport type { OfferAssetCardUi } from '@/client/hooks/offers/shared/offer-asset-card.types';\nimport type { OfferId } from '@/universal/types/offer';\n\n/** Platform equities / past-sales catalogue is at most 3 columns. */\nconst DEFAULT_MAX_COLUMNS = 3;\n\nexport interface OffersAssetGridProps {\n offers: OfferAssetCardUi[];\n /**\n * When set, each card is the hit target and reports its `OfferId`. Omit to\n * render a non-interactive browse grid.\n */\n onOfferClick?: (offerId: OfferId) => void;\n /** Maximum number of columns when horizontal space allows. Caps at platform 3. */\n maxColumns?: number;\n /** Optional className applied to the grid element. */\n className?: string;\n /** Optional className applied to the outer wrapper element. */\n containerClassName?: string;\n}\n\n/**\n * Responsive browse grid of {@link OfferAssetCard} leaves. Pure: no fetch, no\n * provider. Distinct from {@link OffersGridView}, which lays out live-sale\n * cards — hosts pick which grid to embed. Self-scoped. Mobile is one column;\n * then 2 from `sm`, and up to 3 from `md` when `maxColumns` allows.\n */\nexport function OffersAssetGrid({\n offers,\n onOfferClick,\n maxColumns,\n className,\n containerClassName,\n}: OffersAssetGridProps): ReactNode {\n const cols = Math.min(\n DEFAULT_MAX_COLUMNS,\n Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS)\n );\n // Desktop gap 24px (gap-6); tighter on mobile like the sale grid.\n const maxGridWidth = `calc(${cols} * 20rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;\n const interactive = onOfferClick !== undefined;\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:justify-center',\n containerClassName\n )}\n >\n <div\n className={cn(\n 'clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6',\n cols >= 2 && 'clcosdk:sm:grid-cols-2',\n cols >= 3 && 'clcosdk:md:grid-cols-3',\n className\n )}\n style={{ maxWidth: maxGridWidth }}\n >\n {offers.map((offer) => (\n <OfferAssetCard\n key={offer.id}\n offer={offer}\n onClick={interactive ? () => onOfferClick(offer.id) : undefined}\n />\n ))}\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { ArrowRight } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { ThemedImage } from '@/client/components/design-system/ThemedImage';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { onOfferCardKeyDown } from '@/client/components/offers/shared/offer-card-keyboard';\nimport {\n type SaleCardStatusPhase,\n saleCardStatus,\n} from '@/client/components/offers/shared/sale-card-status';\nimport type { OfferSaleCardUi } from '@/client/hooks/offers/shared/offer-sale-card.types';\nimport { useCountdown } from '@/client/ui/hooks/useCountdown';\n\n// The header logo is 32px below `md` and 36px from it (`h-8` / `md:h-9`);\n// the watermark is 15rem below `md` and 20rem from it. `sizes` tells the\n// browser which `srcSet` candidate covers each at the screen's density.\nconst HEADER_LOGO_SIZES = '(min-width: 768px) 36px, 32px';\nconst WATERMARK_SIZES = '(min-width: 768px) 20rem, 15rem';\n\nexport interface OfferSaleCardProps {\n offer: OfferSaleCardUi;\n /** Host click handler. View offer always renders; this wires the hit target. */\n onClick?: () => void;\n /** Optional className applied to the card root element. */\n className?: string;\n /** Optional className applied to an outer wrapper element. */\n containerClassName?: string;\n}\n\n/**\n * Dark live-sale catalogue card. Self-scoped. Header is the offer's `logo`\n * (the token registry's where it lists the token, the catalogue's otherwise)\n * beside the `name` as an h2, then the tagline — not a wordmark. The same\n * logo is painted as a faint right-shifted watermark over the gradient.\n * Responsive hug layout; View offer always renders. No token price, FDV or unlock.\n */\nexport function OfferSaleCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: OfferSaleCardProps): ReactNode {\n const secondsUntilStart = useCountdown({ until: offer.startsAt });\n const secondsLeft = useCountdown({ until: offer.endsAt });\n const status = saleCardStatus({\n endsAt: offer.endsAt,\n secondsUntilStart,\n secondsLeft,\n });\n const interactive = onClick !== undefined;\n // The card's chrome is always dark (see `--sale-card-surface`), whatever the\n // page theme, so the registry's dark-theme logo is the right one whenever\n // it exists - the page theme decides nothing here.\n const logo = offer.logo ? (offer.logo.dark ?? offer.logo.light) : null;\n\n const card = (\n <article\n className={cn(\n 'clcosdk:relative clcosdk:flex clcosdk:h-full clcosdk:w-full clcosdk:flex-col clcosdk:gap-4 clcosdk:overflow-hidden clcosdk:rounded-[28px] clcosdk:border-2 clcosdk:border-sale-card-border clcosdk:bg-[image:var(--sale-card-surface)] clcosdk:p-5 clcosdk:shadow-[0px_4px_12px_0px_rgba(0,0,0,0.08),0px_12px_28px_0px_rgba(0,0,0,0.13)]',\n 'clcosdk:md:gap-6 clcosdk:md:rounded-[40px] clcosdk:md:p-8',\n interactive &&\n 'clcosdk:group clcosdk:cursor-pointer clcosdk:transition-transform clcosdk:duration-300 clcosdk:ease-out clcosdk:hover:scale-[1.02] clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-sale-card-focus-ring clcosdk:focus-visible:ring-offset-2 clcosdk:focus-visible:outline-none clcosdk:max-md:hover:scale-100',\n className\n )}\n aria-label={\n interactive ? cardActionLabel(offer, status.phase) : undefined\n }\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n interactive ? (event) => onOfferCardKeyDown(event, onClick) : undefined\n }\n >\n {logo ? (\n <div\n aria-hidden=\"true\"\n className=\"clcosdk:pointer-events-none clcosdk:absolute clcosdk:top-1/2 clcosdk:right-[-14%] clcosdk:z-0 clcosdk:size-[15rem] clcosdk:-translate-y-1/2 clcosdk:md:right-[-10%] clcosdk:md:size-[20rem]\"\n style={{ mixBlendMode: 'overlay' }}\n >\n <ThemedImage\n light={logo}\n sizes={WATERMARK_SIZES}\n alt=\"\"\n className=\"clcosdk:size-full clcosdk:rounded-full clcosdk:object-cover\"\n style={{ maxWidth: 'none', width: '100%', height: '100%' }}\n />\n </div>\n ) : null}\n\n <div className=\"clcosdk:relative clcosdk:z-10 clcosdk:flex clcosdk:flex-col clcosdk:gap-2 clcosdk:md:gap-3\">\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2.5 clcosdk:md:gap-3\">\n {logo ? (\n <div className=\"clcosdk:h-8 clcosdk:w-8 clcosdk:shrink-0 clcosdk:overflow-hidden clcosdk:rounded-full clcosdk:md:h-9 clcosdk:md:w-9\">\n <ThemedImage\n light={logo}\n sizes={HEADER_LOGO_SIZES}\n alt=\"\"\n width={36}\n height={36}\n className=\"clcosdk:size-full clcosdk:object-cover\"\n style={{ maxWidth: 'none', width: '100%', height: '100%' }}\n />\n </div>\n ) : null}\n {offer.name ? (\n <h2\n className={cn(\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-medium clcosdk:text-sale-card-text clcosdk:md:text-[28px] clcosdk:md:leading-[120%]'\n )}\n >\n {offer.name}\n </h2>\n ) : null}\n </div>\n {offer.tagline ? (\n <p\n className={cn(\n typeClasses.bodySm,\n 'clcosdk:text-sale-card-text-muted clcosdk:md:text-[16px] clcosdk:md:leading-[160%]'\n )}\n >\n {offer.tagline}\n </p>\n ) : null}\n </div>\n\n <div className=\"clcosdk:relative clcosdk:z-10 clcosdk:mt-auto clcosdk:flex clcosdk:h-11 clcosdk:w-full clcosdk:min-w-0 clcosdk:items-center clcosdk:justify-between clcosdk:gap-2 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:py-1.5 clcosdk:pr-1.5 clcosdk:pl-3 clcosdk:md:h-[54px] clcosdk:md:gap-3 clcosdk:md:py-2 clcosdk:md:pr-2 clcosdk:md:pl-4\">\n <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:items-center clcosdk:gap-2 clcosdk:md:gap-3\">\n {status.phase === 'live' ? (\n <span\n className=\"clcosdk:relative clcosdk:inline-flex clcosdk:size-2 clcosdk:shrink-0\"\n aria-hidden=\"true\"\n >\n <span className=\"clcosdk-status-dot-ping clcosdk:absolute clcosdk:inset-0 clcosdk:rounded-full clcosdk:bg-positive\" />\n <span className=\"clcosdk:relative clcosdk:inline-flex clcosdk:size-full clcosdk:rounded-full clcosdk:bg-positive\" />\n </span>\n ) : null}\n <p\n className={cn(\n typeClasses.data,\n 'clcosdk:min-w-0 clcosdk:truncate clcosdk:text-sale-card-text'\n )}\n >\n {status.label}\n </p>\n </div>\n <span\n className={cn(\n 'clcosdk:inline-flex clcosdk:h-full clcosdk:shrink-0 clcosdk:items-center clcosdk:gap-1.5 clcosdk:rounded-full clcosdk:border clcosdk:border-sale-card-chrome-border clcosdk:bg-sale-card-chrome-bg clcosdk:px-3 clcosdk:text-sm clcosdk:font-semibold clcosdk:text-sale-card-text-strong clcosdk:md:px-6 clcosdk:md:text-base',\n interactive &&\n 'clcosdk:transition-[background-color,border-color] clcosdk:duration-500 clcosdk:ease-out clcosdk:group-hover:border-sale-card-chrome-emphasis-border clcosdk:group-hover:bg-sale-card-chrome-emphasis-bg clcosdk:group-focus-visible:border-sale-card-chrome-emphasis-border clcosdk:group-focus-visible:bg-sale-card-chrome-emphasis-bg'\n )}\n aria-hidden=\"true\"\n >\n View<span className=\"clcosdk:max-md:hidden\"> offer</span>\n <ArrowRight className=\"clcosdk:size-4\" aria-hidden />\n </span>\n </div>\n </article>\n );\n\n const wrapped = containerClassName ? (\n <div className={containerClassName}>{card}</div>\n ) : (\n card\n );\n\n return <CoinListStyleScope>{wrapped}</CoinListStyleScope>;\n}\n\nconst SALE_PHASE_LABEL: Record<SaleCardStatusPhase, string> = {\n upcoming: 'Upcoming',\n live: 'Live',\n ended: 'Ended',\n};\n\nfunction cardActionLabel(\n offer: OfferSaleCardUi,\n phase: SaleCardStatusPhase\n): string {\n // The phase word, not the ticking countdown: the countdown changes every\n // second, and re-announcing a changing label is noise. The phase is what a\n // screen-reader user needs to know which stage the sale is in.\n const title = offer.name || offer.tagline;\n return [title, SALE_PHASE_LABEL[phase], 'View offer']\n .filter(Boolean)\n .join('. ');\n}\n","import { formatSaleCardCountdown } from '@/client/ui/format/duration';\n\nexport type SaleCardStatusPhase = 'upcoming' | 'live' | 'ended';\n\n/**\n * Countdown / live / ended label for {@link OfferSaleCard}. Pure: takes the\n * same second-resolution values `useCountdown` returns so the leaf can tick\n * without baking clock logic into this helper. Only live shows a status dot.\n */\nexport function saleCardStatus({\n endsAt,\n secondsUntilStart,\n secondsLeft,\n}: {\n endsAt: Date | null;\n secondsUntilStart: number | null;\n secondsLeft: number | null;\n}): { phase: SaleCardStatusPhase; label: string } {\n if (secondsUntilStart !== null && secondsUntilStart > 0) {\n return {\n phase: 'upcoming',\n label: formatSaleCardCountdown(secondsUntilStart),\n };\n }\n if (endsAt === null) {\n return { phase: 'live', label: 'Live' };\n }\n if (secondsLeft === null || secondsLeft <= 0) {\n return { phase: 'ended', label: 'Ended' };\n }\n return {\n phase: 'live',\n label: formatSaleCardCountdown(secondsLeft),\n };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { OfferSaleCard } from '@/client/components/offers/shared/OfferSaleCard';\nimport type {\n OffersGridUiEvent,\n OffersGridUiState,\n} from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\nimport type { OfferSaleCardUi } from '@/client/hooks/offers/shared/offer-sale-card.types';\n\nconst DEFAULT_MAX_COLUMNS = 2;\n\nexport interface OffersGridViewProps {\n state: OffersGridUiState;\n onEvent: (event: OffersGridUiEvent) => void;\n /** Maximum number of columns to render when horizontal space allows. Caps at platform 2. */\n maxColumns?: number;\n /** Optional className applied to the grid element. */\n className?: string;\n /** Optional className applied to the outer wrapper element. */\n containerClassName?: string;\n /** Optional loading slot shown while offers are being fetched. */\n loading?: ReactNode;\n /** Optional error slot shown when loading offers fails. */\n error?: ReactNode;\n /** Optional empty state slot shown when there are no available offers. */\n emptyState?: ReactNode;\n}\n\n/**\n * Renders every state of the live-sale offers grid ({@link OfferSaleCard}).\n * Pure: it holds no state, fetches nothing, and reports clicks through\n * `onEvent`. Platform layout is at most 2×2 with 24px gaps on desktop (16px on\n * mobile, single column). For equities / past-sales browse rows, embed\n * {@link OffersAssetGrid} instead.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed.\n */\nexport function OffersGridView(props: OffersGridViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OffersGridViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OffersGridViewBody({\n state,\n onEvent,\n maxColumns,\n className,\n containerClassName,\n loading,\n error,\n emptyState,\n}: OffersGridViewProps): ReactNode {\n switch (state.type) {\n case 'loading':\n return loading ?? <LoadingState />;\n case 'error':\n return error ?? <ErrorState message={state.message} />;\n case 'empty':\n return emptyState ?? <EmptyState />;\n case 'content':\n return (\n <OffersGridContent\n offers={state.offers}\n interactive={state.interactive}\n onEvent={onEvent}\n maxColumns={maxColumns}\n className={className}\n containerClassName={containerClassName}\n />\n );\n default: {\n // A new UI state without a case here is a compile error.\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction OffersGridContent({\n offers,\n interactive,\n onEvent,\n maxColumns,\n className,\n containerClassName,\n}: {\n offers: OfferSaleCardUi[];\n interactive: boolean;\n onEvent: (event: OffersGridUiEvent) => void;\n maxColumns?: number;\n className?: string;\n containerClassName?: string;\n}): ReactNode {\n const cols = Math.min(\n DEFAULT_MAX_COLUMNS,\n Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS)\n );\n // Desktop gap 24px (gap-6); tighter on mobile to match sale-card chrome.\n const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;\n\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:justify-center',\n containerClassName\n )}\n >\n <div\n className={cn(\n 'clcosdk:grid clcosdk:w-full clcosdk:grid-cols-1 clcosdk:gap-4 clcosdk:md:gap-6',\n cols >= 2 && 'clcosdk:md:grid-cols-2',\n className\n )}\n style={{ maxWidth: maxGridWidth }}\n >\n {offers.map((offer) => (\n <OfferSaleCard\n key={offer.id}\n offer={offer}\n onClick={\n interactive\n ? () => onEvent({ type: 'ON_OFFER_CLICK', offerId: offer.id })\n : undefined\n }\n />\n ))}\n </div>\n </div>\n );\n}\n\nfunction LoadingState(): ReactNode {\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6\"\n >\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Loading offers...\n </p>\n </output>\n );\n}\n\nfunction ErrorState({ message }: { message: string }): ReactNode {\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={message}\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n );\n}\n\nfunction EmptyState(): ReactNode {\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:min-h-40 clcosdk:flex-col clcosdk:items-center clcosdk:justify-center clcosdk:gap-2 clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-center\"\n >\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n No offers available\n </p>\n <p className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}>\n Check back soon for upcoming opportunities.\n </p>\n </output>\n );\n}\n","'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport { useOffers } from '@/client/hooks/offers/data/useOffers';\nimport type {\n OffersGridUiEvent,\n OffersGridUiState,\n} from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\nimport { OfferSaleCardUi } from '@/client/hooks/offers/shared/offer-sale-card.types';\nimport {\n type LoadTokenRegistryState,\n useTokenRegistry,\n} from '@/client/hooks/shared/useTokenRegistry';\nimport { TokenRegistrySnapshot } from '@/universal/core/tokens/token-registry-snapshot';\nimport type { Offer } from '@/universal/types/offer';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * What the grid fetches, pre-fetched on the server instead. Each half is\n * independent: seed `offers` (via `CoinListServer#offers.list()`) and the\n * client still fetches the registry, seed `tokens` (via\n * `CoinListServer#tokens.list()`) and it still fetches the offers, seed both\n * and the grid makes no request of its own.\n */\nexport interface OffersGridData {\n offers?: Offer[];\n tokens?: TokenMetadata[];\n}\n\nexport interface UseOffersGridViewModelOptions {\n /** See {@link OffersGridData}. */\n data?: OffersGridData;\n /**\n * Default `true`. When `false` nothing is fetched, so the hook can be called\n * unconditionally while the grid is not needed yet.\n */\n enabled?: boolean;\n /** Called with the domain offer behind the card the user clicked. */\n onOfferClick?: (offer: Offer) => void;\n}\n\nexport interface UseOffersGridViewModelResult {\n state: OffersGridUiState;\n onEvent: (event: OffersGridUiEvent) => void;\n}\n\nconst NOT_AUTHENTICATED_MESSAGE = 'Sign in to view available offers.';\nconst GENERIC_ERROR_MESSAGE =\n 'Unable to load offers right now. Please try again.';\n\n/**\n * Drives {@link OffersGridView}: loads the offers and the public token\n * registry, formats each offer for its card - registry name and logo where\n * the registry lists its token, the offer's own fields otherwise - and\n * resolves a clicked card back to its domain offer for the host callback.\n *\n * The grid waits for both loads before showing content, so a card paints\n * once with its final artwork rather than flashing the catalogue logo and\n * then the registry's. A registry failure degrades rather than blanks: every\n * card falls back to the offer's own fields.\n *\n * Pass `enabled: false` to skip both fetches when the hook must be called but\n * the grid is not needed yet.\n */\nexport function useOffersGridViewModel(\n options: UseOffersGridViewModelOptions = {}\n): UseOffersGridViewModelResult {\n const { data, onOfferClick, enabled = true } = options;\n const { offersState } = useOffers({ data: data?.offers, enabled });\n const { state: registryState } = useTokenRegistry({\n data: data?.tokens,\n enabled,\n });\n\n const state = useMemo<OffersGridUiState>(\n () => toUiState(offersState, registryState, onOfferClick !== undefined),\n [offersState, registryState, onOfferClick]\n );\n\n const onEvent = useCallback(\n (event: OffersGridUiEvent) => {\n switch (event.type) {\n case 'ON_OFFER_CLICK': {\n if (offersState.type !== 'CONTENT' || !onOfferClick) {\n return;\n }\n const offer = offersState.offers.find((o) => o.id === event.offerId);\n if (offer) {\n onOfferClick(offer);\n }\n return;\n }\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event.type;\n return exhaustive;\n }\n }\n },\n [offersState, onOfferClick]\n );\n\n return { state, onEvent };\n}\n\nfunction toUiState(\n offersState: ReturnType<typeof useOffers>['offersState'],\n registryState: LoadTokenRegistryState,\n interactive: boolean\n): OffersGridUiState {\n switch (offersState.type) {\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR':\n return {\n type: 'error',\n message:\n offersState.reason === 'not-authenticated'\n ? NOT_AUTHENTICATED_MESSAGE\n : GENERIC_ERROR_MESSAGE,\n };\n case 'CONTENT': {\n if (offersState.offers.length === 0) {\n return { type: 'empty' };\n }\n // One paint with the final artwork beats a card that flashes the\n // catalogue logo and then swaps in the registry's.\n if (registryState.type === 'LOADING') {\n return { type: 'loading' };\n }\n const registry =\n registryState.type === 'CONTENT' ? registryState.registry : null;\n return {\n type: 'content',\n offers: offersState.offers.map((offer) =>\n OfferSaleCardUi.fromOffer(\n offer,\n registry ? TokenRegistrySnapshot.forOffer(registry, offer) : null\n )\n ),\n interactive,\n };\n }\n default: {\n // A new load state without a case here is a compile error.\n const exhaustive: never = offersState;\n return exhaustive;\n }\n }\n}\n","import { useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { Offer } from '@/universal/types/offer';\n\nexport type LoadOffersReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOffersState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOffersReason;\n }\n | {\n type: 'CONTENT';\n offers: Offer[];\n };\n\nexport interface UseOffersOptions {\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer#offers.list()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n /**\n * When `false`, the hook sends no request. A seeded or already-fetched\n * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nexport interface UseOffersResult {\n offersState: LoadOffersState;\n}\n\nconst LOADING_STATE: LoadOffersState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList offers for the current user and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely. Pass `enabled: false` to skip the fetch\n * when the hook must be called but the data is not needed yet.\n *\n * Returns `LOADING` while CoinList is initializing or while offers are being fetched.\n * Returns `CONTENT` with all offers when `fetchOffers()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOffers(options: UseOffersOptions = {}): UseOffersResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOffers');\n const { data: serverOffers, enabled = true } = options;\n const [offersState, setOffersState] = useState<LoadOffersState>(\n serverOffers !== undefined\n ? { type: 'CONTENT', offers: serverOffers }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n return () => {\n isCancelled = true;\n };\n }\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (serverOffers === undefined) {\n setOffersState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (serverOffers !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOffersState(LOADING_STATE);\n coinlist.offers\n .list()\n .then((offers) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', count: offers.length },\n }));\n setOffersState({ type: 'CONTENT', offers });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOffersReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setOffersState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, serverOffers, log]);\n\n return { offersState };\n}\n","import { tokenLogoSrcSet, tokenLogoUrl } from '@/client/ui/format/asset-icon';\nimport type {\n TokenLogo,\n TokenMetadata,\n} from '@/universal/types/token-metadata';\n\n/**\n * One image as an `<img>` renders it: a `src` for a consumer that takes a\n * single URL, and the `srcSet` candidates for one that also knows the size\n * it renders at. `srcSet` is absent for a vector logo and for the offer's own\n * artwork, neither of which offers the browser a choice.\n */\nexport type LogoImageUi = {\n src: string;\n srcSet?: string;\n};\n\n/**\n * The logo a catalogue card renders for an offer, with the registry's\n * dark-theme counterpart when it configures one.\n *\n * `dark` is `null` rather than absent so a renderer has to decide what to do\n * without one: fall back to `light`, which is the registry's own rule.\n */\nexport type OfferLogoUi = {\n light: LogoImageUi;\n dark: LogoImageUi | null;\n};\n\n/**\n * The widest a catalogue card renders a logo at, at 2x density: 48px in\n * {@link OfferAssetCard}. `src` covers that so a single-URL consumer gets a\n * crisp icon; `srcSet` lets the browser go higher where it must, such as the\n * sale card's watermark.\n */\nconst CARD_LOGO_WIDTH = 96;\n\nexport const OfferLogoUi = {\n /**\n * The registry's logo for the token an offer is about, or the offer's own\n * artwork otherwise, or `null` when neither exists.\n *\n * The registry wins when both exist because it is the token's real artwork\n * where `Offer.logoUrl` is catalogue artwork, and because a swap publishes\n * without artwork more often than not - which is why `logoUrl` is `null`\n * on the swap variants.\n */\n fromOffer: (\n offer: { logoUrl: string | null },\n tokenMetadata: TokenMetadata | null\n ): OfferLogoUi | null => {\n const light = tokenMetadata ? logoImage(tokenMetadata.logo) : null;\n if (light !== null) {\n const dark = tokenMetadata?.logoDark\n ? logoImage(tokenMetadata.logoDark)\n : null;\n return { light, dark };\n }\n return offer.logoUrl ? { light: { src: offer.logoUrl }, dark: null } : null;\n },\n};\n\nfunction logoImage(logo: TokenLogo): LogoImageUi | null {\n const src = tokenLogoUrl(logo, CARD_LOGO_WIDTH);\n if (src === null) {\n return null;\n }\n const srcSet = tokenLogoSrcSet(logo);\n return srcSet === null ? { src } : { src, srcSet };\n}\n","import { OfferLogoUi } from '@/client/hooks/offers/shared/offer-logo.types';\nimport type { Offer, OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * An offer as {@link OfferSaleCard} renders it. Countdown copy is derived in\n * the leaf from `startsAt` / `endsAt` so it can tick; the mapper does not\n * invent a price, FDV, unlock schedule, banner overlay, or wordmark.\n *\n * `name` and `logo` come from the public token registry when the caller\n * hands over the metadata of the token the offer is about, and from the\n * offer otherwise. The list payload carries no name, so `fromOffer` leaves\n * `name` absent without registry metadata - do not derive one from `slug`.\n * The card pairs `logo` with `name` as an h2 and renders each only when\n * present. Prefer {@link OfferSaleCardUi.fromDetail} when the host has a\n * name and no registry answer.\n *\n * `tagline` and `startsAt` are null for an offer that runs no sale window, an\n * Ondo swap: the card then omits the tagline and, with nothing to count down\n * to, reads as live.\n */\nexport type OfferSaleCardUi = {\n id: OfferId;\n /** Absent when neither the registry nor a detail payload names the offer. */\n name?: string;\n tagline: string | null;\n /** `null` when neither the registry nor the offer carries artwork. */\n logo: OfferLogoUi | null;\n startsAt: Date | null;\n endsAt: Date | null;\n};\n\nexport const OfferSaleCardUi = {\n /**\n * `tokenMetadata` is the registry's entry for the token the offer is about\n * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The\n * registry names win over the offer's own where both exist: they are the\n * token's canonical name and artwork, where the offer's are catalogue copy.\n */\n fromOffer: (\n offer: Offer,\n tokenMetadata: TokenMetadata | null = null\n ): OfferSaleCardUi => ({\n id: offer.id,\n ...(tokenMetadata ? { name: tokenMetadata.name } : {}),\n ...saleWindow(offer),\n logo: OfferLogoUi.fromOffer(offer, tokenMetadata),\n endsAt: offer.endsAt,\n }),\n fromDetail: (\n detail: OfferDetail,\n tokenMetadata: TokenMetadata | null = null\n ): OfferSaleCardUi => ({\n id: detail.id,\n name: tokenMetadata?.name ?? detail.name,\n ...saleWindow(detail),\n logo: OfferLogoUi.fromOffer(detail, tokenMetadata),\n endsAt: detail.endsAt,\n }),\n};\n\n/**\n * The copy and countdown of the sale window, per variant. Exhaustive: a\n * fourth offer type has to say here whether it runs a window.\n */\nfunction saleWindow(\n offer: Offer | OfferDetail\n): Pick<OfferSaleCardUi, 'tagline' | 'startsAt'> {\n switch (offer.type) {\n case 'coinlist::token_sale':\n case 'superstate::swap':\n return { tagline: offer.tagline, startsAt: offer.startsAt };\n case 'ondo::swap':\n return { tagline: null, startsAt: null };\n default: {\n const exhaustive: never = offer;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { TokenRegistrySnapshot } from '@/universal/core/tokens/token-registry-snapshot';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * The state of a token-registry snapshot load.\n *\n * `CONTENT` holds the whole snapshot, indexed: ask it\n * `TokenRegistrySnapshot.forOffer(registry, offer)` per card. `ERROR` means\n * the snapshot could not be read - the registry always publishes it, so this\n * is an outage or a blocked request, and callers render their own display\n * defaults for every offer rather than nothing. `DISABLED` means the hook was\n * switched off before an answer arrived, so there is nothing to render a\n * loading UI for. No `not-authenticated` reason: the registry is public.\n */\nexport type LoadTokenRegistryState =\n | { type: 'DISABLED' }\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: 'generic-error' }\n | { type: 'CONTENT'; registry: TokenRegistrySnapshot };\n\nexport interface UseTokenRegistryOptions {\n /**\n * The snapshot pre-fetched on the server (via `CoinListServer#tokens.list()`).\n * When provided, the hook indexes it as-is and skips the initial\n * client-side fetch; {@link UseTokenRegistryResult.refetch} still fetches.\n */\n data?: TokenMetadata[];\n /** When false: no request; see {@link LoadTokenRegistryState}. Default true. */\n enabled?: boolean;\n}\n\nexport interface UseTokenRegistryResult {\n state: LoadTokenRegistryState;\n /**\n * Fetches again: the recovery path after a transient `ERROR`, and the way\n * past a server seed (`data`), which only the first fetch honours. No-op\n * while disabled.\n */\n refetch: () => void;\n}\n\nconst DISABLED_STATE: LoadTokenRegistryState = { type: 'DISABLED' };\nconst LOADING_STATE: LoadTokenRegistryState = { type: 'LOADING' };\n\n/**\n * Loads the complete public token registry - every token on every chain the\n * SDK models, in one request - and indexes it for per-offer lookups. This is\n * what a catalogue mounts once, where `useTokenMetadata` is what a single\n * screen mounts for one token.\n *\n * No polling: registry content is immutable per version, so the answer does\n * not change under the page. `refetch` exists for error recovery and for\n * bypassing a server seed, not for freshness.\n *\n * Disabled without an answer in hand it reports `DISABLED` rather than\n * `LOADING` (nothing is in flight, so a spinner would wait forever) and\n * rather than an empty `CONTENT` (an empty snapshot asserts \"the registry\n * lists nothing\" - an answer this hook would not actually have). A seeded or\n * already-fetched `CONTENT` survives disabling.\n */\nexport function useTokenRegistry(\n options: UseTokenRegistryOptions = {}\n): UseTokenRegistryResult {\n const { data, enabled = true } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useTokenRegistry');\n\n const [state, setState] = useState<LoadTokenRegistryState>(() =>\n data !== undefined\n ? { type: 'CONTENT', registry: TokenRegistrySnapshot.fromTokens(data) }\n : LOADING_STATE\n );\n const [refetchCount, setRefetchCount] = useState(0);\n\n const refetch = useCallback(() => {\n setRefetchCount((count) => count + 1);\n }, []);\n\n useEffect(() => {\n let isCancelled = false;\n\n // The seed answers the initial render only; an explicit refetch is a\n // request for the client's own answer.\n const seedActive = data !== undefined && refetchCount === 0;\n if (!isReady || !enabled || seedActive) {\n return () => {\n isCancelled = true;\n };\n }\n\n setState(LOADING_STATE);\n coinlist.tokens\n .list()\n .then((tokens) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', count: tokens.length },\n }));\n setState({\n type: 'CONTENT',\n registry: TokenRegistrySnapshot.fromTokens(tokens),\n });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n log.failure(\n () => ({\n msg: 'settled',\n fields: { state: 'ERROR', reason: 'generic-error' },\n }),\n error\n );\n setState({ type: 'ERROR', reason: 'generic-error' });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, data, refetchCount, log]);\n\n return {\n // LOADING would be a lie while disabled: nothing is in flight and nothing\n // will replace it. Settled states (a seed, a previous answer) survive.\n state: !enabled && state.type === 'LOADING' ? DISABLED_STATE : state,\n refetch,\n };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { OffersGridView } from '@/client/components/offers/grid/OffersGridView';\nimport {\n type OffersGridData,\n useOffersGridViewModel,\n} from '@/client/hooks/offers/grid/useOffersGridViewModel';\nimport type { Offer } from '@/universal/types/offer';\n\nexport interface OffersGridContainerProps {\n /** Maximum number of columns to render when horizontal space allows. */\n maxColumns?: number;\n /** Optional className applied to the grid element. */\n className?: string;\n /** Optional className applied to the outer wrapper element. */\n containerClassName?: string;\n /** Optional loading slot shown while offers are being fetched. */\n loading?: ReactNode;\n /** Optional error slot shown when loading offers fails. */\n error?: ReactNode;\n /** Optional empty state slot shown when there are no available offers. */\n emptyState?: ReactNode;\n /** Optional per-offer click handler; when omitted, cards are not clickable. */\n onOfferClick?: (offer: Offer) => void;\n /**\n * What the grid would otherwise fetch, pre-fetched on the server: `offers`\n * via `CoinListServer#offers.list()`, `tokens` via\n * `CoinListServer#tokens.list()`. Each half skips its own client-side\n * fetch; pass both for a grid that makes no request of its own.\n */\n data?: OffersGridData;\n /**\n * Default `true`. When `false` nothing is fetched, so the container can be\n * mounted while the grid is not needed yet.\n */\n enabled?: boolean;\n}\n\n/**\n * Displays a responsive live-sale grid of {@link OfferSaleCard}, backed by\n * {@link useOffersGridViewModel}. Each card is named and illustrated by the\n * public token registry where it lists the offer's token, and by the offer's\n * own fields otherwise - list offers carry no display name, so an unlisted\n * one shows logo + tagline until the host maps from detail. For equities /\n * past-sales browse rows, compose {@link OffersAssetGrid} instead.\n *\n * Pass `data` (offers and tokens pre-fetched server-side) to use them as-is\n * and skip the client-side fetches. Pass `enabled={false}` to skip the fetches\n * when the container is mounted but the grid is not needed yet. Uses the\n * `loading` / `error` / `emptyState` slots when provided; otherwise renders\n * the standard fallbacks. Cards are interactive only when `onOfferClick` is\n * provided.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed.\n */\nexport function OffersGridContainer({\n data,\n onOfferClick,\n enabled = true,\n ...viewProps\n}: OffersGridContainerProps = {}): ReactNode {\n const { state, onEvent } = useOffersGridViewModel({\n data,\n onOfferClick,\n enabled,\n });\n\n return <OffersGridView state={state} onEvent={onEvent} {...viewProps} />;\n}\n","'use client';\n\nimport { type ReactNode, useState } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n ConnectedWalletUi,\n WalletsStatus,\n} from '@/client/hooks/requirements/useRequirementsChecklistViewModel.types';\n\nexport interface ConnectedWalletListProps {\n wallets: ConnectedWalletUi[];\n /**\n * Removes a connected wallet by id. May return a promise; the row shows a\n * removing state until it settles and surfaces an inline error on rejection.\n * `null`/omitted hides the remove control (read-only list).\n */\n onRemove?: ((id: string) => void | Promise<void>) | null;\n /** Opens the connect flow to add another wallet. Omit to hide the button. */\n onAdd?: (() => void) | null;\n /** Label for the add button. Defaults to \"Add wallet\". */\n addLabel?: string;\n /**\n * Load state of the wallets. `'loading'`/`'error'` render a status message so\n * a failed or in-flight fetch is not mistaken for a genuinely empty list.\n * Defaults to `'ready'`.\n */\n status?: WalletsStatus;\n className?: string;\n}\n\ntype RowState = 'idle' | 'confirming' | 'removing' | 'error';\n\nfunction ConnectedWalletRow({\n wallet,\n onRemove,\n}: {\n wallet: ConnectedWalletUi;\n onRemove?: ((id: string) => void | Promise<void>) | null;\n}): ReactNode {\n const [state, setState] = useState<RowState>('idle');\n\n const remove = async () => {\n if (!onRemove) return;\n setState('removing');\n try {\n await onRemove(wallet.id);\n // On success the list is refetched and this row usually unmounts. Reset to\n // idle anyway so a row that survives the refetch (eventual consistency)\n // isn't stuck showing \"Removing…\" with no way out.\n setState('idle');\n } catch {\n setState('error');\n }\n };\n\n return (\n <div className=\"clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2\">\n <span\n title={wallet.address}\n className={cn(\n typeClasses.body,\n 'clcosdk:font-mono clcosdk:text-text-primary'\n )}\n >\n {wallet.shortAddress}\n </span>\n\n {onRemove != null &&\n (state === 'confirming' ? (\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-2\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Remove?\n </span>\n <ClButton size=\"sm\" variant=\"destructive\" onClick={remove}>\n Remove\n </ClButton>\n <ClButton\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => setState('idle')}\n >\n Cancel\n </ClButton>\n </div>\n ) : state === 'error' ? (\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-2\">\n <span className={cn(typeClasses.subhead, 'clcosdk:text-error')}>\n Couldn't remove.\n </span>\n <ClButton\n size=\"sm\"\n variant=\"destructiveLink\"\n onClick={() => setState('confirming')}\n >\n Try again\n </ClButton>\n </div>\n ) : (\n <ClButton\n size=\"sm\"\n variant=\"destructiveLink\"\n disabled={state === 'removing'}\n onClick={() => setState('confirming')}\n >\n {state === 'removing' ? 'Removing…' : 'Remove'}\n </ClButton>\n ))}\n </div>\n );\n}\n\n/**\n * Presentational list of a user's connected wallets for a whitelisted-wallet\n * requirement: each row shows the address with an inline two-step remove\n * confirmation, plus an optional \"Add wallet\" button. Self-contained - holds\n * only per-row confirm/removing/error UI state; all data and side effects come\n * from props.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed. Also composed by {@link RequirementItem}.\n */\nexport function ConnectedWalletList(\n props: ConnectedWalletListProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <ConnectedWalletListBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction ConnectedWalletListBody({\n wallets,\n onRemove,\n onAdd,\n addLabel = 'Add wallet',\n status = 'ready',\n className,\n}: ConnectedWalletListProps): ReactNode {\n return (\n <div\n className={cn('clcosdk:flex clcosdk:flex-col clcosdk:gap-2', className)}\n >\n {status === 'loading' ? (\n <AlertBanner variant=\"info\" content=\"Loading your connected wallets…\" />\n ) : status === 'error' ? (\n <AlertBanner\n variant=\"error\"\n content=\"Couldn't load your connected wallets.\"\n />\n ) : wallets.length === 0 ? (\n <AlertBanner variant=\"info\" content=\"No wallets connected yet.\" />\n ) : (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {wallets.map((wallet) => (\n <ConnectedWalletRow\n key={wallet.id}\n wallet={wallet}\n onRemove={onRemove}\n />\n ))}\n </div>\n )}\n\n {onAdd != null && status !== 'loading' && (\n <ClButton\n size=\"sm\"\n variant=\"secondary\"\n onClick={onAdd}\n className=\"clcosdk:self-start\"\n >\n {addLabel}\n </ClButton>\n )}\n </div>\n );\n}\n","'use client';\n\nimport SumsubWebSdk from '@sumsub/websdk-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n IdentityVerificationUiEvent,\n IdentityVerificationUiState,\n} from '@/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel.types';\n\nexport interface IdentityVerificationViewProps {\n state: IdentityVerificationUiState;\n onEvent: (event: IdentityVerificationUiEvent) => void;\n className?: string;\n}\n\n/**\n * Renders the inline Sumsub identity verification flow: its loading state, its\n * failure states, and the Sumsub iframe itself. Pure: the access token arrives\n * in `state`, and flow outcomes leave through `onEvent`.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed.\n */\nexport function IdentityVerificationView(\n props: IdentityVerificationViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <IdentityVerificationViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction IdentityVerificationViewBody({\n state,\n onEvent,\n className,\n}: IdentityVerificationViewProps): ReactNode {\n switch (state.type) {\n case 'loading':\n return (\n <output\n aria-live=\"polite\"\n className={cn(\n 'clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center',\n className\n )}\n >\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Loading identity verification...\n </p>\n </output>\n );\n case 'error':\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:flex-col clcosdk:gap-4',\n className\n )}\n >\n <AlertBanner variant=\"error\" icon content={state.message} />\n {state.retryable && (\n <ClButton size=\"sm\" onClick={() => onEvent({ type: 'ON_RETRY' })}>\n Try again\n </ClButton>\n )}\n </div>\n );\n case 'ready':\n return (\n <div className={cn('clcosdk:w-full', className)}>\n <SumsubWebSdk\n accessToken={state.accessToken}\n expirationHandler={state.refreshToken}\n config={state.locale === undefined ? {} : { lang: state.locale }}\n options={{ addViewportTag: false, adaptIframeHeight: true }}\n onMessage={(type: string, payload: unknown) => {\n onSumsubMessage(type, payload, onEvent);\n }}\n onError={(error: unknown) => {\n onEvent({ type: 'ON_ERROR', error: toError(error) });\n }}\n />\n </div>\n );\n default: {\n // A new UI state without a case here is a compile error.\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction onSumsubMessage(\n type: string,\n payload: unknown,\n onEvent: (event: IdentityVerificationUiEvent) => void\n): void {\n switch (type) {\n case 'idCheck.onApplicantSubmitted':\n onEvent({ type: 'ON_SUBMITTED' });\n return;\n case 'idCheck.onError': {\n const message =\n (payload as { message?: string })?.message ?? 'Verification error';\n onEvent({ type: 'ON_ERROR', error: new Error(message) });\n return;\n }\n default:\n return;\n }\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error('Verification error');\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useKycToken } from '@/client/hooks/requirements/data/useKycToken';\nimport type {\n IdentityVerificationUiEvent,\n IdentityVerificationUiState,\n} from '@/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel.types';\nimport type { KycLevelName } from '@/universal/types/kyc';\n\nexport interface UseIdentityVerificationViewModelOptions {\n /**\n * Sumsub verification level to start. Determines which screens the Sumsub\n * WebSDK shows. Defaults to the backend's standard identity level.\n */\n levelName?: KycLevelName;\n /**\n * Reset the Sumsub applicant before starting the flow, so an\n * already-approved level can be executed again (e.g. to update stale PII).\n * Applies only to the initial token: mid-flow token refreshes never repeat\n * the reset.\n */\n reset?: boolean;\n /** BCP-47 language tag for the Sumsub UI, e.g. `'en'`. */\n locale?: string;\n /**\n * Called when the user submits their data in the Sumsub flow. Verification\n * continues asynchronously on the backend, so the requirement typically moves\n * to a pending state first.\n */\n onSubmitted?: () => void;\n /** Called when the Sumsub flow reports an error. */\n onError?: (error: Error) => void;\n}\n\nexport interface UseIdentityVerificationViewModelResult {\n state: IdentityVerificationUiState;\n onEvent: (event: IdentityVerificationUiEvent) => void;\n}\n\nconst NOT_AUTHENTICATED_MESSAGE = 'Sign in to verify your identity.';\nconst GENERIC_ERROR_MESSAGE =\n 'Unable to start identity verification right now. Please try again.';\n\n/**\n * Drives {@link IdentityVerificationView}: fetches the Sumsub access token once\n * on mount, exposes the refresh callback the WebSDK needs, and forwards flow\n * outcomes to the host.\n */\nexport function useIdentityVerificationViewModel(\n options: UseIdentityVerificationViewModelOptions = {}\n): UseIdentityVerificationViewModelResult {\n const { levelName, reset, locale, onSubmitted, onError } = options;\n const { kycTokenState, fetchToken } = useKycToken(levelName, reset);\n const fetchedRef = useRef(false);\n\n useEffect(() => {\n if (fetchedRef.current) {\n return;\n }\n fetchedRef.current = true;\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState; swallow the rejection.\n });\n }, [fetchToken]);\n\n const state = useMemo<IdentityVerificationUiState>(() => {\n switch (kycTokenState.type) {\n case 'IDLE':\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR': {\n const notAuthenticated = kycTokenState.reason === 'not-authenticated';\n return {\n type: 'error',\n message: notAuthenticated\n ? NOT_AUTHENTICATED_MESSAGE\n : GENERIC_ERROR_MESSAGE,\n retryable: !notAuthenticated,\n };\n }\n case 'CONTENT':\n return {\n type: 'ready',\n accessToken: kycTokenState.token,\n locale,\n refreshToken: fetchToken,\n };\n default: {\n // A new token state without a case here is a compile error.\n const exhaustive: never = kycTokenState;\n return exhaustive;\n }\n }\n }, [kycTokenState, locale, fetchToken]);\n\n const onEvent = useCallback(\n (event: IdentityVerificationUiEvent) => {\n switch (event.type) {\n case 'ON_RETRY':\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState.\n });\n return;\n case 'ON_SUBMITTED':\n onSubmitted?.();\n return;\n case 'ON_ERROR':\n onError?.(event.error);\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n },\n [fetchToken, onSubmitted, onError]\n );\n\n return { state, onEvent };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { KycLevelName } from '@/universal/types/kyc';\n\nexport type KycTokenErrorReason = 'not-authenticated' | 'generic-error';\n\nexport type KycTokenState =\n | {\n type: 'IDLE';\n }\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: KycTokenErrorReason;\n }\n | {\n type: 'CONTENT';\n token: string;\n };\n\nexport interface UseKycTokenResult {\n kycTokenState: KycTokenState;\n /**\n * Fetches a fresh Sumsub WebSDK access token and transitions the state to\n * `CONTENT` (or `ERROR`). Resolves with the token so it can also be used\n * imperatively, e.g. as the Sumsub `expirationHandler`. Rejects on failure.\n */\n fetchToken: () => Promise<string>;\n}\n\nconst IDLE_STATE: KycTokenState = { type: 'IDLE' };\nconst LOADING_STATE: KycTokenState = { type: 'LOADING' };\n\n/**\n * Creates Sumsub WebSDK access tokens for the current user via\n * {@link CoinListClient#createKycToken}, exposed as a state machine.\n *\n * Starts in `IDLE`; call `fetchToken()` to request a token. Returns `LOADING`\n * while the request is in flight, then `CONTENT` with the token on success, or\n * `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n *\n * `reset` (resetting the Sumsub applicant so an already-approved level can be\n * redone) tracks the latest value of the `reset` argument up until a token is\n * first issued; after that, mid-flow token refreshes must never repeat the\n * reset, or the user's in-progress submission would be wiped, so further\n * changes to `reset` are ignored. Failed attempts keep the reset pending, so\n * retrying still requests it — the backend treats resetting an\n * already-pristine applicant as a no-op.\n */\nexport function useKycToken(\n levelName?: KycLevelName,\n reset?: boolean\n): UseKycTokenResult {\n const { coinlist } = useCoinList();\n const log = useLogger('useKycToken');\n const [kycTokenState, setKycTokenState] = useState<KycTokenState>(IDLE_STATE);\n const resetPendingRef = useRef(reset === true);\n const tokenIssuedRef = useRef(false);\n\n useEffect(() => {\n if (!tokenIssuedRef.current) {\n resetPendingRef.current = reset === true;\n }\n }, [reset]);\n\n const fetchToken = useCallback(async () => {\n setKycTokenState(LOADING_STATE);\n try {\n const kycToken = await coinlist.requirements.createKycToken({\n levelName,\n reset: resetPendingRef.current,\n });\n resetPendingRef.current = false;\n tokenIssuedRef.current = true;\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT' },\n }));\n setKycTokenState({ type: 'CONTENT', token: kycToken.token });\n return kycToken.token;\n } catch (error) {\n const reason: KycTokenErrorReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setKycTokenState({ type: 'ERROR', reason });\n throw error;\n }\n }, [coinlist, levelName, log]);\n\n return { kycTokenState, fetchToken };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { IdentityVerificationView } from '@/client/components/requirements/identity-verification/IdentityVerificationView';\nimport { useIdentityVerificationViewModel } from '@/client/hooks/requirements/identity-verification/useIdentityVerificationViewModel';\nimport type { KycLevelName } from '@/universal/types/kyc';\n\nexport interface IdentityVerificationContainerProps {\n /**\n * Sumsub verification level to start. Determines which screens the Sumsub\n * WebSDK shows. Defaults to the backend's standard identity level.\n */\n levelName?: KycLevelName;\n /**\n * Reset the Sumsub applicant before starting the flow, so an\n * already-approved level can be executed again (e.g. to update stale PII).\n * Pass the `kycReset` value from the requirement status. Applies only to\n * the initial token: mid-flow token refreshes never repeat the reset.\n */\n reset?: boolean;\n /** BCP-47 language tag for the Sumsub UI, e.g. `'en'`. */\n locale?: string;\n /**\n * Called when the user submits their data in the Sumsub flow. Verification\n * continues asynchronously on the backend, so the requirement typically moves\n * to a pending state first - refetch requirement statuses to observe it.\n */\n onSubmitted?: () => void;\n /** Called when the Sumsub flow reports an error. */\n onError?: (error: Error) => void;\n className?: string;\n}\n\n/**\n * Inline Sumsub identity verification flow, backed by\n * {@link useIdentityVerificationViewModel}, which fetches the Sumsub WebSDK\n * access token via {@link useKycToken}. Used by\n * `RequirementsChecklistContainer` for KYC-backed requirements, and can also\n * be rendered standalone.\n */\nexport function IdentityVerificationContainer({\n levelName,\n reset,\n locale,\n onSubmitted,\n onError,\n className,\n}: IdentityVerificationContainerProps): ReactNode {\n const { state, onEvent } = useIdentityVerificationViewModel({\n levelName,\n reset,\n locale,\n onSubmitted,\n onError,\n });\n\n return (\n <IdentityVerificationView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport { ChevronRight } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { StepStatusIcon } from '@/client/components/design-system/StepStatusIcon';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { ConnectedWalletList } from '@/client/components/requirements/ConnectedWalletList';\nimport type {\n ConnectedWalletUi,\n RequirementItemUi,\n RequirementStatus,\n WalletsStatus,\n} from '@/client/hooks/requirements/useRequirementsChecklistViewModel.types';\n\nexport interface RequirementItemProps {\n ui: RequirementItemUi;\n expanded?: boolean;\n onToggle?: () => void;\n className?: string;\n /** Connect / change / add-wallet action (opens the connect flow). */\n onAction?: (() => void) | null;\n /** Removes a bound wallet by id (whitelisted-wallet requirements only). */\n onRemoveWallet?: ((id: string) => void | Promise<void>) | null;\n /**\n * Load state of {@link RequirementItemUi.connectedWallets}. `'loading'` /\n * `'error'` keep a fetch-in-flight or failed fetch from looking like an empty\n * wallet list. Defaults to `'ready'`.\n */\n walletsStatus?: WalletsStatus;\n onContactSupport?: (() => void) | null;\n /**\n * 16px under the open section, so its button does not sit on the next row's\n * divider. The last row omits this: the checklist's own gap is the space\n * before the footer.\n */\n spaceBeforeNextRow?: boolean;\n}\n\nconst DEFAULT_PENDING = \"Under review. We'll notify you when complete.\";\nconst DEFAULT_REJECTED = 'Verification rejected.';\nconst SUPPORT_LINK = 'Contact support';\n\nfunction VerificationActionZone({\n status,\n statusMessages,\n onAction,\n onContactSupport,\n}: {\n status: RequirementStatus;\n statusMessages: RequirementItemUi['statusMessages'];\n onAction?: (() => void) | null;\n onContactSupport?: (() => void) | null;\n}): ReactNode {\n switch (status) {\n case 'required':\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" className=\"clcosdk:self-start\" onClick={onAction}>\n Continue\n </ClButton>\n );\n case 'pending':\n return (\n <AlertBanner\n variant=\"warning\"\n content={statusMessages?.pending ?? DEFAULT_PENDING}\n />\n );\n case 'completed':\n return (\n <AlertBanner\n variant=\"success\"\n content={statusMessages?.completed ?? 'Identity verified.'}\n />\n );\n case 'rejected':\n return (\n <AlertBanner\n variant=\"error\"\n content={\n <RejectedMessage\n message={statusMessages?.rejected ?? DEFAULT_REJECTED}\n onContactSupport={onContactSupport}\n />\n }\n />\n );\n }\n}\n\nfunction RejectedMessage({\n message,\n onContactSupport,\n}: {\n message: string;\n onContactSupport?: (() => void) | null;\n}): ReactNode {\n const linkAt = message.indexOf(SUPPORT_LINK);\n if (onContactSupport == null) {\n return message;\n }\n if (linkAt === -1) {\n return (\n <>\n {message}{' '}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"clcosdk:underline\"\n >\n {SUPPORT_LINK}\n </button>\n .\n </>\n );\n }\n return (\n <>\n {message.slice(0, linkAt)}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"clcosdk:underline\"\n >\n {SUPPORT_LINK}\n </button>\n {message.slice(linkAt + SUPPORT_LINK.length)}\n </>\n );\n}\n\nfunction WalletActionZone({\n status,\n multiWallet,\n connectedWallets,\n walletsStatus,\n onAction,\n onRemoveWallet,\n}: {\n status: RequirementStatus;\n multiWallet: boolean;\n connectedWallets: ConnectedWalletUi[];\n walletsStatus?: WalletsStatus;\n onAction?: (() => void) | null;\n onRemoveWallet?: ((id: string) => void | Promise<void>) | null;\n}): ReactNode {\n // Whitelisted-wallet: a list the user adds to (up to the backend cap) and\n // removes from, regardless of completion. The \"Add wallet\" button falls back\n // to `onAction`; the backend enforces the cap and rejects with\n // `max_wallets_reached`.\n if (multiWallet) {\n return (\n <>\n <ConnectedWalletList\n wallets={connectedWallets}\n onRemove={onRemoveWallet}\n onAdd={onAction ?? undefined}\n status={walletsStatus}\n />\n {status === 'rejected' && (\n <AlertBanner\n variant=\"error\"\n content=\"One of these wallets is not eligible for this sale.\"\n />\n )}\n </>\n );\n }\n\n // Single-slot external_wallet.\n if (status === 'completed') {\n const connected = connectedWallets[0];\n return (\n <>\n {onAction !== null && (\n <ClButton\n size=\"sm\"\n variant=\"secondary\"\n className=\"clcosdk:self-start\"\n onClick={onAction}\n >\n Change wallet\n </ClButton>\n )}\n {/* A failed/in-flight address fetch must not hide behind the success\n banner, which would mask the error the way the multi-slot list\n already guards against. */}\n {walletsStatus === 'loading' ? (\n <AlertBanner\n variant=\"info\"\n content=\"Loading your connected wallet…\"\n />\n ) : walletsStatus === 'error' ? (\n <AlertBanner\n variant=\"error\"\n content=\"Couldn't load your connected wallet.\"\n />\n ) : (\n <AlertBanner\n variant=\"success\"\n content={connected ? connected.shortAddress : 'Wallet connected.'}\n />\n )}\n </>\n );\n }\n\n if (status === 'rejected') {\n return (\n <>\n {onAction !== null && (\n <ClButton size=\"sm\" className=\"clcosdk:self-start\" onClick={onAction}>\n Connect wallet\n </ClButton>\n )}\n <AlertBanner\n variant=\"error\"\n content=\"This wallet is not eligible for this sale.\"\n />\n </>\n );\n }\n\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" className=\"clcosdk:self-start\" onClick={onAction}>\n Connect wallet\n </ClButton>\n );\n}\n\n/**\n * A single requirement row (label, status, expandable action zone). Self-scoped:\n * renders fully styled on its own, with no `CoinListStyleScope` needed. Also composed\n * by {@link RequirementsChecklist}.\n */\nexport function RequirementItem({\n ui,\n expanded = false,\n onToggle,\n className,\n onAction,\n onRemoveWallet,\n walletsStatus,\n onContactSupport,\n spaceBeforeNextRow = true,\n}: RequirementItemProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col',\n className\n )}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"clcosdk:-mx-2 clcosdk:flex clcosdk:h-14 clcosdk:w-[calc(100%+16px)] clcosdk:cursor-pointer clcosdk:items-center clcosdk:justify-between clcosdk:rounded-2xl clcosdk:px-2 clcosdk:transition-colors clcosdk:hover:bg-surface\"\n >\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-3\">\n <StepStatusIcon status={ui.status} />\n <span\n className={cn(\n typeClasses.body,\n 'clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {ui.label}\n </span>\n </div>\n <ChevronRight\n className={cn(\n 'clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0 clcosdk:text-text-secondary clcosdk:transition-transform clcosdk:duration-300',\n expanded && 'clcosdk:rotate-90'\n )}\n aria-hidden=\"true\"\n />\n </button>\n\n <div\n className={cn(\n 'clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out',\n expanded ? 'clcosdk:grid-rows-[1fr]' : 'clcosdk:grid-rows-[0fr]'\n )}\n >\n {/* min-h-0 lets the grid item collapse to 0 when grid-rows is 0fr */}\n <div className=\"clcosdk:min-h-0 clcosdk:overflow-hidden\">\n <div\n className={cn(\n 'clcosdk:flex clcosdk:flex-col clcosdk:gap-4',\n spaceBeforeNextRow && 'clcosdk:pb-4'\n )}\n >\n <p\n className={cn(\n typeClasses.bodySm,\n 'clcosdk:text-text-secondary'\n )}\n >\n {ui.description}\n </p>\n {ui.variant === 'verification' ? (\n <VerificationActionZone\n status={ui.status}\n statusMessages={ui.statusMessages}\n onAction={onAction}\n onContactSupport={onContactSupport}\n />\n ) : (\n <WalletActionZone\n status={ui.status}\n multiWallet={ui.multiWallet}\n connectedWallets={ui.connectedWallets}\n walletsStatus={walletsStatus}\n onAction={onAction}\n onRemoveWallet={onRemoveWallet}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, CircleX, Info } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type StepStatus = 'required' | 'pending' | 'completed' | 'rejected';\n\ninterface StepStatusIconProps {\n status: StepStatus;\n className?: string;\n}\n\nconst statusConfig: Record<\n StepStatus,\n { Icon: LucideIcon; colorClass: string; fillClass: string }\n> = {\n required: {\n Icon: Info,\n colorClass: 'clcosdk:text-warning',\n fillClass: 'clcosdk:[&_circle]:fill-warning-subtle',\n },\n pending: {\n Icon: Info,\n colorClass: 'clcosdk:text-warning',\n fillClass: 'clcosdk:[&_circle]:fill-warning-subtle',\n },\n completed: {\n Icon: CircleCheck,\n colorClass: 'clcosdk:text-success',\n fillClass: 'clcosdk:[&_circle]:fill-success-subtle',\n },\n rejected: {\n Icon: CircleX,\n colorClass: 'clcosdk:text-error',\n fillClass: 'clcosdk:[&_circle]:fill-error-subtle',\n },\n};\n\nexport function StepStatusIcon({ status, className }: StepStatusIconProps) {\n const { Icon, colorClass, fillClass } = statusConfig[status];\n return (\n <Icon\n className={cn(\n 'clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0',\n colorClass,\n fillClass,\n className\n )}\n aria-hidden=\"true\"\n />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { Skeleton } from '@/client/components/design-system/Skeleton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { RequirementItem } from '@/client/components/requirements/RequirementItem';\nimport type {\n RequirementsChecklistItemUi,\n RequirementsChecklistUiEvent,\n RequirementsChecklistUiState,\n} from '@/client/hooks/requirements/useRequirementsChecklistViewModel.types';\n\nexport interface RequirementsChecklistViewProps {\n state: RequirementsChecklistUiState;\n onEvent: (event: RequirementsChecklistUiEvent) => void;\n /** Optional loading slot. */\n loading?: ReactNode;\n /** Replaces the error banner under the title. The title still renders. */\n error?: ReactNode;\n className?: string;\n}\n\n/**\n * Renders the requirements checklist: its header, one row per requirement, and\n * the continue row. Pure: the rows arrive already shaped in `state`, and every\n * interaction leaves through `onEvent`.\n *\n * The flows the checklist can open (tax document, wallet connect, identity\n * verification) are composed by `RequirementsChecklistContainer`, which owns\n * the host inputs they need.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed.\n */\nexport function RequirementsChecklistView(\n props: RequirementsChecklistViewProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <RequirementsChecklistViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction RequirementsChecklistViewBody({\n state,\n onEvent,\n loading,\n error,\n className,\n}: RequirementsChecklistViewProps): ReactNode {\n switch (state.type) {\n case 'loading':\n return (\n loading ?? (\n <LoadingState\n title={state.title}\n description={state.description}\n className={className}\n />\n )\n );\n case 'error':\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4',\n className\n )}\n >\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {state.title}\n </h3>\n {error ?? (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Unable to load requirements. Refresh the page to try again.\"\n />\n )}\n </div>\n );\n case 'content':\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {state.title}\n </h3>\n {state.blockedMessage == null && (\n <p\n className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}\n >\n {state.items.length === 0\n ? 'No requirements to complete.'\n : state.description}\n </p>\n )}\n </div>\n\n {state.blockedMessage != null ? (\n <AlertBanner variant=\"info\" icon content={state.blockedMessage} />\n ) : state.items.length === 0 ? (\n state.continueAction && (\n <ClButton\n variant=\"primary\"\n fullWidth\n disabled={!state.continueAction.enabled}\n onClick={() => onEvent({ type: 'ON_CONTINUE' })}\n >\n Continue\n </ClButton>\n )\n ) : (\n <>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {state.items.map((row, index) => (\n <RequirementItem\n key={row.id}\n ui={row.item}\n expanded={row.expanded}\n spaceBeforeNextRow={index < state.items.length - 1}\n onToggle={() =>\n onEvent({ type: 'ON_TOGGLE_ITEM', requirementId: row.id })\n }\n onAction={\n row.actionEnabled\n ? () =>\n onEvent({\n type: 'ON_REQUIREMENT_ACTION',\n requirementId: row.id,\n })\n : null\n }\n onRemoveWallet={\n row.wallets ? (id) => state.removeWallet(id) : undefined\n }\n walletsStatus={row.wallets?.status}\n onContactSupport={\n row.contactSupportEnabled\n ? () =>\n onEvent({\n type: 'ON_CONTACT_SUPPORT',\n requirementId: row.id,\n })\n : null\n }\n />\n ))}\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-row clcosdk:items-center clcosdk:justify-between clcosdk:gap-6\">\n <span\n className={cn(\n typeClasses.subhead,\n 'clcosdk:min-w-0',\n state.ineligible\n ? 'clcosdk:text-error'\n : 'clcosdk:text-text-secondary'\n )}\n >\n {state.ineligible\n ? 'You are not eligible to invest.'\n : completedLabel(state.items)}\n </span>\n {state.continueAction && (\n <ClButton\n variant=\"primary\"\n disabled={!state.continueAction.enabled}\n onClick={() => onEvent({ type: 'ON_CONTINUE' })}\n className=\"clcosdk:shrink-0\"\n >\n Continue\n </ClButton>\n )}\n </div>\n </>\n )}\n </div>\n );\n default: {\n // A new UI state without a case here is a compile error.\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\nfunction completedLabel(items: RequirementsChecklistItemUi[]): string {\n const completed = items.filter(\n (row) => row.item.status === 'completed'\n ).length;\n return `${completed}/${items.length} completed`;\n}\n\nconst LOADING_ROW_WIDTHS = [\n 'clcosdk:w-3/5',\n 'clcosdk:w-2/5',\n 'clcosdk:w-1/2',\n] as const;\n\nfunction LoadingState({\n title,\n description,\n className,\n}: {\n title: string;\n description: string;\n className?: string;\n}): ReactNode {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4',\n className\n )}\n >\n {/* The skeletons are aria-hidden, so this line is what a screen reader hears. */}\n <output className=\"clcosdk:sr-only\">Loading requirements...</output>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {title}\n </h3>\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n {description}\n </p>\n </div>\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-3\">\n {LOADING_ROW_WIDTHS.map((width) => (\n <Skeleton key={width} className={cn('clcosdk:h-8', width)} />\n ))}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n TaxDocumentFieldUi,\n TaxDocumentModalUiEvent,\n TaxDocumentModalUiState,\n TaxDocumentScreenUi,\n} from '@/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel.types';\n\nexport interface TaxDocumentModalViewProps {\n state: TaxDocumentModalUiState;\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n className?: string;\n}\n\n/**\n * Modal for the tax document (W-8BEN / W-8BEN-E) signing flow: individuals\n * review and edit their PII before signing, company/trust entities get a plain\n * sign screen with no fields. Pure: it renders the screen it is handed.\n *\n * No portal is used - rendering stays inside the normal DOM tree. Self-scoped:\n * renders fully styled on its own, with no `CoinListStyleScope` needed, so it\n * is styled wherever the host places it and wherever the checklist renders it\n * (as a sibling of `RequirementsChecklistView`, outside that View's scope).\n */\nexport function TaxDocumentModalView({\n state,\n onEvent,\n className,\n}: TaxDocumentModalViewProps): ReactNode {\n // Bail before the scope, so a closed modal leaves nothing in the DOM rather\n // than an empty .clco-sdk-root.\n if (state.type === 'hidden') {\n return null;\n }\n\n return (\n <CoinListStyleScope>\n <div className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4\">\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {state.title}\n </h3>\n <CloseButton onClick={() => onEvent({ type: 'ON_CLOSE' })} />\n </div>\n\n <Screen screen={state.screen} onEvent={onEvent} />\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction Screen({\n screen,\n onEvent,\n}: {\n screen: TaxDocumentScreenUi;\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n}): ReactNode {\n switch (screen.type) {\n case 'loading':\n return <LoadingScreen />;\n case 'error':\n return <AlertBanner variant=\"error\" icon content={screen.message} />;\n case 'review':\n return (\n <ReviewScreen\n fields={screen.fields}\n piiUnavailable={screen.piiUnavailable}\n signing={screen.signing}\n signError={screen.signError}\n onEvent={onEvent}\n />\n );\n case 'editing':\n return <EditScreen fields={screen.fields} onEvent={onEvent} />;\n case 'sign-only':\n return (\n <SignOnlyScreen\n signing={screen.signing}\n signError={screen.signError}\n onEvent={onEvent}\n />\n );\n default: {\n // A new screen without a case here is a compile error.\n const exhaustive: never = screen;\n return exhaustive;\n }\n }\n}\n\nfunction LoadingScreen(): ReactNode {\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\"\n >\n {[0, 1, 2, 3, 4].map((row) => (\n <div key={row} className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <div className=\"clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface\" />\n <div className=\"clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface\" />\n </div>\n ))}\n </output>\n );\n}\n\nfunction ReviewScreen({\n fields,\n piiUnavailable,\n signing,\n signError,\n onEvent,\n}: {\n fields: TaxDocumentFieldUi[];\n piiUnavailable: boolean;\n signing: boolean;\n signError: string | null;\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n}): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Review your information below. If anything looks incorrect, edit before\n signing.\n </p>\n\n {piiUnavailable && (\n <AlertBanner\n variant=\"info\"\n icon\n content=\"We don't have this information on file yet — please fill it in below.\"\n />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n {fields.map(({ field, label, displayValue }) => (\n <div\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}\n >\n {label}\n </span>\n <span className={cn(typeClasses.body, 'clcosdk:text-text-primary')}>\n {displayValue}\n </span>\n </div>\n ))}\n </div>\n\n <p className={cn(typeClasses.caption, 'clcosdk:text-text-secondary')}>\n By signing, you certify that the information above is accurate and that\n you are the beneficial owner of the income this form relates to. This\n document cannot be edited once signed.\n </p>\n\n {signError && <AlertBanner variant=\"error\" icon content={signError} />}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <ClButton\n fullWidth\n onClick={() => onEvent({ type: 'ON_SIGN' })}\n isLoading={signing}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN\n </ClButton>\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_START_EDIT' })}\n disabled={signing}\n >\n Edit information\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction EditScreen({\n fields,\n onEvent,\n}: {\n fields: TaxDocumentFieldUi[];\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n}): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n {fields.map(({ field, label, placeholder, value }) => (\n <label\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}\n >\n {label}\n </span>\n <input\n type=\"text\"\n value={value}\n placeholder={placeholder}\n onChange={(e) =>\n onEvent({\n type: 'ON_EDIT_FIELD',\n field,\n value: e.target.value,\n })\n }\n className={cn(\n typeClasses.body,\n 'clcosdk:rounded-lg clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:px-3 clcosdk:py-2 clcosdk:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400'\n )}\n />\n </label>\n ))}\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <ClButton fullWidth onClick={() => onEvent({ type: 'ON_SAVE_EDIT' })}>\n Save &amp; review\n </ClButton>\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_CANCEL_EDIT' })}\n >\n Cancel\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction SignOnlyScreen({\n signing,\n signError,\n onEvent,\n}: {\n signing: boolean;\n signError: string | null;\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n}): ReactNode {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n As an entity investor, you must complete a W-8BEN-E to confirm your\n foreign tax status and claim applicable treaty benefits. You'll receive\n an email to complete the signing.\n </p>\n\n {signError && <AlertBanner variant=\"error\" icon content={signError} />}\n\n <ClButton\n fullWidth\n onClick={() => onEvent({ type: 'ON_SIGN' })}\n isLoading={signing}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN-E\n </ClButton>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo } from 'react';\nimport type { TaxDocumentState } from '@/client/hooks/requirements/data/useTaxDocument';\nimport { useTaxDocument } from '@/client/hooks/requirements/data/useTaxDocument';\nimport type { TaxDocumentFields } from '@/client/hooks/requirements/shared/tax-document.types';\nimport type {\n TaxDocumentFieldUi,\n TaxDocumentModalUiEvent,\n TaxDocumentModalUiState,\n TaxDocumentScreenUi,\n} from '@/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel.types';\nimport type { DocumentSubmission } from '@/universal/types/document-submission';\n\nexport interface UseTaxDocumentModalViewModelOptions {\n isOpen: boolean;\n onClose: () => void;\n /** Called once the document is successfully signed, right before the modal closes. */\n onSubmitted?: (submission: DocumentSubmission) => void;\n}\n\nexport interface UseTaxDocumentModalViewModelResult {\n state: TaxDocumentModalUiState;\n onEvent: (event: TaxDocumentModalUiEvent) => void;\n}\n\nconst FIELD_ROWS: ReadonlyArray<{\n field: keyof TaxDocumentFields;\n label: string;\n placeholder?: string;\n}> = [\n { field: 'fullLegalName', label: 'Full legal name' },\n { field: 'dob', label: 'Date of birth', placeholder: 'MM/DD/YYYY' },\n { field: 'countryOfCitizenship', label: 'Country of citizenship' },\n { field: 'taxId', label: 'Tax ID' },\n { field: 'permanentAddress', label: 'Permanent address' },\n];\n\nconst EMPTY_VALUE = '—';\n\nconst NOT_AUTHENTICATED_MESSAGE = 'Sign in to complete your tax document.';\nconst GENERIC_ERROR_MESSAGE =\n 'Unable to load your tax information right now. Please try again.';\n\n/**\n * Drives {@link TaxDocumentModalView}: runs the W-8BEN / W-8BEN-E signing flow\n * through {@link useTaxDocument}, shapes each screen for rendering, and closes\n * the modal once the document is signed.\n */\nexport function useTaxDocumentModalViewModel({\n isOpen,\n onClose,\n onSubmitted,\n}: UseTaxDocumentModalViewModelOptions): UseTaxDocumentModalViewModelResult {\n const { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign } =\n useTaxDocument({ isOpen });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: only react to a SUBMITTED transition, not every state change\n useEffect(() => {\n if (state.type === 'SUBMITTED') {\n onSubmitted?.(state.submission);\n onClose();\n }\n }, [state]);\n\n const uiState = useMemo<TaxDocumentModalUiState>(() => {\n if (!isOpen || state.type === 'SUBMITTED') {\n return { type: 'hidden' };\n }\n return { type: 'content', title: toTitle(state), screen: toScreen(state) };\n }, [isOpen, state]);\n\n const onEvent = useCallback(\n (event: TaxDocumentModalUiEvent) => {\n switch (event.type) {\n case 'ON_CLOSE':\n onClose();\n return;\n case 'ON_START_EDIT':\n onStartEdit();\n return;\n case 'ON_EDIT_FIELD':\n onEditField(event.field, event.value);\n return;\n case 'ON_SAVE_EDIT':\n onSaveEdit();\n return;\n case 'ON_CANCEL_EDIT':\n onCancelEdit();\n return;\n case 'ON_SIGN':\n onSign();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n },\n [onClose, onStartEdit, onEditField, onSaveEdit, onCancelEdit, onSign]\n );\n\n return { state: uiState, onEvent };\n}\n\nfunction toTitle(state: TaxDocumentState): string {\n switch (state.type) {\n case 'EDITING':\n return 'Edit your W-8BEN';\n case 'REVIEW':\n return 'Confirm your W-8BEN';\n case 'SIGN_ONLY':\n return 'Confirm your W-8BEN-E';\n default:\n return 'Tax document';\n }\n}\n\nfunction toScreen(state: TaxDocumentState): TaxDocumentScreenUi {\n switch (state.type) {\n case 'LOADING':\n return { type: 'loading' };\n case 'ERROR':\n return {\n type: 'error',\n message:\n state.reason === 'not-authenticated'\n ? NOT_AUTHENTICATED_MESSAGE\n : GENERIC_ERROR_MESSAGE,\n };\n case 'REVIEW':\n return {\n type: 'review',\n fields: toFieldsUi(state.fields),\n piiUnavailable: state.piiUnavailable,\n signing: state.sign.type === 'signing',\n signError: state.sign.type === 'idle' ? state.sign.error : null,\n };\n case 'EDITING':\n return { type: 'editing', fields: toFieldsUi(state.fields) };\n case 'SIGN_ONLY':\n return {\n type: 'sign-only',\n signing: state.sign.type === 'signing',\n signError: state.sign.type === 'idle' ? state.sign.error : null,\n };\n default:\n // SUBMITTED never reaches here: the modal is hidden by then.\n return { type: 'loading' };\n }\n}\n\nfunction toFieldsUi(fields: TaxDocumentFields): TaxDocumentFieldUi[] {\n return FIELD_ROWS.map(({ field, label, placeholder }) => ({\n field,\n label,\n placeholder,\n value: fields[field],\n displayValue: fields[field] || EMPTY_VALUE,\n }));\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { TaxDocumentFields } from '@/client/hooks/requirements/shared/tax-document.types';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { DocumentSubmission } from '@/universal/types/document-submission';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { Pii } from '@/universal/types/pii';\n\n/**\n * Structured address pieces sent split in the payload (`City` / `Country`).\n * Kept separate from the single editable `permanentAddress` display string\n * and never shown or edited in the form.\n */\nexport type TaxDocumentAddressParts = {\n city: string;\n country: string;\n};\n\n/**\n * Signing-in-flight and the last sign error live inside the REVIEW/SIGN_ONLY\n * state (not a separate top-level state) so a failed sign never loses the\n * user's fields.\n */\nexport type SignState =\n | { type: 'idle'; error: string | null }\n | { type: 'signing' };\n\nexport type TaxDocumentState =\n | { type: 'LOADING' } // always fetches PII first, solely to read `kind`\n | {\n type: 'REVIEW';\n fields: TaxDocumentFields;\n addressParts: TaxDocumentAddressParts;\n piiUnavailable: boolean;\n sign: SignState;\n } // person only\n | {\n type: 'EDITING';\n fields: TaxDocumentFields;\n original: TaxDocumentFields;\n addressParts: TaxDocumentAddressParts;\n piiUnavailable: boolean;\n } // person only\n | { type: 'SIGN_ONLY'; sign: SignState } // company/trust only — no fields shown, ever\n | { type: 'ERROR'; reason: 'not-authenticated' | 'generic-error' } // fetchPii() failure only\n | { type: 'SUBMITTED'; submission: DocumentSubmission };\n\nexport interface UseTaxDocumentOptions {\n /** The hook only fetches PII while open; state resets each time it opens. */\n isOpen: boolean;\n}\n\nexport interface UseTaxDocumentResult {\n state: TaxDocumentState;\n onEditField: (field: keyof TaxDocumentFields, value: string) => void;\n onStartEdit: () => void; // REVIEW -> EDITING\n onSaveEdit: () => void; // EDITING -> REVIEW, local only, not submitted\n onCancelEdit: () => void; // EDITING -> REVIEW, discards changes\n onSign: () => void; // REVIEW.sign or SIGN_ONLY.sign: idle -> signing -> (SUBMITTED | idle w/ error)\n}\n\nconst IDLE_SIGN: SignState = { type: 'idle', error: null };\nconst LOADING_STATE: TaxDocumentState = { type: 'LOADING' };\nconst SIGN_FAILED_MESSAGE = 'Unable to sign document. Please try again.';\nconst DOB_INVALID_MESSAGE = 'Enter your date of birth as MM/DD/YYYY.';\n\n/**\n * Maps each editable field to its DocuSeal field name for the\n * `tax_certification` template. Values are forwarded verbatim to\n * Passport/DocuSeal by Frontline — see POST\n * /v1/documents/:document_type/submission. Keys must match the template's\n * field names exactly; unknown keys are silently ignored by DocuSeal.\n */\nconst FIELD_KEYS: Record<keyof TaxDocumentFields, string> = {\n fullLegalName: 'Full Name',\n dob: 'DOB',\n countryOfCitizenship: 'Country Of Citizenship',\n taxId: 'Foreign Tax Number',\n permanentAddress: 'Permanent Address',\n};\n\n/** Formats a `Date` as US `MM/DD/YYYY`. */\nfunction formatUsDate(date: Date): string {\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const year = String(date.getFullYear()).padStart(4, '0');\n return `${month}/${day}/${year}`;\n}\n\n/**\n * Converts a date-only ISO string (`YYYY-MM-DD`) to US `MM/DD/YYYY`.\n *\n * Reorders the parts as strings rather than going through `new Date()`, which\n * would interpret a bare date as UTC midnight and can shift the day in\n * negative timezones. Returns `''` for empty or malformed input.\n */\nfunction formatIsoDateOnly(isoDate: string): string {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(isoDate);\n if (!match) return '';\n const [, year, month, day] = match;\n return `${month}/${day}/${year}`;\n}\n\n/**\n * Returns `true` when `value` is a real calendar date in US `MM/DD/YYYY`\n * form. Rejects bad formats (`\"ABC\"`) and impossible dates (`\"02/30/2024\"`).\n */\nfunction isValidUsDate(value: string): boolean {\n const match = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/.exec(value);\n if (!match) return false;\n const [, mm, dd, yyyy] = match;\n const month = Number(mm);\n const day = Number(dd);\n const year = Number(yyyy);\n const date = new Date(year, month - 1, day);\n return (\n date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day\n );\n}\n\nfunction mapPiiToFields(pii: Pii): TaxDocumentFields {\n const { street, city, state, postalCode } = pii.permanentAddress;\n const cityLine = [postalCode, city].filter(Boolean).join(' ');\n const permanentAddress = [street, cityLine, state].filter(Boolean).join(', ');\n\n return {\n fullLegalName: pii.fullLegalName ?? '',\n // Date-only ISO from the backend, shown as MM/DD/YYYY. Blank until the\n // backend has a date of birth (the field is editable in the meantime).\n dob: formatIsoDateOnly(pii.dateOfBirth ?? ''),\n countryOfCitizenship: pii.jurisdiction?.name ?? '',\n taxId: pii.taxId ?? '',\n permanentAddress,\n };\n}\n\nfunction addressPartsFromPii(pii: Pii): TaxDocumentAddressParts {\n return {\n city: pii.permanentAddress.city ?? '',\n country: pii.permanentAddress.country ?? '',\n };\n}\n\nfunction hasAnyFieldValue(fields: TaxDocumentFields): boolean {\n return Object.values(fields).some((value) => value.trim() !== '');\n}\n\n/**\n * `Signature` echoes the full name (DocuSeal renders it as a font signature\n * on the template's signature field — required for Passport's auto-sign to\n * produce a signed document) and `Date` is the signing date.\n */\nfunction toSubmissionFields(\n fields: TaxDocumentFields,\n addressParts: TaxDocumentAddressParts\n): Record<string, string> {\n return {\n [FIELD_KEYS.fullLegalName]: fields.fullLegalName,\n [FIELD_KEYS.dob]: fields.dob,\n [FIELD_KEYS.countryOfCitizenship]: fields.countryOfCitizenship,\n [FIELD_KEYS.taxId]: fields.taxId,\n [FIELD_KEYS.permanentAddress]: fields.permanentAddress,\n City: addressParts.city,\n Country: addressParts.country,\n Signature: fields.fullLegalName,\n Date: formatUsDate(new Date()),\n };\n}\n\n/**\n * Loads the current user's PII and drives the tax document (W-8BEN /\n * W-8BEN-E) signing flow.\n *\n * Always fetches PII once per open — it's the only way to learn the\n * entity's `kind`. For company/trust entities the fetched values are\n * discarded (only `kind` is used) and the form is skipped entirely\n * (`SIGN_ONLY`); for individuals they seed the review screen (`REVIEW`).\n */\nexport function useTaxDocument({\n isOpen,\n}: UseTaxDocumentOptions): UseTaxDocumentResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useTaxDocument');\n const [state, setState] = useState<TaxDocumentState>(LOADING_STATE);\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!isOpen) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n setState(LOADING_STATE);\n return () => {\n isCancelled = true;\n };\n }\n\n setState(LOADING_STATE);\n coinlist.requirements\n .getPii()\n .then((pii) => {\n if (isCancelled) return;\n if (pii.kind === 'company') {\n setState({ type: 'SIGN_ONLY', sign: IDLE_SIGN });\n return;\n }\n const fields = mapPiiToFields(pii);\n setState({\n type: 'REVIEW',\n fields,\n addressParts: addressPartsFromPii(pii),\n piiUnavailable: !hasAnyFieldValue(fields),\n sign: IDLE_SIGN,\n });\n })\n .catch((error: unknown) => {\n if (isCancelled) return;\n const reason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setState({ type: 'ERROR', reason });\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, isOpen, log]);\n\n const onEditField = useCallback(\n (field: keyof TaxDocumentFields, value: string) => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? { ...prev, fields: { ...prev.fields, [field]: value } }\n : prev\n );\n },\n []\n );\n\n const onStartEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'REVIEW'\n ? {\n type: 'EDITING',\n fields: prev.fields,\n original: prev.fields,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n }\n : prev\n );\n }, []);\n\n const onSaveEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? {\n type: 'REVIEW',\n fields: prev.fields,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n sign: IDLE_SIGN,\n }\n : prev\n );\n }, []);\n\n const onCancelEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? {\n type: 'REVIEW',\n fields: prev.original,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n sign: IDLE_SIGN,\n }\n : prev\n );\n }, []);\n\n const onSign = useCallback(() => {\n if (state.type !== 'REVIEW' && state.type !== 'SIGN_ONLY') return;\n\n // Light validation: a blank DOB is allowed (the backend may not have one\n // yet); a non-blank DOB must be a real MM/DD/YYYY date.\n if (\n state.type === 'REVIEW' &&\n state.fields.dob.trim() !== '' &&\n !isValidUsDate(state.fields.dob)\n ) {\n setState({\n ...state,\n sign: { type: 'idle', error: DOB_INVALID_MESSAGE },\n });\n return;\n }\n\n setState({ ...state, sign: { type: 'signing' } });\n\n coinlist.requirements\n .submitDocument({\n documentType: 'tax_certification',\n fields:\n state.type === 'REVIEW'\n ? toSubmissionFields(state.fields, state.addressParts)\n : {},\n })\n .then((submission) => {\n setState({ type: 'SUBMITTED', submission });\n })\n .catch((error: unknown) => {\n log.failure(() => ({ msg: 'signing the tax document failed' }), error);\n setState((prev) =>\n prev.type === 'REVIEW' || prev.type === 'SIGN_ONLY'\n ? { ...prev, sign: { type: 'idle', error: SIGN_FAILED_MESSAGE } }\n : prev\n );\n });\n }, [state, coinlist, log]);\n\n return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { TaxDocumentModalView } from '@/client/components/requirements/tax-document/TaxDocumentModalView';\nimport { useTaxDocumentModalViewModel } from '@/client/hooks/requirements/tax-document/useTaxDocumentModalViewModel';\nimport type { DocumentSubmission } from '@/universal/types/document-submission';\n\nexport interface TaxDocumentModalContainerProps {\n isOpen: boolean;\n onClose: () => void;\n /** Called once the document is successfully signed, right before the modal closes. */\n onSubmitted?: (submission: DocumentSubmission) => void;\n className?: string;\n}\n\n/**\n * Batteries-included modal for the tax document (W-8BEN / W-8BEN-E) signing\n * flow, backed by {@link useTaxDocumentModalViewModel}. Fetches the current\n * user's PII via {@link useTaxDocument}, lets individuals review and edit it\n * before signing; company/trust entities see a plain sign screen with no\n * fields.\n */\nexport function TaxDocumentModalContainer({\n isOpen,\n onClose,\n onSubmitted,\n className,\n}: TaxDocumentModalContainerProps): ReactNode {\n const { state, onEvent } = useTaxDocumentModalViewModel({\n isOpen,\n onClose,\n onSubmitted,\n });\n\n return (\n <TaxDocumentModalView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\n\nexport interface VerificationOverlayProps {\n onClose: () => void;\n children: ReactNode;\n}\n\n/**\n * Full-screen overlay hosting the identity verification flow. Mirrors\n * frontline-web, where verification runs on a dedicated full page rather than\n * inside the requirement row.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope`\n * needed. It has to be, because the checklist renders it as a sibling of\n * `RequirementsChecklistView` rather than inside it, and its backdrop\n * (`bg-overlay`) is token-backed: outside `.clco-sdk-root` the token is\n * undefined and the scrim disappears entirely.\n */\nexport function VerificationOverlay({\n onClose,\n children,\n}: VerificationOverlayProps): ReactNode {\n return (\n <CoinListStyleScope>\n <VerificationOverlayBody onClose={onClose}>\n {children}\n </VerificationOverlayBody>\n </CoinListStyleScope>\n );\n}\n\nfunction VerificationOverlayBody({\n onClose,\n children,\n}: VerificationOverlayProps): ReactNode {\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Identity verification\"\n className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4\"\n >\n <div className=\"clcosdk:relative clcosdk:flex clcosdk:max-h-[92vh] clcosdk:w-full clcosdk:max-w-[760px] clcosdk:flex-col clcosdk:overflow-y-auto clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6 clcosdk:pt-14\">\n <CloseButton\n onClick={onClose}\n className=\"clcosdk:absolute clcosdk:top-4 clcosdk:right-4\"\n />\n {children}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { type ReactNode, useId } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n ConnectWalletModalUiEvent,\n ConnectWalletModalUiState,\n ConnectWalletScreenUi,\n} from '@/client/hooks/requirements/wallet/useConnectWalletModalViewModel.types';\n\nexport interface ConnectWalletModalViewProps {\n state: ConnectWalletModalUiState;\n onEvent: (event: ConnectWalletModalUiEvent) => void;\n className?: string;\n}\n\n/**\n * Modal for the external-wallet ownership flow: prompt for a wallet, then ask\n * the user to sign a message proving they own it. Pure: signing is requested\n * through `onEvent` and performed by the host's wallet, since the SDK never\n * bundles a wallet stack.\n *\n * No portal is used - rendering stays inside the normal DOM tree. Self-scoped:\n * renders fully styled on its own, with no `CoinListStyleScope` needed, so it\n * is styled wherever the host places it and wherever the checklist renders it\n * (as a sibling of `RequirementsChecklistView`, outside that View's scope).\n */\nexport function ConnectWalletModalView({\n state,\n onEvent,\n className,\n}: ConnectWalletModalViewProps): ReactNode {\n // Instance-local so two open modals can't collide on a shared heading id.\n // Called before the early return, so the hook order never varies.\n const titleId = useId();\n\n // Bail before the scope, so a closed modal leaves nothing in the DOM rather\n // than an empty .clco-sdk-root.\n if (state.type === 'hidden') {\n return null;\n }\n\n return (\n <CoinListStyleScope>\n <div className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4\">\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4\">\n <h3\n id={titleId}\n className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}\n >\n Connect your wallet\n </h3>\n <CloseButton onClick={() => onEvent({ type: 'ON_CLOSE' })} />\n </div>\n\n <Screen\n screen={state.screen}\n canRequestConnect={state.canRequestConnect}\n onEvent={onEvent}\n />\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n\nfunction Screen({\n screen,\n canRequestConnect,\n onEvent,\n}: {\n screen: ConnectWalletScreenUi;\n canRequestConnect: boolean;\n onEvent: (event: ConnectWalletModalUiEvent) => void;\n}): ReactNode {\n switch (screen.type) {\n case 'needs-wallet':\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Connect an external wallet to prove ownership and bind it to this\n offer.\n </p>\n {canRequestConnect && (\n <ClButton\n fullWidth\n onClick={() => onEvent({ type: 'ON_REQUEST_CONNECT' })}\n >\n Connect wallet\n </ClButton>\n )}\n </div>\n );\n case 'ready':\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Sign a message with your connected wallet to prove you own it. This\n does not cost gas or move any funds.\n </p>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}\n >\n Wallet address\n </span>\n <span className={cn(typeClasses.body, 'clcosdk:text-text-primary')}>\n {screen.shortAddress}\n </span>\n </div>\n\n {screen.signError && (\n // Live region: the error is inserted async after a failed attempt,\n // so screen readers need it announced rather than silently\n // rendered.\n <div role=\"alert\">\n <AlertBanner variant=\"error\" icon content={screen.signError} />\n </div>\n )}\n\n <ClButton\n fullWidth\n onClick={() => onEvent({ type: 'ON_SIGN' })}\n isLoading={screen.signing}\n loadingText=\"Waiting for signature...\"\n disabled={screen.signDisabled}\n >\n Sign &amp; connect\n </ClButton>\n\n {canRequestConnect && (\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={() => onEvent({ type: 'ON_REQUEST_CONNECT' })}\n disabled={screen.signing}\n >\n Use a different wallet\n </ClButton>\n )}\n </div>\n );\n default: {\n // A new screen without a case here is a compile error.\n const exhaustive: never = screen;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo } from 'react';\nimport { useConnectWallet } from '@/client/hooks/requirements/data/useConnectWallet';\nimport type {\n ConnectWalletModalUiEvent,\n ConnectWalletModalUiState,\n} from '@/client/hooks/requirements/wallet/useConnectWalletModalViewModel.types';\nimport { shortenAddress } from '@/universal/core/shared/blockchain/formatters';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { OfferOptionAddress } from '@/universal/types/offer-option-address';\nimport type { WalletChallengeType } from '@/universal/types/wallet-ownership-challenge';\n\nexport interface UseConnectWalletModalViewModelOptions {\n isOpen: boolean;\n onClose: () => void;\n offerId: OfferId;\n optionId: OfferOptionId;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet: ConnectWallet | null;\n /** Called once the wallet is bound to the offer option, right before close. */\n onConnected?: (binding: OfferOptionAddress) => void;\n /**\n * Called when the user asks to connect (or switch) a wallet: the \"Connect\n * wallet\" button when none is connected, and \"Use a different wallet\" when\n * one already is.\n */\n onRequestConnect?: () => void;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n}\n\nexport interface UseConnectWalletModalViewModelResult {\n state: ConnectWalletModalUiState;\n onEvent: (event: ConnectWalletModalUiEvent) => void;\n}\n\n/**\n * Drives {@link ConnectWalletModalView}: runs the external-wallet ownership\n * flow through {@link useConnectWallet} (challenge -> host signs -> connect)\n * for one offer option, and closes the modal once the wallet is bound.\n */\nexport function useConnectWalletModalViewModel({\n isOpen,\n onClose,\n offerId,\n optionId,\n wallet,\n onConnected,\n onRequestConnect,\n challengeType,\n statement,\n}: UseConnectWalletModalViewModelOptions): UseConnectWalletModalViewModelResult {\n const { state, onSign } = useConnectWallet({\n isOpen,\n offerId,\n offerOptionId: optionId,\n wallet,\n challengeType,\n statement,\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: only react to a CONNECTED transition, not every state change\n useEffect(() => {\n if (state.type === 'CONNECTED') {\n onConnected?.(state.binding);\n onClose();\n }\n }, [state]);\n\n const uiState = useMemo<ConnectWalletModalUiState>(() => {\n if (!isOpen || state.type === 'CONNECTED') {\n return { type: 'hidden' };\n }\n\n const canRequestConnect = onRequestConnect !== undefined;\n\n if (state.type === 'NEEDS_WALLET') {\n return {\n type: 'content',\n screen: { type: 'needs-wallet' },\n canRequestConnect,\n };\n }\n\n const signError = state.sign.type === 'idle' ? state.sign.error : null;\n return {\n type: 'content',\n screen: {\n type: 'ready',\n shortAddress: shortenAddress(state.address),\n signing: state.sign.type === 'signing',\n signError: signError?.message ?? null,\n signDisabled: signError !== null && !signError.retryable,\n },\n canRequestConnect,\n };\n }, [isOpen, state, onRequestConnect]);\n\n const onEvent = useCallback(\n (event: ConnectWalletModalUiEvent) => {\n switch (event.type) {\n case 'ON_CLOSE':\n onClose();\n return;\n case 'ON_SIGN':\n onSign();\n return;\n case 'ON_REQUEST_CONNECT':\n onRequestConnect?.();\n return;\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n },\n [onClose, onSign, onRequestConnect]\n );\n\n return { state: uiState, onEvent };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n type ConnectWalletErrorCode,\n connectExternalWalletFlow,\n} from '@/client/core/wallets/connect-external-wallet';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { EvmWalletAddress } from '@/universal/types/blockchain/core';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { OfferOptionAddress } from '@/universal/types/offer-option-address';\nimport type { WalletChallengeType } from '@/universal/types/wallet-ownership-challenge';\n\n/**\n * A display-ready connect-wallet error: the core flow's machine-readable code\n * and `retryable` flag, plus copy for the UI.\n */\nexport type ConnectWalletError = {\n code: ConnectWalletErrorCode;\n message: string;\n retryable: boolean;\n};\n\n/**\n * Signing-in-flight and the last sign error live inside the READY state (not a\n * separate top-level state) so a failed attempt returns to READY and can be\n * retried without re-opening the modal. Mirrors {@link SignState} in\n * `useTaxDocument`.\n */\nexport type ConnectWalletSignState =\n | { type: 'idle'; error: ConnectWalletError | null }\n | { type: 'signing' };\n\nexport type ConnectWalletState =\n | { type: 'NEEDS_WALLET' } // no wallet connected yet; host must connect one\n | { type: 'READY'; address: EvmWalletAddress; sign: ConnectWalletSignState }\n | { type: 'CONNECTED'; binding: OfferOptionAddress };\n\nexport interface UseConnectWalletOptions {\n /** The hook resets state each time it opens. */\n isOpen: boolean;\n offerId: OfferId;\n offerOptionId: OfferOptionId;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet: ConnectWallet | null;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n}\n\nexport interface UseConnectWalletResult {\n state: ConnectWalletState;\n /** READY.sign: idle -> signing -> (CONNECTED | idle w/ error). No-op otherwise. */\n onSign: () => void;\n}\n\nconst IDLE_SIGN: ConnectWalletSignState = { type: 'idle', error: null };\n\nconst ERROR_COPY: Record<ConnectWalletErrorCode, string> = {\n not_authenticated: 'Sign in to connect your wallet.',\n user_rejected:\n 'Signature request declined. Approve it in your wallet to continue.',\n wallet_not_whitelisted: 'This wallet is not approved for this offer.',\n max_wallets_reached:\n \"You've reached the maximum number of wallets for this option.\",\n unknown: 'Unable to connect your wallet. Please try again.',\n};\n\nfunction displayError(error: {\n code: ConnectWalletErrorCode;\n retryable: boolean;\n}): ConnectWalletError {\n return {\n code: error.code,\n message: ERROR_COPY[error.code],\n retryable: error.retryable,\n };\n}\n\n/**\n * React wrapper over {@link connectExternalWalletFlow}. Owns the modal state\n * machine, the display copy, and generation-token supersession (so a wallet\n * switch, modal close, or unmount cancels an in-flight attempt). The flow logic\n * itself lives in the framework-free core so non-React consumers can drive it.\n */\nexport function useConnectWallet({\n isOpen,\n offerId,\n offerOptionId,\n wallet,\n challengeType,\n statement,\n}: UseConnectWalletOptions): UseConnectWalletResult {\n const { coinlist } = useCoinList();\n const [state, setState] = useState<ConnectWalletState>(() =>\n wallet\n ? { type: 'READY', address: wallet.address, sign: IDLE_SIGN }\n : { type: 'NEEDS_WALLET' }\n );\n\n // Generation token for the in-flight attempt. Each `onSign` bumps it; the\n // reset effect (open / address change) and unmount bump it too, superseding\n // any attempt still in flight so its continuation becomes a no-op.\n const attempt = useRef(0);\n\n // Reset when the modal opens or the connected address changes. Keyed on the\n // address (not the wallet object) so re-creating the adapter with the same\n // address doesn't wipe an in-flight sign or a surfaced error.\n // biome-ignore lint/correctness/useExhaustiveDependencies: reset only on open/address change, not on every wallet-object identity change\n useEffect(() => {\n // Invalidate any in-flight attempt, including on close (isOpen -> false).\n attempt.current += 1;\n if (!isOpen) return;\n setState(\n wallet\n ? { type: 'READY', address: wallet.address, sign: IDLE_SIGN }\n : { type: 'NEEDS_WALLET' }\n );\n }, [isOpen, wallet?.address]);\n\n // Invalidate any in-flight attempt if the hook unmounts. A host can\n // conditionally unmount the exported modal mid-signature; without this the\n // pending flow could bind after the UI is gone.\n useEffect(\n () => () => {\n attempt.current += 1;\n },\n []\n );\n\n const onSign = useCallback(() => {\n if (!wallet || state.type !== 'READY') return;\n\n attempt.current += 1;\n const gen = attempt.current;\n\n setState({\n type: 'READY',\n address: wallet.address,\n sign: { type: 'signing' },\n });\n\n connectExternalWalletFlow({\n coinlist,\n wallet,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n // Cancels the flow before signing / binding if this attempt is superseded.\n isCancelled: () => attempt.current !== gen,\n }).then((result) => {\n // A supersession that lands between the core's last check and here.\n if (attempt.current !== gen) return;\n if (result.type === 'success') {\n setState({ type: 'CONNECTED', binding: result.binding });\n } else if (result.type === 'error') {\n setState({\n type: 'READY',\n address: wallet.address,\n sign: { type: 'idle', error: displayError(result.error) },\n });\n }\n // 'cancelled' -> no-op; a newer attempt owns the state.\n });\n }, [\n wallet,\n state,\n coinlist,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n ]);\n\n return { state, onSign };\n}\n","import type { Hex } from 'viem';\nimport { classifyWalletError } from '@/client/core/shared/blockchain/wallet-error';\nimport type { WalletsNamespace } from '@/universal/core/wallets/wallets-namespace';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { OfferOptionAddress } from '@/universal/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletChallengeType,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\n/**\n * Machine-readable classification of a connect-wallet failure, so consumers can\n * branch on the cause (e.g. hide a retry affordance on a terminal failure)\n * instead of pattern-matching a display string.\n */\nexport type ConnectWalletErrorCode =\n | 'not_authenticated'\n | 'user_rejected'\n | 'wallet_not_whitelisted'\n | 'max_wallets_reached'\n | 'unknown';\n\n/**\n * A classified connect-wallet failure. `retryable` is false when re-signing the\n * same wallet can never succeed (a terminal binding rejection, or no signed-in\n * session). Display copy is the caller's concern, kept out of the core.\n */\nexport type ConnectWalletFlowError = {\n code: ConnectWalletErrorCode;\n retryable: boolean;\n};\n\n/** Progress phases emitted by {@link connectExternalWalletFlow}, in order. */\nexport type ConnectWalletPhase =\n | 'requesting-challenge'\n | 'signing-message'\n | 'submitting-signature';\n\nexport type ConnectWalletFlowResult =\n | { type: 'success'; binding: OfferOptionAddress }\n | { type: 'cancelled' }\n | { type: 'error'; error: ConnectWalletFlowError };\n\n/**\n * The client surface the flow actually depends on, kept narrow on purpose.\n *\n * Named as a structural slice rather than `Pick<CoinListClient, 'wallets'>` so\n * this feature does not import its layer's entry point: a flow takes the\n * namespaces it needs, the way `@/client/core/checkout/**` flows do.\n */\ntype ConnectWalletClient = { wallets: WalletsNamespace };\n\nexport type ConnectWalletFlowParams = {\n coinlist: ConnectWalletClient;\n /** Host-provided connected wallet the flow signs with. */\n wallet: ConnectWallet;\n offerId: OfferId;\n offerOptionId: OfferOptionId;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n /**\n * Polled before each irreversible step (signing, binding). Return true to\n * abandon a superseded attempt; the flow then resolves `{ type: 'cancelled' }`\n * without prompting the wallet or binding. React hooks pass a generation\n * check here; non-React callers can omit it.\n */\n isCancelled?: () => boolean;\n /** Reports flow progress for consumers rendering loading states. */\n onProgress?: (phase: ConnectWalletPhase) => void;\n};\n\nconst DEFAULT_STATEMENT =\n 'Sign this message to prove you own this wallet. This does not cost gas or move funds.';\n\n// Codes for which re-signing the same wallet can never succeed: no signed-in\n// session, or a terminal binding rejection.\nconst TERMINAL_CODES: ReadonlySet<ConnectWalletErrorCode> = new Set([\n 'not_authenticated',\n 'wallet_not_whitelisted',\n 'max_wallets_reached',\n]);\n\n// The subset the connect endpoint returns as a machine-readable `code` in its\n// 422 ApiErrorDto body.\nconst API_ERROR_CODES: ReadonlySet<ConnectWalletErrorCode> = new Set([\n 'wallet_not_whitelisted',\n 'max_wallets_reached',\n]);\n\nfunction flowError(code: ConnectWalletErrorCode): ConnectWalletFlowError {\n return { code, retryable: !TERMINAL_CODES.has(code) };\n}\n\n/**\n * Returns `{ domain, uri }` for a SIWE challenge, derived from the current page.\n * The flow only runs from a user action, so `window` is present; the\n * empty-string fallback just keeps this total for SSR and is never reached.\n */\nfunction siweContext(): { domain: string; uri: string } {\n if (typeof window === 'undefined') return { domain: '', uri: '' };\n return { domain: window.location.host, uri: window.location.origin };\n}\n\n/**\n * Reads the machine-readable `code` off an HTTP failure's `ApiErrorDto` body.\n * Duck-typed on the response shape rather than `instanceof HttpError`: the core\n * avoids importing the `@/universal/api` layer, so we match the structure instead.\n */\nfunction apiErrorCode(error: unknown): string | undefined {\n if (typeof error !== 'object' || error === null) return undefined;\n const body = (error as { response?: { body?: { code?: unknown } } }).response\n ?.body;\n return typeof body?.code === 'string' ? body.code : undefined;\n}\n\n/**\n * Classifies a challenge/connect API failure (not a wallet-thrown error). The\n * connect endpoint returns a machine-readable `code` in its 422 body for\n * terminal binding failures; everything else (a transient error, or an\n * expired/consumed-challenge 422 a fresh challenge retries) stays `unknown` and\n * retryable.\n */\nfunction classifyApiError(error: unknown): ConnectWalletFlowError {\n if (error instanceof NotAuthenticatedError) {\n return flowError('not_authenticated');\n }\n const code = apiErrorCode(error);\n if (\n code !== undefined &&\n API_ERROR_CODES.has(code as ConnectWalletErrorCode)\n ) {\n return flowError(code as ConnectWalletErrorCode);\n }\n return flowError('unknown');\n}\n\n/**\n * Builds the challenge-request params for the wallet's chain and framing. The\n * exhaustive `switch` makes adding a 3rd challenge type a compile error here\n * rather than a silent wrong branch.\n */\nfunction challengeParams(\n wallet: ConnectWallet,\n challengeType: WalletChallengeType,\n statement: string | undefined\n): CreateWalletOwnershipChallengeParams {\n switch (challengeType) {\n case 'siwe':\n return {\n walletAddress: wallet.address,\n chain: wallet.chain,\n challengeType: 'siwe',\n ...siweContext(),\n statement: statement ?? DEFAULT_STATEMENT,\n };\n case 'plain':\n return {\n walletAddress: wallet.address,\n chain: wallet.chain,\n challengeType: 'plain',\n };\n default: {\n const _exhaustive: never = challengeType;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Drives the external-wallet ownership flow for one offer option:\n * `createWalletOwnershipChallenge` -> host `wallet.signMessage` ->\n * `connectExternalWallet`. Pure and signer-agnostic: signing is delegated to\n * the host-provided {@link ConnectWallet}, and no React is involved so non-hook\n * consumers can drive it directly (mirrors `authorizeWallet` in `swap-flows`).\n * EVM / EOA + SIWE only for now.\n */\nexport async function connectExternalWalletFlow(\n params: ConnectWalletFlowParams\n): Promise<ConnectWalletFlowResult> {\n const {\n coinlist,\n wallet,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n isCancelled,\n onProgress,\n } = params;\n const emit = (phase: ConnectWalletPhase) => onProgress?.(phase);\n const cancelled = () => isCancelled?.() ?? false;\n\n // Step 1: Request a single-use ownership challenge to sign.\n emit('requesting-challenge');\n let challenge: WalletOwnershipChallenge;\n try {\n challenge = await coinlist.wallets.createOwnershipChallenge(\n challengeParams(wallet, challengeType ?? 'siwe', statement)\n );\n } catch (error) {\n return { type: 'error', error: classifyApiError(error) };\n }\n\n // Superseded while the challenge was in flight: don't prompt the old wallet.\n if (cancelled()) return { type: 'cancelled' };\n\n // Step 2: Sign the challenge message with the host wallet.\n emit('signing-message');\n let signature: Hex;\n try {\n signature = await wallet.signMessage(challenge.message);\n } catch (error) {\n // Reuse the shared viem/user-rejection classifier for wallet-thrown errors.\n if (classifyWalletError(error).type === 'user_rejected') {\n return { type: 'error', error: flowError('user_rejected') };\n }\n return { type: 'error', error: flowError('unknown') };\n }\n\n // Superseded during signing: don't perform the irreversible bind.\n if (cancelled()) return { type: 'cancelled' };\n\n // Step 3: Submit the signature to bind the wallet to the offer option.\n emit('submitting-signature');\n try {\n const binding = await coinlist.wallets.connectExternal({\n offerId,\n offerOptionId,\n walletAddress: wallet.address,\n chain: wallet.chain,\n signature,\n });\n return { type: 'success', binding };\n } catch (error) {\n return { type: 'error', error: classifyApiError(error) };\n }\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { ConnectWalletModalView } from '@/client/components/requirements/wallet/ConnectWalletModalView';\nimport { useConnectWalletModalViewModel } from '@/client/hooks/requirements/wallet/useConnectWalletModalViewModel';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { OfferOptionAddress } from '@/universal/types/offer-option-address';\nimport type { WalletChallengeType } from '@/universal/types/wallet-ownership-challenge';\n\nexport interface ConnectWalletModalContainerProps {\n isOpen: boolean;\n onClose: () => void;\n offerId: OfferId;\n optionId: OfferOptionId;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet: ConnectWallet | null;\n /** Called once the wallet is bound to the offer option, right before close. */\n onConnected?: (binding: OfferOptionAddress) => void;\n /**\n * Called when the user asks to connect (or switch) a wallet: the \"Connect\n * wallet\" button when none is connected, and \"Use a different wallet\" when one\n * already is.\n */\n onRequestConnect?: () => void;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n className?: string;\n}\n\n/**\n * Batteries-included modal for the external-wallet ownership flow, backed by\n * {@link useConnectWalletModalViewModel}, which drives\n * {@link useConnectWallet} (challenge -> host signs -> connect) for one offer\n * option. Signing is delegated to the host-provided {@link ConnectWallet}: the\n * SDK never bundles a wallet stack.\n */\nexport function ConnectWalletModalContainer({\n className,\n ...options\n}: ConnectWalletModalContainerProps): ReactNode {\n const { state, onEvent } = useConnectWalletModalViewModel(options);\n\n return (\n <ConnectWalletModalView\n state={state}\n onEvent={onEvent}\n className={className}\n />\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useOptionAddresses } from '@/client/hooks/requirements/data/useOptionAddresses';\nimport type { RequirementsData } from '@/client/hooks/requirements/data/useRequirements';\nimport { useRequirements } from '@/client/hooks/requirements/data/useRequirements';\nimport {\n ChecklistStatus,\n RequirementItemUi,\n type RequirementsChecklistUiEvent,\n type RequirementsChecklistUiState,\n type RequirementsVerificationUi,\n RequirementVariant,\n type WalletsStatus,\n} from '@/client/hooks/requirements/useRequirementsChecklistViewModel.types';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport { OfferOptionAddressId } from '@/universal/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/universal/types/requirement';\n\nexport interface UseRequirementsChecklistViewModelOptions {\n offerId: OfferId;\n optionId: OfferOptionId;\n title: string;\n description: string;\n onContinue?: () => void;\n /**\n * Called when the user clicks a requirement's action button. Defaults to\n * `CoinListClient#requirements.handle`, except for `document` requirements,\n * which open the built-in tax document modal, and wallet requirements with a\n * host wallet, which open the built-in connect flow. Pass `null` to disable\n * the action button entirely.\n */\n onRequirementActionOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Called when the user clicks \"Contact support\" on a rejected requirement.\n * Defaults to `CoinListClient#support.contact`. Pass `null` to disable the\n * button entirely.\n */\n onContactSupportOverride?: ((requirement: Requirement) => void) | null;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet?: ConnectWallet | null;\n /** Called when the user asks to connect a wallet and none is connected yet. */\n onRequestConnect?: () => void;\n /** Override the default label for a requirement type. */\n getLabel?: (requirement: Requirement) => string;\n /** Override the default description for a requirement type. */\n getDescription?: (requirement: Requirement) => string | null;\n /** Requirements pre-fetched on the server. */\n data?: RequirementsData;\n /**\n * Default `true`. When `false` nothing is fetched, so the hook can be called\n * unconditionally while the checklist is not needed yet.\n */\n enabled?: boolean;\n /** Options for the inline Sumsub verification flow. */\n identityVerificationOptions?: {\n levelName?: KycLevelName;\n locale?: string;\n };\n}\n\nexport interface UseRequirementsChecklistViewModelResult {\n state: RequirementsChecklistUiState;\n onEvent: (event: RequirementsChecklistUiEvent) => void;\n}\n\nconst DEFAULT_LABELS: Record<RequirementType, string> = {\n kyc_approved: 'Identity Verification',\n external_wallet: 'External Wallet',\n whitelisted_wallet: 'Whitelisted Wallet',\n jurisdiction: 'Jurisdiction Check',\n accreditation: 'Accreditation',\n document: 'Tax Documentation',\n};\n\nconst DEFAULT_DESCRIPTIONS: Record<RequirementType, string> = {\n kyc_approved: 'Complete Know Your Customer (KYC) verification.',\n external_wallet: 'Connect an external wallet.',\n whitelisted_wallet: 'Connect a whitelisted wallet.',\n jurisdiction: 'Confirm your jurisdiction eligibility.',\n accreditation: 'Confirm that you meet accredited investor requirements.',\n document: 'Review and sign the required tax documentation.',\n};\n\n/** How often to check requirement statuses after the Sumsub flow is submitted. */\nconst VERIFICATION_POLL_INTERVAL_MS = 5_000;\n/** How long to keep checking before giving up and refreshing the checklist anyway. */\nconst VERIFICATION_POLL_TIMEOUT_MS = 120_000;\n\nconst isWalletRequirement = (requirement: Requirement): boolean =>\n RequirementVariant.fromType(requirement.type) === 'wallet';\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Drives {@link RequirementsChecklistView}: loads the requirements and their\n * statuses for one offer option, shapes each row, and owns the three flows the\n * checklist can open (tax document, wallet connect, identity verification).\n *\n * Pass `enabled: false` to skip fetches when the hook must be called but\n * the checklist is not needed yet.\n */\nexport function useRequirementsChecklistViewModel(\n options: UseRequirementsChecklistViewModelOptions\n): UseRequirementsChecklistViewModelResult {\n const {\n offerId,\n optionId,\n title,\n description,\n onContinue,\n onRequirementActionOverride,\n onContactSupportOverride,\n wallet,\n onRequestConnect,\n getLabel,\n getDescription,\n data,\n enabled = true,\n identityVerificationOptions,\n } = options;\n const log = useLogger('useRequirementsChecklistViewModel');\n\n const { coinlist } = useCoinList();\n const { requirementsState, refetch } = useRequirements(offerId, {\n data,\n enabled,\n });\n const [expandedId, setExpandedId] = useState<RequirementId | null>(null);\n const [taxDocumentOpen, setTaxDocumentOpen] = useState(false);\n const [connectWalletOpen, setConnectWalletOpen] = useState(false);\n const [verifyingRequirementId, setVerifyingRequirementId] =\n useState<RequirementId | null>(null);\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n // The connected wallets are per-option, so fetch them once for this option and\n // only when it actually has a wallet requirement to display them against.\n // Latch on the last known CONTENT: a requirements refetch (remove / connect /\n // tax / verify) dips requirementsState to LOADING, and reading the flag off\n // that dip would flip the fetch off and on, churning the wallet list.\n const [hasWalletRequirement, setHasWalletRequirement] = useState(false);\n useEffect(() => {\n if (requirementsState.type === 'CONTENT') {\n setHasWalletRequirement(\n (requirementsState.requirements[optionId] ?? []).some(\n isWalletRequirement\n )\n );\n }\n }, [requirementsState, optionId]);\n\n const {\n addressesState,\n refetch: refetchAddresses,\n disconnect,\n } = useOptionAddresses(offerId, optionId, {\n enabled: enabled && hasWalletRequirement,\n });\n\n const removeWallet = useCallback(\n async (addressId: string) => {\n await disconnect(OfferOptionAddressId(addressId));\n // Removing a wallet can flip the requirement back to actionable, so\n // refresh the statuses too (disconnect already refetched the wallets).\n refetch();\n },\n [disconnect, refetch]\n );\n\n // After the user submits the Sumsub flow, the verification result arrives\n // asynchronously (Sumsub webhook -> backend). Poll requirement statuses until\n // this requirement's status moves off its pre-submit value, then refresh.\n const awaitVerificationResult = useCallback(\n (\n requirementId: RequirementId,\n statusBeforeSubmit: RequirementStatusValue\n ) => {\n void (async () => {\n const deadline = Date.now() + VERIFICATION_POLL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await sleep(VERIFICATION_POLL_INTERVAL_MS);\n if (!isMountedRef.current) return;\n try {\n const statuses = await coinlist.requirements.statuses(offerId);\n const current = statuses.find(\n (s) => s.id === requirementId\n )?.status;\n if (current !== undefined && current !== statusBeforeSubmit) break;\n } catch (_) {\n // Transient fetch errors: keep polling until the deadline. The\n // call itself is already reported by the REQUIREMENTS namespace,\n // with its cause; only the swallow is news here.\n log.debug(() => ({\n msg: 'status poll tick failed; retrying until deadline',\n }));\n }\n }\n if (isMountedRef.current) {\n setVerifyingRequirementId(null);\n refetch();\n }\n })();\n },\n [coinlist, offerId, refetch, log]\n );\n\n const requirements = useMemo(\n () =>\n requirementsState.type === 'CONTENT'\n ? (requirementsState.requirements[optionId] ?? [])\n : [],\n [requirementsState, optionId]\n );\n\n const statusById = useMemo(() => {\n if (requirementsState.type !== 'CONTENT') {\n return new Map<RequirementId, RequirementStatusInfo>();\n }\n const ids = new Set(requirements.map((r) => r.id));\n return new Map(\n requirementsState.statuses\n .filter((s) => ids.has(s.id))\n .map((s) => [s.id, s])\n );\n }, [requirementsState, requirements]);\n\n const state = useMemo<RequirementsChecklistUiState>(() => {\n switch (requirementsState.type) {\n case 'LOADING':\n return { type: 'loading', title, description };\n case 'ERROR':\n return { type: 'error', title };\n case 'CONTENT': {\n const optionStatuses = [...statusById.values()];\n const checklistStatus = ChecklistStatus.derive(optionStatuses);\n const optionAddresses =\n addressesState.type === 'CONTENT' ? addressesState.addresses : [];\n // A failed or in-flight wallet fetch must not read as \"no wallets\n // connected\", so surface its load state rather than an empty list.\n const walletsStatus: WalletsStatus =\n addressesState.type === 'ERROR'\n ? 'error'\n : addressesState.type === 'LOADING'\n ? 'loading'\n : 'ready';\n\n return {\n type: 'content',\n title,\n description,\n ineligible: checklistStatus === 'ineligible',\n continueAction: onContinue\n ? { enabled: checklistStatus === 'eligible' }\n : null,\n taxDocumentOpen,\n connectWalletOpen,\n verification: toVerificationUi(\n verifyingRequirementId,\n statusById,\n identityVerificationOptions\n ),\n removeWallet,\n items: requirements.map((requirement) => {\n const statusInfo = statusById.get(requirement.id);\n const walletRequirement = isWalletRequirement(requirement);\n return {\n id: requirement.id,\n item: RequirementItemUi.fromDomain(\n requirement,\n statusInfo,\n getLabel?.(requirement) ?? DEFAULT_LABELS[requirement.type],\n getDescription?.(requirement) ??\n DEFAULT_DESCRIPTIONS[requirement.type],\n walletRequirement ? optionAddresses : []\n ),\n expanded: expandedId === requirement.id,\n actionEnabled: onRequirementActionOverride !== null,\n contactSupportEnabled: onContactSupportOverride !== null,\n wallets: walletRequirement ? { status: walletsStatus } : null,\n };\n }),\n };\n }\n default: {\n // A new requirements state without a case here is a compile error.\n const exhaustive: never = requirementsState;\n return exhaustive;\n }\n }\n }, [\n requirementsState,\n requirements,\n statusById,\n addressesState,\n title,\n description,\n onContinue,\n onRequirementActionOverride,\n onContactSupportOverride,\n getLabel,\n getDescription,\n expandedId,\n taxDocumentOpen,\n connectWalletOpen,\n verifyingRequirementId,\n identityVerificationOptions,\n removeWallet,\n ]);\n\n const handleRequirementAction = useCallback(\n (requirement: Requirement) => {\n // The backend prescribes the inline Sumsub flow by putting a kycLevel on\n // the status.\n const inlineVerification =\n statusById.get(requirement.id)?.kycLevel !== undefined &&\n onRequirementActionOverride === undefined;\n if (inlineVerification) {\n setVerifyingRequirementId(requirement.id);\n return;\n }\n if (onRequirementActionOverride) {\n onRequirementActionOverride(requirement);\n return;\n }\n if (onRequirementActionOverride === null) {\n return;\n }\n if (requirement.type === 'document') {\n setTaxDocumentOpen(true);\n return;\n }\n // Only drive the in-app modal when it can actually complete the\n // requirement: a connected wallet to sign with, or a way to connect one\n // (`onRequestConnect`). A bare `wallet={null}` with no `onRequestConnect`\n // would strand the user on a dead-end screen, so fall through to\n // `requirements.handle` instead.\n if (\n isWalletRequirement(requirement) &&\n wallet !== undefined &&\n (wallet !== null || onRequestConnect !== undefined)\n ) {\n setConnectWalletOpen(true);\n return;\n }\n coinlist.requirements.handle(requirement);\n },\n [\n statusById,\n onRequirementActionOverride,\n wallet,\n onRequestConnect,\n coinlist,\n ]\n );\n\n const onEvent = useCallback(\n (event: RequirementsChecklistUiEvent) => {\n switch (event.type) {\n case 'ON_TOGGLE_ITEM':\n setExpandedId((prev) =>\n prev === event.requirementId ? null : event.requirementId\n );\n return;\n case 'ON_REQUIREMENT_ACTION': {\n const requirement = requirements.find(\n (r) => r.id === event.requirementId\n );\n if (requirement) {\n handleRequirementAction(requirement);\n }\n return;\n }\n case 'ON_CONTACT_SUPPORT': {\n if (onContactSupportOverride === null) {\n return;\n }\n const requirement = requirements.find(\n (r) => r.id === event.requirementId\n );\n if (!requirement) {\n return;\n }\n if (onContactSupportOverride) {\n onContactSupportOverride(requirement);\n return;\n }\n coinlist.support.contact();\n return;\n }\n case 'ON_CONTINUE':\n onContinue?.();\n return;\n case 'ON_CLOSE_TAX_DOCUMENT':\n setTaxDocumentOpen(false);\n return;\n case 'ON_TAX_DOCUMENT_SUBMITTED':\n refetch();\n return;\n case 'ON_CLOSE_CONNECT_WALLET':\n setConnectWalletOpen(false);\n return;\n case 'ON_WALLET_CONNECTED':\n refetch();\n refetchAddresses();\n return;\n case 'ON_CLOSE_VERIFICATION':\n setVerifyingRequirementId(null);\n return;\n case 'ON_VERIFICATION_SUBMITTED': {\n if (verifyingRequirementId === null) {\n return;\n }\n awaitVerificationResult(\n verifyingRequirementId,\n statusById.get(verifyingRequirementId)?.status ?? 'not_started'\n );\n return;\n }\n default: {\n // A new event without a case here is a compile error.\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n },\n [\n requirements,\n handleRequirementAction,\n onContactSupportOverride,\n coinlist,\n onContinue,\n refetch,\n refetchAddresses,\n verifyingRequirementId,\n statusById,\n awaitVerificationResult,\n ]\n );\n\n return { state, onEvent };\n}\n\nfunction toVerificationUi(\n verifyingRequirementId: RequirementId | null,\n statusById: Map<RequirementId, RequirementStatusInfo>,\n identityVerificationOptions:\n | { levelName?: KycLevelName; locale?: string }\n | undefined\n): RequirementsVerificationUi | null {\n if (verifyingRequirementId === null) {\n return null;\n }\n const statusInfo = statusById.get(verifyingRequirementId);\n return {\n requirementId: verifyingRequirementId,\n levelName: identityVerificationOptions?.levelName ?? statusInfo?.kycLevel,\n reset: statusInfo?.kycReset ?? false,\n locale: identityVerificationOptions?.locale,\n };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type {\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\n\nexport type LoadOptionAddressesReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOptionAddressesState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: LoadOptionAddressesReason }\n | { type: 'CONTENT'; addresses: OfferOptionAddress[] };\n\nexport interface UseOptionAddressesOptions {\n /**\n * Bound wallets pre-fetched on the server (e.g. via\n * `CoinListServer#wallets.list()`). When provided, the hook uses this\n * data as-is and skips the initial client-side fetch. Calling `refetch()`\n * (or `disconnect()`) will still trigger a fresh fetch.\n */\n data?: OfferOptionAddress[];\n /**\n * When `false`, the hook stays in a benign empty `CONTENT` state and sends no\n * request. Use it to avoid fetching bindings for options with no wallet\n * requirement. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nexport interface UseOptionAddressesResult {\n addressesState: LoadOptionAddressesState;\n /** Triggers a re-fetch of the bound wallets. */\n refetch: () => void;\n /**\n * Removes a bound wallet, then refetches the list. Rejects (without\n * refetching) if the removal fails, so callers can surface the error.\n */\n disconnect: (addressId: OfferOptionAddressId) => Promise<void>;\n}\n\nconst LOADING_STATE: LoadOptionAddressesState = { type: 'LOADING' };\nconst EMPTY_STATE: LoadOptionAddressesState = {\n type: 'CONTENT',\n addresses: [],\n};\n\n/**\n * Loads the user's proven wallet bindings for a single offer option, then\n * exposes them via a state machine plus `refetch`/`disconnect` actions.\n *\n * Returns `LOADING` while CoinList is initializing or data is being fetched,\n * `CONTENT` with the bindings on success, and `ERROR` with `not-authenticated`\n * (logged-out, or a {@link NotAuthenticatedError}) or `generic-error` otherwise.\n */\nexport function useOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId,\n options: UseOptionAddressesOptions = {}\n): UseOptionAddressesResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOptionAddresses');\n const { data, enabled = true } = options;\n const [addressesState, setAddressesState] =\n useState<LoadOptionAddressesState>(\n data !== undefined ? { type: 'CONTENT', addresses: data } : LOADING_STATE\n );\n const [fetchKey, setFetchKey] = useState(0);\n const refetch = useCallback(() => setFetchKey((k) => k + 1), []);\n\n const disconnect = useCallback(\n async (addressId: OfferOptionAddressId): Promise<void> => {\n await coinlist.wallets.remove({ offerId, addressId });\n refetch();\n },\n [coinlist, offerId, refetch]\n );\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetchKey is an intentional refetch trigger\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n // Disabled means \"don't fetch\", not \"discard seeded data\" — keep any\n // server-provided bindings instead of blanking them to empty.\n setAddressesState(\n data !== undefined ? { type: 'CONTENT', addresses: data } : EMPTY_STATE\n );\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n if (data === undefined) {\n setAddressesState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined && fetchKey === 0) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (coinlist.auth.getState() === 'logged-out') {\n setAddressesState({ type: 'ERROR', reason: 'not-authenticated' });\n return () => {\n isCancelled = true;\n };\n }\n\n setAddressesState(LOADING_STATE);\n coinlist.wallets\n .list({ offerId, offerOptionId })\n .then((addresses) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', count: addresses.length },\n }));\n setAddressesState({ type: 'CONTENT', addresses });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOptionAddressesReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setAddressesState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey, log]);\n\n return { addressesState, refetch, disconnect };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport type LoadRequirementsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadRequirementsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadRequirementsReason;\n }\n | {\n type: 'CONTENT';\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n };\n\nexport type RequirementsData = {\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n};\n\nexport interface UseRequirementsOptions {\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\n * When provided, the hook uses this data as-is and skips the initial client-side fetch.\n * Calling `refetch()` will still trigger a fresh fetch.\n */\n data?: RequirementsData;\n /**\n * When `false`, the hook sends no request. A seeded or already-fetched\n * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.\n * `refetch()` is a no-op while disabled.\n */\n enabled?: boolean;\n}\n\nexport interface UseRequirementsResult {\n requirementsState: LoadRequirementsState;\n /** Triggers a re-fetch of requirements and statuses. */\n refetch: () => void;\n}\n\nconst LOADING_STATE: LoadRequirementsState = { type: 'LOADING' };\n\n/**\n * Loads requirements (grouped by option ID) and requirement statuses for a\n * given offer, then exposes them via a state machine.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch. Calling `refetch()` will still trigger a fresh fetch.\n * Pass `enabled: false` to skip the fetch when the hook must be called but\n * the data is not needed yet.\n *\n * Returns `LOADING` while CoinList is initializing or while data is being fetched.\n * Returns `CONTENT` with requirements and statuses on success.\n * Returns `ERROR` with:\n * - `not-authenticated` immediately (no request is sent) when the client's\n * auth state is logged-out, or when fetching fails with\n * {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useRequirements(\n offerId: OfferId,\n options: UseRequirementsOptions = {}\n): UseRequirementsResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useRequirements');\n const { data, enabled = true } = options;\n const [requirementsState, setRequirementsState] =\n useState<LoadRequirementsState>(\n data !== undefined ? { type: 'CONTENT', ...data } : LOADING_STATE\n );\n const [fetchKey, setFetchKey] = useState(0);\n const refetch = useCallback(() => setFetchKey((k) => k + 1), []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetchKey is an intentional refetch trigger\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n if (data === undefined) {\n setRequirementsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined && fetchKey === 0) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (coinlist.auth.getState() === 'logged-out') {\n setRequirementsState({ type: 'ERROR', reason: 'not-authenticated' });\n return () => {\n isCancelled = true;\n };\n }\n\n setRequirementsState(LOADING_STATE);\n Promise.all([\n coinlist.requirements.forOffer(offerId),\n coinlist.requirements.statuses(offerId),\n ])\n .then(([requirementsByOptionId, statuses]) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: {\n state: 'CONTENT',\n options: Object.keys(requirementsByOptionId).length,\n statuses: statuses.length,\n },\n }));\n setRequirementsState({\n type: 'CONTENT',\n requirements: requirementsByOptionId,\n statuses,\n });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadRequirementsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setRequirementsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, fetchKey, log]);\n\n return { requirementsState, refetch };\n}\n","import { shortenAddress } from '@/universal/core/shared/blockchain/formatters';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { OfferOptionAddress } from '@/universal/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/universal/types/requirement';\n\nexport type RequirementsChecklistUiState =\n | { type: 'loading'; title: string; description: string }\n | { type: 'error'; title: string }\n | {\n type: 'content';\n title: string;\n description: string;\n items: RequirementsChecklistItemUi[];\n ineligible: boolean;\n /**\n * Unsupported jurisdiction, once the country is known. When set, the\n * description, rows, and Continue are replaced by this neutral banner.\n * Absent otherwise.\n */\n blockedMessage?: string;\n /** `null` when the host passed no `onContinue`, so no button is shown. */\n continueAction: { enabled: boolean } | null;\n taxDocumentOpen: boolean;\n connectWalletOpen: boolean;\n verification: RequirementsVerificationUi | null;\n /**\n * Removing a wallet has to be awaitable, because the wallet row shows a\n * removing state until it settles and an inline error if it rejects. An\n * event returns nothing, so this stays a callback.\n */\n removeWallet: (addressId: string) => Promise<void>;\n };\n\nexport type RequirementsChecklistUiEvent =\n | { type: 'ON_TOGGLE_ITEM'; requirementId: RequirementId }\n | { type: 'ON_REQUIREMENT_ACTION'; requirementId: RequirementId }\n | { type: 'ON_CONTACT_SUPPORT'; requirementId: RequirementId }\n | { type: 'ON_CONTINUE' }\n | { type: 'ON_CLOSE_TAX_DOCUMENT' }\n | { type: 'ON_TAX_DOCUMENT_SUBMITTED' }\n | { type: 'ON_CLOSE_CONNECT_WALLET' }\n | { type: 'ON_WALLET_CONNECTED' }\n | { type: 'ON_CLOSE_VERIFICATION' }\n | { type: 'ON_VERIFICATION_SUBMITTED' };\n\n/** One row of the checklist, ready to render. */\nexport type RequirementsChecklistItemUi = {\n id: RequirementId;\n item: RequirementItemUi;\n expanded: boolean;\n /** `false` hides the action button (the host disabled it). */\n actionEnabled: boolean;\n /** `false` hides the contact-support button (the host disabled it). */\n contactSupportEnabled: boolean;\n /**\n * Wallet rows show the user's connected wallets and their load state.\n * `null` for non-wallet requirements.\n */\n wallets: { status: WalletsStatus } | null;\n};\n\n/** The inline Sumsub flow the overlay should start. */\nexport type RequirementsVerificationUi = {\n requirementId: RequirementId;\n levelName: KycLevelName | undefined;\n reset: boolean;\n locale: string | undefined;\n};\n\n/** One requirement as a checklist row renders it. */\nexport type RequirementItemUi = {\n variant: RequirementVariant;\n status: RequirementStatus;\n label: string;\n description: string;\n /**\n * `true` for `whitelisted_wallet` (a multi-slot list the user can add to and\n * remove from), `false` for the single-slot `external_wallet`.\n */\n multiWallet: boolean;\n /** The user's connected wallets. Single-slot requirements have at most one. */\n connectedWallets: ConnectedWalletUi[];\n /** Absent means the shared verification sentences. */\n statusMessages?: {\n /** Absent for tax documentation: `in_progress` stays a required step. */\n pending?: string;\n completed: string;\n /** Full sentence. \"Contact support\" inside it is the support link. */\n rejected: string;\n };\n};\n\nexport const RequirementItemUi = {\n fromDomain(\n req: Requirement,\n statusInfo: RequirementStatusInfo | undefined,\n label: string,\n description: string,\n addresses: OfferOptionAddress[] = []\n ): RequirementItemUi {\n return {\n variant: RequirementVariant.fromType(req.type),\n status: requirementStatus(req, statusInfo),\n label,\n description,\n multiWallet: req.type === 'whitelisted_wallet',\n connectedWallets: addresses.map((address) => ({\n id: address.id,\n address: address.address,\n shortAddress: shortenAddress(address.address),\n })),\n statusMessages: statusMessagesFor(req.type),\n };\n },\n};\n\nconst IDENTITY_STATUS_MESSAGES = {\n pending: \"Verification under review. We'll notify you when it's complete.\",\n completed: 'Identity verified.',\n rejected: \"We couldn't verify your identity. Contact support for help.\",\n};\n\nconst ACCREDITATION_STATUS_MESSAGES = {\n pending: \"Accreditation under review. We'll notify you when it's complete.\",\n completed: 'Accreditation verified.',\n rejected: \"We couldn't verify your accreditation. Contact support for help.\",\n};\n\nconst TAX_DOCUMENTATION_STATUS_MESSAGES = {\n completed: 'Tax documentation completed.',\n rejected:\n \"We couldn't accept your tax documentation. Contact support for help.\",\n};\n\nfunction statusMessagesFor(type: RequirementType) {\n switch (type) {\n case 'kyc_approved':\n return IDENTITY_STATUS_MESSAGES;\n case 'accreditation':\n return ACCREDITATION_STATUS_MESSAGES;\n case 'document':\n return TAX_DOCUMENTATION_STATUS_MESSAGES;\n default:\n return undefined;\n }\n}\n\n/** A tax document stays required while the user still has to sign it. */\nfunction requirementStatus(\n req: Requirement,\n statusInfo: RequirementStatusInfo | undefined\n): RequirementStatus {\n if (!statusInfo) return 'required';\n if (req.type === 'document' && statusInfo.status === 'in_progress') {\n return 'required';\n }\n return RequirementStatus.fromStatusValue(statusInfo.status);\n}\n\nexport type RequirementVariant = 'verification' | 'wallet';\nexport const RequirementVariant = {\n fromType(type: RequirementType): RequirementVariant {\n switch (type) {\n case 'external_wallet':\n case 'whitelisted_wallet':\n return 'wallet';\n default:\n return 'verification';\n }\n },\n};\n\nexport type RequirementStatus =\n | 'required'\n | 'pending'\n | 'completed'\n | 'rejected';\nexport const RequirementStatus = {\n fromStatusValue(status: RequirementStatusValue): RequirementStatus {\n switch (status) {\n case 'not_started':\n case 'action_needed':\n return 'required';\n case 'in_progress':\n return 'pending';\n case 'completed':\n return 'completed';\n case 'rejected':\n return 'rejected';\n }\n },\n};\n\nexport type ChecklistStatus = 'inProgress' | 'eligible' | 'ineligible';\nexport const ChecklistStatus = {\n derive(statuses: RequirementStatusInfo[]): ChecklistStatus {\n if (statuses.some((s) => s.status === 'rejected')) return 'ineligible';\n if (statuses.every((s) => s.status === 'completed')) return 'eligible';\n return 'inProgress';\n },\n};\n\n/** A single connected wallet, shaped for display in a connected-wallet list. */\nexport type ConnectedWalletUi = {\n /** Id of the connected wallet, used to remove it. */\n id: string;\n /** Full wallet address (for `title`/`aria`). */\n address: string;\n /** Shortened address for display (e.g. `0x1234…abcd`). */\n shortAddress: string;\n};\n\n/** Load state of a connected-wallet list. */\nexport type WalletsStatus = 'ready' | 'loading' | 'error';\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { IdentityVerificationContainer } from '@/client/components/requirements/identity-verification/IdentityVerificationContainer';\nimport { RequirementsChecklistView } from '@/client/components/requirements/RequirementsChecklistView';\nimport { TaxDocumentModalContainer } from '@/client/components/requirements/tax-document/TaxDocumentModalContainer';\nimport { VerificationOverlay } from '@/client/components/requirements/VerificationOverlay';\nimport { ConnectWalletModalContainer } from '@/client/components/requirements/wallet/ConnectWalletModalContainer';\nimport type { RequirementsData } from '@/client/hooks/requirements/data/useRequirements';\nimport { useRequirementsChecklistViewModel } from '@/client/hooks/requirements/useRequirementsChecklistViewModel';\nimport type { ConnectWallet } from '@/universal/types/blockchain/evm-wallet';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Requirement } from '@/universal/types/requirement';\n\nexport interface RequirementsChecklistContainerProps {\n offerId: OfferId;\n optionId: OfferOptionId;\n title: string;\n description: string;\n onContinue?: () => void;\n /**\n * Called when the user clicks a requirement's action button (e.g. \"Continue\", \"Connect wallet\").\n * Defaults to {@link CoinListClient#requirements.handle}, which opens the corresponding CoinList\n * page in a new tab - except for `document` requirements, which default to opening a built-in\n * {@link TaxDocumentModalContainer} instead. Pass your own handler to override this behavior for all\n * requirement types, or pass `null` to disable the action button entirely.\n */\n onRequirementActionOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Called when the user clicks \"Contact support\" on a rejected requirement.\n * Defaults to {@link CoinListClient#support.contact}, which opens the CoinList support ticket\n * page in a new tab. Pass your own handler to override this behavior, or pass `null` to disable\n * the contact support button entirely.\n */\n onContactSupportOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Host-provided connected wallet used to satisfy `external_wallet` /\n * `whitelisted_wallet` requirements in-app via {@link ConnectWalletModalContainer}.\n * Pass a connected {@link ConnectWallet}, or `null` while none is connected\n * (then also pass {@link onRequestConnect} so the modal can prompt to\n * connect). When this prop is omitted entirely - or is `null` without an\n * {@link onRequestConnect} to act on - wallet requirements fall back to\n * {@link CoinListClient#requirements.handle} (opening CoinList in a new tab).\n */\n wallet?: ConnectWallet | null;\n /** Called when the user asks to connect a wallet and none is connected yet. */\n onRequestConnect?: () => void;\n /** Override the default label for a requirement type. */\n getLabel?: (requirement: Requirement) => string;\n /** Override the default description for a requirement type. */\n getDescription?: (requirement: Requirement) => string | null;\n /** Optional loading slot. */\n loading?: ReactNode;\n /**\n * Replaces the error banner under the title. The title still renders.\n */\n error?: ReactNode;\n className?: string;\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer#requirements.forOffer()` + `statuses()`).\n * When provided, the component uses this data as-is and skips the client-side\n * requirements fetch. Connected-wallet addresses for wallet requirements are\n * not part of `RequirementsData` and are always fetched client-side.\n */\n data?: RequirementsData;\n /**\n * Default `true`. When `false` nothing is fetched, so the container can be\n * mounted while the checklist is not needed yet.\n */\n enabled?: boolean;\n /**\n * Options for the inline Sumsub verification flow, shown when\n * `onRequirementActionOverride` is not provided. The flow starts whenever\n * the requirement's status carries a `kycLevel` - the backend prescribes\n * both the level and whether the applicant must be reset first.\n */\n identityVerificationOptions?: {\n /** Override the backend-prescribed Sumsub verification level. */\n levelName?: KycLevelName;\n /** BCP-47 language tag for the Sumsub UI, e.g. `'en'`. */\n locale?: string;\n };\n}\n\n/**\n * Connected requirements checklist, backed by\n * {@link useRequirementsChecklistViewModel}, which fetches requirements and\n * statuses via {@link useRequirements} and renders requirement rows for the\n * specified option.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip the\n * initial client-side fetch. Pass `enabled={false}` to skip fetches when the\n * container is mounted but the checklist is not needed yet.\n *\n * A logged-out session renders the error state and does not fetch. The host\n * should not mount the checklist when it already knows the user is logged out.\n *\n * By default, clicking a requirement's action button opens the corresponding\n * CoinList page in a new tab via {@link CoinListClient#requirements.handle}. It\n * is recommended to omit `onRequirementActionOverride` and rely on this\n * default. Pass your own handler only if you need custom navigation behavior,\n * or `null` to disable the action button entirely.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope` needed.\n */\nexport function RequirementsChecklistContainer({\n loading,\n error,\n className,\n enabled = true,\n ...options\n}: RequirementsChecklistContainerProps): ReactNode {\n const { state, onEvent } = useRequirementsChecklistViewModel({\n ...options,\n enabled,\n });\n\n return (\n <>\n <RequirementsChecklistView\n state={state}\n onEvent={onEvent}\n loading={loading}\n error={error}\n className={className}\n />\n\n {state.type === 'content' && (\n <>\n <TaxDocumentModalContainer\n isOpen={state.taxDocumentOpen}\n onClose={() => onEvent({ type: 'ON_CLOSE_TAX_DOCUMENT' })}\n onSubmitted={() => onEvent({ type: 'ON_TAX_DOCUMENT_SUBMITTED' })}\n />\n\n {state.verification && (\n <VerificationOverlay\n onClose={() => onEvent({ type: 'ON_CLOSE_VERIFICATION' })}\n >\n <IdentityVerificationContainer\n levelName={state.verification.levelName}\n reset={state.verification.reset}\n locale={state.verification.locale}\n onSubmitted={() =>\n onEvent({ type: 'ON_VERIFICATION_SUBMITTED' })\n }\n />\n </VerificationOverlay>\n )}\n\n <ConnectWalletModalContainer\n isOpen={state.connectWalletOpen}\n onClose={() => onEvent({ type: 'ON_CLOSE_CONNECT_WALLET' })}\n offerId={options.offerId}\n optionId={options.optionId}\n wallet={options.wallet ?? null}\n onRequestConnect={options.onRequestConnect}\n onConnected={() => onEvent({ type: 'ON_WALLET_CONNECTED' })}\n />\n </>\n )}\n </>\n );\n}\n","import { pino } from 'pino';\nimport {\n loggerOverPino,\n PINO_LEVEL,\n SDK_LOGGER_NAME,\n} from '@/universal/core/shared/observability/pino-logger';\nimport type { Logger, PinoLoggerOptions } from '@/universal/types/logger';\n\n/**\n * A {@link Logger} that writes structured records to the browser console\n * through pino.\n *\n * ```ts\n * createCoinListClient({\n * ...config,\n * logger: pinoClientLogger({ isDev: false, level: 'info' }),\n * });\n * ```\n *\n * The browser counterpart of {@link pinoServerLogger}. Two factories rather\n * than one that sniffs `typeof window`, because the environment is the\n * outermost axis of this codebase: the client build resolves pino's browser\n * entry and the server build resolves its node entry, neither pays for the\n * other, and neither has a branch in it.\n *\n * `browser: { asObject: true }` is the one non-default: pino's browser default\n * hands its arguments to `console.info` unchanged, which is not a structured\n * record. With it, each line is a single object carrying `level`, `time`,\n * `name`, `scope`, the bindings and every field - the same shape the server\n * writes as ndjson, so a record read in devtools and a record read in a log\n * aggregator are the same record.\n *\n * ## Production\n *\n * **Running this in a production browser is not advised**, and the browser is\n * where that advice is easiest to justify. **A browser console is readable by\n * anyone with the page open**, and extensions can scrape it, so even the\n * redacted levels put SDK-authored classification and server-minted ids\n * somewhere you do not control. Nothing is transmitted anywhere either: pino's\n * browser build writes to the console and stops, so what you get for the risk\n * is a record only the end user can read.\n *\n * If you run one anyway, `isDev: false` restricts you to `'error'`, `'warn'`\n * and `'info'` - `{ isDev: false, level: 'debug' }` does not compile, see\n * {@link PinoLoggerOptions}. Those levels are redacted by construction; what\n * follows from that in your environment is your call to make, not a warranty\n * the SDK offers.\n *\n * If you want these records off the page, implement {@link Logger} yourself\n * over your own transport, or pass a pino instance configured with\n * `browser.transmit` - the seam is deliberately small enough to make that easy.\n *\n * Holds no module-level state: every call builds its own pino instance, and\n * the level is fixed at construction, so two loggers never interfere. Fixed is\n * this implementation's choice, not the seam's - the SDK re-reads\n * {@link Logger.level} before every log call - so if you want a level you can\n * change at runtime, implement {@link Logger} over your own pino instance\n * rather than calling this.\n */\nexport function pinoClientLogger(options: PinoLoggerOptions): Logger {\n return loggerOverPino(\n // `name` as a child binding rather than pino's `name` option: the option\n // is honoured by pino's node build and silently dropped by its browser\n // build, so a binding is the only spelling that identifies the SDK in\n // both environments.\n pino({\n level: PINO_LEVEL[options.level],\n browser: { asObject: true },\n }).child({ name: SDK_LOGGER_NAME }),\n options.level\n );\n}\n","import type {\n DebugEvent,\n Logger,\n LogLevel,\n SafeEvent,\n} from '@/universal/types/logger';\n\n/**\n * The SDK's logging seam expressed over pino, minus the environment.\n *\n * Imports no pino - {@link PinoSink} is a structural type - so `@/universal`\n * stays pino-free and the `./universal` entry point costs a consumer nothing.\n * Both shipped implementations\n * ({@link pinoClientLogger}, {@link pinoServerLogger}) differ only in the pino\n * instance they construct; everything worth testing lives here.\n *\n * ## Nothing here may throw\n *\n * A {@link Logger} implementation is called inline, on the codepath of the\n * work it reports, and the SDK does not catch it - so a log line that fails to\n * render would turn a successful request into an exception. That risk is real\n * rather than theoretical: `'debug'` fields carry whatever the SDK was\n * handling, and this codebase routinely handles `bigint` (every uint256 on\n * every DTO), which `JSON.stringify` throws on. Response bodies may be\n * circular, params may hold functions, and a host's object may have a getter\n * that throws.\n *\n * So {@link toPinoRecord} is total by construction: every value is rendered\n * into something a JSON serialiser cannot refuse, every property read is\n * guarded, and the whole translation has a fallback. Pino is never handed a\n * value it could fail on.\n */\n\n/**\n * Flattens an event into the object pino merges into its output line.\n *\n * Flat rather than nested, because nesting is what a host has to un-nest\n * before they can facet on it: `scope`, the {@link LogBindings} and every\n * field sit at the top level, and only `cause` stays an object because its\n * arms are a closed union a host switches on.\n *\n * `msg` is **not** included: it is pino's own second argument.\n *\n * Never throws. A value it cannot render becomes a `<tag>` string rather than\n * an exception, and a translation that fails entirely degrades to a record\n * naming the failure.\n */\nexport function toPinoRecord(event: SafeEvent | DebugEvent): PinoRecord {\n try {\n const record: Record<string, unknown> = {};\n\n for (const key of ownKeys(event.fields)) {\n record[key] = readProperty(event.fields, key, 0, new WeakSet());\n }\n\n const cause = 'cause' in event ? event.cause : undefined;\n if (cause !== undefined) {\n record.cause = sanitize(cause, 0, new WeakSet());\n }\n\n // Last, so the stamped keys win. `scope` and the bindings are what a host\n // routes and filters on, and they are stamped by `internalLogger` rather\n // than written at a call site - so a field that happened to be named\n // `scope` or `op` must not be able to take their place.\n return { ...record, scope: event.scope, ...event.bindings };\n } catch (_) {\n // The event itself is malformed - a Proxy for `fields`, a frozen exotic\n // object. Report that rather than losing the line, and never rethrow.\n return { 'log.render': '<unrenderable event>' };\n }\n}\n\n/** What pino merges into one output line. */\nexport type PinoRecord = Readonly<Record<string, unknown>>;\n\n/**\n * The SDK's five levels in pino's vocabulary.\n *\n * `'none'` is pino's `'silent'`; the other four are the same word in both, and\n * deliberately so. The SDK does not adopt pino's seven because `'trace'` would\n * sit below `'debug'`, and the guarantee \"`debug` is unredacted and every\n * other level is not\" only closes while `'debug'` is the bottom.\n */\nexport const PINO_LEVEL = {\n none: 'silent',\n error: 'error',\n warn: 'warn',\n info: 'info',\n debug: 'debug',\n} as const satisfies Record<LogLevel, string>;\n\n/**\n * How deep a `'debug'` field is followed before it is summarised.\n *\n * A bound rather than a guess at what is deep enough: a self-referential\n * structure is already caught by the cycle check, but a legitimately deep DTO\n * would otherwise cost real time inside a log line.\n */\nconst MAX_DEPTH = 8;\n\n/**\n * Renders any value into something a JSON serialiser cannot refuse.\n *\n * `bigint` is the one that matters in practice - every uint256 the SDK handles\n * is one - but the rest are all reachable from a `'debug'` field: `undefined`\n * and functions from an operation's params, `NaN` from arithmetic, symbols\n * from a host's object.\n */\nfunction sanitize(\n value: unknown,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return value;\n case 'number':\n // `NaN` and the infinities serialise to `null`, which reads as \"absent\"\n // rather than \"not a number\". Name them instead.\n return Number.isFinite(value) ? value : String(value);\n case 'bigint':\n return value.toString();\n case 'undefined':\n return '<undefined>';\n case 'function':\n return '<function>';\n case 'symbol':\n return value.toString();\n case 'object':\n return value === null ? null : sanitizeObject(value, depth, seen);\n default:\n return '<unrenderable>';\n }\n}\n\nfunction sanitizeObject(\n value: object,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n if (seen.has(value)) return '<circular>';\n if (depth >= MAX_DEPTH) return '<max depth>';\n\n // `name`, `message` and `stack` are all non-enumerable, so an `Error` handed\n // to a structured sink as an object serialises to `{}`.\n if (value instanceof Error) return describeError(value);\n if (value instanceof Date) return describeDate(value);\n\n seen.add(value);\n try {\n if (Array.isArray(value)) {\n return value.map((_item, index) =>\n readProperty(value, String(index), depth, seen)\n );\n }\n\n const out: Record<string, unknown> = {};\n for (const key of ownKeys(value)) {\n out[key] = readProperty(value, key, depth, seen);\n }\n return out;\n } finally {\n // Removed on the way out, so a value referenced twice in a tree renders\n // twice. Only a genuine cycle is `<circular>`.\n seen.delete(value);\n }\n}\n\n/**\n * One property read, guarded. A getter may throw, and a log line is not\n * allowed to be the reason a request fails.\n */\nfunction readProperty(\n owner: object,\n key: string,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n try {\n return sanitize((owner as Record<string, unknown>)[key], depth + 1, seen);\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/** Own enumerable keys, guarded: an exotic object may refuse to be enumerated. */\nfunction ownKeys(value: object): readonly string[] {\n try {\n return Object.keys(value);\n } catch (_) {\n return [];\n }\n}\n\nfunction describeError(error: Error): Record<string, unknown> {\n return {\n name: safeRead(() => error.name),\n message: safeRead(() => error.message),\n stack: safeRead(() => error.stack),\n };\n}\n\nfunction describeDate(date: Date): unknown {\n // An invalid `Date` throws from `toISOString`.\n return safeRead(() => date.toISOString());\n}\n\nfunction safeRead(read: () => unknown): unknown {\n try {\n const value = read();\n return typeof value === 'string' ? value : '<unreadable>';\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/**\n * The part of a pino logger this adapter uses.\n *\n * Structural rather than `import type { Logger } from 'pino'`, so that\n * `@/universal` takes no dependency on pino at all. A real pino instance - node\n * or browser build - satisfies it.\n */\nexport type PinoSink = {\n debug(record: PinoRecord, msg: string): void;\n info(record: PinoRecord, msg: string): void;\n warn(record: PinoRecord, msg: string): void;\n error(record: PinoRecord, msg: string): void;\n};\n\n/**\n * The `name` binding every SDK line carries, so a partner can separate the\n * SDK's output from their own in a shared aggregator without matching on\n * `scope`.\n *\n * Applied through `pino.child({ name })` rather than pino's `name` *option*,\n * which its browser build ignores. The browser lane's spec is what caught\n * that, and is what keeps it caught.\n */\nexport const SDK_LOGGER_NAME = '@coinlist-co/react';\n\n/**\n * Adapts a pino instance into the {@link Logger} the SDK consumes.\n *\n * **Total, and that is the point.** The SDK calls a `Logger` inline and does\n * not catch it, so an exception raised while reporting a successful request\n * would fail that request. Three things could raise one - the event lambda\n * itself, rendering the event, and the sink - and all three are caught here.\n * A render failure is reported through the sink rather than swallowed, since a\n * log line that silently vanishes is a bug nobody finds; if the sink is what\n * broke, there is nowhere left to report it and the error stops here.\n *\n * **The level is fixed here, and that is this adapter's choice rather than the\n * seam's.** {@link InternalLogger} calls {@link Logger.level} before *every*\n * log call and caches nothing, so a host-implemented `Logger` reading a mutable\n * field has a level they can change at runtime. This adapter captures `level`\n * instead, and the pino instance it wraps is built with a fixed one - so\n * `Logger.level` is a constant lookup and two loggers never interfere. A host\n * who wants to turn `'debug'` on without rebuilding implements {@link Logger}\n * directly over their own pino instance; the port is four methods and this\n * function is the worked example.\n */\nexport function loggerOverPino(sink: PinoSink, level: LogLevel): Logger {\n return {\n level: () => level,\n debug: (event) => emit(sink, 'debug', event),\n info: (event) => emit(sink, 'info', event),\n warn: (event) => emit(sink, 'warn', event),\n error: (event) => emit(sink, 'error', event),\n };\n}\n\nfunction emit(\n sink: PinoSink,\n method: keyof PinoSink,\n event: () => SafeEvent | DebugEvent\n): void {\n try {\n const value = event();\n sink[method](toPinoRecord(value), value.msg);\n } catch (error) {\n reportRenderFailure(sink, error);\n }\n}\n\nfunction reportRenderFailure(sink: PinoSink, error: unknown): void {\n try {\n sink.error(\n { 'error.type': error instanceof Error ? error.name : typeof error },\n 'log event failed to render'\n );\n } catch (_) {\n // The sink itself threw. There is nowhere left to report this, and the SDK\n // is on the other side of the call that got us here.\n }\n}\n","import { useEffect, useRef } from 'react';\nimport type { OauthClientErrorReason } from '@/client/core/auth/types';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { AuthorizationCode, CodeVerifier } from '@/universal/types/oauth';\n\n/**\n * Reasons passed to {@link UseCompleteOAuthOptions.onFailure} when the\n * OAuth callback cannot be completed. Includes PKCE / redirect validation\n * errors from {@link CoinListClient.completeOAuth} and a dedicated value when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails or rejects.\n */\nexport type CompleteOAuthFailureReason =\n | OauthClientErrorReason\n | 'complete_request_failed';\n\nexport interface UseCompleteOAuthOptions {\n /**\n * Exchange the authorization code on your backend (e.g. POST to your API).\n * Return `true` when the session was established successfully, `false` when\n * the request completed but signing in failed. Rejections are treated like\n * `false` and reported as {@link CompleteOAuthFailureReason}\n * `\"complete_request_failed\"`.\n */\n postOAuthComplete: (payload: {\n code: AuthorizationCode;\n codeVerifier: CodeVerifier;\n }) => Promise<boolean>;\n /**\n * Called when the user denied access (`error` query parameter), when\n * {@link CoinListClient.completeOAuth} fails PKCE/state validation, or when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails.\n */\n onFailure: (reason: CompleteOAuthFailureReason) => void | Promise<void>;\n /** Invoked after {@link UseCompleteOAuthOptions.postOAuthComplete} succeeds and {@link CoinListClient.init} has refreshed the client session. */\n onSuccess: () => void | Promise<void>;\n}\n\n/**\n * Runs the CoinList OAuth callback once on mount: validates the redirect URL via\n * {@link CoinListClient.completeOAuth}, exchanges the code via {@link UseCompleteOAuthOptions.postOAuthComplete},\n * refreshes tokens with {@link CoinListClient.init}, then calls {@link UseCompleteOAuthOptions.onSuccess}.\n *\n * Framework-agnostic: reads `window.location` like {@link CoinListClient.completeOAuth}. Supply\n * {@link UseCompleteOAuthOptions.postOAuthComplete}, {@link UseCompleteOAuthOptions.onFailure},\n * and {@link UseCompleteOAuthOptions.onSuccess} to perform redirects or routing in your app.\n *\n * Must be used within {@link CoinListProvider}.\n */\nexport function useCompleteOAuth(options: UseCompleteOAuthOptions): void {\n const { coinlist } = useCoinList();\n const log = useLogger('useCompleteOAuth');\n\n const postOAuthCompleteRef = useRef(options.postOAuthComplete);\n const onFailureRef = useRef(options.onFailure);\n const onSuccessRef = useRef(options.onSuccess);\n\n postOAuthCompleteRef.current = options.postOAuthComplete;\n onFailureRef.current = options.onFailure;\n onSuccessRef.current = options.onSuccess;\n\n const hasStartedExchangeRef = useRef(false);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const params = new URLSearchParams(window.location.search);\n if (!params.has('code') && !params.has('error')) return;\n\n if (hasStartedExchangeRef.current) return;\n\n const oauthResult = coinlist.auth.completeOAuth();\n if (oauthResult.type === 'error') {\n log.error(() => ({\n msg: 'oauth callback rejected',\n fields: { reason: oauthResult.reason },\n }));\n void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(\n (error: unknown) => {\n log.failure(\n () => ({ msg: 'the host onFailure handler threw' }),\n error\n );\n }\n );\n return;\n }\n\n hasStartedExchangeRef.current = true;\n let cancelled = false;\n\n void (async () => {\n try {\n const ok = await postOAuthCompleteRef.current({\n code: oauthResult.code,\n codeVerifier: oauthResult.codeVerifier,\n });\n\n if (cancelled) return;\n\n if (!ok) {\n log.error(() => ({\n msg: 'the host postOAuthComplete handler reported failure',\n fields: { reason: 'complete_request_failed' },\n }));\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n return;\n }\n\n await coinlist.init();\n\n if (cancelled) return;\n\n log.info(() => ({ msg: 'session established' }));\n await onSuccessRef.current();\n } catch (error) {\n if (cancelled) return;\n log.failure(\n () => ({\n msg: 'settled',\n fields: { state: 'ERROR', reason: 'complete_request_failed' },\n }),\n error\n );\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n }\n })();\n\n return () => {\n cancelled = true;\n hasStartedExchangeRef.current = false;\n };\n }, [coinlist, log]);\n}\n","import { useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { Participation } from '@/universal/types/providers/coin-list/token-sale';\n\nexport type LoadParticipationsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadParticipationsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadParticipationsReason;\n }\n | {\n type: 'CONTENT';\n participations: Participation[];\n };\n\nexport interface UseParticipationsOptions {\n /**\n * Participations pre-fetched on the server (e.g. via `CoinListServer#tokenSale.list()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Participation[];\n /**\n * When `false`, the hook sends no request. A seeded or already-fetched\n * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nexport interface UseParticipationsResult {\n participationsState: LoadParticipationsState;\n}\n\nconst LOADING_STATE: LoadParticipationsState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList participations for the current user and exposes a UI-friendly state.\n * Optionally filters by offer when `offerId` is provided.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely. Pass `enabled: false` to skip the fetch\n * when the hook must be called but the data is not needed yet.\n *\n * Returns `LOADING` while CoinList is initializing or while participations are being fetched.\n * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useParticipations(\n offerId?: OfferId,\n options: UseParticipationsOptions = {}\n): UseParticipationsResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useParticipations');\n const { data, enabled = true } = options;\n const [participationsState, setParticipationsState] =\n useState<LoadParticipationsState>(\n data !== undefined\n ? { type: 'CONTENT', participations: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n return () => {\n isCancelled = true;\n };\n }\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (data === undefined) {\n setParticipationsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setParticipationsState(LOADING_STATE);\n coinlist.tokenSale\n .list(offerId)\n .then((participations) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', count: participations.length },\n }));\n setParticipationsState({ type: 'CONTENT', participations });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadParticipationsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setParticipationsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, data, log]);\n\n return { participationsState };\n}\n","import { useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\n\nexport type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOfferDetailsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOfferDetailsReason;\n }\n | {\n type: 'CONTENT';\n offerDetail: OfferDetail;\n };\n\nexport interface UseOfferDetailsOptions {\n /**\n * Offer detail pre-fetched on the server (e.g. via `CoinListServer#offers.get()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: OfferDetail;\n /**\n * When `false`, the hook sends no request. A seeded or already-fetched\n * `CONTENT` survives; otherwise the hook stays `LOADING`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nexport interface UseOfferDetailsResult {\n offerDetailsState: LoadOfferDetailsState;\n}\n\nconst LOADING_STATE: LoadOfferDetailsState = { type: 'LOADING' };\n\n/**\n * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely. Pass `enabled: false` to skip the fetch\n * when the hook must be called but the data is not needed yet.\n *\n * Returns `LOADING` while CoinList is initializing or while details are being fetched.\n * Returns `CONTENT` with the offer when `offers.get()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOfferDetails(\n offerId: OfferId,\n options: UseOfferDetailsOptions = {}\n): UseOfferDetailsResult {\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOfferDetails');\n const { data, enabled = true } = options;\n const [offerDetailsState, setOfferDetailsState] =\n useState<LoadOfferDetailsState>(\n data !== undefined\n ? { type: 'CONTENT', offerDetail: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n if (data === undefined) {\n setOfferDetailsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOfferDetailsState(LOADING_STATE);\n coinlist.offers\n .get(offerId)\n .then((offerDetail) => {\n if (!isCancelled) {\n log.debug(() => ({\n msg: 'settled',\n fields: { state: 'CONTENT', offerId: offerDetail.id },\n }));\n setOfferDetailsState({ type: 'CONTENT', offerDetail });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOfferDetailsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n log.failure(\n () => ({ msg: 'settled', fields: { state: 'ERROR', reason } }),\n error\n );\n setOfferDetailsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, data, log]);\n\n return { offerDetailsState };\n}\n","import { OfferLogoUi } from '@/client/hooks/offers/shared/offer-logo.types';\nimport type { Offer, OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * An offer as {@link OfferAssetCard} renders it. Browse chrome: circular\n * `logo`, `name`, and asset `symbol`. No wordmark.\n *\n * All three come from the public token registry when the caller hands over\n * the metadata of the token the offer is about. Without it, `fromOffer`\n * omits `name` and `symbol` - the list payload has neither - so a list-mapped\n * card is honest about being logo-only, and `fromDetail` reads them from the\n * detail payload (`name`, `asset.code`).\n */\nexport type OfferAssetCardUi = {\n id: OfferId;\n /** Absent when neither the registry nor a detail payload names the offer. */\n name?: string;\n /** Absent when neither the registry nor a detail payload carries a ticker. */\n symbol?: string;\n /** `null` when neither the registry nor the offer carries artwork. */\n logo: OfferLogoUi | null;\n};\n\nexport const OfferAssetCardUi = {\n /**\n * `tokenMetadata` is the registry's entry for the token the offer is about\n * (`TokenRegistrySnapshot.forOffer`), or `null` when it lists none. The\n * registry names win over the offer's own where both exist: they are the\n * token's canonical name, ticker and artwork, where the offer's are\n * catalogue copy.\n */\n fromOffer: (\n offer: Offer,\n tokenMetadata: TokenMetadata | null = null\n ): OfferAssetCardUi => ({\n id: offer.id,\n ...(tokenMetadata\n ? { name: tokenMetadata.name, symbol: String(tokenMetadata.symbol) }\n : {}),\n logo: OfferLogoUi.fromOffer(offer, tokenMetadata),\n }),\n fromDetail: (\n detail: OfferDetail,\n tokenMetadata: TokenMetadata | null = null\n ): OfferAssetCardUi => ({\n id: detail.id,\n name: tokenMetadata?.name ?? detail.name,\n symbol: tokenMetadata ? String(tokenMetadata.symbol) : detail.asset.code,\n logo: OfferLogoUi.fromOffer(detail, tokenMetadata),\n }),\n};\n","/**\n * Date presentation helpers.\n *\n * Every function takes an explicit `locale`, the way\n * `@/universal/core/shared/blockchain/formatters` does: the UI layer never reads the\n * locale from React context, so it stays pure and testable. Callers get the\n * locale from `useLocale()` in a viewmodel and pass it down.\n */\n\n/**\n * Formats a date as a short month and full year, e.g. `Mar 2026` for `en-US`.\n * Used for offer start and end dates, where the day is noise.\n *\n * Rendered in UTC, for the same reason the locale defaults to a fixed\n * `'en-US'`: the machine's time zone is not a stable input. A server rendering\n * in UTC and a browser at UTC-8 would otherwise disagree about the month of an\n * offer that starts just after midnight, and hydration would mismatch. Offer\n * windows are backend-defined instants, so UTC is their canonical reading.\n */\nexport function formatMonthYear(date: Date, locale: string): string {\n return new Intl.DateTimeFormat(locale, {\n month: 'short',\n year: 'numeric',\n timeZone: 'UTC',\n }).format(date);\n}\n"],"mappings":"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","names":["import_react","userAgent","http","base","requestId","import_viem","emit","base","base","import_viem","import_viem","import_viem","import_viem","emit","emit","emit","import_viem","import_viem","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","title","description","import_jsx_runtime","import_jsx_runtime","title","subtitle","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","title","subtitle","import_jsx_runtime","import_jsx_runtime","TITLE","import_lucide_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","TITLE","PRICE_PER_SHARE_LABEL","ActiveView","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_react","import_jsx_runtime","import_jsx_runtime","title","import_jsx_runtime","TITLE","detailRows","import_lucide_react","import_react","import_jsx_runtime","import_jsx_runtime","TITLE","description","ActiveView","CompletedView","import_jsx_runtime","import_react","import_react","import_react","import_react","import_react","import_react","phaseMessage","import_react","size","import_react","LOADING","MARKET_CLOSED","import_react","error","isEmbedded","import_react","import_jsx_runtime","import_jsx_runtime","TITLE","AMOUNT_LABEL","AMOUNT_PLACEHOLDER","EMBEDDED_WALLET_LABEL","REVIEW_NOTE","title","ActiveView","CompletedView","MaxButton","import_lucide_react","import_jsx_runtime","TITLE","PRICE_PER_SHARE_LABEL","DELIVERED_TO_LABEL","DONE_LABEL","VIEW_TRANSACTION_LABEL","subtitle","SuccessGlyph","detailRows","ExplorerLink","import_lucide_react","import_jsx_runtime","TITLE","YOU_RECEIVE_LABEL","RECEIVING_WALLET_LABEL","PRICE_PER_SHARE_LABEL","PRICE_PER_SHARE_TOOLTIP","COINLIST_FEE_LABEL","COINLIST_FEE_TOOLTIP","REFRESH_QUOTE_LABEL","LOADING_STATUS","ERROR_TITLE","ERROR_DESCRIPTION","title","LoadingView","ErrorView","ActiveView","InfoIcon","QuoteLine","QuoteStatusLine","Disclaimer","DisclaimerLink","import_jsx_runtime","import_react","import_react","import_react","NO_WALLET","MARKET_CLOSED","INVALID_AMOUNT","AMOUNT_ZERO","sellAsset","phaseMessage","preparationErrorMessage","capAmount","import_react","import_react","stableKey","toQuoteStatusUi","phaseMessage","executionErrorMessage","refreshErrorMessage","expiresInLabel","priceSize","toOrderConfirmedUi","walletStepInput","amountStepInput","reviewStepInput","import_jsx_runtime","import_jsx_runtime","TITLE","AMOUNT_LABEL","AMOUNT_PLACEHOLDER","PAY_WITH_LABEL","REVIEW_NOTE","ActiveView","CompletedView","MaxButton","PayWithSection","import_lucide_react","import_jsx_runtime","TITLE","TOTAL_COST_LABEL","SHARES_RECEIVED_LABEL","PRICE_PER_SHARE_LABEL","DELIVERED_TO_LABEL","DONE_LABEL","VIEW_TRANSACTION_LABEL","subtitle","SuccessGlyph","detailRows","ExplorerLink","import_lucide_react","import_lucide_react","import_react","import_jsx_runtime","import_jsx_runtime","TITLE","YOU_RECEIVE_LABEL","RECEIVING_WALLET_LABEL","PRICE_PER_SHARE_LABEL","PRICE_PER_SHARE_TOOLTIP","COINLIST_FEE_LABEL","COINLIST_FEE_TOOLTIP","TOTAL_LABEL","LOADING_STATUS","ERROR_TITLE","ERROR_DESCRIPTION","LoadingView","ErrorView","ActiveView","InfoIcon","Disclaimer","import_jsx_runtime","TITLE","SHOW_DETAILS_LABEL","HIDE_DETAILS_LABEL","ISSUER_LABEL","NETWORK_LABEL","PriceValue","detailRows","import_lucide_react","import_jsx_runtime","TITLE","EMBEDDED_WALLET_LABEL","EXTERNAL_WALLET_LABEL","ActiveView","CompletedView","ExternalWalletRow","EmbeddedWalletRow","WalletGlyph","DisconnectControl","import_jsx_runtime","ERROR_TITLE","ERROR_DESCRIPTION","UNSUPPORTED_CHAIN_TITLE","UNSUPPORTED_CHAIN_DESCRIPTION","ErrorView","import_react","import_react","NO_WALLET","INVALID_AMOUNT","AMOUNT_ZERO","toInputAssetUi","import_react","LOADING_STATE","import_react","import_react","phaseMessage","executionErrorMessage","import_react","CONNECT_FAILED","resolveWallet","toEmbeddedWalletUi","toExternalWalletUi","toConfirmedWalletUi","phaseMessage","error","findEmbedded","isEmbedded","walletStepInput","amountStepInput","reviewStepInput","toOrderConfirmedUi","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_jsx_runtime","cardActionLabel","title","import_jsx_runtime","DEFAULT_MAX_COLUMNS","import_react","import_react","LOADING_STATE","import_react","DISABLED_STATE","LOADING_STATE","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","SumsubWebSdk","import_react","import_react","LOADING_STATE","NOT_AUTHENTICATED_MESSAGE","GENERIC_ERROR_MESSAGE","import_jsx_runtime","import_lucide_react","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","LoadingState","title","description","import_jsx_runtime","import_react","import_react","LOADING_STATE","NOT_AUTHENTICATED_MESSAGE","GENERIC_ERROR_MESSAGE","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","Screen","import_react","import_react","apiErrorCode","emit","IDLE_SIGN","import_jsx_runtime","import_react","import_react","LOADING_STATE","import_react","LOADING_STATE","description","title","description","import_jsx_runtime","import_react","import_react","LOADING_STATE","import_react","LOADING_STATE"]}