@coinlist-co/react 0.10.1 → 0.11.1-rc.209af8d

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 (38) hide show
  1. package/README.md +32 -0
  2. package/dist/chunk-3Z4PLLV7.js +2249 -0
  3. package/dist/chunk-3Z4PLLV7.js.map +1 -0
  4. package/dist/{chunk-AQVCOWOV.js → chunk-T4ANQVQA.js} +216 -317
  5. package/dist/chunk-T4ANQVQA.js.map +1 -0
  6. package/dist/chunk-YPFS2SAD.js +279 -0
  7. package/dist/chunk-YPFS2SAD.js.map +1 -0
  8. package/dist/client/index.cjs +11325 -3316
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +4243 -881
  11. package/dist/client/index.d.ts +4243 -881
  12. package/dist/client/index.js +9103 -2389
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/collections-B0nu_6q5.d.ts +116 -0
  15. package/dist/collections-DdLA4_GN.d.cts +116 -0
  16. package/dist/config-D0r6GyPL.d.cts +2638 -0
  17. package/dist/config-D0r6GyPL.d.ts +2638 -0
  18. package/dist/server/index.cjs +1631 -514
  19. package/dist/server/index.cjs.map +1 -1
  20. package/dist/server/index.d.cts +266 -162
  21. package/dist/server/index.d.ts +266 -162
  22. package/dist/server/index.js +235 -169
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/shared/index.cjs +2235 -926
  25. package/dist/shared/index.cjs.map +1 -1
  26. package/dist/shared/index.d.cts +256 -132
  27. package/dist/shared/index.d.ts +256 -132
  28. package/dist/shared/index.js +102 -28
  29. package/package.json +12 -8
  30. package/dist/chunk-AQVCOWOV.js.map +0 -1
  31. package/dist/chunk-TBU3EBNM.js +0 -442
  32. package/dist/chunk-TBU3EBNM.js.map +0 -1
  33. package/dist/chunk-UOHD7US2.js +0 -855
  34. package/dist/chunk-UOHD7US2.js.map +0 -1
  35. package/dist/collections-Bv1Oxzu_.d.ts +0 -28
  36. package/dist/collections-DDyxbOPZ.d.cts +0 -28
  37. package/dist/requirement-oVZA1INj.d.cts +0 -1040
  38. package/dist/requirement-oVZA1INj.d.ts +0 -1040
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/CoinListProvider.tsx","../../src/shared/utils.ts","../../src/client/core/api/middleware/device-id.ts","../../src/shared/api/frontline/config.ts","../../src/shared/api/http-attributes.ts","../../src/client/core/api/middleware/user-agent.ts","../../src/shared/api/http.ts","../../src/shared/api/http-client.ts","../../src/shared/api/middleware/attach-session-middleware.ts","../../src/shared/api/middleware/idempotency-key.ts","../../src/shared/api/middleware/request-retry.ts","../../src/shared/api/middleware/session-renewal.ts","../../src/shared/api/authenticated-api-client.ts","../../src/client/core/api/api-client.ts","../../src/client/core/blockchain/wallet-error.ts","../../src/shared/core/blockchain/abis/erc20.ts","../../src/client/core/blockchain/erc20-approval.ts","../../src/shared/core/blockchain/abis/superstate-swap.ts","../../src/shared/types/blockchain/core.ts","../../src/shared/core/blockchain/bps.ts","../../src/shared/core/blockchain/swap/math.ts","../../src/shared/core/blockchain/swap/status.ts","../../src/shared/core/blockchain/swap/swapped-event.ts","../../src/client/core/blockchain/swap-flows.ts","../../src/shared/types/swap.ts","../../src/shared/api/frontline/swap.ts","../../src/shared/types/asset.ts","../../src/shared/types/offer.ts","../../src/shared/types/offer-detail.ts","../../src/shared/types/offer-option-address.ts","../../src/shared/types/wallet-ownership-challenge.ts","../../src/shared/api/frontline/wallet-connect.ts","../../src/shared/core/swap-namespace.ts","../../src/client/core/client-swap-namespace.ts","../../src/shared/api/pagination.ts","../../src/shared/types/blockchain/ui.ts","../../src/shared/core/blockchain/formatters.ts","../../src/shared/core/blockchain/swap/constants.ts","../../src/shared/core/blockchain/swap/quote.ts","../../src/shared/core/blockchain/token-registry.ts","../../src/shared/core/erc20-namespace.ts","../../src/shared/types/participation.ts","../../src/shared/api/frontline/participations.ts","../../src/shared/core/token-sale-namespace.ts","../../src/shared/types/oauth.ts","../../src/shared/pkce.ts","../../src/shared/types/document-submission.ts","../../src/shared/types/errors.ts","../../src/shared/types/kyc.ts","../../src/shared/types/pii.ts","../../src/shared/types/requirement.ts","../../src/client/core/blockchain/token-sale-flow.ts","../../src/client/core/client-token-sale-namespace.ts","../../src/shared/api/frontline/documents.ts","../../src/shared/api/frontline/kyc.ts","../../src/shared/api/frontline/offers.ts","../../src/shared/api/frontline/pii.ts","../../src/shared/api/frontline/requirements.ts","../../src/client/core/coinlist-client.ts","../../src/client/CoinListStyleScope.tsx","../../src/client/generated/sdk-styles.gen.ts","../../src/client/components/design-system/AlertBanner.tsx","../../src/client/components/design-system/tokens/typography.ts","../../src/client/components/design-system/utils.ts","../../src/client/components/design-system/CloseButton.tsx","../../src/client/components/design-system/logos/CoinListWordmark.tsx","../../src/client/components/design-system/PoweredByCoinList.tsx","../../src/client/components/design-system/ClButton.tsx","../../src/client/components/design-system/logos/CoinListLogomark.tsx","../../src/client/components/oauth/CoinListSignInButton.tsx","../../src/client/hooks/useCoinList.ts","../../src/client/components/oauth/CoinListSignInCard.tsx","../../src/client/components/offers/OfferCard.tsx","../../src/client/hooks/useOffers.ts","../../src/client/components/offers/OffersGrid.tsx","../../src/client/components/requirements/ConnectedWalletList.tsx","../../src/client/components/requirements/ConnectWalletModal.tsx","../../src/client/hooks/useConnectWallet.ts","../../src/client/core/connect-external-wallet.ts","../../src/client/components/requirements/IdentityVerification.tsx","../../src/client/hooks/useKycToken.ts","../../src/client/components/requirements/RequirementItem.tsx","../../src/client/components/design-system/StepStatusIcon.tsx","../../src/client/components/requirements/RequirementsChecklist.tsx","../../src/client/components/requirements/TaxDocumentModal.tsx","../../src/client/hooks/useTaxDocument.ts","../../src/client/hooks/useOptionAddresses.ts","../../src/client/hooks/useRequirements.ts","../../src/client/hooks/swap/useSwapOutputToken.ts","../../src/client/hooks/swap/useSwapQuote.ts","../../src/client/hooks/swap/useSwapTokenBalances.ts","../../src/client/hooks/useCompleteOAuth.ts","../../src/client/hooks/useOfferDetails.ts","../../src/client/hooks/useParticipations.ts"],"sourcesContent":["// Provider\nexport * from '@/client/CoinListProvider';\nexport * from '@/client/CoinListStyleScope';\n// Components\nexport * from '@/client/components/oauth/CoinListSignInCard';\nexport {\n OfferCard,\n OfferCardUi,\n type Props as OfferCardProps,\n} from '@/client/components/offers/OfferCard';\nexport * from '@/client/components/offers/OffersGrid';\nexport * from '@/client/components/requirements/ConnectedWalletList';\nexport * from '@/client/components/requirements/ConnectWalletModal';\nexport * from '@/client/components/requirements/IdentityVerification';\nexport * from '@/client/components/requirements/RequirementItem';\nexport * from '@/client/components/requirements/RequirementsChecklist';\nexport * from '@/client/components/requirements/TaxDocumentModal';\nexport * from '@/client/core/blockchain/evm-wallet';\nexport * from '@/client/core/blockchain/swap-flows';\nexport * from '@/client/core/blockchain/token-sale-flow';\nexport * from '@/client/core/blockchain/wallet-error';\n// Core client\nexport * from '@/client/core/client-swap-namespace';\nexport * from '@/client/core/client-token-sale-namespace';\nexport * from '@/client/core/coinlist-client';\nexport * from '@/client/core/connect-external-wallet';\nexport * from '@/client/core/types/client-types';\n// Swap hooks\nexport * from '@/client/hooks/swap/useSwapOutputToken';\nexport * from '@/client/hooks/swap/useSwapQuote';\nexport * from '@/client/hooks/swap/useSwapTokenBalances';\n// Hooks\nexport * from '@/client/hooks/useCoinList';\nexport * from '@/client/hooks/useCompleteOAuth';\nexport * from '@/client/hooks/useConnectWallet';\nexport * from '@/client/hooks/useKycToken';\nexport * from '@/client/hooks/useOfferDetails';\nexport * from '@/client/hooks/useOffers';\nexport * from '@/client/hooks/useOptionAddresses';\nexport * from '@/client/hooks/useParticipations';\nexport * from '@/client/hooks/useRequirements';\nexport * from '@/client/hooks/useTaxDocument';\n// Wallet\n// Shared types\nexport * from '@/shared/types/kyc';\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\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';\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 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 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.getAuthState() === '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\n return (\n <CoinListContext.Provider value={value}>\n {children}\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 * (CoinListSignInCard, OffersGrid, ...) 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 '@/shared/utils';\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_VERIFIED_PATH =\n '/verify-identity/identity_verified';\nexport const VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH =\n '/verify-identity/proof_of_address';\nexport const VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH =\n '/verify-identity/source_of_funds';\nexport const VERIFY_IDENTITY_ACCREDITATION_PATH =\n '/verify-identity/accreditation_full';\nexport const WALLET_PATH = '/wallet';\n","import type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\n\nexport type HttpRequestAttributes = {\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 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 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 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 clientCredentials,\n getClientCredentials,\n} as const;\n","'use client';\n\nimport { getDeviceId } from '@/client/core/api/middleware/device-id';\nimport { HEADER_USER_AGENT } from '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/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 '@/shared/api/http-attributes';\n\nexport type HttpClientConfig = {\n baseUrl: string;\n xApiVersion: string;\n};\n\nexport type QueryParamValue = string | number | boolean | null | undefined;\nexport type QueryParamValues = QueryParamValue | QueryParamValue[];\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\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\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 const body = text ? (JSON.parse(text) as TResponse) : null;\n\n return {\n status: response.status,\n body,\n headers: responseHeaders,\n };\n}\n\nfunction 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 { HEADER_API_VERSION } from '@/shared/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/shared/api/http';\nimport { makeRequest } from '@/shared/api/http';\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 class HttpClient {\n constructor(\n readonly config: HttpClientConfig,\n readonly middleware: HttpClientMiddleware = {}\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 response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) =>\n this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >,\n })) as HttpResponse<TResponse>;\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 [HEADER_API_VERSION]: this.config.xApiVersion,\n };\n\n return {\n ...request,\n url,\n headers,\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 private executeRequest<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n return makeRequest<TResponse>(request);\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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport function attachSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): BeforeRequestMiddleware {\n return async (request: HttpRequest): Promise<HttpRequest> => {\n if (!Attributes.isProtected(request.attributes)) {\n return request;\n }\n\n let accessToken = await fetchAccessToken(false);\n if (!accessToken) {\n const clientCreds = Attributes.getClientCredentials(request.attributes);\n if (clientCreds) {\n accessToken = clientCreds;\n }\n }\n\n if (accessToken === null) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n Authorization: `Bearer ${accessToken.value}`,\n },\n };\n };\n}\n","import { HEADER_IDEMPOTENCY_KEY } from '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport { getUUIDv4 } from '@/shared/utils';\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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/shared/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 (!isRetryableStatus(response.status)) {\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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/shared/api/http-client';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport function renewSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\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(true);\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 '@/shared/api/http';\nimport { HttpError } from '@/shared/api/http';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport { HttpClient } from '@/shared/api/http-client';\nimport { attachSessionMiddleware } from '@/shared/api/middleware/attach-session-middleware';\nimport { idempotencyKeyMiddleware } from '@/shared/api/middleware/idempotency-key';\nimport { requestRetryMiddleware } from '@/shared/api/middleware/request-retry';\nimport { renewSessionMiddleware } from '@/shared/api/middleware/session-renewal';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\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 */\nexport class AuthenticatedApiClient {\n private readonly httpClient: HttpClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\n additionalBeforeRequest: BeforeRequestMiddleware[] = []\n ) {\n this.httpClient = new HttpClient(config, {\n beforeRequest: [\n attachSessionMiddleware(fetchAccessToken),\n ...additionalBeforeRequest,\n idempotencyKeyMiddleware,\n ],\n afterRequest: [\n renewSessionMiddleware(fetchAccessToken),\n requestRetryMiddleware,\n ],\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 '@/shared/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/shared/api/http';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n ) {\n this.client = new AuthenticatedApiClient(config, fetchAccessToken, [\n userAgentMiddleware,\n ]);\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","import {\n ContractFunctionRevertedError,\n type Hash,\n InsufficientFundsError,\n UserRejectedRequestError,\n WaitForTransactionReceiptTimeoutError,\n} from 'viem';\n\n/**\n * A classified wallet/transaction failure. The SDK derives this from whatever\n * the {@link EvmWallet} throws, so consumers get a stable, typed error\n * shape regardless of the underlying wallet library.\n */\nexport type WalletError =\n | { type: 'user_rejected' }\n | { type: 'insufficient_funds' }\n | { type: 'contract_reverted'; reason: string }\n | { type: 'timeout'; hash: Hash }\n | { type: 'unknown'; cause: unknown };\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 */\nexport function classifyWalletError(\n error: unknown,\n ctx?: { hash?: Hash }\n): WalletError {\n if (error instanceof UserRejectedRequestError) {\n return { type: 'user_rejected' };\n }\n if (error instanceof InsufficientFundsError) {\n return { type: 'insufficient_funds' };\n }\n if (error instanceof ContractFunctionRevertedError) {\n return { type: 'contract_reverted', reason: error.reason ?? error.message };\n }\n if (error instanceof WaitForTransactionReceiptTimeoutError && ctx?.hash) {\n return { type: 'timeout', hash: ctx.hash };\n }\n return { type: 'unknown', cause: error };\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 type { EvmWallet } from '@/client/core/blockchain/evm-wallet';\nimport {\n classifyWalletError,\n type WalletError,\n} from '@/client/core/blockchain/wallet-error';\nimport { ERC20_ABI } from '@/shared/core/blockchain/abis/erc20';\nimport type {\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\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","export const SUPERSTATE_SWAP_ABI = [\n {\n type: 'function',\n name: 'authorized',\n inputs: [{ name: 'user', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'stopped',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'SWAP_LEVEL',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'preview',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Preview',\n components: [\n { name: 'input', type: 'uint256', internalType: 'uint256' },\n { name: 'fee', type: 'uint256', internalType: 'uint256' },\n { name: 'output', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'swap',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n { name: 'slip', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'tokenBalance',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputToken',\n inputs: [],\n outputs: [{ name: '', type: 'address', internalType: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputTokenBalance',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'setBps',\n inputs: [{ name: 'points', type: 'uint256', internalType: 'uint256' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'event',\n name: 'Swapped',\n inputs: [\n { name: 'user', type: 'address', indexed: true, internalType: 'address' },\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: '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 { name: 'to', type: 'address', indexed: true, internalType: 'address' },\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: 'InvalidAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InsufficientAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'SwapFailed',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n },\n] as const;\n","import type { Newtype } from '@/shared/types/newtype';\n\nexport type EthereumChain = 'ethereum_mainnet' | 'ethereum_sepolia';\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\nexport type HexEncodedTransactionData = Newtype<\n `0x${string}`,\n 'HexEncodedTransactionData'\n>;\nexport const HexEncodedTransactionData = (\n value: string\n): HexEncodedTransactionData => value as HexEncodedTransactionData;\n\nexport type AssetDecimals = Newtype<number, 'AssetDecimals'>;\nexport const AssetDecimals = (value: number): AssetDecimals =>\n value as AssetDecimals;\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 raw bigint falls within uint256 bounds, throwing otherwise. Use at\n * on-chain arithmetic boundaries (bps math, price computation) where a computed\n * value could underflow below zero or overflow above 2^256-1.\n */\nexport const assertUint256 = (value: bigint): Uint256 => {\n if (value < 0n || value > MAX_UINT_256) {\n throw new Error(`Value out of uint256 bounds: ${value}`);\n }\n return value;\n};\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 }\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 Error(\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 Error(`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 {\n assertUint256,\n Bps,\n type Uint256,\n} from '@/shared/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 { applyBps, BPS_DENOM } from '@/shared/core/blockchain/bps';\nimport type { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport {\n assertUint256,\n BlockchainAmount,\n Bps,\n} from '@/shared/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 type { SwapStatus } from '@/shared/types/swap';\n\n/**\n * Interprets the on-chain swap availability read from `stopped()` and\n * `SWAP_LEVEL()`.\n *\n * The contract tracks paused operations as a bitmask in `stopped`. The swap is\n * stopped when the SWAP_LEVEL flag is set:\n *\n * (stopped & SWAP_LEVEL) != 0 -> stopped (not active)\n */\nexport function isStopped(status: SwapStatus): boolean {\n return (status.stopped & status.swapLevel) !== 0n;\n}\n","import { parseEventLogs, type TransactionReceipt } from 'viem';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/blockchain/abis/superstate-swap';\nimport {\n type AssetDecimals,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/shared/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 type { Hash, Hex, TransactionReceipt } from 'viem';\nimport {\n type Erc20ApprovalError,\n submitErc20Approval,\n} from '@/client/core/blockchain/erc20-approval';\nimport type { EvmWallet } from '@/client/core/blockchain/evm-wallet';\nimport {\n classifyWalletError,\n type WalletError,\n} from '@/client/core/blockchain/wallet-error';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/blockchain/abis/superstate-swap';\nimport { computePrice, computeSlip } from '@/shared/core/blockchain/swap/math';\nimport type { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport { isStopped } from '@/shared/core/blockchain/swap/status';\nimport { decodeSwappedOutputAmount } from '@/shared/core/blockchain/swap/swapped-event';\nimport type { CoinListErc20Namespace } from '@/shared/core/erc20-namespace';\nimport type { CoinListSwapNamespace } from '@/shared/core/swap-namespace';\nimport {\n BlockchainAmount,\n type Bps,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapStatus,\n TokenAllowance,\n} from '@/shared/types/swap';\nimport type { WalletOwnershipChallenge } from '@/shared/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 | { step: 'swap-stopped' }\n | { step: 'allowance-check' }\n | Erc20ApprovalError\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 outputAmount: BlockchainAmount;\n pricePerShare: BlockchainAmount | null;\n recipientAddress: EvmWalletAddress;\n }\n | { type: 'error'; error: SwapExecutionError };\n\nexport type ExecuteSwapParams = {\n swap: CoinListSwapNamespace;\n erc20: CoinListErc20Namespace;\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 const inputAmount = BlockchainAmount.add(\n quote.inputTokenAmount,\n quote.fee\n ).raw;\n const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;\n\n // Step 0: Refuse to swap when the contract is stopped (paused). Run before\n // any approval so the user never signs a tx that the swap would revert.\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 (isStopped(status)) {\n return { type: 'error', error: { step: 'swap-stopped' } };\n }\n\n // Step 1: Read the current ERC-20 allowance for the swap contract.\n emit('checking-allowance');\n let allowance: TokenAllowance;\n try {\n allowance = await erc20.getTokenAllowance({\n tokenAddress: inputTokenAddress,\n owner: wallet.address,\n spender: contractAddress,\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.allowance < inputAmount) {\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.allowance > 0n) {\n const reset = await submitErc20Approval({\n wallet,\n tokenAddress: inputTokenAddress,\n spender: contractAddress,\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: inputTokenAddress,\n spender: contractAddress,\n chain,\n value: inputAmount,\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 // 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, 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.\n const outputAmount =\n decodeSwappedOutputAmount(receipt, quote.outputTokenAmount.decimals) ??\n 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 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: CoinListSwapNamespace;\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, wallet, offerId, contractAddress, chain, onProgress } = 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 auth: SwapAuthorization;\n try {\n auth = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (auth.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 swap.requestWalletOwnershipChallenge({\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: SwapAuthorization;\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.authorized) {\n return { type: 'error', error: { step: 'not-authorized' } };\n }\n\n return { type: 'success' };\n}\n","import {\n assertUint256,\n EvmContractAddress,\n HexEncodedTransactionData,\n type Uint256,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/swap';\n\n/**\n * Whether a wallet is authorized to interact with a given swap contract.\n */\nexport type SwapAuthorization = {\n authorized: boolean;\n};\n\nexport const SwapAuthorization = {\n fromDto: (dto: WalletAuthorizationDto): SwapAuthorization => ({\n authorized: dto.authorized,\n }),\n};\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 fromDto: (dto: SwapPreviewDto): SwapPreview => ({\n inputAmount: assertUint256(BigInt(dto.pay_input_amount)),\n fee: assertUint256(BigInt(dto.fee)),\n outputAmount: assertUint256(BigInt(dto.receive_output_amount)),\n }),\n};\n\n/**\n * The on-chain state of a swap contract.\n *\n * - `stopped`: non-zero when the contract is paused/halted.\n * - `swapLevel`: the current swap level/tier.\n */\nexport type SwapStatus = {\n stopped: Uint256;\n swapLevel: Uint256;\n};\n\nexport const SwapStatus = {\n fromDto: (dto: SwapStatusDto): SwapStatus => ({\n stopped: assertUint256(BigInt(dto.stopped)),\n swapLevel: assertUint256(BigInt(dto.swap_level)),\n }),\n};\n\n/**\n * The ERC-20 allowance an owner has granted a spender for a token.\n */\nexport type TokenAllowance = {\n allowance: Uint256;\n};\n\nexport const TokenAllowance = {\n fromDto: (dto: TokenAllowanceDto): TokenAllowance => ({\n allowance: assertUint256(BigInt(dto.allowance)),\n }),\n};\n\n/**\n * The raw ERC-20 balance an owner holds of a token (uint256).\n */\nexport type TokenBalance = {\n balance: Uint256;\n};\n\nexport const TokenBalance = {\n fromDto: (dto: TokenBalanceDto): TokenBalance => ({\n balance: assertUint256(BigInt(dto.balance)),\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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/shared/core/erc20-namespace';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/shared/core/swap-namespace';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapOutputTokenDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/swap';\nimport {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n TokenAllowance,\n TokenBalance,\n} from '@/shared/types/swap';\n\nexport async function getSwapAuthorization(\n api: Sender,\n params: GetSwapAuthorizationParams\n): Promise<SwapAuthorization> {\n const dto = await api.send<WalletAuthorizationDto>({\n method: 'GET',\n url: '/v1/wallet/authorized',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n wallet_address: params.walletAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapAuthorization.fromDto(dto);\n}\n\nexport async function getSwapOutputToken(\n api: Sender,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const dto = await api.send<SwapOutputTokenDto>({\n method: 'GET',\n url: '/v1/swap/output-token',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return toErc20Asset(dto);\n}\n\nexport async function getSwapPreview(\n api: Sender,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const dto = await api.send<SwapPreviewDto>({\n method: 'GET',\n url: '/v1/swap/preview',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n input_token: params.inputToken,\n amount: params.amount.toString(),\n },\n attributes: Attributes.protected(),\n });\n return SwapPreview.fromDto(dto);\n}\n\nexport async function getSwapStatus(\n api: Sender,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const dto = await api.send<SwapStatusDto>({\n method: 'GET',\n url: '/v1/swap/status',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapStatus.fromDto(dto);\n}\n\nexport async function getTokenAllowance(\n api: Sender,\n params: GetTokenAllowanceParams\n): Promise<TokenAllowance> {\n const dto = await api.send<TokenAllowanceDto>({\n method: 'GET',\n url: '/v1/token/allowance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n spender: params.spender,\n },\n attributes: Attributes.protected(),\n });\n return TokenAllowance.fromDto(dto);\n}\n\nexport async function getTokenBalance(\n api: Sender,\n params: GetTokenBalanceParams\n): Promise<TokenBalance> {\n const dto = await api.send<TokenBalanceDto>({\n method: 'GET',\n url: '/v1/token/balance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n },\n attributes: Attributes.protected(),\n });\n return TokenBalance.fromDto(dto);\n}\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\nfunction toErc20Asset(dto: SwapOutputTokenDto): Erc20Asset {\n return {\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n };\n}\n","import type { AssetDto } from '@/shared/types/dto/asset';\nimport type { Newtype } from '@/shared/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 type { OfferDto, OfferTypeDto } from '@/shared/types/dto/offer';\nimport type { Newtype } from '@/shared/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\nexport type Offer = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n startsAt: Date;\n endsAt: Date | null;\n};\n\nexport const Offer = {\n fromDto: (dto: OfferDto): Offer => ({\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n }),\n};\n","import { Asset } from '@/shared/types/asset';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailTermDto,\n} from '@/shared/types/dto/offer-detail';\nimport type { Newtype } from '@/shared/types/newtype';\nimport { OfferId, OfferSlug, type OfferType } from '@/shared/types/offer';\nimport { notBlankStringOrNull } from '@/shared/utils';\n\nexport type OfferDetail = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n name: string;\n\n asset: Asset;\n fundingAssets: Asset[];\n\n about: string | null;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n category: string;\n\n startsAt: Date;\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\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n if (!Array.isArray(dto.funding_assets)) {\n throw new Error(`funding_assets must be an array`);\n }\n\n if (!Array.isArray(dto.options)) {\n throw new Error(`options must be an array`);\n }\n\n if (!Array.isArray(dto.terms)) {\n throw new Error(`terms must be an array`);\n }\n\n if (!Array.isArray(dto.links)) {\n throw new Error(`links must be an array`);\n }\n\n if (!Array.isArray(dto.faqs)) {\n throw new Error(`faqs must be an array`);\n }\n\n if (!Array.isArray(dto.milestones)) {\n throw new Error(`milestones must be an array`);\n }\n\n return {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n name: dto.name,\n\n asset: Asset.fromDto(dto.asset),\n fundingAssets: dto.funding_assets.map(Asset.fromDto),\n\n about: notBlankStringOrNull(dto.about),\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n category: dto.category,\n\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: dto.faqs.map(FaqItem.fromDto),\n links: dto.links.map(Link.fromDto),\n milestones: dto.milestones.map(Milestone.fromDto),\n options: dto.options.map(OfferOption.fromDto),\n terms: dto.terms.map(TermItem.fromDto),\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 type { Hex } from 'viem';\nimport {\n type EthereumChain,\n EvmWalletAddress,\n type WalletProtocol,\n} from '@/shared/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/shared/types/dto/offer-option-address';\nimport type { Newtype } from '@/shared/types/newtype';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/shared/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: OfferOptionIdType;\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 option to bind the wallet to. */\n offerOptionId: OfferOptionIdType;\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 '@/shared/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { OfferOptionAddressDto } from '@/shared/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/shared/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/shared/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/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 offerId: OfferId,\n params: ConnectExternalWalletParams\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'POST',\n url: `/v1/offers/${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 {\n allowWallet,\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/shared/api/frontline/swap';\nimport { createWalletOwnershipChallenge } from '@/shared/api/frontline/wallet-connect';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport type {\n Erc20Asset,\n EthereumChain,\n EvmContractAddress,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n} from '@/shared/types/swap';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\n/** Parameters shared by contract reads scoped to a chain. */\nexport type SwapContractRef = {\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n};\n\nexport type GetSwapAuthorizationParams = SwapContractRef & {\n walletAddress: EvmWalletAddress;\n};\n\nexport type GetSwapPreviewParams = SwapContractRef & {\n inputToken: EvmContractAddress;\n amount: bigint;\n};\n\nexport type AllowWalletParams = {\n offerId: OfferId;\n walletAddress: EvmWalletAddress;\n chain: EthereumChain;\n signature: string;\n};\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, checking token allowances, and proving/allow-listing wallet\n * ownership.\n */\nexport interface CoinListSwapNamespace {\n /**\n * Checks whether a wallet is authorized to swap against the given contract.\n */\n getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization>;\n\n /**\n * Fetches a read-only quote for swapping `amount` of `inputToken`.\n */\n getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;\n\n /**\n * Reads the current on-chain state of a swap contract.\n */\n getStatus(params: SwapContractRef): Promise<SwapStatus>;\n\n /**\n * Reads the ERC-20 output token a swap contract pays out.\n */\n getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;\n\n /**\n * Requests a single-use challenge the user must sign to prove wallet\n * ownership, via `POST /v1/wallet-ownership`. Supports both `plain` and\n * `siwe` challenges. This is the same operation as the top-level\n * `createWalletOwnershipChallenge`, scoped under the swap namespace for the\n * allow-wallet flow.\n */\n requestWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n\n /**\n * Submits a signed wallet-ownership challenge to allow-list the wallet for\n * an offer, identified by its offer id.\n */\n allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;\n}\n\nexport class SwapNamespaceImpl implements CoinListSwapNamespace {\n constructor(private readonly ctx: SharedNamespaceContext) {}\n\n async getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization> {\n await this.ctx.ensureUserAuthenticated();\n return getSwapAuthorization(this.ctx.api, params);\n }\n\n async getPreview(params: GetSwapPreviewParams): Promise<SwapPreview> {\n await this.ctx.ensureUserAuthenticated();\n return getSwapPreview(this.ctx.api, params);\n }\n\n async getStatus(params: SwapContractRef): Promise<SwapStatus> {\n await this.ctx.ensureUserAuthenticated();\n return getSwapStatus(this.ctx.api, params);\n }\n\n async getOutputToken(params: SwapContractRef): Promise<Erc20Asset> {\n await this.ctx.ensureUserAuthenticated();\n return getSwapOutputToken(this.ctx.api, params);\n }\n\n async requestWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n await this.ctx.ensureUserAuthenticated();\n return createWalletOwnershipChallenge(this.ctx.api, params);\n }\n\n async allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse> {\n await this.ctx.ensureUserAuthenticated();\n return allowWallet(this.ctx.api, params);\n }\n}\n","import {\n type AuthorizeWalletParams,\n authorizeWallet,\n type ExecuteSwapParams,\n executeSwap,\n type SwapExecutionResult,\n type WalletAuthorizationResult,\n} from '@/client/core/blockchain/swap-flows';\nimport type { CoinListErc20Namespace } from '@/shared/core/erc20-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type CoinListSwapNamespace,\n SwapNamespaceImpl,\n} from '@/shared/core/swap-namespace';\n\n/**\n * The client-side swap namespace: everything the shared\n * {@link CoinListSwapNamespace} reads/writes over the API, plus the on-chain\n * flows that drive a wallet (`executeSwap`, `authorizeWallet`). The flows take\n * the wallet and addresses per call; the namespace itself supplies the API\n * reads they depend on.\n */\nexport interface CoinListClientSwapNamespace extends CoinListSwapNamespace {\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 executeSwap(\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.\n */\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap'>\n ): Promise<WalletAuthorizationResult>;\n}\n\nexport class ClientSwapNamespaceImpl\n extends SwapNamespaceImpl\n implements CoinListClientSwapNamespace\n{\n constructor(\n ctx: SharedNamespaceContext,\n private readonly erc20: CoinListErc20Namespace\n ) {\n super(ctx);\n }\n\n executeSwap(\n params: Omit<ExecuteSwapParams, 'swap' | 'erc20'>\n ): Promise<SwapExecutionResult> {\n return executeSwap({ ...params, swap: this, erc20: this.erc20 });\n }\n\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap'>\n ): Promise<WalletAuthorizationResult> {\n return authorizeWallet({ ...params, swap: this });\n }\n}\n","import type { QueryParamValue } from '@/shared/api/http';\nimport type { Newtype } from '@/shared/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 PaginatedResponseDto<T> {\n data: T[];\n starting_after?: string;\n starting_before?: string;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n startingAfter: Cursor | null;\n startingBefore: Cursor | null;\n}\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\nexport const PaginatedResponse = {\n fromDto: <A, B>(\n dto: PaginatedResponseDto<A>,\n itemMapper: (item: A) => B\n ): PaginatedResponse<B> => ({\n data: dto.data.map(itemMapper),\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 { Newtype } from '@/shared/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 { formatUnits } from 'viem';\nimport { computePrice } from '@/shared/core/blockchain/swap/math';\nimport type { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport { AssetDecimals } from '@/shared/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/shared/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\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 =\n maxFractionDigits !== undefined\n ? Math.min(maxFractionDigits, amount.decimals)\n : Math.min(2, amount.decimals);\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 const fraction =\n minFractionDigits === 0 ? '' : fractionPart.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 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\n/** Formats a quote's implied price per output token as a USD amount. */\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 { Bps, EvmContractAddress } from '@/shared/types/blockchain/core';\n\nexport const SUPERSTATE_TOS_URL = 'https://superstate.com/terms';\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 Superstate swap contract on Ethereum Sepolia. The mainnet address is not\n * yet finalized upstream, so it is intentionally not exported — callers pass\n * the contract address explicitly.\n */\nexport const SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA: EvmContractAddress =\n EvmContractAddress('0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557');\n","import {\n type AssetDecimals,\n BlockchainAmount,\n} from '@/shared/types/blockchain/core';\nimport type { SwapPreview } from '@/shared/types/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 {\n AssetDecimals,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type KnownAssetSymbol,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\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};\n\nconst USDT_ADDRESSES: TokenAddresses = {\n ethereum_mainnet: EvmContractAddress(\n '0xdac17f958d2ee523a2206206994597c13d831ec7'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x7169D38820dfd117C3FA1f22a697dBA58d90BA06'\n ),\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 Error(`Unknown asset symbol: ${symbol}`);\n }\n },\n contractAddress: (\n symbol: KnownAssetSymbol,\n chain: EthereumChain\n ): EvmContractAddress => {\n switch (symbol) {\n case 'USDC':\n return USDC_ADDRESSES[chain];\n case 'USDT':\n return USDT_ADDRESSES[chain];\n default:\n throw new Error(`Unknown asset symbol: ${symbol}`);\n }\n },\n};\n","import {\n getTokenAllowance,\n getTokenBalance,\n} from '@/shared/api/frontline/swap';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport type {\n EthereumChain,\n EvmContractAddress,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { TokenAllowance, TokenBalance } from '@/shared/types/swap';\n\nexport type GetTokenAllowanceParams = {\n tokenAddress: EvmContractAddress;\n owner: EvmWalletAddress;\n spender: EvmContractAddress;\n chain: EthereumChain;\n};\n\nexport type GetTokenBalanceParams = {\n tokenAddress: EvmContractAddress;\n owner: EvmWalletAddress;\n chain: EthereumChain;\n};\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 */\nexport interface CoinListErc20Namespace {\n /**\n * Reads the ERC-20 allowance an `owner` has granted a `spender`.\n */\n getTokenAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance>;\n\n /**\n * Reads the raw ERC-20 balance an `owner` holds of a token.\n */\n getTokenBalance(params: GetTokenBalanceParams): Promise<TokenBalance>;\n}\n\nexport class Erc20NamespaceImpl implements CoinListErc20Namespace {\n constructor(private readonly ctx: SharedNamespaceContext) {}\n\n async getTokenAllowance(\n params: GetTokenAllowanceParams\n ): Promise<TokenAllowance> {\n await this.ctx.ensureUserAuthenticated();\n return getTokenAllowance(this.ctx.api, params);\n }\n\n async getTokenBalance(params: GetTokenBalanceParams): Promise<TokenBalance> {\n await this.ctx.ensureUserAuthenticated();\n return getTokenBalance(this.ctx.api, params);\n }\n}\n","import type { QueryParamValue } from '@/shared/api/http';\nimport { PaginationParams } from '@/shared/api/pagination';\nimport { Asset, type AssetId } from '@/shared/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/shared/types/dto/participation';\nimport type { Newtype } from '@/shared/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/shared/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/shared/types/offer-detail';\nimport { notBlankStringOrNull } from '@/shared/utils';\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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport {\n fetchAllPages,\n PaginatedResponse,\n type PaginatedResponseDto,\n} from '@/shared/api/pagination';\nimport type { ParticipationDto } from '@/shared/types/dto/participation';\nimport type { OfferId } from '@/shared/types/offer';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/participation';\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 {\n createParticipation,\n fetchParticipation,\n fetchParticipations,\n fetchParticipationsPage,\n} from '@/shared/api/frontline/participations';\nimport type { PaginatedResponse } from '@/shared/api/pagination';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport type { OfferId } from '@/shared/types/offer';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/participation';\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 fetchParticipations(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 fetchParticipationsPage(\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 fetchParticipation(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 TokenSaleNamespaceImpl implements CoinListTokenSaleNamespace {\n constructor(private readonly ctx: SharedNamespaceContext) {}\n\n async fetchParticipations(offerId?: OfferId): Promise<Participation[]> {\n await this.ctx.ensureUserAuthenticated();\n return fetchParticipations(this.ctx.api, offerId);\n }\n\n async fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n await this.ctx.ensureUserAuthenticated();\n return fetchParticipationsPage(this.ctx.api, params);\n }\n\n async fetchParticipation(id: ParticipationId): Promise<Participation> {\n await this.ctx.ensureUserAuthenticated();\n return fetchParticipation(this.ctx.api, id);\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n await this.ctx.ensureUserAuthenticated();\n return createParticipation(this.ctx.api, params);\n }\n}\n","import type { Newtype } from '@/shared/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 type {\n CodeChallenge as CodeChallengeType,\n CodeVerifier as CodeVerifierType,\n PKCEState as PKCEStateType,\n} from '@/shared/types/oauth';\nimport {\n type ClientId,\n CodeChallenge,\n CodeVerifier,\n PKCEState,\n type RedirectUri,\n} from '@/shared/types/oauth';\nimport {\n arrayBufferToBase64Url,\n generateSecureRandomBase64Url,\n sha256,\n} from '@/shared/utils';\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 {\n DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/shared/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","/**\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","import type { KycTokenDto } from '@/shared/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 type {\n PiiAddressDto,\n PiiDto,\n PiiJurisdictionDto,\n PiiKindDto,\n} from '@/shared/types/dto/pii';\nimport type { Newtype } from '@/shared/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 type {\n RequirementActionNeededReasonDto,\n RequirementDto,\n RequirementStatusesDto,\n RequirementStatusValueDto,\n RequirementTypeDto,\n} from '@/shared/types/dto/requirement';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { Newtype } from '@/shared/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 type { Hash } from 'viem';\nimport {\n type Erc20ApprovalError,\n submitErc20Approval,\n} from '@/client/core/blockchain/erc20-approval';\nimport type { EvmWallet } from '@/client/core/blockchain/evm-wallet';\nimport type { WalletError } from '@/client/core/blockchain/wallet-error';\nimport { formatRawAmount } from '@/shared';\nimport type { CoinListErc20Namespace } from '@/shared/core/erc20-namespace';\nimport type { CoinListTokenSaleNamespace } from '@/shared/core/token-sale-namespace';\nimport type { AssetId } from '@/shared/types/asset';\nimport type {\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport {\n Blockchain,\n type Participation,\n WalletAddress,\n} from '@/shared/types/participation';\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: CoinListErc20Namespace;\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 const allowance = await erc20.getTokenAllowance({\n tokenAddress: paymentTokenAddress,\n owner: wallet.address,\n spender: fundingContractAddress,\n chain,\n });\n currentAllowance = allowance.allowance;\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 {\n type ExecuteTokenSaleParams,\n executeTokenSale,\n type TokenSaleExecutionResult,\n} from '@/client/core/blockchain/token-sale-flow';\nimport type { CoinListErc20Namespace } from '@/shared/core/erc20-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type CoinListTokenSaleNamespace,\n TokenSaleNamespaceImpl,\n} from '@/shared/core/token-sale-namespace';\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 (`executeTokenSale`). The flow takes the\n * wallet and addresses per call; the namespace supplies the participation\n * writes and (via the ERC-20 namespace) the allowance read it depends on.\n */\nexport interface CoinListClientTokenSaleNamespace\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 executeTokenSale(\n params: Omit<ExecuteTokenSaleParams, 'erc20' | 'tokenSale'>\n ): Promise<TokenSaleExecutionResult>;\n}\n\nexport class ClientTokenSaleNamespaceImpl\n extends TokenSaleNamespaceImpl\n implements CoinListClientTokenSaleNamespace\n{\n constructor(\n ctx: SharedNamespaceContext,\n private readonly erc20: CoinListErc20Namespace\n ) {\n super(ctx);\n }\n\n executeTokenSale(\n params: Omit<ExecuteTokenSaleParams, 'erc20' | 'tokenSale'>\n ): Promise<TokenSaleExecutionResult> {\n return executeTokenSale({ ...params, erc20: this.erc20, tokenSale: this });\n }\n}\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/shared/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/shared/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 { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { KycTokenDto } from '@/shared/types/dto/kyc';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport { KycToken } from '@/shared/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 { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport {\n fetchAllPages,\n PaginatedResponse,\n type PaginatedResponseDto,\n PaginationParams,\n} from '@/shared/api/pagination';\nimport type { OfferDto } from '@/shared/types/dto/offer';\nimport type { OfferDetailDto } from '@/shared/types/dto/offer-detail';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport { Offer, type OfferId } from '@/shared/types/offer';\nimport { OfferDetail } from '@/shared/types/offer-detail';\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.fromDto(pageDto, Offer.fromDto);\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 { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { PiiDto } from '@/shared/types/dto/pii';\nimport { Pii } from '@/shared/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 { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/shared/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { Requirement, RequirementStatusInfo } from '@/shared/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 { ApiClient } from '@/client/core/api/api-client';\nimport {\n ClientSwapNamespaceImpl,\n type CoinListClientSwapNamespace,\n} from '@/client/core/client-swap-namespace';\nimport {\n ClientTokenSaleNamespaceImpl,\n type CoinListClientTokenSaleNamespace,\n} from '@/client/core/client-token-sale-namespace';\nimport type {\n AuthState,\n OauthClientResult,\n} from '@/client/core/types/client-types';\nimport {\n API_VERSION,\n COINLIST_BASE_URL,\n OAUTH_PAGE_PATH,\n PUBLIC_API_BASE_URL,\n SUPPORT_NEW_TICKET_URL,\n VERIFY_IDENTITY_ACCREDITATION_PATH,\n VERIFY_IDENTITY_PATH,\n VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH,\n VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH,\n VERIFY_IDENTITY_VERIFIED_PATH,\n WALLET_PATH,\n} from '@/shared/api/frontline/config';\nimport * as documentsApi from '@/shared/api/frontline/documents';\nimport * as kycApi from '@/shared/api/frontline/kyc';\nimport * as offersApi from '@/shared/api/frontline/offers';\nimport * as piiApi from '@/shared/api/frontline/pii';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport * as walletConnectApi from '@/shared/api/frontline/wallet-connect';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/api/pagination';\nimport {\n type CoinListErc20Namespace,\n Erc20NamespaceImpl,\n} from '@/shared/core/erc20-namespace';\nimport { generatePKCEParams } from '@/shared/pkce';\nimport type { Config } from '@/shared/types/config';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/shared/types/document-submission';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { KycLevelName, KycToken } from '@/shared/types/kyc';\nimport { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail, OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport type { Pii } from '@/shared/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\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\nexport interface ClientConfig extends Config {\n /**\n * The SDK user must provide this function. It is responsible for fetching a\n * valid {@link OAuthAccessToken}, or **null** for logged-out users. If your\n * backend is in TypeScript, it is recommended to use\n * {@link CoinListServer#accessToken} from `@/server/coinlist.server`.\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\nexport interface CoinListClient {\n /**\n * Calls the provided {@link ClientConfig.getAccessToken} lambda to determine\n * the user's {@link AuthState}. This is called automatically by {@link CoinListProvider};\n * you typically do not need to call it yourself unless you are using the client\n * outside of the provider.\n */\n init(): Promise<AuthState>;\n /**\n * Returns the current auth state: `'logged-in'`, `'logged-out'`, or `'unknown'`.\n * Returns **unknown** until {@link CoinListClient.init} has completed. It is\n * recommended to use the `const { isReady, coinlist } = useCoinList()` hook to know when\n * the SDK has initialized, or to manually await {@link CoinListClient.init}\n * before relying on this value.\n */\n getAuthState(): AuthState;\n /**\n * Starts the OAuth flow with PKCE. Generates a random `state` and `code_verifier`,\n * stores them in sessionStorage (for validation in {@link CoinListClient.completeOAuth}\n * on redirect), then redirects the user to the CoinList authorization page. After\n * the user authorizes, they are sent back to your application's redirect URI; call\n * {@link CoinListClient.completeOAuth} on that page to finish the flow.\n */\n startOAuth(): Promise<void>;\n /**\n * Completes the OAuth flow on the FE with PKCE and state validation. Parses the\n * redirect URL (state, code) and validates them against sessionStorage\n * (state, code_verifier). The state check protects against CSRF (cross-site\n * request forgery). Call this on the frontend page the user is redirected\n * to after authorizing.\n *\n * On `ok`: Call your backend to exchange the short-lived `authorizationCode`\n * (and the returned `codeVerifier`) for a long-lived session. If your backend\n * is in TypeScript, you can use {@link CoinListServer#completeOAuth} from\n * `@/server/coinlist.server` (CoinListServer) to perform that exchange.\n *\n * On `error`: `reason` is an {@link OauthClientErrorReason} (e.g. `'missing_state'`, `'invalid_state'`) so you can switch on it and surface a message to the user.\n */\n completeOAuth(): OauthClientResult;\n /**\n * Clears the in-memory access token. Note: you need to manually\n * also logout on the backend via CoinListServer#logout to clear the session cookie.\n */\n logout(): void;\n\n /**\n * Fetches all offers by iterating through every paginated response.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffers(): Promise<Offer[]>;\n /**\n * Fetches a single page of offers.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffersPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n /**\n * Fetches details for a given offer by its id.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferDetails(id: OfferId): Promise<OfferDetail>;\n /**\n * Creates a single-use wallet-ownership challenge for the given wallet and\n * chain. The user signs the returned {@link WalletOwnershipChallenge.message}\n * with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n /**\n * Connects a proven external wallet to an offer option, using a signature of\n * a challenge from {@link createWalletOwnershipChallenge}.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n connectExternalWallet(\n offerId: OfferId,\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n /**\n * Lists the user's proven wallet bindings for a single offer option (the\n * bound address for `external_wallet`, or all whitelisted wallets for\n * `whitelisted_wallet`).\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n listOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId\n ): Promise<OfferOptionAddress[]>;\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n removeOptionAddress(\n offerId: OfferId,\n addressId: OfferOptionAddressId\n ): Promise<OfferOptionAddress>;\n /**\n * Fetches the requirements for all options of a given offer, grouped by option ID.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n /**\n * Fetches the user's requirement statuses for a given offer.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchRequirementStatuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\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 * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchPii(): Promise<Pii>;\n /**\n * Starts (or resumes) a document signing submission for the given type\n * (currently only `tax_certification`, e.g. W-8BEN/W-8BEN-E). `fields` are\n * signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to Passport to pre-fill the document.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n submitDocument(\n documentType: DocumentType,\n fields: Record<string, string>\n ): Promise<DocumentSubmission>;\n /**\n * Creates a short-lived Sumsub WebSDK access token for the current user so an\n * identity verification (KYC) flow can be started, e.g. by the\n * `IdentityVerification` component. `levelName` selects the Sumsub\n * verification level; defaults to the backend's standard level. `reset`\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\n * from the requirement status, and never on mid-flow token refreshes.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createKycToken(levelName?: KycLevelName, reset?: boolean): Promise<KycToken>;\n /**\n * Opens the CoinList page for completing a given requirement in a new tab.\n * For `jurisdiction` and `document` requirements there is no CTA, so this\n * is a no-op — `document` requires the caller to use {@link fetchPii} and\n * {@link submitDocument} directly (e.g. via a custom\n * `onRequirementActionOverride`).\n */\n handleRequirement(requirement: Requirement): void;\n /**\n * Opens the CoinList support ticket page in a new tab.\n */\n contactSupport(): void;\n\n /**\n * Generic ERC-20 reads (token allowance and balance) shared across the\n * on-chain flows — e.g. `coinlist.erc20.getTokenBalance({ ... })`.\n *\n * These reads must be called only when the user's {@link AuthState} is\n * `'logged-in'`; if the user is not authenticated, they throw\n * {@link NotAuthenticatedError}.\n */\n readonly erc20: CoinListErc20Namespace;\n\n /**\n * Token-sale operations: listing/reading/recording participations, plus the\n * on-chain `executeTokenSale` flow that submits the ERC-20 approval and\n * records the participation over a caller-supplied {@link EvmWallet} —\n * e.g. `coinlist.tokenSale.executeTokenSale({ ... })`.\n *\n * The API-backed reads/writes must be called only when the user's\n * {@link AuthState} is `'logged-in'`; if the user is not authenticated, they\n * throw {@link NotAuthenticatedError}. `executeTokenSale` additionally drives\n * a caller-supplied wallet and returns a step-tagged result rather than\n * throwing.\n */\n readonly tokenSale: CoinListClientTokenSaleNamespace;\n\n /**\n * On-chain swap operations: quoting a swap, reading swap-contract state, and\n * proving/allow-listing wallet ownership — e.g.\n * `coinlist.swap.getOutputToken({ contractAddress, chain })`.\n *\n * The API-backed reads must be called only when the user's {@link AuthState}\n * is `'logged-in'`; if the user is not authenticated, they throw\n * {@link NotAuthenticatedError}. The on-chain flows (`executeSwap`,\n * `authorizeWallet`) additionally drive a caller-supplied wallet.\n */\n readonly swap: CoinListClientSwapNamespace;\n}\n\nclass CoinListClientImpl implements CoinListClient {\n /** Cached access token: undefined = loading, null = no token, AccessToken = logged in */\n private _accessToken: OAuthAccessToken | null | undefined = undefined;\n private readonly api: ApiClient;\n readonly erc20: CoinListErc20Namespace;\n readonly tokenSale: CoinListClientTokenSaleNamespace;\n readonly swap: CoinListClientSwapNamespace;\n\n constructor(readonly _config: ClientConfig) {\n this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl || PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n this.fetchAccessToken.bind(this)\n );\n const ctx = {\n api: this.api,\n ensureUserAuthenticated: async () => this.ensureAuthenticated(),\n };\n this.erc20 = new Erc20NamespaceImpl(ctx);\n this.tokenSale = new ClientTokenSaleNamespaceImpl(ctx, this.erc20);\n this.swap = new ClientSwapNamespaceImpl(ctx, this.erc20);\n }\n\n async init(): Promise<AuthState> {\n await this.fetchAccessToken(true);\n return this.getAuthState();\n }\n\n async fetchAccessToken(refresh: boolean): Promise<OAuthAccessToken | null> {\n if (!refresh && this._accessToken !== undefined) return this._accessToken;\n\n try {\n const accessToken = await this._config.getAccessToken();\n this._accessToken = accessToken;\n return accessToken;\n } catch (_) {\n this._accessToken = null;\n return null;\n }\n }\n\n getAuthState(): AuthState {\n if (this._accessToken === undefined) {\n return 'unknown';\n }\n return this._accessToken !== null ? 'logged-in' : 'logged-out';\n }\n\n async startOAuth(): 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 const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;\n window.location.href = url;\n }\n\n completeOAuth(): 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 logout(): void {\n this._accessToken = null;\n }\n\n async fetchOffers(): Promise<Offer[]> {\n this.ensureAuthenticated();\n return offersApi.fetchOffers(this.api, undefined);\n }\n\n async fetchOffersPage(\n params: PaginationParams\n ): Promise<PaginatedResponse<Offer>> {\n this.ensureAuthenticated();\n return offersApi.fetchOffersPage(this.api, params, undefined);\n }\n\n async fetchOfferDetails(id: OfferId): Promise<OfferDetail> {\n this.ensureAuthenticated();\n return offersApi.fetchOfferDetails(this.api, id, undefined);\n }\n\n async createWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n this.ensureAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(this.api, params);\n }\n\n async connectExternalWallet(\n offerId: OfferId,\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n this.ensureAuthenticated();\n return walletConnectApi.connectExternalWallet(this.api, offerId, params);\n }\n\n async listOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId\n ): Promise<OfferOptionAddress[]> {\n this.ensureAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.api,\n offerId,\n offerOptionId\n );\n }\n\n async removeOptionAddress(\n offerId: OfferId,\n addressId: OfferOptionAddressId\n ): Promise<OfferOptionAddress> {\n this.ensureAuthenticated();\n return walletConnectApi.removeOptionAddress(this.api, offerId, addressId);\n }\n\n async fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n this.ensureAuthenticated();\n return requirementsApi.fetchOfferRequirements(this.api, offerId, undefined);\n }\n\n async fetchRequirementStatuses(\n offerId: OfferId\n ): Promise<RequirementStatusInfo[]> {\n this.ensureAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.api, offerId);\n }\n\n async fetchPii(): Promise<Pii> {\n this.ensureAuthenticated();\n return piiApi.fetchPii(this.api);\n }\n\n async submitDocument(\n documentType: DocumentType,\n fields: Record<string, string>\n ): Promise<DocumentSubmission> {\n this.ensureAuthenticated();\n return documentsApi.submitDocument(this.api, documentType, fields);\n }\n\n async createKycToken(\n levelName?: KycLevelName,\n reset?: boolean\n ): Promise<KycToken> {\n this.ensureAuthenticated();\n return kycApi.createKycToken(this.api, levelName, reset);\n }\n\n handleRequirement(requirement: Requirement): void {\n const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n let path: string | null;\n switch (requirement.type) {\n case 'kyc_approved':\n path = VERIFY_IDENTITY_PATH;\n break;\n case 'identity_verified':\n path = VERIFY_IDENTITY_VERIFIED_PATH;\n break;\n case 'proof_of_address':\n path = VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH;\n break;\n case 'source_of_funds':\n path = VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH;\n break;\n case 'accreditation':\n path = VERIFY_IDENTITY_ACCREDITATION_PATH;\n break;\n case 'external_wallet':\n case 'whitelisted_wallet':\n path = WALLET_PATH;\n break;\n case 'jurisdiction':\n path = null;\n break;\n case 'document':\n path = null;\n break;\n default: {\n const _exhaustive: never = requirement.type;\n return;\n }\n }\n if (path === null) return;\n openInNewTab(new URL(path, baseUrl).toString());\n }\n\n contactSupport(): void {\n openInNewTab(SUPPORT_NEW_TICKET_URL);\n }\n\n private ensureAuthenticated() {\n if (this.getAuthState() !== 'logged-in') {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nfunction openInNewTab(url: string): void {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n\nexport function createCoinListClient(config: ClientConfig): CoinListClient {\n return new CoinListClientImpl(config);\n}\n","'use client';\n\n/**\n * Styling scope for SDK visual components.\n * Wrap any SDK visual components (CoinListSignInCard, OffersGrid, ...) 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 → OfferCard, 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.2.1 | 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-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking: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-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@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-md:28rem;--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-font-weight-normal:400;--clcosdk-font-weight-medium:500;--clcosdk-font-weight-semibold:600;--clcosdk-radius-md:.375rem;--clcosdk-radius-lg:.5rem;--clcosdk-radius-2xl:1rem;--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}@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}}: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}.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 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 img,.clco-sdk-root svg{max-width:100%;display:block}}@layer components;@layer utilities{.clcosdk\\\\:absolute{position:absolute}.clcosdk\\\\:fixed{position:fixed}.clcosdk\\\\:relative{position:relative}.clcosdk\\\\:inset-0{inset:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\\\:top-4{top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:right-4{right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:z-50{z-index:50}.clcosdk\\\\:mt-4{margin-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:mb-6{margin-bottom:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:flex{display:flex}.clcosdk\\\\:grid{display:grid}.clcosdk\\\\:inline-flex{display:inline-flex}.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-9{height:calc(var(--clcosdk-spacing) * 9)}.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-28{height:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\\\:h-52{height:calc(var(--clcosdk-spacing) * 52)}.clcosdk\\\\:h-\\\\[18px\\\\]{height:18px}.clcosdk\\\\:h-auto{height:auto}.clcosdk\\\\:h-full{height:100%}.clcosdk\\\\:max-h-\\\\[92vh\\\\]{max-height:92vh}.clcosdk\\\\:min-h-0{min-height:calc(var(--clcosdk-spacing) * 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-\\\\[2\\\\.4rem\\\\]{min-height:2.4rem}.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-12{width:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:w-16{width:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\\\:w-28{width:calc(var(--clcosdk-spacing) * 28)}.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-\\\\[448px\\\\]{width:448px}.clcosdk\\\\:w-auto{width:auto}.clcosdk\\\\:w-full{width:100%}.clcosdk\\\\:max-w-\\\\[22rem\\\\]{max-width:22rem}.clcosdk\\\\:max-w-\\\\[28rem\\\\]{max-width:28rem}.clcosdk\\\\:max-w-\\\\[30rem\\\\]{max-width:30rem}.clcosdk\\\\:max-w-\\\\[760px\\\\]{max-width:760px}.clcosdk\\\\:max-w-\\\\[1200px\\\\]{max-width:1200px}.clcosdk\\\\:max-w-md{max-width:var(--clcosdk-container-md)}.clcosdk\\\\:shrink-0{flex-shrink:0}.clcosdk\\\\:rotate-90{rotate:90deg}.clcosdk\\\\:animate-pulse{animation:var(--clcosdk-animate-pulse)}.clcosdk\\\\:animate-spin{animation:var(--clcosdk-animate-spin)}.clcosdk\\\\:cursor-pointer{cursor:pointer}.clcosdk\\\\:grid-cols-2{grid-template-columns:repeat(2,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-wrap{flex-wrap:wrap}.clcosdk\\\\:items-center{align-items:center}.clcosdk\\\\:items-start{align-items:flex-start}.clcosdk\\\\:justify-between{justify-content:space-between}.clcosdk\\\\:justify-center{justify-content:center}.clcosdk\\\\:gap-1{gap:calc(var(--clcosdk-spacing) * 1)}.clcosdk\\\\:gap-2{gap:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:gap-5{gap:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:gap-8{gap:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:gap-\\\\[5px\\\\]{gap:5px}: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-border>:not(:last-child)){border-color:var(--color-border)}:where(.clcosdk\\\\:divide-divider>:not(:last-child)){border-color:var(--color-divider)}.clcosdk\\\\:self-start{align-self:flex-start}.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-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\\\\:border{border-style:var(--tw-border-style);border-width:1px}.clcosdk\\\\:border-2{border-style:var(--tw-border-style);border-width:2px}.clcosdk\\\\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.clcosdk\\\\:border-dashed{--tw-border-style:dashed;border-style:dashed}.clcosdk\\\\:border-accent\\\\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-accent\\\\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.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-border,.clcosdk\\\\:border-border\\\\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-border\\\\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.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-success-border{border-color:var(--color-success-border)}.clcosdk\\\\:border-warning-border{border-color:var(--color-warning-border)}.clcosdk\\\\:border-t-transparent{border-top-color:#0000}.clcosdk\\\\:bg-accent\\\\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:bg-accent\\\\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.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-error-subtle{background-color:var(--color-error-subtle)}.clcosdk\\\\:bg-overlay{background-color:var(--color-overlay)}.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-transparent{background-color:#0000}.clcosdk\\\\:bg-warning-subtle{background-color:var(--color-warning-subtle)}.clcosdk\\\\:bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:from-surface{--tw-gradient-from:var(--color-surface);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:via-section{--tw-gradient-via:var(--color-section);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:via-transparent{--tw-gradient-via:transparent;--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:to-background{--tw-gradient-to:var(--color-background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:var(--color-overlay)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:color-mix(in oklab, var(--color-overlay) 35%, transparent)}}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:object-cover{object-fit:cover}.clcosdk\\\\:p-0{padding:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\\\:p-1\\\\.5{padding:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:p-3{padding:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:p-4{padding:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:p-8{padding:calc(var(--clcosdk-spacing) * 8)}.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-2{padding-block:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pt-14{padding-top:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:pb-4{padding-bottom:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:text-center{text-align:center}.clcosdk\\\\:text-left{text-align:left}.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-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-\\\\[14px\\\\]{font-size:14px}.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-\\\\[110\\\\%\\\\]{--tw-leading:110%;line-height:110%}.clcosdk\\\\:leading-\\\\[120\\\\%\\\\]{--tw-leading:120%;line-height:120%}.clcosdk\\\\:leading-\\\\[125\\\\%\\\\]{--tw-leading:125%;line-height:125%}.clcosdk\\\\:leading-\\\\[130\\\\%\\\\]{--tw-leading:130%;line-height:130%}.clcosdk\\\\:leading-\\\\[135\\\\%\\\\]{--tw-leading:135%;line-height:135%}.clcosdk\\\\:leading-\\\\[140\\\\%\\\\]{--tw-leading:140%;line-height:140%}.clcosdk\\\\:leading-\\\\[150\\\\%\\\\]{--tw-leading:150%;line-height:150%}.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\\\\.12px\\\\]{--tw-tracking:.12px;letter-spacing:.12px}.clcosdk\\\\:tracking-\\\\[0\\\\.28px\\\\]{--tw-tracking:.28px;letter-spacing:.28px}.clcosdk\\\\:whitespace-nowrap{white-space:nowrap}.clcosdk\\\\:text-error{color:var(--color-error)}.clcosdk\\\\:text-success{color:var(--color-success)}.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\\\\:underline{text-decoration-line:underline}.clcosdk\\\\:underline-offset-2{text-underline-offset:2px}.clcosdk\\\\:underline-offset-4{text-underline-offset:4px}.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-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f62e);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-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f640);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-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#0000002e);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-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#00000040);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\\\\: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-all{transition-property:all;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-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\\\\:ease-in-out{--tw-ease:var(--clcosdk-ease-in-out);transition-timing-function:var(--clcosdk-ease-in-out)}@media (hover:hover){.clcosdk\\\\:hover\\\\:-translate-y-0\\\\.5:hover{--tw-translate-y:calc(var(--clcosdk-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\\\:hover\\\\:border-divider:hover{border-color:var(--color-divider)}.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\\\\:shadow-\\\\[0px_14px_32px_-10px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.35\\\\)\\\\]:hover{--tw-shadow:0px 14px 32px -10px var(--tw-shadow-color,#00000059);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-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-accent-focus:focus-visible{--tw-ring-color:var(--color-accent-focus)}.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-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\\\\:disabled\\\\:pointer-events-none:disabled{pointer-events:none}.clcosdk\\\\:disabled\\\\:opacity-40:disabled{opacity:.4}@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-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-gradient-position{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-via-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:100%}@property --tw-leading{syntax:\\\"*\\\";inherits:false}@property --tw-font-weight{syntax:\\\"*\\\";inherits:false}@property --tw-tracking{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-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}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}\";\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.subhead, text)}>{content}</p>\n </div>\n );\n}\n","/**\n * CoinList Sale SDK — Typography Tokens\n *\n * Scale based on design system.\n * fontSize in px, lineHeight as percentage string, fontWeight as number.\n * Use the cn() Tailwind classes where possible, these values\n * are for programmatic access or non-Tailwind contexts.\n */\n\nexport const typeScale = {\n hero: {\n fontSize: 64,\n lineHeight: '110%',\n fontWeight: 600,\n },\n display: {\n fontSize: 48,\n lineHeight: '110%',\n fontWeight: 600,\n },\n h1: {\n fontSize: 36,\n lineHeight: '120%',\n fontWeight: 600,\n },\n h2: {\n fontSize: 28,\n lineHeight: '125%',\n fontWeight: 600,\n },\n h3: {\n fontSize: 22,\n lineHeight: '130%',\n fontWeight: 600,\n },\n h4: {\n fontSize: 18,\n lineHeight: '135%',\n fontWeight: 500,\n },\n body: {\n fontSize: 16,\n lineHeight: '150%',\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: 400,\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-[110%] clcosdk:font-semibold',\n display: 'clcosdk:text-[48px] clcosdk:leading-[110%] clcosdk:font-semibold',\n h1: 'clcosdk:text-[36px] clcosdk:leading-[120%] clcosdk:font-semibold',\n h2: 'clcosdk:text-[28px] clcosdk:leading-[125%] clcosdk:font-semibold',\n h3: 'clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-semibold',\n h4: 'clcosdk:text-[18px] clcosdk:leading-[135%] clcosdk:font-medium',\n body: 'clcosdk:text-[16px] clcosdk:leading-[150%] 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 data: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-normal',\n} as const;\n\nexport type TypeScale = keyof typeof typeScale;\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","'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","import type { SVGProps } from 'react';\n\nexport function CoinListWordmark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"638\"\n height=\"125\"\n viewBox=\"0 0 638 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M68.7724 123.966C74.8226 124.172 80.7696 123.519 86.5104 121.799C97.4076 118.531 106.551 112.58 113.942 103.947C113.942 103.947 113.942 103.947 113.908 103.912C111.879 102.193 109.851 100.507 107.857 98.8218L105.829 97.1363C105.451 96.8268 105.107 96.5172 104.729 96.2076C103.939 95.5197 103.148 94.8662 102.323 94.2126C95.3107 98.8562 87.6104 101.539 79.1196 101.883C74.8569 102.055 70.6287 101.642 66.5036 100.507C59.5252 98.6154 53.2688 95.1757 48.2499 89.7755C39.1059 79.938 35.8745 68.1743 38.2465 55.0348C39.7246 46.9172 43.4373 40.0723 49.1093 34.5C47.9061 34.7408 46.703 35.016 45.5342 35.3943C36.5277 38.2148 29.6181 43.6839 24.6336 51.6639C20.6803 58.0273 18.5834 64.9411 18.3428 72.4739C18.2053 76.7047 18.4803 80.7979 19.4428 84.7879C22.5023 97.2395 29.3087 107.043 39.6903 114.335H39.7934V114.403C40.1372 114.644 40.4809 114.919 40.8247 115.16C49.2812 120.801 58.5971 123.691 68.7724 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M72.2101 89.052C68.1881 90.8406 64.0286 91.8725 59.6973 92.2165C64.9912 95.209 70.8007 96.688 77.1259 96.8256C79.1885 96.86 81.251 96.6536 83.4167 96.3097C88.745 95.4841 93.6951 93.5579 98.3015 90.7374C93.9358 87.057 89.6044 83.4109 85.2386 79.7305C81.526 83.6861 77.1946 86.8506 72.2101 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M66.9848 0.241609C66.4348 0.276006 65.8848 0.344799 65.3691 0.413592C70.663 1.4111 75.7851 3.13093 80.6321 5.71068C90.0511 10.7326 97.3732 17.9215 102.289 27.4494L104.936 25.1448C107.652 22.7714 110.368 20.3981 113.084 18.0247C106.655 11.1797 99.092 6.15784 90.223 3.06214C84.3103 0.998336 78.2601 -0.0335643 72.0381 0.000832319C70.388 0.000832319 68.7036 0.138419 66.9848 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M25.4242 107.871C17.4833 97.9988 13.1519 86.7167 13.2207 73.818C13.2207 67.317 14.5614 61.0568 17.1396 55.1062C20.9553 46.2662 26.9711 39.1805 35.4276 34.2962C43.3685 29.687 51.9968 27.8984 61.1752 29.2743C70.5943 30.7189 78.3976 35.2249 84.6541 42.2762C84.6541 42.2762 84.8603 42.5514 84.9634 42.6546C85.8916 41.8291 86.8541 41.0035 87.7823 40.178L88.9167 39.1805C89.8792 38.355 90.8417 37.4951 91.8043 36.6696C94.0043 34.7434 96.17 32.8515 98.3357 30.9253C94.1075 22.223 87.7479 15.55 79.3258 10.8377C69.3911 5.26541 58.7002 3.54557 47.3904 5.02463C41.7528 5.78136 36.3557 7.50119 31.1993 10.0465C13.702 18.7145 1.08597 36.532 0.0546833 58.4771C-0.117196 62.0887 0.123436 65.7348 0.673452 69.3464C2.04849 78.3239 5.34859 86.4759 10.6425 93.8368C14.7676 99.5123 19.6834 104.19 25.3898 107.871H25.4242Z\"\n fill=\"currentColor\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M366.034 58.1654C366.034 46.8145 375.178 37.665 386.419 37.665C397.66 37.665 406.804 46.8145 406.804 58.1654V99.3727H420.727V58.1654C420.727 39.1785 405.395 23.7344 386.419 23.7344C367.444 23.7344 352.112 39.1785 352.112 58.1654V99.3727H366.034V58.1654ZM278.616 38.1466C265.141 38.1466 254.244 49.0503 254.244 62.5338C254.244 76.0173 265.141 86.9211 278.616 86.9211C292.092 86.9211 302.989 76.0173 302.989 62.5338C302.989 49.0503 292.092 38.1466 278.616 38.1466ZM240.321 62.5338C240.321 41.3799 257.475 24.2159 278.616 24.2159C299.757 24.2159 316.911 41.3799 316.911 62.5338C316.911 83.6878 299.757 100.852 278.616 100.852C257.475 100.852 240.321 83.6878 240.321 62.5338ZM208.386 38.2154C195.082 37.9402 184.048 48.5 183.738 61.8115C183.463 75.123 194.017 86.1643 207.32 86.4739C215.192 86.6459 222.274 82.9998 226.812 77.2212L237.777 85.8204C230.662 94.9011 219.455 100.645 207.011 100.37C186.007 99.923 169.335 82.5183 169.782 61.5019C170.229 40.4856 187.623 23.8032 208.627 24.2503C219.524 24.4911 229.287 29.3066 236.059 36.8051L225.712 46.1266C221.415 41.3455 215.227 38.3186 208.317 38.1466L208.386 38.2154ZM340.527 25.2134V99.3727H326.605V25.2134H340.527ZM508.282 25.2134H494.36V99.8542H508.282V25.2134ZM483.154 99.8542H448.846C439.221 99.8542 431.452 92.0462 431.452 82.4495V25.2134H445.374V82.4495C445.374 84.3757 446.921 85.9236 448.846 85.9236H483.154V99.8542ZM583.772 25.2134H567.856H542.83C530.661 25.2134 520.933 35.1885 520.933 47.2273C520.933 59.2661 530.661 69.2412 542.83 69.2412H552.421C556.821 69.2412 560.396 72.8184 560.396 77.1868V77.9435C560.396 82.3463 556.821 85.8892 552.421 85.8892H520.451V99.8198H552.421C564.522 99.8198 574.319 90.0168 574.319 77.9091V77.1524C574.319 65.0448 564.522 55.2417 552.421 55.2417H542.83C538.499 55.2417 534.855 51.6301 534.855 47.1585C534.855 42.6869 538.499 39.0753 542.83 39.0753H574.319H583.772C591.472 39.0753 597.694 45.3011 597.694 53.0059V99.3039H611.617V53.0059C611.617 37.6306 599.138 25.1446 583.772 25.1446V25.2134ZM637.021 39.1441H609.038V25.2134H637.021V39.1441Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","import { CoinListWordmark } from '@/client/components/design-system/logos/CoinListWordmark';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface PoweredByCoinListProps {\n className?: string;\n}\n\nexport function PoweredByCoinList({ className }: PoweredByCoinListProps) {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-[5px] clcosdk:text-text-secondary',\n className\n )}\n >\n <span className={cn(typeClasses.caption, 'clcosdk:tracking-[0.12px]')}>\n Powered by\n </span>\n <CoinListWordmark className=\"clcosdk:h-3 clcosdk:w-auto\" />\n </div>\n );\n}\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\nconst 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 // 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 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: '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\ninterface 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\nconst 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\nexport type { ClButtonProps };\nexport { buttonVariants, ClButton };\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 {\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\nexport function CoinListSignInButton({\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 { 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 { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { PoweredByCoinList } from '@/client/components/design-system/PoweredByCoinList';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { CoinListSignInButton } from '@/client/components/oauth/CoinListSignInButton';\nimport { useCoinList } from '@/client/hooks/useCoinList';\n\nexport interface CoinListSignInCardProps {\n state?: 'idle' | 'error';\n /**\n * Called when the user clicks the sign-in button. Defaults to\n * {@link CoinListClient#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.\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#startOAuth}; pass `onSignIn` to override.\n *\n * Self-scoped: renders fully styled on its own, no `CoinListStyleScope` needed.\n */\nexport function CoinListSignInCard({\n state = 'idle',\n onSignIn,\n onClose,\n className,\n}: CoinListSignInCardProps = {}): ReactNode {\n const { coinlist } = useCoinList();\n const handleSignIn =\n onSignIn ??\n (() => {\n void coinlist.startOAuth();\n });\n\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 {onClose && (\n <CloseButton\n onClick={onClose}\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={handleSignIn}\n fullWidth\n className=\"clcosdk:mt-4\"\n />\n\n {state === 'error' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Error signing in. Please try again.\"\n className=\"clcosdk:mt-4\"\n />\n )}\n\n <PoweredByCoinList className=\"clcosdk:mt-4\" />\n </div>\n </CoinListStyleScope>\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 { Offer } from '@/shared/types/offer';\n\nexport type OfferCardUi = {\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n formattedStartsAt: string;\n formattedEndsAt: string | null;\n};\n\nconst monthYearFormatter = new Intl.DateTimeFormat('en-US', {\n month: 'short',\n year: 'numeric',\n});\n\nexport const OfferCardUi = {\n fromDomain: (offer: Offer): OfferCardUi => ({\n tagline: offer.tagline,\n bannerUrl: offer.bannerUrl,\n logoUrl: offer.logoUrl,\n formattedStartsAt: monthYearFormatter.format(offer.startsAt),\n formattedEndsAt: offer.endsAt\n ? monthYearFormatter.format(offer.endsAt)\n : null,\n }),\n};\n\nexport interface Props {\n offer: OfferCardUi;\n /** Optional click handler. When provided, the card renders as interactive. */\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 * Offer card. Self-scoped: renders fully styled on its own, with no\n * `CoinListStyleScope` needed. Also composed by {@link OffersGrid}.\n */\nexport function OfferCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: Props): ReactNode {\n const cardLabel = 'Open offer details';\n\n const cardContent = (\n <>\n <div className=\"clcosdk:relative clcosdk:mb-6 clcosdk:h-52 clcosdk:w-full clcosdk:overflow-hidden clcosdk:rounded-2xl clcosdk:border clcosdk:border-border/60 clcosdk:bg-section\">\n {offer.bannerUrl ? (\n <img\n src={offer.bannerUrl}\n alt=\"Offer banner\"\n className=\"clcosdk:h-full clcosdk:w-full clcosdk:object-cover\"\n />\n ) : (\n <div className=\"clcosdk:h-full clcosdk:w-full clcosdk:bg-gradient-to-br clcosdk:from-surface clcosdk:via-section clcosdk:to-background\" />\n )}\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:bg-gradient-to-b clcosdk:from-transparent clcosdk:via-transparent clcosdk:to-overlay/35\" />\n\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:p-6\">\n {offer.logoUrl ? (\n <img\n src={offer.logoUrl}\n alt=\"Offer logo\"\n className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:object-cover clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.25)]\"\n />\n ) : (\n <div className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.18)]\" />\n )}\n </div>\n </div>\n\n {offer.tagline && (\n <p\n className={cn(\n typeClasses.h3,\n 'clcosdk:min-h-[2.4rem] clcosdk:text-text-primary'\n )}\n >\n {offer.tagline}\n </p>\n )}\n\n <div className=\"clcosdk:mt-4 clcosdk:grid clcosdk:grid-cols-2 clcosdk:gap-5 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Starts\n </span>\n <span className={cn(typeClasses.label, 'clcosdk:text-text-primary')}>\n {offer.formattedStartsAt}\n </span>\n </div>\n\n {offer.formattedEndsAt && (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Ends\n </span>\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-primary')}\n >\n {offer.formattedEndsAt}\n </span>\n </div>\n )}\n </div>\n </>\n );\n\n const baseClasses = cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-[28rem] clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-left clcosdk:shadow-card clcosdk:transition-all clcosdk:duration-200',\n className,\n onClick &&\n 'clcosdk:cursor-pointer clcosdk:hover:-translate-y-0.5 clcosdk:hover:border-divider clcosdk:hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-accent-focus clcosdk:focus-visible:ring-offset-2'\n );\n\n let cardNode: ReactNode;\n if (onClick) {\n cardNode = (\n <button\n type=\"button\"\n aria-label={cardLabel}\n className={baseClasses}\n onClick={onClick}\n >\n {cardContent}\n </button>\n );\n } else {\n cardNode = <div className={baseClasses}>{cardContent}</div>;\n }\n\n const card = containerClassName ? (\n <div className={containerClassName}>{cardNode}</div>\n ) : (\n cardNode\n );\n\n return <CoinListStyleScope>{card}</CoinListStyleScope>;\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Offer } from '@/shared/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.fetchOffers()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\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.\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 { data: serverOffers } = 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 // 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\n .fetchOffers()\n .then((offers) => {\n if (!isCancelled) {\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 setOffersState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, serverOffers]);\n\n return { offersState };\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 { OfferCard, OfferCardUi } from '@/client/components/offers/OfferCard';\nimport { useOffers } from '@/client/hooks/useOffers';\nimport type { Offer } from '@/shared/types/offer';\n\nconst DEFAULT_MAX_COLUMNS = 3;\n\nexport interface OffersGridProps {\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 * Offers pre-fetched on the server (e.g. via `CoinListServer.fetchOffers()`).\n * When provided, the component uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n}\n\nfunction OffersGridBody({\n data,\n maxColumns,\n className,\n containerClassName,\n loading,\n error,\n emptyState,\n onOfferClick,\n}: OffersGridProps = {}): ReactNode {\n const { offersState } = useOffers({ data });\n const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);\n\n if (offersState.type === 'LOADING') {\n if (loading) {\n return loading;\n }\n\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\n if (offersState.type === 'ERROR') {\n if (error) {\n return error;\n }\n\n const errorMessage =\n offersState.reason === 'not-authenticated'\n ? 'Sign in to view available offers.'\n : 'Unable to load offers right now. Please try again.';\n\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={errorMessage}\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n );\n }\n\n if (offersState.offers.length === 0) {\n if (emptyState) {\n return emptyState;\n }\n\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: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\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('clcosdk:grid clcosdk:w-full clcosdk:gap-6', className)}\n style={{\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 20rem), 1fr))',\n maxWidth: maxGridWidth,\n }}\n >\n {offersState.offers.map((offer) => (\n <OfferCard\n key={offer.id}\n offer={OfferCardUi.fromDomain(offer)}\n onClick={onOfferClick ? () => onOfferClick(offer) : undefined}\n />\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * Displays a responsive grid of offers backed by {@link useOffers}.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Uses `loading` / `error` slots when provided; otherwise renders standard\n * fallback loading and error states. Offer cards are interactive only when\n * `onOfferClick` is provided.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope` needed.\n */\nexport function OffersGrid(props: OffersGridProps = {}): ReactNode {\n return (\n <CoinListStyleScope>\n <OffersGridBody {...props} />\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { type ReactNode, useState } from 'react';\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';\n\n/** Load state of a connected-wallet list. */\nexport type WalletsStatus = 'ready' | 'loading' | 'error';\n\n/** A single connected wallet, shaped for display in {@link ConnectedWalletList}. */\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\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 */\nexport function ConnectedWalletList({\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 { useEffect, useId } from 'react';\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 ConnectWallet,\n ConnectWalletSignState,\n} from '@/client/hooks/useConnectWallet';\nimport { useConnectWallet } from '@/client/hooks/useConnectWallet';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type { EvmWalletAddress } from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/types/wallet-ownership-challenge';\n\nexport interface ConnectWalletModalProps {\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. Drives\n * {@link useConnectWallet} (challenge -> host signs -> connect) for one offer\n * option. Signing is delegated to the host-provided {@link ConnectWallet}: the SDK\n * never bundles a wallet stack.\n *\n * No portal is used — rendering stays inside the normal DOM tree so it keeps\n * this SDK's `.clco-sdk-root`-scoped theme tokens without needing its own\n * {@link CoinListStyleScope}.\n */\nexport function ConnectWalletModal({\n isOpen,\n onClose,\n offerId,\n optionId,\n wallet,\n onConnected,\n onRequestConnect,\n challengeType,\n statement,\n className,\n}: ConnectWalletModalProps) {\n const { state, onSign } = useConnectWallet({\n isOpen,\n offerId,\n offerOptionId: optionId,\n wallet,\n challengeType,\n statement,\n });\n // Instance-local so two open modals can't collide on a shared heading id.\n const titleId = useId();\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 if (!isOpen || state.type === 'CONNECTED') return null;\n\n return (\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={onClose} />\n </div>\n\n {state.type === 'NEEDS_WALLET' && (\n <NeedsWalletScreen onRequestConnect={onRequestConnect} />\n )}\n {state.type === 'READY' && (\n <ReadyScreen\n address={state.address}\n sign={state.sign}\n onSign={onSign}\n onRequestConnect={onRequestConnect}\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction NeedsWalletScreen({\n onRequestConnect,\n}: {\n onRequestConnect?: () => void;\n}) {\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 offer.\n </p>\n {onRequestConnect && (\n <ClButton fullWidth onClick={onRequestConnect}>\n Connect wallet\n </ClButton>\n )}\n </div>\n );\n}\n\nfunction ReadyScreen({\n address,\n sign,\n onSign,\n onRequestConnect,\n}: {\n address: EvmWalletAddress;\n sign: ConnectWalletSignState;\n onSign: () => void;\n onRequestConnect?: () => void;\n}) {\n const hasTerminalError =\n sign.type === 'idle' && sign.error !== null && !sign.error.retryable;\n\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 does\n 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 className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}>\n Wallet address\n </span>\n <span className={cn(typeClasses.body, 'clcosdk:text-text-primary')}>\n {shortenAddress(address)}\n </span>\n </div>\n\n {sign.type === 'idle' && sign.error && (\n // Live region: the error is inserted async after a failed attempt, so\n // screen readers need it announced rather than silently rendered.\n <div role=\"alert\">\n <AlertBanner variant=\"error\" icon content={sign.error.message} />\n </div>\n )}\n\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Waiting for signature...\"\n // A terminal failure (e.g. wallet not whitelisted, max wallets) can\n // never succeed by re-signing the same wallet — only switching helps.\n disabled={hasTerminalError}\n >\n Sign & connect\n </ClButton>\n\n {onRequestConnect && (\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={onRequestConnect}\n disabled={sign.type === 'signing'}\n >\n Use a different wallet\n </ClButton>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n type ConnectWallet,\n type ConnectWalletErrorCode,\n connectExternalWalletFlow,\n} from '@/client/core/connect-external-wallet';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { EvmWalletAddress } from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/types/wallet-ownership-challenge';\n\n// Re-export so consumers importing the hook also get the wallet input type.\nexport type { ConnectWallet } from '@/client/core/connect-external-wallet';\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 type { EvmSigner } from '@/client/core/blockchain/evm-wallet';\nimport { classifyWalletError } from '@/client/core/blockchain/wallet-error';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\nimport type { EthereumChain } from '@/shared/types/blockchain/core';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletChallengeType,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\n/**\n * The host-provided wallet the ownership flow signs with: the signing-only\n * {@link EvmSigner} plus the {@link EthereumChain} the signature is proven on.\n * `chain` rides on the wallet (not the offer) because the binding is\n * chain-agnostic: it only records which EVM chain signed.\n */\nexport type ConnectWallet = EvmSigner & { readonly chain: EthereumChain };\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/** The client surface the flow actually depends on, kept narrow on purpose. */\ntype ConnectWalletClient = Pick<\n CoinListClient,\n 'createWalletOwnershipChallenge' | 'connectExternalWallet'\n>;\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 `@/shared/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.createWalletOwnershipChallenge(\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.connectExternalWallet(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 SumsubWebSdk from '@sumsub/websdk-react';\nimport { type ReactNode, useEffect, useRef } from 'react';\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 { useKycToken } from '@/client/hooks/useKycToken';\nimport type { KycLevelName } from '@/shared/types/kyc';\n\nexport interface IdentityVerificationProps {\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. Fetches a Sumsub WebSDK access\n * token via {@link useKycToken} and renders the Sumsub iframe. Used by\n * `RequirementsChecklist` for `identity_verified` requirements, and can also\n * be rendered standalone.\n */\nexport function IdentityVerification({\n levelName,\n reset,\n locale,\n onSubmitted,\n onError,\n className,\n}: IdentityVerificationProps): ReactNode {\n const { kycTokenState, fetchToken } = useKycToken(levelName, reset);\n const fetchedRef = useRef(false);\n\n useEffect(() => {\n if (fetchedRef.current) return;\n fetchedRef.current = true;\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState; swallow the rejection.\n });\n }, [fetchToken]);\n\n const handleMessage = (type: string, payload: unknown) => {\n switch (type) {\n case 'idCheck.onApplicantSubmitted':\n onSubmitted?.();\n break;\n case 'idCheck.onError': {\n const message =\n (payload as { message?: string })?.message ?? 'Verification error';\n onError?.(new Error(message));\n break;\n }\n default:\n break;\n }\n };\n\n const handleError = (error: unknown) => {\n onError?.(error instanceof Error ? error : new Error('Verification error'));\n };\n\n if (kycTokenState.type === 'IDLE' || kycTokenState.type === '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 }\n\n if (kycTokenState.type === 'ERROR') {\n const errorMessage =\n kycTokenState.reason === 'not-authenticated'\n ? 'Sign in to verify your identity.'\n : 'Unable to start identity verification right now. Please try again.';\n return (\n <div\n className={cn('clcosdk:flex clcosdk:flex-col clcosdk:gap-4', className)}\n >\n <AlertBanner variant=\"error\" icon content={errorMessage} />\n {kycTokenState.reason !== 'not-authenticated' && (\n <ClButton\n size=\"sm\"\n onClick={() => {\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState.\n });\n }}\n >\n Try again\n </ClButton>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('clcosdk:w-full', className)}>\n <SumsubWebSdk\n accessToken={kycTokenState.token}\n expirationHandler={fetchToken}\n config={locale === undefined ? {} : { lang: locale }}\n options={{ addViewportTag: false, adaptIframeHeight: true }}\n onMessage={handleMessage}\n onError={handleError}\n />\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { KycLevelName } from '@/shared/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 [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.createKycToken(\n levelName,\n resetPendingRef.current\n );\n resetPendingRef.current = false;\n tokenIssuedRef.current = true;\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 setKycTokenState({ type: 'ERROR', reason });\n throw error;\n }\n }, [coinlist, levelName]);\n\n return { kycTokenState, fetchToken };\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 {\n ConnectedWalletList,\n type ConnectedWalletUi,\n type WalletsStatus,\n} from '@/client/components/requirements/ConnectedWalletList';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\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\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};\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: statusInfo\n ? RequirementStatus.fromStatusValue(statusInfo.status)\n : 'required',\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 };\n },\n};\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\nfunction VerificationActionZone({\n status,\n onAction,\n onContactSupport,\n}: {\n status: RequirementStatus;\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\" onClick={onAction}>\n Continue\n </ClButton>\n );\n case 'pending':\n return (\n <AlertBanner\n variant=\"warning\"\n content=\"Under review. We'll notify you when complete.\"\n />\n );\n case 'completed':\n return <AlertBanner variant=\"success\" content=\"Identity verified.\" />;\n case 'rejected':\n return (\n <AlertBanner\n variant=\"error\"\n content={\n onContactSupport === null ? (\n 'Verification rejected.'\n ) : (\n <>\n Verification rejected.{' '}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"clcosdk:underline\"\n >\n Contact support\n </button>\n .\n </>\n )\n }\n />\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 size=\"sm\" variant=\"secondary\" onClick={onAction}>\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\" 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\" 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}: 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:flex clcosdk:h-14 clcosdk:w-full 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 className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4\">\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:text-text-secondary'\n )}\n >\n {ui.description}\n </p>\n {ui.variant === 'verification' ? (\n <VerificationActionZone\n status={ui.status}\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, useEffect, useRef, 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 { 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 { CoinListSignInCard } from '@/client/components/oauth/CoinListSignInCard';\nimport type { WalletsStatus } from '@/client/components/requirements/ConnectedWalletList';\nimport { ConnectWalletModal } from '@/client/components/requirements/ConnectWalletModal';\nimport { IdentityVerification } from '@/client/components/requirements/IdentityVerification';\nimport {\n ChecklistStatus,\n RequirementItem,\n RequirementItemUi,\n RequirementVariant,\n} from '@/client/components/requirements/RequirementItem';\nimport { TaxDocumentModal } from '@/client/components/requirements/TaxDocumentModal';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { ConnectWallet } from '@/client/hooks/useConnectWallet';\nimport { useOptionAddresses } from '@/client/hooks/useOptionAddresses';\nimport type { RequirementsData } from '@/client/hooks/useRequirements';\nimport { useRequirements } from '@/client/hooks/useRequirements';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { OfferOptionAddressId } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\n\nconst isWalletRequirement = (requirement: Requirement): boolean =>\n RequirementVariant.fromType(requirement.type) === 'wallet';\n\nconst DEFAULT_LABELS: Record<RequirementType, string> = {\n kyc_approved: 'KYC Verification',\n identity_verified: 'Identity Verification',\n proof_of_address: 'Proof of Address',\n source_of_funds: 'Source of Funds',\n external_wallet: 'External Wallet',\n whitelisted_wallet: 'Whitelisted Wallet',\n jurisdiction: 'Jurisdiction Check',\n accreditation: 'Accreditation',\n document: 'Document',\n};\n\nconst DEFAULT_DESCRIPTIONS: Record<RequirementType, string> = {\n kyc_approved: 'Complete Know Your Customer verification.',\n identity_verified: 'Verify your identity.',\n proof_of_address: 'Provide proof of your residential address.',\n source_of_funds: 'Provide documentation for your source of funds.',\n external_wallet: 'Connect an external wallet.',\n whitelisted_wallet: 'Connect a whitelisted wallet.',\n jurisdiction: 'Confirm your jurisdiction eligibility.',\n accreditation: 'Verify your accreditation status.',\n document: 'Confirm your Tax Documents.',\n};\n\nexport interface RequirementsChecklistProps {\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#handleRequirement}, which opens the corresponding CoinList\n * page in a new tab — except for `document` requirements, which default to opening a built-in\n * {@link TaxDocumentModal} 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#contactSupport}, 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 ConnectWalletModal}.\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#handleRequirement} (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 * Rendered when the user is not authenticated. Defaults to\n * {@link CoinListSignInCard}, which prompts the user to sign in and starts\n * the CoinList OAuth flow. Pass `null` to render nothing.\n */\n unauthenticatedState?: ReactNode;\n /** Optional error slot. */\n error?: ReactNode;\n className?: string;\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\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 * Options for the inline Sumsub verification flow shown for KYC-backed\n * requirements (`identity_verified`, `kyc_approved`, `accreditation`) 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/** 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\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Full-screen overlay hosting the Sumsub identity verification flow — mirrors\n * frontline-web, where verification runs on a dedicated full page rather than\n * inside the requirement row.\n */\nfunction VerificationOverlay({\n onClose,\n children,\n}: {\n onClose: () => void;\n children: ReactNode;\n}): 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\nfunction RequirementsChecklistBody({\n offerId,\n optionId,\n title,\n description,\n onContinue,\n onRequirementActionOverride,\n onContactSupportOverride,\n wallet,\n onRequestConnect,\n getLabel,\n getDescription,\n loading,\n unauthenticatedState,\n error,\n className,\n data,\n identityVerificationOptions,\n}: RequirementsChecklistProps): ReactNode {\n const { coinlist } = useCoinList();\n const { requirementsState, refetch } = useRequirements(offerId, { data });\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n const [taxDocumentOpen, setTaxDocumentOpen] = useState(false);\n const [walletConnectOpen, 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 const {\n addressesState,\n refetch: refetchAddresses,\n disconnect,\n } = useOptionAddresses(offerId, optionId, {\n enabled: hasWalletRequirement,\n });\n const optionAddresses =\n addressesState.type === 'CONTENT' ? addressesState.addresses : [];\n // A failed/in-flight wallet fetch must not read as \"no wallets connected\", so\n // surface its load state to the wallet UI 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 const onRemoveWallet = async (id: string) => {\n await disconnect(OfferOptionAddressId(id));\n // Removing a wallet can flip the requirement back to actionable, so refresh\n // the requirement statuses too (disconnect already refetched the wallets).\n refetch();\n };\n\n const onRequirementAction =\n onRequirementActionOverride !== undefined\n ? onRequirementActionOverride\n : (requirement: Requirement) => {\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\n // one (`onRequestConnect`). A bare `wallet={null}` with no\n // `onRequestConnect` would strand the user on a dead-end screen, so\n // fall through to `handleRequirement` instead.\n if (\n (requirement.type === 'external_wallet' ||\n requirement.type === 'whitelisted_wallet') &&\n wallet !== undefined &&\n (wallet !== null || onRequestConnect !== undefined)\n ) {\n setConnectWalletOpen(true);\n return;\n }\n coinlist.handleRequirement(requirement);\n };\n const onContactSupport =\n onContactSupportOverride !== undefined\n ? onContactSupportOverride\n : () => coinlist.contactSupport();\n\n // After the user submits the Sumsub flow, the verification result arrives\n // asynchronously (Sumsub webhook -> backend). Poll requirement statuses\n // until this requirement's status moves off its pre-submit value, then\n // refresh the checklist.\n const awaitVerificationResult = (\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.fetchRequirementStatuses(offerId);\n const current = statuses.find((s) => s.id === requirementId)?.status;\n if (current !== undefined && current !== statusBeforeSubmit) break;\n } catch (_) {\n // Transient fetch errors: keep polling until the deadline.\n }\n }\n if (isMountedRef.current) {\n setVerifyingRequirementId(null);\n refetch();\n }\n })();\n };\n\n if (requirementsState.type === 'LOADING') {\n if (loading) return loading;\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 requirements...\n </p>\n </output>\n );\n }\n\n if (requirementsState.type === 'ERROR') {\n if (requirementsState.reason === 'not-authenticated') {\n return unauthenticatedState !== undefined ? (\n unauthenticatedState\n ) : (\n <CoinListSignInCard />\n );\n }\n if (error) return error;\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Unable to load requirements right now. Please try again.\"\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n );\n }\n\n const { requirements: requirementsByOptionId, statuses } = requirementsState;\n const requirements = requirementsByOptionId[optionId] ?? [];\n const requirementIds = new Set(requirements.map((r) => r.id));\n const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));\n const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));\n const checklistStatus: ChecklistStatus =\n ChecklistStatus.derive(optionStatuses);\n\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 {title}\n </h3>\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n {description}\n </p>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {requirements.map((req, index) => {\n const statusInfo = statusByRequirementId.get(req.id);\n const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];\n const itemDescription =\n (getDescription ? getDescription(req) : null) ??\n DEFAULT_DESCRIPTIONS[req.type];\n\n // Inline Sumsub flow whenever the backend prescribed one for this\n // status (kycLevel present) — identity_verified, kyc_approved, and\n // accreditation.\n const inlineVerification =\n statusInfo?.kycLevel !== undefined &&\n onRequirementActionOverride === undefined;\n\n let onActionBound: (() => void) | null | undefined;\n if (onRequirementAction === null) {\n onActionBound = null;\n } else if (inlineVerification) {\n onActionBound = () => setVerifyingRequirementId(req.id);\n } else if (onRequirementAction) {\n onActionBound = () => onRequirementAction(req);\n }\n\n let onContactSupportBound: (() => void) | null | undefined;\n if (onContactSupport === null) {\n onContactSupportBound = null;\n } else if (onContactSupport) {\n onContactSupportBound = () => onContactSupport(req);\n }\n\n // Wallet requirements show the user's real connected wallet(s) fetched\n // from the partner API. Non-wallet requirements get no addresses.\n const walletRequirement = isWalletRequirement(req);\n return (\n <RequirementItem\n key={req.id}\n ui={RequirementItemUi.fromDomain(\n req,\n statusInfo,\n label,\n itemDescription,\n walletRequirement ? optionAddresses : []\n )}\n expanded={expandedIndex === index}\n onToggle={() =>\n setExpandedIndex((prev) => (prev === index ? null : index))\n }\n onAction={onActionBound}\n onRemoveWallet={walletRequirement ? onRemoveWallet : undefined}\n walletsStatus={walletRequirement ? walletsStatus : undefined}\n onContactSupport={onContactSupportBound}\n />\n );\n })}\n </div>\n\n {checklistStatus === 'ineligible' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"You are not eligible to participate.\"\n />\n )}\n\n {onContinue && (\n <ClButton\n fullWidth\n disabled={checklistStatus !== 'eligible'}\n onClick={onContinue}\n >\n Continue\n </ClButton>\n )}\n\n <TaxDocumentModal\n isOpen={taxDocumentOpen}\n onClose={() => setTaxDocumentOpen(false)}\n onSubmitted={() => refetch()}\n />\n\n {verifyingRequirementId !== null && (\n <VerificationOverlay onClose={() => setVerifyingRequirementId(null)}>\n <IdentityVerification\n levelName={\n identityVerificationOptions?.levelName ??\n statusByRequirementId.get(verifyingRequirementId)?.kycLevel\n }\n reset={\n statusByRequirementId.get(verifyingRequirementId)?.kycReset ??\n false\n }\n locale={identityVerificationOptions?.locale}\n onSubmitted={() =>\n awaitVerificationResult(\n verifyingRequirementId,\n statusByRequirementId.get(verifyingRequirementId)?.status ??\n 'not_started'\n )\n }\n />\n </VerificationOverlay>\n )}\n\n <ConnectWalletModal\n isOpen={walletConnectOpen}\n onClose={() => setConnectWalletOpen(false)}\n offerId={offerId}\n optionId={optionId}\n wallet={wallet ?? null}\n onRequestConnect={onRequestConnect}\n onConnected={() => {\n refetch();\n refetchAddresses();\n }}\n />\n </div>\n );\n}\n\n/**\n * Connected requirements checklist that fetches requirements and statuses\n * via {@link useRequirements} and renders requirement items for the\n * specified option.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch.\n *\n * When the user is not authenticated, renders a sign-in card instead of the\n * checklist — without fetching. Pass `unauthenticatedState` to customize\n * that state, or `null` to render nothing.\n *\n * By default, clicking a requirement's action button opens the corresponding\n * CoinList page in a new tab via {@link CoinListClient#handleRequirement}. It is\n * recommended to omit `onRequirementActionOverride` and rely on this default.\n * Pass your own handler only if you need custom navigation behavior, or `null`\n * to disable the action button entirely.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope` needed.\n */\nexport function RequirementsChecklist(\n props: RequirementsChecklistProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <RequirementsChecklistBody {...props} />\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\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 { TaxDocumentFields } from '@/client/hooks/useTaxDocument';\nimport { useTaxDocument } from '@/client/hooks/useTaxDocument';\nimport type { DocumentSubmission } from '@/shared/types/document-submission';\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\nexport interface TaxDocumentModalProps {\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. Fetches the current user's PII via {@link useTaxDocument}, lets\n * individuals review/edit it before signing; company/trust entities see a\n * plain sign screen with no fields.\n *\n * No portal is used — rendering stays inside the normal DOM tree so it keeps\n * this SDK's `.clco-sdk-root`-scoped theme tokens without needing its own\n * {@link CoinListStyleScope}.\n */\nexport function TaxDocumentModal({\n isOpen,\n onClose,\n onSubmitted,\n className,\n}: TaxDocumentModalProps) {\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 if (!isOpen || state.type === 'SUBMITTED') return null;\n\n return (\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 <TaxDocumentModalHeading state={state} />\n <CloseButton onClick={onClose} />\n </div>\n\n {state.type === 'LOADING' && <LoadingScreen />}\n {state.type === 'ERROR' && <ErrorScreen reason={state.reason} />}\n {state.type === 'REVIEW' && (\n <ReviewScreen\n fields={state.fields}\n piiUnavailable={state.piiUnavailable}\n sign={state.sign}\n onStartEdit={onStartEdit}\n onSign={onSign}\n />\n )}\n {state.type === 'EDITING' && (\n <EditScreen\n fields={state.fields}\n onEditField={onEditField}\n onSaveEdit={onSaveEdit}\n onCancelEdit={onCancelEdit}\n />\n )}\n {state.type === 'SIGN_ONLY' && (\n <SignOnlyScreen sign={state.sign} onSign={onSign} />\n )}\n </div>\n </div>\n );\n}\n\nfunction TaxDocumentModalHeading({\n state,\n}: {\n state: ReturnType<typeof useTaxDocument>['state'];\n}) {\n const title =\n state.type === 'EDITING'\n ? 'Edit your W-8BEN'\n : state.type === 'REVIEW'\n ? 'Confirm your W-8BEN'\n : state.type === 'SIGN_ONLY'\n ? 'Confirm your W-8BEN-E'\n : 'Tax document';\n\n return (\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>{title}</h3>\n );\n}\n\nfunction LoadingScreen() {\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\"\n >\n {FIELD_ROWS.map(({ field }) => (\n <div\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\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 ErrorScreen({\n reason,\n}: {\n reason: 'not-authenticated' | 'generic-error';\n}) {\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={\n reason === 'not-authenticated'\n ? 'Sign in to complete your tax document.'\n : 'Unable to load your tax information right now. Please try again.'\n }\n />\n );\n}\n\nfunction ReviewScreen({\n fields,\n piiUnavailable,\n sign,\n onStartEdit,\n onSign,\n}: {\n fields: TaxDocumentFields;\n piiUnavailable: boolean;\n sign: { type: 'idle'; error: string | null } | { type: 'signing' };\n onStartEdit: () => void;\n onSign: () => void;\n}) {\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 {FIELD_ROWS.map(({ field, label }) => (\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 {fields[field] || '—'}\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 {sign.type === 'idle' && sign.error && (\n <AlertBanner variant=\"error\" icon content={sign.error} />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN\n </ClButton>\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={onStartEdit}\n disabled={sign.type === 'signing'}\n >\n Edit information\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction EditScreen({\n fields,\n onEditField,\n onSaveEdit,\n onCancelEdit,\n}: {\n fields: TaxDocumentFields;\n onEditField: (field: keyof TaxDocumentFields, value: string) => void;\n onSaveEdit: () => void;\n onCancelEdit: () => void;\n}) {\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 {FIELD_ROWS.map(({ field, label, placeholder }) => (\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={fields[field]}\n placeholder={placeholder}\n onChange={(e) => onEditField(field, e.target.value)}\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={onSaveEdit}>\n Save & review\n </ClButton>\n <ClButton fullWidth variant=\"secondary\" onClick={onCancelEdit}>\n Cancel\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction SignOnlyScreen({\n sign,\n onSign,\n}: {\n sign: { type: 'idle'; error: string | null } | { type: 'signing' };\n onSign: () => void;\n}) {\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 {sign.type === 'idle' && sign.error && (\n <AlertBanner variant=\"error\" icon content={sign.error} />\n )}\n\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN-E\n </ClButton>\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { DocumentSubmission } from '@/shared/types/document-submission';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Pii } from '@/shared/types/pii';\n\nexport type TaxDocumentFields = {\n fullLegalName: string;\n dob: string;\n countryOfCitizenship: string;\n taxId: string;\n permanentAddress: string;\n};\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 [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\n .fetchPii()\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 setState({\n type: 'ERROR',\n reason:\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error',\n });\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, isOpen]);\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\n .submitDocument(\n 'tax_certification',\n state.type === 'REVIEW'\n ? toSubmissionFields(state.fields, state.addressParts)\n : {}\n )\n .then((submission) => {\n setState({ type: 'SUBMITTED', submission });\n })\n .catch(() => {\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]);\n\n return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/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.listOptionAddresses()`). 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 { 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.removeOptionAddress(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.getAuthState() === 'logged-out') {\n setAddressesState({ type: 'ERROR', reason: 'not-authenticated' });\n return () => {\n isCancelled = true;\n };\n }\n\n setAddressesState(LOADING_STATE);\n coinlist\n .listOptionAddresses(offerId, offerOptionId)\n .then((addresses) => {\n if (!isCancelled) {\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 setAddressesState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey]);\n\n return { addressesState, refetch, disconnect };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/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\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 *\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 { data } = 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 (!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.getAuthState() === '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.fetchOfferRequirements(offerId),\n coinlist.fetchRequirementStatuses(offerId),\n ])\n .then(([requirementsByOptionId, statuses]) => {\n if (!isCancelled) {\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 setRequirementsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, fetchKey]);\n\n return { requirementsState, refetch };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type {\n Erc20Asset,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/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\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\n const [outputTokenState, setOutputTokenState] =\n useState<SwapOutputTokenState>(LOADING_STATE);\n\n const fetchIdRef = useRef(0);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n const currentFetchId = ++fetchIdRef.current;\n\n const load = async () => {\n try {\n const outputToken = await coinlist.swap.getOutputToken({\n contractAddress,\n chain,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n setOutputTokenState({ type: 'CONTENT', outputToken });\n } catch {\n if (currentFetchId !== fetchIdRef.current) return;\n setOutputTokenState({ type: 'ERROR' });\n }\n };\n\n load();\n\n return () => {\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, contractAddress, chain, enabled]);\n\n return { outputTokenState };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { SWAP_POLL_INTERVAL_MS } from '@/shared/core/blockchain/swap/constants';\nimport { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport type {\n AssetDecimals,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/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\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.swap.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 {\n // Swallow: keep the last quote and let the next poll tick retry.\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 ]);\n\n return { quote, isLoading, isRefreshing };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { SWAP_POLL_INTERVAL_MS } from '@/shared/core/blockchain/swap/constants';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/types/collections';\n\nexport interface UseSwapTokenBalancesOptions {\n address: EvmWalletAddress;\n chain: EthereumChain;\n /** The assets to read balances for. */\n assets: NonEmptyArray<StablecoinSymbol>;\n /** How often to refresh balances. 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 UseSwapTokenBalancesResult {\n /**\n * Raw on-chain balances keyed by the requested assets. Each requested asset\n * has an entry once a fetch settles (`bigint` on success, `null` on failure).\n * Assets that were not requested are absent.\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. A poll tick is skipped while the\n * previous fetch is still in flight. `assets` is compared by contents, so\n * passing an inline array does 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 useSwapTokenBalances(\n options: UseSwapTokenBalancesOptions\n): UseSwapTokenBalancesResult {\n const {\n address,\n chain,\n assets,\n pollIntervalMs = SWAP_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 coinlist.erc20.getTokenBalance({\n tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),\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 next.set(\n symbol,\n result.status === 'fulfilled' ? result.value.balance : null\n );\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","import { useEffect, useRef } from 'react';\nimport type { OauthClientErrorReason } from '@/client/core/types/client-types';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { AuthorizationCode, CodeVerifier } from '@/shared/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\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.completeOAuth();\n if (oauthResult.type === 'error') {\n void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(\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 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 await onSuccessRef.current();\n } catch {\n if (cancelled) return;\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]);\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/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.fetchOfferDetails()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: OfferDetail;\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.\n *\n * Returns `LOADING` while CoinList is initializing or while details are being fetched.\n * Returns `CONTENT` with the offer when `fetchOfferDetails()` 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 { data } = 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 (!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\n .fetchOfferDetails(offerId)\n .then((offerDetail) => {\n if (!isCancelled) {\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 setOfferDetailsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { offerDetailsState };\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { Participation } from '@/shared/types/participation';\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.fetchParticipations()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Participation[];\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.\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 { data } = 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 // 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 .fetchParticipations(offerId)\n .then((participations) => {\n if (!isCancelled) {\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 setParticipationsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { participationsState };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcA,mBAMO;;;AChBP,eAAsB,OAAO,MAAiD;AAC5E,QAAM,QACJ,OAAO,SAAS,WAAW,IAAI,YAAY,EAAE,OAAO,IAAI,IAAI;AAC9D,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACA,SAAO,OAAO,OAAO,OAAO,WAAW,MAAM;AAC/C;AAMO,SAAS,uBACd,QACA,UAAmB,MACX;AACR,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,EACxC;AACA,MAAI,SAAS,KAAK,MAAM;AACxB,WAAS,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG;AACtD,MAAI,CAAC,SAAS;AACZ,aAAS,OAAO,QAAQ,OAAO,EAAE;AAAA,EACnC;AACA,SAAO;AACT;AAOO,SAAS,8BAA8B,YAA4B;AACxE,QAAM,QAAQ,IAAI,WAAW,UAAU;AACvC,SAAO,gBAAgB,KAAK;AAC5B,QAAM,SAAS,MAAM;AACrB,SAAO,uBAAuB,QAAQ,KAAK;AAC7C;AAMO,SAAS,YAAoB;AAClC,MACE,OAAO,WAAW,eAClB,OAAO,OAAO,eAAe,YAC7B;AACA,WAAO,OAAO,WAAW;AAAA,EAC3B;AAEA,MACE,OAAO,WAAW,eAClB,OAAO,OAAO,oBAAoB,YAClC;AACA,UAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,WAAO,gBAAgB,KAAK;AAC5B,UAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAC/B,UAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAC/B,UAAM,MAAM,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACpE,WAAO,GAAG,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC;AAAA,EACvJ;AAEA,SAAO,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACjE;AAEO,SAAS,qBAAqB,OAAsC;AACzE,MAAI,OAAO,KAAK,GAAG;AACjB,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;;;AC5EA,IAAM,gBAAgB;AAMf,SAAS,cAAsB;AACpC,MAAI,WAAW,aAAa,QAAQ,aAAa;AAEjD,MAAI,CAAC,UAAU;AACb,eAAW,UAAU;AACrB,iBAAa,QAAQ,eAAe,QAAQ;AAAA,EAC9C;AAEA,SAAO;AACT;;;ACnBO,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAC3B,IAAM,oBAAoB;AAC1B,IAAM,yBAAyB;AAC/B,IAAM,cAAc;AAEpB,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AAExB,IAAM,yBACX;AAEK,IAAM,uBAAuB;AAC7B,IAAM,gCACX;AACK,IAAM,wCACX;AACK,IAAM,uCACX;AACK,IAAM,qCACX;AACK,IAAM,cAAc;;;ACP3B,IAAM,QAAoB,CAAC;AAE3B,IAAM,SAAS,CAAC,MAAkB,WAAmC;AAAA,EACnE,GAAG;AAAA,EACH,GAAG;AACL;AAEA,IAAM,YAAY,IAAI,UAAoC;AACxD,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,aAAS,OAAO,QAAQ,IAAI;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,IAAM,mBAAmB,OAAmB,EAAE,WAAW,KAAK;AAC9D,IAAM,YAAY,OAAmB,EAAE,WAAW,KAAK;AACvD,IAAM,iBAAiB,OAAmB;AAAA,EACxC,gBAAgB;AAClB;AAEA,IAAM,oBAAoB,CACxB,iBACgB;AAAA,EAChB,mBAAmB;AACrB;AAEA,IAAM,eAAe,CAAC,aAAiC;AAAA,EACrD,cAAc;AAChB;AACA,IAAM,iBAAiB,CAAC,WAAgC;AAAA,EACtD,gBAAgB;AAClB;AAEA,IAAM,cAAc,CAAC,UACnB,OAAO,cAAc;AACvB,IAAM,gBAAgB,CAAC,UACrB,OAAO,cAAc;AACvB,IAAM,eAAe,CAAC,UACpB,OAAO,mBAAmB;AAC5B,IAAM,kBAAkB,CAAC,UACvB,OAAO,gBAAgB;AACzB,IAAM,oBAAoB,CAAC,UACzB,OAAO,mBAAmB;AAC5B,IAAM,uBAAuB,CAC3B,UACuC,OAAO;AAEzC,IAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACtEO,IAAM,sBAA+C,OAC1D,YACyB;AACzB,MAAI,CAAC,WAAW,cAAc,QAAQ,UAAU,GAAG;AACjD,WAAO;AAAA,EACT;AAEA,QAAMA,aAAY,kBAAkB;AACpC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS;AAAA,MACP,GAAI,QAAQ,WAAW,CAAC;AAAA,MACxB,CAAC,iBAAiB,GAAGA;AAAA,IACvB;AAAA,EACF;AACF;AAIA,SAAS,oBAA4B;AACnC,QAAM,UAAU;AAChB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AAEvB,QAAM,cAAc;AAEpB,QAAM,WAAW,YAAY;AAC7B,QAAM,gBAAgB,YAAY,QAAQ;AAE1C,SAAO,GAAG,OAAO,KAAK,UAAU,KAAK,cAAc,KAAK,WAAW,KAAK,aAAa;AACvF;;;ACOO,IAAM,YAAN,cAAyC,MAAM;AAAA,EAGpD,YAAY,UAA+B;AACzC,UAAM,uBAAuB,SAAS,MAAM,SAAS;AACrD,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAEA,eAAsB,YACpB,SACkC;AAClC,QAAM,UAAkC;AAAA,IACtC,QAAQ;AAAA,IACR,GAAI,QAAQ,WAAW,UAAU,QAAQ,SAAS,SAC9C,EAAE,gBAAgB,mBAAmB,IACrC,CAAC;AAAA,IACL,GAAI,QAAQ,WAAW,CAAC;AAAA,EAC1B;AAEA,QAAM,OAAoB;AAAA,IACxB,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA,GAAI,QAAQ,aAAa,SAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,EACzE;AAEA,MAAI,QAAQ,WAAW,UAAU,QAAQ,SAAS,QAAW;AAC3D,SAAK,OAAO,KAAK,UAAU,QAAQ,IAAI;AAAA,EACzC;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB,wBAAwB,QAAQ,KAAK,QAAQ,WAAW;AAAA,IACxD;AAAA,EACF;AACA,QAAM,kBAAkB,gBAAgB,SAAS,OAAO;AAExD,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AACnD,UAAM,SAAS,KAAK;AACpB,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAM,OAAO,OAAQ,KAAK,MAAM,IAAI,IAAkB;AAEtD,SAAO;AAAA,IACL,QAAQ,SAAS;AAAA,IACjB;AAAA,IACA,SAAS;AAAA,EACX;AACF;AAEA,SAAS,wBACP,KACA,aACQ;AACR,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,IAAI,gBAAgB;AAEzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,QAAQ,OAAO;AACxB,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC;AAAA,QACF;AACA,qBAAa,OAAO,KAAK,OAAO,IAAI,CAAC;AAAA,MACvC;AACA;AAAA,IACF;AAEA,iBAAa,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,EACxC;AAEA,QAAM,cAAc,aAAa,SAAS;AAC1C,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,SAAS,GAAG,IAAI,GAAG,GAAG,IAAI,WAAW,KAAK,GAAG,GAAG,IAAI,WAAW;AAC5E;AAEA,SAAS,gBAAgB,SAA0C;AACjE,QAAM,SAAiC,CAAC;AACxC,UAAQ,QAAQ,CAAC,OAAO,QAAQ;AAC9B,WAAO,IAAI,YAAY,CAAC,IAAI;AAAA,EAC9B,CAAC;AACD,SAAO;AACT;AAEA,SAAS,iBACP,SACA,OACa;AACb,QAAM,iBAAiB,WAAW;AAAA,IAChC,QAAQ,cAAc,WAAW;AAAA,IACjC;AAAA,EACF;AACA,QAAM,cAA8B;AAAA,IAClC,GAAG;AAAA,IACH,YAAY;AAAA,EACd;AACA,SAAO;AACT;AAEO,IAAM,UAAU;AAAA,EACrB;AACF;;;ACnJO,IAAM,aAAN,MAAiB;AAAA,EACtB,YACW,QACA,aAAmC,CAAC,GAC7C;AAFS;AACA;AAAA,EACR;AAAA,EAEH,MAAM,KACJ,SACkC;AAClC,WAAO,KAAK,8BAAyC,OAAO;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,8BACZ,SACkC;AAClC,UAAM,kBAAkB,MAAM,KAAK;AAAA,MACjC,KAAK,mBAAmB,OAAO;AAAA,IACjC;AACA,QAAI,WAAW,MAAM,KAAK,eAA0B,eAAe;AAEnE,eAAW,cAAc,KAAK,WAAW,gBAAgB,CAAC,GAAG;AAC3D,iBAAY,MAAM,WAAW;AAAA,QAC3B,SAAS;AAAA,QACT;AAAA,QACA,OAAO,CAAC,cAAc,oBACpB,KAAK,8BAA8B,WAAW;AAAA,MAGlD,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,SAAmC;AAC5D,UAAM,MAAM,KAAK,WAAW,QAAQ,GAAG;AACvC,UAAM,UAAU;AAAA,MACd,GAAI,QAAQ,WAAW,CAAC;AAAA,MACxB,CAAC,kBAAkB,GAAG,KAAK,OAAO;AAAA,IACpC;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,KAAqB;AAE9B,QAAI,IAAI,WAAW,SAAS,KAAK,IAAI,WAAW,UAAU,GAAG;AAC3D,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,KAAK,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAClD,UAAM,OAAO,IAAI,WAAW,GAAG,IAAI,MAAM,IAAI,GAAG;AAChD,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAc,2BACZ,gBACsB;AACtB,QAAI,UAAU;AACd,eAAW,cAAc,KAAK,WAAW,iBAAiB,CAAC,GAAG;AAC5D,gBAAU,MAAM,WAAW,OAAO;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,eACN,SACkC;AAClC,WAAO,YAAuB,OAAO;AAAA,EACvC;AACF;;;AC3GO,SAAS,wBACd,kBACyB;AACzB,SAAO,OAAO,YAA+C;AAC3D,QAAI,CAAC,WAAW,YAAY,QAAQ,UAAU,GAAG;AAC/C,aAAO;AAAA,IACT;AAEA,QAAI,cAAc,MAAM,iBAAiB,KAAK;AAC9C,QAAI,CAAC,aAAa;AAChB,YAAM,cAAc,WAAW,qBAAqB,QAAQ,UAAU;AACtE,UAAI,aAAa;AACf,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,gBAAgB,MAAM;AACxB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS;AAAA,QACP,GAAI,QAAQ,WAAW,CAAC;AAAA,QACxB,eAAe,UAAU,YAAY,KAAK;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;;;AC3BO,IAAM,2BAAoD,OAC/D,YACyB;AACzB,MAAI,CAAC,WAAW,aAAa,QAAQ,UAAU,GAAG;AAChD,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,QAAQ,WAAW,CAAC;AAC5C,MAAI,gBAAgB,sBAAsB,GAAG;AAC3C,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS;AAAA,MACP,GAAG;AAAA,MACH,CAAC,sBAAsB,GAAG,UAAU;AAAA,IACtC;AAAA,EACF;AACF;;;ACrBA,IAAM,eAAe;AACrB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AAErB,IAAM,gBAAgB,oBAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC;AAEtC,SAAS,kBAAkB,QAAyB;AACzD,SAAQ,UAAU,OAAO,SAAS,OAAQ,cAAc,IAAI,MAAM;AACpE;AAEA,SAAS,gBAAgB,SAAyB;AAChD,SAAO,KAAK,IAAI,mBAAmB,MAAM,UAAU,IAAI,YAAY;AACrE;AAcO,SAAS,6BACd,UAAyC,CAAC,GAClB;AACxB,QAAM,UAAU,QAAQ,WAAW;AAEnC,SAAO,OAAO,EAAE,SAAS,UAAU,MAAM,MAAM;AAC7C,QAAI,CAAC,kBAAkB,SAAS,MAAM,GAAG;AACvC,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,WAAW,gBAAgB,QAAQ,UAAU;AACpE,QAAI,kBAAkB,eAAe,GAAG;AACtC,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,iBAAiB;AACrC,UAAM,QAAQ,gBAAgB,WAAW,CAAC;AAE1C,UAAM,cAAc,QAAQ;AAAA,MAC1B;AAAA,MACA,WAAW,aAAa,WAAW;AAAA,IACrC;AACA,WAAO,MAAM,WAAW;AAAA,EAC1B;AACF;AAEA,SAAS,aAAa,IAA2B;AAC/C,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAQO,IAAM,yBACX,6BAA6B;;;AC9DxB,SAAS,uBACd,kBACwB;AACxB,SAAO,OAAO,EAAE,SAAS,UAAU,MAAM,MAAM;AAC7C,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AACA,QAAI,CAAC,WAAW,YAAY,QAAQ,UAAU,GAAG;AAC/C,aAAO;AAAA,IACT;AACA,QAAI,WAAW,kBAAkB,QAAQ,UAAU,GAAG;AACpD,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,iBAAiB,IAAI;AAC5C,QAAI,UAAU;AACZ,YAAM,cAAc,QAAQ;AAAA,QAC1B;AAAA,QACA,WAAW,eAAe,IAAI;AAAA,MAChC;AACA,aAAO,MAAM,WAAW;AAAA,IAC1B,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACdO,IAAM,yBAAN,MAA6B;AAAA,EAGlC,YACE,QACA,kBACA,0BAAqD,CAAC,GACtD;AACA,SAAK,aAAa,IAAI,WAAW,QAAQ;AAAA,MACvC,eAAe;AAAA,QACb,wBAAwB,gBAAgB;AAAA,QACxC,GAAG;AAAA,QACH;AAAA,MACF;AAAA,MACA,cAAc;AAAA,QACZ,uBAAuB,gBAAgB;AAAA,QACvC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAgB,SAA0C;AAC9D,UAAM,WAAW,MAAM,KAAK,WAAW,KAAgB,OAAO;AAC9D,QAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AACnD,aAAO,SAAS;AAAA,IAClB,OAAO;AACL,YAAM,IAAI,UAAU,QAAQ;AAAA,IAC9B;AAAA,EACF;AACF;;;ACtCO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YACE,QACA,kBACA;AACA,SAAK,SAAS,IAAI,uBAAuB,QAAQ,kBAAkB;AAAA,MACjE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAgB,SAA0C;AAC9D,WAAO,KAAK,OAAO,KAAgB,OAAO;AAAA,EAC5C;AACF;;;ACtBA,kBAMO;AAmBA,SAAS,oBACd,OACA,KACa;AACb,MAAI,iBAAiB,sCAA0B;AAC7C,WAAO,EAAE,MAAM,gBAAgB;AAAA,EACjC;AACA,MAAI,iBAAiB,oCAAwB;AAC3C,WAAO,EAAE,MAAM,qBAAqB;AAAA,EACtC;AACA,MAAI,iBAAiB,2CAA+B;AAClD,WAAO,EAAE,MAAM,qBAAqB,QAAQ,MAAM,UAAU,MAAM,QAAQ;AAAA,EAC5E;AACA,MAAI,iBAAiB,qDAAyC,KAAK,MAAM;AACvE,WAAO,EAAE,MAAM,WAAW,MAAM,IAAI,KAAK;AAAA,EAC3C;AACA,SAAO,EAAE,MAAM,WAAW,OAAO,MAAM;AACzC;;;ACrCO,IAAM,YAAY;AAAA,EACvB;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,IACrC;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,MACnC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,WAAW,MAAM,UAAU,CAAC;AAAA,IAC7C,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;AAAA,IACrC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,IACtC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,IACtC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACvC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,aAAa,MAAM,UAAU;AAAA,MACrC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,MAClC,EAAE,MAAM,aAAa,MAAM,UAAU;AAAA,MACrC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,IACpC,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,KAAK;AAAA,MAChD,EAAE,MAAM,WAAW,MAAM,WAAW,SAAS,KAAK;AAAA,MAClD,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,MAAM;AAAA,IACnD;AAAA,IACA,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,QAAQ,MAAM,WAAW,SAAS,KAAK;AAAA,MAC/C,EAAE,MAAM,MAAM,MAAM,WAAW,SAAS,KAAK;AAAA,MAC7C,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,MAAM;AAAA,IACnD;AAAA,IACA,WAAW;AAAA,EACb;AACF;;;AC1EA,eAAsB,oBAA0C,MASzB;AACrC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,OAAK,OAAO;AACZ,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,OAAO,cAAc;AAAA,MAChC,KAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAc;AAAA,MACd,MAAM,CAAC,SAAS,KAAK;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM,YAAY,OAAO,oBAAoB,KAAK,EAAE;AAAA,IAC/D;AAAA,EACF;AAEA,OAAK,UAAU;AACf,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,OAAO,QAAQ,MAAM,KAAK;AAAA,EAC5C,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM,YAAY,OAAO,oBAAoB,OAAO,EAAE,KAAK,CAAC,EAAE;AAAA,IACzE;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,WAAW;AAChC,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,oBAAoB,EAAE;AAAA,EAC/D;AACA,SAAO,EAAE,MAAM,MAAM,QAAQ,KAAK;AACpC;;;AChFO,IAAM,sBAAsB;AAAA,EACjC;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IACnE,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,cAAc,OAAO,CAAC;AAAA,IAC1D,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,MAC1D,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,IAC7D;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY;AAAA,UACV,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,UAC1D,EAAE,MAAM,OAAO,MAAM,WAAW,cAAc,UAAU;AAAA,UACxD,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,MAC1D,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,MAC3D,EAAE,MAAM,QAAQ,MAAM,WAAW,cAAc,UAAU;AAAA,IAC3D;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IACpE,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IAChE,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IACpE,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY;AAAA,UACV,EAAE,MAAM,YAAY,MAAM,WAAW,cAAc,UAAU;AAAA,UAC7D,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,UAC3D,EAAE,MAAM,aAAa,MAAM,WAAW,cAAc,UAAU;AAAA,UAC9D,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,QAAQ,MAAM,WAAW,cAAc,UAAU;AAAA,MACzD,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,IAC5D;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY;AAAA,UACV,EAAE,MAAM,YAAY,MAAM,WAAW,cAAc,UAAU;AAAA,UAC7D,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,UAC3D,EAAE,MAAM,aAAa,MAAM,WAAW,cAAc,UAAU;AAAA,UAC9D,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,WAAW,cAAc,UAAU;AAAA,MACvD,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,IAC7D;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,cAAc,OAAO,CAAC;AAAA,IAC1D,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,WAAW,cAAc,UAAU;AAAA,MACvD,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,MAC1D,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,IAC7D;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,cAAc,OAAO,CAAC;AAAA,IAC1D,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,WAAW,cAAc,UAAU,CAAC;AAAA,IACrE,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,cAAc,OAAO,CAAC;AAAA,IAC1D,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,QAAQ,MAAM,WAAW,SAAS,MAAM,cAAc,UAAU;AAAA,MACxE;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,WAAW,SAAS,MAAM,cAAc,UAAU;AAAA,MACtE;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,QAAQ,MAAM,WAAW,cAAc,UAAU;AAAA,MACzD,EAAE,MAAM,SAAS,MAAM,WAAW,cAAc,UAAU;AAAA,IAC5D;AAAA,EACF;AACF;;;ACxMO,IAAM,mBAAmB,CAAC,UAC/B;AAGK,IAAM,qBAAqB,CAAC,UACjC;AAMK,IAAM,4BAA4B,CACvC,UAC8B;AAGzB,IAAM,gBAAgB,CAAC,UAC5B;AAEK,IAAM,eAAe,MAAM,OAAO;AAclC,IAAM,gBAAgB,CAAC,UAA2B;AACvD,MAAI,QAAQ,MAAM,QAAQ,cAAc;AACtC,UAAM,IAAI,MAAM,gCAAgC,KAAK,EAAE;AAAA,EACzD;AACA,SAAO;AACT;AAYO,IAAM,mBAAmB,OAAO;AAAA,EACrC,CAAC,UACC;AAAA,EACF;AAAA,IACE,KAAK,CAAC,GAAqB,MACzB,eAAe,GAAG,GAAG,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,IACtC,KAAK,CAAC,GAAqB,MACzB,eAAe,GAAG,GAAG,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EACxC;AACF;AASA,SAAS,eACP,GACA,GACA,IACkB;AAClB,MAAI,EAAE,aAAa,EAAE,UAAU;AAC7B,UAAM,IAAI;AAAA,MACR,6DACK,EAAE,QAAQ,OAAO,EAAE,QAAQ;AAAA,IAClC;AAAA,EACF;AACA,QAAM,MAAM,GAAG,EAAE,KAAK,EAAE,GAAG;AAC3B,MAAI,MAAM,MAAM,MAAM,cAAc;AAClC,UAAM,IAAI,MAAM,2CAA2C,GAAG,EAAE;AAAA,EAClE;AACA,SAAO,iBAAiB,EAAE,KAAK,UAAU,EAAE,SAAS,CAAC;AACvD;AAGO,IAAM,cAAc,CAAC,UAA+B;AAOpD,IAAM,mBAAmB,CAAC,UAC/B;AAYK,IAAM,MAAM,CAAC,UAAuB;;;ACvHpC,IAAM,YAAiB,IAAI,MAAO;AAOlC,SAAS,SAAS,QAAiB,KAAmB;AAC3D,SAAO,cAAe,SAAS,MAAO,SAAS;AACjD;;;ACCO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AACF,GAAuC;AACrC,MAAI,kBAAkB,QAAQ,GAAI,QAAO;AAEzC,QAAM,QAAQ,OAAO,OAAO,kBAAkB,QAAQ;AACtD,QAAM,MAAM;AAAA,IACT,iBAAiB,MAAM,QAAS,kBAAkB;AAAA,EACrD;AAEA,SAAO,iBAAiB,EAAE,KAAK,UAAU,iBAAiB,SAAS,CAAC;AACtE;AAOO,SAAS,YACd,QACA,UACkB;AAClB,QAAM,WAAW,IAAI,cAAc,YAAY,QAAQ,CAAC;AACxD,QAAM,UAAU,SAAS,OAAO,KAAK,QAAQ;AAC7C,SAAO,iBAAiB,EAAE,KAAK,SAAS,UAAU,OAAO,SAAS,CAAC;AACrE;;;AChCO,SAAS,UAAU,QAA6B;AACrD,UAAQ,OAAO,UAAU,OAAO,eAAe;AACjD;;;ACbA,IAAAC,eAAwD;AAgBjD,SAAS,0BACd,SACA,gBACyB;AACzB,MAAI;AACF,UAAM,CAAC,OAAO,QAAI,6BAAe;AAAA,MAC/B,KAAK;AAAA,MACL,WAAW;AAAA,MACX,MAAM,QAAQ;AAAA,IAChB,CAAC;AACD,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,MAAM,QAAQ,KAAK;AACzB,QAAI,MAAM,MAAM,MAAM,aAAc,QAAO;AAC3C,WAAO,iBAAiB,EAAE,KAAK,UAAU,eAAe,CAAC;AAAA,EAC3D,QAAQ;AAGN,WAAO;AAAA,EACT;AACF;;;AC2DA,eAAsB,YACpB,QAC8B;AAC9B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,OAAO,CAAC,UAA8B,aAAa,KAAK;AAE9D,QAAM,cAAc,iBAAiB;AAAA,IACnC,MAAM;AAAA,IACN,MAAM;AAAA,EACR,EAAE;AACF,QAAM,SAAS,YAAY,MAAM,mBAAmB,WAAW,EAAE;AAIjE,OAAK,iBAAiB;AACtB,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,KAAK,UAAU,EAAE,iBAAiB,MAAM,CAAC;AAAA,EAC1D,QAAQ;AAEN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,eAAe,EAAE;AAAA,EAC1D;AACA,MAAI,UAAU,MAAM,GAAG;AACrB,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,eAAe,EAAE;AAAA,EAC1D;AAGA,OAAK,oBAAoB;AACzB,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,MAAM,kBAAkB;AAAA,MACxC,cAAc;AAAA,MACd,OAAO,OAAO;AAAA,MACd,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,kBAAkB,EAAE;AAAA,EAC7D;AAGA,MAAI,UAAU,YAAY,aAAa;AAGrC,QAAI,UAAU,YAAY,IAAI;AAC5B,YAAM,QAAQ,MAAM,oBAAoB;AAAA,QACtC;AAAA,QACA,cAAc;AAAA,QACd,SAAS;AAAA,QACT;AAAA,QACA,OAAO;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AACD,UAAI,MAAM,SAAS,QAAS,QAAO,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM;AAAA,IACzE;AAEA,UAAM,UAAU,MAAM,oBAAoB;AAAA,MACxC;AAAA,MACA,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AACD,QAAI,QAAQ,SAAS;AACnB,aAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,MAAM;AAAA,EACjD;AAGA,OAAK,UAAU;AACf,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,OAAO,cAAc;AAAA,MACtC,KAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAc;AAAA,MACd,MAAM,CAAC,mBAAmB,aAAa,MAAM;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM,QAAQ,OAAO,oBAAoB,KAAK,EAAE;AAAA,IAC3D;AAAA,EACF;AAGA,OAAK,iBAAiB;AACtB,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,OAAO,QAAQ,YAAY,KAAK;AAAA,EAClD,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO,oBAAoB,OAAO,EAAE,MAAM,WAAW,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,WAAW;AAChC,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,gBAAgB,EAAE;AAAA,EAC3D;AAIA,QAAM,eACJ,0BAA0B,SAAS,MAAM,kBAAkB,QAAQ,KACnE,MAAM;AACR,QAAM,aAAwB,EAAE,GAAG,OAAO,mBAAmB,aAAa;AAE1E,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,aAAa,WAAW;AAAA,IACxB,KAAK,WAAW;AAAA,IAChB;AAAA,IACA,eAAe,aAAa,UAAU;AAAA,IACtC,kBAAkB,OAAO;AAAA,EAC3B;AACF;AA+CA,eAAsB,gBACpB,QACoC;AACpC,QAAM,EAAE,MAAM,QAAQ,SAAS,iBAAiB,OAAO,WAAW,IAAI;AACtE,QAAM,OAAO,CAAC,UAAoC,aAAa,KAAK;AACpE,QAAM,gBAAgB,OAAO;AAG7B,OAAK,wBAAwB;AAC7B,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,KAAK,iBAAiB;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,sBAAsB,EAAE;AAAA,EACjE;AACA,MAAI,KAAK,WAAY,QAAO,EAAE,MAAM,UAAU;AAG9C,OAAK,sBAAsB;AAC3B,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,KAAK,gCAAgC;AAAA,MACrD;AAAA,MACA;AAAA,MACA,eAAe;AAAA,IACjB,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,oBAAoB,EAAE;AAAA,EAC/D;AAGA,OAAK,iBAAiB;AACtB,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,OAAO,YAAY,UAAU,OAAO;AAAA,EACxD,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM,WAAW,OAAO,oBAAoB,KAAK,EAAE;AAAA,IAC9D;AAAA,EACF;AAGA,OAAK,sBAAsB;AAC3B,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,KAAK,YAAY;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,eAAe,EAAE;AAAA,EAC1D;AAGA,MAAI,MAAM,WAAW,yBAAyB;AAC5C,SAAK,0BAA0B;AAC/B,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,OAAO,eAAe;AAAA,QACjC,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO,EAAE,MAAM,aAAa,OAAO,oBAAoB,KAAK,EAAE;AAAA,MAChE;AAAA,IACF;AAEA,SAAK,uBAAuB;AAC5B,QAAI;AACF,YAAM,OAAO,QAAQ,MAAM,KAAK;AAAA,IAClC,SAAS,OAAO;AACd,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,oBAAoB,OAAO,EAAE,KAAK,CAAC;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,OAAK,yBAAyB;AAC9B,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,KAAK,iBAAiB;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,sBAAsB,EAAE;AAAA,EACjE;AACA,MAAI,CAAC,QAAQ,YAAY;AACvB,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,iBAAiB,EAAE;AAAA,EAC5D;AAEA,SAAO,EAAE,MAAM,UAAU;AAC3B;;;AC3WO,IAAM,oBAAoB;AAAA,EAC/B,SAAS,CAAC,SAAoD;AAAA,IAC5D,YAAY,IAAI;AAAA,EAClB;AACF;AAYO,IAAM,cAAc;AAAA,EACzB,SAAS,CAAC,SAAsC;AAAA,IAC9C,aAAa,cAAc,OAAO,IAAI,gBAAgB,CAAC;AAAA,IACvD,KAAK,cAAc,OAAO,IAAI,GAAG,CAAC;AAAA,IAClC,cAAc,cAAc,OAAO,IAAI,qBAAqB,CAAC;AAAA,EAC/D;AACF;AAaO,IAAM,aAAa;AAAA,EACxB,SAAS,CAAC,SAAoC;AAAA,IAC5C,SAAS,cAAc,OAAO,IAAI,OAAO,CAAC;AAAA,IAC1C,WAAW,cAAc,OAAO,IAAI,UAAU,CAAC;AAAA,EACjD;AACF;AASO,IAAM,iBAAiB;AAAA,EAC5B,SAAS,CAAC,SAA4C;AAAA,IACpD,WAAW,cAAc,OAAO,IAAI,SAAS,CAAC;AAAA,EAChD;AACF;AASO,IAAM,eAAe;AAAA,EAC1B,SAAS,CAAC,SAAwC;AAAA,IAChD,SAAS,cAAc,OAAO,IAAI,OAAO,CAAC;AAAA,EAC5C;AACF;AAkBO,IAAM,sBAAsB;AAAA,EACjC,SAAS,CAAC,QAAqD;AAC7D,YAAQ,IAAI,QAAQ;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,IAAI,mBAAmB,IAAI,EAAE;AAAA,UAC7B,MAAM,0BAA0B,IAAI,IAAI;AAAA,QAC1C;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,gBAAgB,IAAI;AAAA,QACtB;AAAA,MACF,SAAS;AACP,cAAM,cAAqB;AAC3B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;;;AC3FA,eAAsB,qBACpB,KACA,QAC4B;AAC5B,QAAM,MAAM,MAAM,IAAI,KAA6B;AAAA,IACjD,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,kBAAkB,OAAO;AAAA,MACzB,gBAAgB,OAAO;AAAA,IACzB;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,kBAAkB,QAAQ,GAAG;AACtC;AAEA,eAAsB,mBACpB,KACA,QACqB;AACrB,QAAM,MAAM,MAAM,IAAI,KAAyB;AAAA,IAC7C,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,kBAAkB,OAAO;AAAA,IAC3B;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,aAAa,GAAG;AACzB;AAEA,eAAsB,eACpB,KACA,QACsB;AACtB,QAAM,MAAM,MAAM,IAAI,KAAqB;AAAA,IACzC,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,kBAAkB,OAAO;AAAA,MACzB,aAAa,OAAO;AAAA,MACpB,QAAQ,OAAO,OAAO,SAAS;AAAA,IACjC;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,YAAY,QAAQ,GAAG;AAChC;AAEA,eAAsB,cACpB,KACA,QACqB;AACrB,QAAM,MAAM,MAAM,IAAI,KAAoB;AAAA,IACxC,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,kBAAkB,OAAO;AAAA,IAC3B;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,WAAW,QAAQ,GAAG;AAC/B;AAEA,eAAsB,kBACpB,KACA,QACyB;AACzB,QAAM,MAAM,MAAM,IAAI,KAAwB;AAAA,IAC5C,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,SAAS,OAAO;AAAA,IAClB;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,eAAe,QAAQ,GAAG;AACnC;AAEA,eAAsB,gBACpB,KACA,QACuB;AACvB,QAAM,MAAM,MAAM,IAAI,KAAsB;AAAA,IAC1C,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa;AAAA,MACX,OAAO,OAAO;AAAA,MACd,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,IAChB;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,aAAa,QAAQ,GAAG;AACjC;AAEA,eAAsB,YACpB,KACA,QAC8B;AAC9B,QAAM,MAAM,MAAM,IAAI,KAA6B;AAAA,IACjD,QAAQ;AAAA,IACR,KAAK,cAAc,mBAAmB,OAAO,OAAO,CAAC;AAAA,IACrD,MAAM;AAAA,MACJ,gBAAgB,OAAO;AAAA,MACvB,OAAO,OAAO;AAAA,MACd,WAAW,OAAO;AAAA,IACpB;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,oBAAoB,QAAQ,GAAG;AACxC;AAEA,SAAS,aAAa,KAAqC;AACzD,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,QAAQ,YAAY,IAAI,MAAM;AAAA,IAC9B,UAAU,cAAc,IAAI,QAAQ;AAAA,EACtC;AACF;;;AC5JO,IAAM,UAAU,CAAC,UAAkB;AAGnC,IAAM,YAAY,CAAC,UAAkB;AASrC,IAAM,QAAQ;AAAA,EACnB,SAAS,CAAC,SAA0B;AAAA,IAClC,IAAI,QAAQ,IAAI,EAAE;AAAA,IAClB,MAAM,UAAU,IAAI,IAAI;AAAA,IACxB,MAAM,IAAI;AAAA,IACV,kBAAkB,IAAI;AAAA,EACxB;AACF;;;ACnBO,IAAM,UAAU,CAAC,UAAkB;AAGnC,IAAM,YAAY,CAAC,UAAkB;AAerC,IAAM,QAAQ;AAAA,EACnB,SAAS,CAAC,SAA0B;AAAA,IAClC,IAAI,QAAQ,IAAI,EAAE;AAAA,IAClB,MAAM,UAAU,IAAI,IAAI;AAAA,IACxB,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,IACb,WAAW,IAAI;AAAA,IACf,SAAS,IAAI;AAAA,IACb,UAAU,IAAI,KAAK,IAAI,SAAS;AAAA,IAChC,QAAQ,IAAI,UAAU,IAAI,KAAK,IAAI,OAAO,IAAI;AAAA,EAChD;AACF;;;ACMO,IAAM,gBAAgB,CAAC,UAAkB;AAGzC,IAAM,kBAAkB,CAAC,UAAkB;AAkC3C,IAAM,cAAc;AAAA,EACzB,SAAS,CAAC,QAAqC;AAC7C,QAAI,CAAC,MAAM,QAAQ,IAAI,cAAc,GAAG;AACtC,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,QAAI,CAAC,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC/B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,QAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC7B,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAEA,QAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC7B,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAEA,QAAI,CAAC,MAAM,QAAQ,IAAI,IAAI,GAAG;AAC5B,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAEA,QAAI,CAAC,MAAM,QAAQ,IAAI,UAAU,GAAG;AAClC,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,WAAO;AAAA,MACL,IAAI,QAAQ,IAAI,EAAE;AAAA,MAClB,MAAM,UAAU,IAAI,IAAI;AAAA,MACxB,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MAEV,OAAO,MAAM,QAAQ,IAAI,KAAK;AAAA,MAC9B,eAAe,IAAI,eAAe,IAAI,MAAM,OAAO;AAAA,MAEnD,OAAO,qBAAqB,IAAI,KAAK;AAAA,MACrC,SAAS,IAAI;AAAA,MACb,WAAW,IAAI;AAAA,MACf,SAAS,IAAI;AAAA,MACb,UAAU,IAAI;AAAA,MAEd,UAAU,IAAI,KAAK,IAAI,SAAS;AAAA,MAChC,QAAQ,IAAI,UAAU,IAAI,KAAK,IAAI,OAAO,IAAI;AAAA,MAE9C,MAAM,IAAI,KAAK,IAAI,QAAQ,OAAO;AAAA,MAClC,OAAO,IAAI,MAAM,IAAI,KAAK,OAAO;AAAA,MACjC,YAAY,IAAI,WAAW,IAAI,UAAU,OAAO;AAAA,MAChD,SAAS,IAAI,QAAQ,IAAI,YAAY,OAAO;AAAA,MAC5C,OAAO,IAAI,MAAM,IAAI,SAAS,OAAO;AAAA,IACvC;AAAA,EACF;AACF;AAEO,IAAM,cAAc;AAAA,EACzB,SAAS,CAAC,SAA4C;AAAA,IACpD,IAAI,cAAc,IAAI,EAAE;AAAA,IACxB,MAAM,gBAAgB,IAAI,IAAI;AAAA,IAC9B,cAAc,IAAI;AAAA,IAClB,eAAe,IAAI;AAAA,IACnB,oBAAoB,IAAI;AAAA,IACxB,UAAU,IAAI;AAAA,IACd,kBAAkB,qBAAqB,IAAI,kBAAkB;AAAA,IAC7D,kBAAkB,IAAI;AAAA,EACxB;AACF;AAEO,IAAM,UAAU;AAAA,EACrB,SAAS,CAAC,SAAqC;AAAA,IAC7C,UAAU,qBAAqB,IAAI,QAAQ;AAAA,IAC3C,QAAQ,qBAAqB,IAAI,MAAM;AAAA,EACzC;AACF;AAEO,IAAM,OAAO;AAAA,EAClB,SAAS,CAAC,SAAmC;AAAA,IAC3C,OAAO,qBAAqB,IAAI,KAAK;AAAA,IACrC,KAAK,qBAAqB,IAAI,GAAG;AAAA,EACnC;AACF;AAEO,IAAM,WAAW;AAAA,EACtB,SAAS,CAAC,SAAuC;AAAA,IAC/C,KAAK,qBAAqB,IAAI,GAAG;AAAA,IACjC,OAAO,qBAAqB,IAAI,KAAK;AAAA,EACvC;AACF;AAEO,IAAM,YAAY;AAAA,EACvB,SAAS,CAAC,SAA6C;AAAA,IACrD,MAAM,qBAAqB,IAAI,IAAI;AAAA,IACnC,UAAU,qBAAqB,IAAI,QAAQ;AAAA,IAC3C,QAAQ,IAAI;AAAA,EACd;AACF;;;ACtJO,IAAM,uBAAuB,CAAC,UACnC;AAkCK,IAAM,qBAAqB;AAAA;AAAA,EAEhC,SAAS,CAAC,SAAoD;AAAA,IAC5D,IAAI,qBAAqB,IAAI,EAAE;AAAA,IAC/B,eAAe,cAAc,IAAI,eAAe;AAAA,IAChD,SAAS,iBAAiB,IAAI,OAAO;AAAA,IACrC,UAAU,IAAI;AAAA,IACd,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,EACpC;AACF;AAEO,IAAM,8BAA8B;AAAA;AAAA,EAEzC,OAAO,CACL,YACiC;AAAA,IACjC,iBAAiB,OAAO;AAAA,IACxB,gBAAgB,OAAO;AAAA,IACvB,OAAO,OAAO;AAAA,IACd,WAAW,OAAO;AAAA,EACpB;AACF;;;AChBO,IAAM,2BAA2B;AAAA;AAAA,EAEtC,SAAS,CAAC,SAAgE;AAAA,IACxE,SAAS,IAAI;AAAA,IACb,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,EACpC;AACF;AAEO,IAAM,uCAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,OAAO,CACL,WACsC;AACtC,YAAQ,OAAO,eAAe;AAAA,MAC5B,KAAK;AACH,eAAO;AAAA,UACL,gBAAgB,OAAO;AAAA,UACvB,OAAO,OAAO;AAAA,UACd,gBAAgB;AAAA,QAClB;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,gBAAgB,OAAO;AAAA,UACvB,OAAO,OAAO;AAAA,UACd,gBAAgB;AAAA,UAChB,QAAQ,OAAO;AAAA,UACf,KAAK,OAAO;AAAA,UACZ,WAAW,OAAO;AAAA,QACpB;AAAA,MACF,SAAS;AACP,cAAM,cAAqB;AAC3B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;;;ACtEA,eAAsB,+BACpB,KACA,QACmC;AACnC,QAAM,MAAM,MAAM,IAAI,KAAkC;AAAA,IACtD,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,MAAM,qCAAqC,MAAM,MAAM;AAAA,IACvD,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,yBAAyB,QAAQ,GAAG;AAC7C;AAqBA,eAAsB,sBACpB,KACA,SACA,QAC6B;AAC7B,QAAM,MAAM,MAAM,IAAI,KAA4B;AAAA,IAChD,QAAQ;AAAA,IACR,KAAK,cAAc,OAAO;AAAA,IAC1B,MAAM,4BAA4B,MAAM,MAAM;AAAA,IAC9C,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,mBAAmB,QAAQ,GAAG;AACvC;AAUA,eAAsB,oBACpB,KACA,SACA,eAC+B;AAC/B,QAAM,EAAE,KAAK,IAAI,MAAM,IAAI,KAA6C;AAAA,IACtE,QAAQ;AAAA,IACR,KAAK,cAAc,OAAO;AAAA,IAC1B,aAAa,EAAE,iBAAiB,cAAc;AAAA,IAC9C,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,KAAK,IAAI,mBAAmB,OAAO;AAC5C;AAUA,eAAsB,oBACpB,KACA,SACA,WAC6B;AAC7B,QAAM,MAAM,MAAM,IAAI,KAA4B;AAAA,IAChD,QAAQ;AAAA,IACR,KAAK,cAAc,OAAO,cAAc,SAAS;AAAA,IACjD,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,mBAAmB,QAAQ,GAAG;AACvC;;;ACpBO,IAAM,oBAAN,MAAyD;AAAA,EAC9D,YAA6B,KAA6B;AAA7B;AAAA,EAA8B;AAAA,EAE3D,MAAM,iBACJ,QAC4B;AAC5B,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,qBAAqB,KAAK,IAAI,KAAK,MAAM;AAAA,EAClD;AAAA,EAEA,MAAM,WAAW,QAAoD;AACnE,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,eAAe,KAAK,IAAI,KAAK,MAAM;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,QAA8C;AAC5D,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,cAAc,KAAK,IAAI,KAAK,MAAM;AAAA,EAC3C;AAAA,EAEA,MAAM,eAAe,QAA8C;AACjE,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,mBAAmB,KAAK,IAAI,KAAK,MAAM;AAAA,EAChD;AAAA,EAEA,MAAM,gCACJ,QACmC;AACnC,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,+BAA+B,KAAK,IAAI,KAAK,MAAM;AAAA,EAC5D;AAAA,EAEA,MAAM,YAAY,QAAyD;AACzE,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,YAAY,KAAK,IAAI,KAAK,MAAM;AAAA,EACzC;AACF;;;AC3FO,IAAM,0BAAN,cACG,kBAEV;AAAA,EACE,YACE,KACiB,OACjB;AACA,UAAM,GAAG;AAFQ;AAAA,EAGnB;AAAA,EAEA,YACE,QAC8B;AAC9B,WAAO,YAAY,EAAE,GAAG,QAAQ,MAAM,MAAM,OAAO,KAAK,MAAM,CAAC;AAAA,EACjE;AAAA,EAEA,gBACE,QACoC;AACpC,WAAO,gBAAgB,EAAE,GAAG,QAAQ,MAAM,KAAK,CAAC;AAAA,EAClD;AACF;;;AC1DO,IAAM,SAAS,CAAC,UAAkB;AAyBzC,eAAsB,cAIpB,WACA,YACc;AACd,QAAM,QAAa,CAAC;AACpB,MAAI,SAAwB;AAE5B,KAAG;AACD,UAAM,SAAS;AAAA,MACb,GAAI,cAAc,CAAC;AAAA,MACnB,OAAO,UAAU;AAAA,IACnB;AACA,UAAM,OAAO,MAAM,UAAU,MAAM;AACnC,UAAM,KAAK,GAAG,KAAK,IAAI;AACvB,aAAS,KAAK;AAAA,EAChB,SAAS;AAET,SAAO;AACT;AAEO,IAAM,oBAAoB;AAAA,EAC/B,SAAS,CACP,KACA,gBAC0B;AAAA,IAC1B,MAAM,IAAI,KAAK,IAAI,UAAU;AAAA,IAC7B,eAAe,IAAI,iBAAiB,OAAO,IAAI,cAAc,IAAI;AAAA,IACjE,gBAAgB,IAAI,kBAAkB,OAAO,IAAI,eAAe,IAAI;AAAA,EACtE;AACF;AAEO,IAAM,mBAAmB;AAAA,EAC9B,eAAe,CACb,WACoC;AACpC,UAAM,cAA+C,CAAC;AACtD,QAAI,OAAO,OAAO;AAChB,kBAAY,iBAAiB,OAAO;AAAA,IACtC;AACA,QAAI,OAAO,QAAQ;AACjB,kBAAY,kBAAkB,OAAO;AAAA,IACvC;AACA,QAAI,OAAO,OAAO;AAChB,kBAAY,QAAQ,OAAO;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AACF;;;ACzDO,IAAM,yBAAyB,CAAC,UACrC;AAGK,IAAM,yBAAyB,CAAC,UACrC;;;AC3BF,IAAAC,eAA4B;AAiBrB,SAAS,eACd,SACwB;AACxB,QAAM,QACJ,QAAQ,SAAS,KACb,GAAG,QAAQ,MAAM,GAAG,CAAC,CAAC,SAAI,QAAQ,MAAM,EAAE,CAAC,KAC3C;AACN,SAAO,uBAAuB,KAAK;AACrC;AAgGO,SAAS,gBAAgB,QAAkC;AAChE,aAAO,0BAAY,OAAO,KAAK,OAAO,QAAQ;AAChD;AA0DO,IAAM,qBACX,uBAAuB,GAAG;AAE5B,IAAM,sBAAsB,cAAc,CAAC;;;ACnLpC,IAAM,wBAAwB;AAS9B,IAAM,uBAA8B,CAAC,KAAK,KAAK,MAAM,MAAM,IAAI,EAAE;AAAA,EACtE,CAAC,MAAM,IAAI,CAAC;AACd;AAGO,IAAM,uBAA4B,IAAI,GAAG;AAOzC,IAAM,2CACX,mBAAmB,4CAA4C;;;ACV1D,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvB,aAAa,CACX,SACA,eACA,oBACe;AAAA,IACf,kBAAkB,iBAAiB;AAAA,MACjC,KAAK,QAAQ;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,IACD,KAAK,iBAAiB,EAAE,KAAK,QAAQ,KAAK,UAAU,cAAc,CAAC;AAAA,IACnE,mBAAmB,iBAAiB;AAAA,MAClC,KAAK,QAAQ;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AACF;;;AC7BO,IAAM,cAAgC,iBAAiB,MAAM;AAC7D,IAAM,OAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU,cAAc,CAAC;AAC3B;AAEO,IAAM,cAAgC,iBAAiB,MAAM;AAC7D,IAAM,OAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU,cAAc,CAAC;AAC3B;AAKA,IAAM,iBAAiC;AAAA,EACrC,kBAAkB;AAAA,IAChB;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,EACF;AACF;AAEA,IAAM,iBAAiC;AAAA,EACrC,kBAAkB;AAAA,IAChB;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,EACF;AACF;AAGO,IAAM,iBAAiB;AAAA,EAC5B,OAAO,CAAC,WAAyC;AAC/C,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,cAAM,IAAI,MAAM,yBAAyB,MAAM,EAAE;AAAA,IACrD;AAAA,EACF;AAAA,EACA,iBAAiB,CACf,QACA,UACuB;AACvB,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO,eAAe,KAAK;AAAA,MAC7B,KAAK;AACH,eAAO,eAAe,KAAK;AAAA,MAC7B;AACE,cAAM,IAAI,MAAM,yBAAyB,MAAM,EAAE;AAAA,IACrD;AAAA,EACF;AACF;;;AC3BO,IAAM,qBAAN,MAA2D;AAAA,EAChE,YAA6B,KAA6B;AAA7B;AAAA,EAA8B;AAAA,EAE3D,MAAM,kBACJ,QACyB;AACzB,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,kBAAkB,KAAK,IAAI,KAAK,MAAM;AAAA,EAC/C;AAAA,EAEA,MAAM,gBAAgB,QAAsD;AAC1E,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,gBAAgB,KAAK,IAAI,KAAK,MAAM;AAAA,EAC7C;AACF;;;ACrCO,IAAM,kBAAkB,CAAC,UAAkB;AAK3C,IAAM,aAAa,CAAC,UAAkB;AAKtC,IAAM,gBAAgB,CAAC,UAAyB;AA8DhD,IAAM,iCAAiC;AAAA,EAC5C,eAAe,CACb,WACoC;AACpC,UAAM,cAAc,iBAAiB,cAAc,MAAM;AACzD,QAAI,OAAO,SAAS;AAClB,kBAAY,mBAAmB,IAAI;AACnC,kBAAY,gBAAgB,IAAI;AAChC,kBAAY,mBAAmB,IAAI,OAAO;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AACF;AAEO,IAAM,gBAAgB;AAAA;AAAA,EAE3B,SAAS,CAAC,QAAyC;AACjD,UAAM,gBAAgB,qBAAqB,IAAI,cAAc;AAC7D,WAAO;AAAA,MACL,IAAI,gBAAgB,IAAI,EAAE;AAAA,MAC1B,SAAS,QAAQ,IAAI,QAAQ;AAAA,MAC7B,eAAe,cAAc,IAAI,eAAe;AAAA,MAChD,QAAQ,IAAI;AAAA,MACZ,QAAQ,IAAI;AAAA,MACZ,eAAe,IAAI;AAAA,MACnB,OAAO,MAAM,QAAQ,IAAI,KAAK;AAAA,MAC9B,OAAO,WAAW,IAAI,KAAK;AAAA,MAC3B,YAAY,IAAI,cAAc,IAAI,KAAK,IAAI,WAAW,IAAI;AAAA,MAC1D,WAAW,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;AAAA,MACvD,eAAe,gBACX,cAAc,aAA8B,IAC5C;AAAA,IACN;AAAA,EACF;AACF;AAEO,IAAM,4BAA4B;AAAA;AAAA,EAEvC,OAAO,CAAC,YAA+D;AAAA,IACrE,UAAU,OAAO;AAAA,IACjB,iBAAiB,OAAO;AAAA,IACxB,OAAO,OAAO;AAAA,IACd,gBAAgB,OAAO;AAAA,IACvB,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,2BAA2B,OAAO;AAAA,EACpC;AACF;;;AC1HA,eAAsB,oBACpB,KACA,SAC0B;AAC1B,SAAO;AAAA,IACL,CAAC,WAAW,wBAAwB,KAAK,MAAM;AAAA,IAC/C,EAAE,QAAQ;AAAA,EACZ;AACF;AAEA,eAAsB,wBACpB,KACA,QAC2C;AAC3C,QAAM,UAAU,MAAM,IAAI,KAA6C;AAAA,IACrE,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,aAAa,+BAA+B,cAAc,MAAM;AAAA,IAChE,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,kBAAkB,QAAQ,SAAS,cAAc,OAAO;AACjE;AAEA,eAAsB,mBACpB,KACA,IACwB;AACxB,QAAM,MAAM,MAAM,IAAI,KAAuB;AAAA,IAC3C,QAAQ;AAAA,IACR,KAAK,sBAAsB,EAAE;AAAA,IAC7B,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,cAAc,QAAQ,GAAG;AAClC;AAEA,eAAsB,oBACpB,KACA,QACwB;AACxB,QAAM,MAAM,MAAM,IAAI,KAAuB;AAAA,IAC3C,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,MAAM,0BAA0B,MAAM,MAAM;AAAA,IAC5C,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,cAAc,QAAQ,GAAG;AAClC;;;ACFO,IAAM,yBAAN,MAAmE;AAAA,EACxE,YAA6B,KAA6B;AAA7B;AAAA,EAA8B;AAAA,EAE3D,MAAM,oBAAoB,SAA6C;AACrE,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,oBAAoB,KAAK,IAAI,KAAK,OAAO;AAAA,EAClD;AAAA,EAEA,MAAM,wBACJ,QAC2C;AAC3C,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,wBAAwB,KAAK,IAAI,KAAK,MAAM;AAAA,EACrD;AAAA,EAEA,MAAM,mBAAmB,IAA6C;AACpE,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,mBAAmB,KAAK,IAAI,KAAK,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,oBACJ,QACwB;AACxB,UAAM,KAAK,IAAI,wBAAwB;AACvC,WAAO,oBAAoB,KAAK,IAAI,KAAK,MAAM;AAAA,EACjD;AACF;;;ACnFO,IAAM,oBAAoB,CAAC,UAChC;AAGK,IAAM,eAAe,CAAC,UAC3B;AAGK,IAAM,gBAAgB,CAAC,UAC5B;AAGK,IAAM,YAAY,CAAC,UAAkB;;;ACuB5C,eAAsB,mBACpB,QACqB;AACrB,QAAM,QAAQ,8BAA8B,EAAE;AAC9C,QAAM,eAAe,8BAA8B,EAAE;AACrD,QAAM,mBAAmB,MAAM,OAAO,YAAY;AAClD,QAAM,gBAAgB,uBAAuB,kBAAkB,KAAK;AAEpE,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,cAAc;AAAA,IACd,aAAa,OAAO;AAAA,IACpB,eAAe,cAAc,aAAa;AAAA,IAC1C,qBAAqB;AAAA,IACrB,OAAO,UAAU,KAAK;AAAA,IACtB,cAAc,aAAa,YAAY;AAAA,EACzC;AACF;;;AClCO,IAAM,qBAAqB;AAAA,EAChC,SAAS,CAAC,SAAoD;AAAA,IAC5D,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,EAChB;AACF;;;ACZO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,UAAU,mEACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACNO,IAAM,WAAW;AAAA,EACtB,SAAS,CAAC,SAAgC;AAAA,IACxC,OAAO,IAAI;AAAA,EACb;AACF;;;ACNO,IAAM,kBAAkB,CAAC,UAAkB;AAQ3C,IAAM,kBAAkB;AAAA,EAC7B,SAAS,CAAC,SAA8C;AAAA,IACtD,MAAM,gBAAgB,IAAI,KAAK;AAAA,IAC/B,MAAM,IAAI;AAAA,EACZ;AACF;AAWO,IAAM,aAAa;AAAA,EACxB,SAAS,CAAC,SAAoC;AAAA,IAC5C,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB,SAAS,IAAI;AAAA,EACf;AACF;AAeO,IAAM,MAAM;AAAA,EACjB,SAAS,CAAC,SAAsB;AAAA,IAC9B,MAAM,IAAI;AAAA,IACV,eAAe,IAAI;AAAA,IACnB,aAAa,IAAI;AAAA,IACjB,cAAc,IAAI,eACd,gBAAgB,QAAQ,IAAI,YAAY,IACxC;AAAA,IACJ,OAAO,IAAI;AAAA,IACX,kBAAkB,WAAW,QAAQ,IAAI,iBAAiB;AAAA,EAC5D;AACF;;;AC5DO,IAAM,gBAAgB,CAAC,UAAkB;AAYzC,IAAM,cAAc;AAAA,EACzB,SAAS,CAAC,SAAsC;AAAA,IAC9C,IAAI,cAAc,IAAI,EAAE;AAAA,IACxB,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,EACf;AACF;AAoBO,IAAM,wBAAwB;AAAA,EACnC,iBAAiB,CAAC,QAChB,OAAO,QAAQ,IAAI,QAAQ,EAAE;AAAA,IAAI,CAAC,CAAC,IAAI,KAAK,MAC1C,OAAO,UAAU,WACb,EAAE,IAAI,cAAc,EAAE,GAAG,QAAQ,OAAO,QAAQ,KAAK,IACrD;AAAA,MACE,IAAI,cAAc,EAAE;AAAA,MACpB,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM,UAAU;AAAA,MACxB,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,IAClB;AAAA,EACN;AACJ;;;AC6BA,eAAsB,iBACpB,QACmC;AACnC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,OAAO,CAAC,UAAmC,aAAa,KAAK;AAKnE,OAAK,oBAAoB;AACzB,MAAI;AACJ,MAAI;AACF,UAAM,YAAY,MAAM,MAAM,kBAAkB;AAAA,MAC9C,cAAc;AAAA,MACd,OAAO,OAAO;AAAA,MACd,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AACD,uBAAmB,UAAU;AAAA,EAC/B,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,kBAAkB,EAAE;AAAA,EAC7D;AAMA,MAAI,mBAAmB,IAAI;AACzB,UAAM,QAAQ,MAAM,oBAAoB;AAAA,MACtC;AAAA,MACA,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAGD,QAAI,MAAM,SAAS,SAAS;AAC1B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OACE,MAAM,MAAM,SAAS,sBACjB,EAAE,MAAM,2BAA2B,IACnC,EAAE,MAAM,mBAAmB,OAAO,MAAM,MAAM,MAAM;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,oBAAoB;AAAA,IACxC;AAAA,IACA,cAAc;AAAA,IACd,SAAS;AAAA,IACT;AAAA,IACA,OAAO,OAAO;AAAA,IACd,SAAS;AAAA,IACT,YAAY;AAAA,IACZ;AAAA,EACF,CAAC;AACD,MAAI,QAAQ,SAAS,SAAS;AAC5B,WAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,MAAM;AAAA,EAC/C;AACA,QAAM,iBAAiB,QAAQ;AAQ/B,OAAK,yBAAyB;AAC9B,MAAI;AACJ,MAAI;AACF,oBAAgB,MAAM,UAAU,oBAAoB;AAAA,MAClD;AAAA,MACA;AAAA,MACA,OAAO,WAAW,KAAK;AAAA,MACvB,eAAe,cAAc,OAAO,OAAO;AAAA,MAC3C,QAAQ,gBAAgB,MAAM;AAAA,MAC9B;AAAA,MACA,yBAAyB;AAAA,IAC3B,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,iBAAiB,eAAe,EAAE;AAAA,EAC3E;AAEA,SAAO,EAAE,MAAM,WAAW,eAAe,eAAe;AAC1D;;;ACjKO,IAAM,+BAAN,cACG,uBAEV;AAAA,EACE,YACE,KACiB,OACjB;AACA,UAAM,GAAG;AAFQ;AAAA,EAGnB;AAAA,EAEA,iBACE,QACmC;AACnC,WAAO,iBAAiB,EAAE,GAAG,QAAQ,OAAO,KAAK,OAAO,WAAW,KAAK,CAAC;AAAA,EAC3E;AACF;;;AC/BA,eAAsB,eACpB,KACA,cACA,QAC6B;AAC7B,QAAM,MAAM,MAAM,IAAI,KAA4B;AAAA,IAChD,QAAQ;AAAA,IACR,KAAK,iBAAiB,YAAY;AAAA,IAClC,MAAM;AAAA,IACN,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,mBAAmB,QAAQ,GAAG;AACvC;;;ACtBA,eAAsB,eACpB,KACA,WACA,OACmB;AACnB,QAAM,MAAM,MAAM,IAAI,KAAkB;AAAA,IACtC,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,MAAM;AAAA,MACJ,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,YAAY,UAAU;AAAA,MAC3D,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;AAAA,IACzC;AAAA,IACA,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,SAAS,QAAQ,GAAG;AAC7B;;;ACPA,eAAsB,YACpB,KACA,aACkB;AAClB,SAAO,cAAc,CAAC,WAAW,gBAAgB,KAAK,QAAQ,WAAW,CAAC;AAC5E;AAEA,eAAsB,gBACpB,KACA,QACA,aACmC;AACnC,QAAM,cAAc,iBAAiB,cAAc,MAAM;AACzD,QAAM,UAAU,MAAM,IAAI,KAAqC;AAAA,IAC7D,QAAQ;AAAA,IACR,KAAK;AAAA,IACL;AAAA,IACA,YAAY,WAAW;AAAA,MACrB,WAAW,UAAU;AAAA,MACrB,WAAW,kBAAkB,WAAW;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,SAAO,kBAAkB,QAAQ,SAAS,MAAM,OAAO;AACzD;AAEA,eAAsB,kBACpB,KACA,IACA,aACsB;AACtB,QAAM,MAAM,MAAM,IAAI,KAAqB;AAAA,IACzC,QAAQ;AAAA,IACR,KAAK,cAAc,EAAE;AAAA,IACrB,YAAY,WAAW;AAAA,MACrB,WAAW,UAAU;AAAA,MACrB,WAAW,kBAAkB,WAAW;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,SAAO,YAAY,QAAQ,GAAG;AAChC;;;AChDA,eAAsB,SAAS,KAA2B;AACxD,QAAM,MAAM,MAAM,IAAI,KAAa;AAAA,IACjC,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,IAAI,QAAQ,GAAG;AACxB;;;ACDA,eAAsB,uBACpB,KACA,SACA,aAC+C;AAC/C,QAAM,WAAW,MAAM,IAAI,KAA2B;AAAA,IACpD,QAAQ;AAAA,IACR,KAAK,cAAc,OAAO;AAAA,IAC1B,YAAY,WAAW;AAAA,MACrB,WAAW,UAAU;AAAA,MACrB,WAAW,kBAAkB,WAAW;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,SAAS,OAAO,EAAE,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM;AAAA,MACzD;AAAA,MACA,KAAK,KAAK,IAAI,YAAY,OAAO;AAAA,IACnC,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,yBACpB,KACA,SACkC;AAClC,QAAM,WAAW,MAAM,IAAI,KAA6B;AAAA,IACtD,QAAQ;AAAA,IACR,KAAK,cAAc,OAAO;AAAA,IAC1B,YAAY,WAAW,UAAU;AAAA,EACnC,CAAC;AACD,SAAO,sBAAsB,gBAAgB,QAAQ;AACvD;;;AC0BO,IAAM,kBAAkB;AACxB,IAAM,0BAA0B;AAgPvC,IAAM,qBAAN,MAAmD;AAAA,EAQjD,YAAqB,SAAuB;AAAvB;AANrB;AAAA,SAAQ,eAAoD;AAO1D,SAAK,MAAM,IAAI;AAAA,MACb;AAAA,QACE,SAAS,QAAQ,WAAW;AAAA,QAC5B,aAAa;AAAA,MACf;AAAA,MACA,KAAK,iBAAiB,KAAK,IAAI;AAAA,IACjC;AACA,UAAM,MAAM;AAAA,MACV,KAAK,KAAK;AAAA,MACV,yBAAyB,YAAY,KAAK,oBAAoB;AAAA,IAChE;AACA,SAAK,QAAQ,IAAI,mBAAmB,GAAG;AACvC,SAAK,YAAY,IAAI,6BAA6B,KAAK,KAAK,KAAK;AACjE,SAAK,OAAO,IAAI,wBAAwB,KAAK,KAAK,KAAK;AAAA,EACzD;AAAA,EAEA,MAAM,OAA2B;AAC/B,UAAM,KAAK,iBAAiB,IAAI;AAChC,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA,EAEA,MAAM,iBAAiB,SAAoD;AACzE,QAAI,CAAC,WAAW,KAAK,iBAAiB,OAAW,QAAO,KAAK;AAE7D,QAAI;AACF,YAAM,cAAc,MAAM,KAAK,QAAQ,eAAe;AACtD,WAAK,eAAe;AACpB,aAAO;AAAA,IACT,SAAS,GAAG;AACV,WAAK,eAAe;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,eAA0B;AACxB,QAAI,KAAK,iBAAiB,QAAW;AACnC,aAAO;AAAA,IACT;AACA,WAAO,KAAK,iBAAiB,OAAO,cAAc;AAAA,EACpD;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,aAAa,MAAM,mBAAmB,KAAK,OAAO;AAExD,mBAAe,QAAQ,iBAAiB,WAAW,KAAK;AACxD,mBAAe,QAAQ,yBAAyB,WAAW,YAAY;AAEvE,UAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,WAAW,WAAW;AAAA,MACtB,eAAe,WAAW;AAAA,MAC1B,cAAc,WAAW;AAAA,MACzB,gBAAgB,WAAW;AAAA,MAC3B,uBAAuB,WAAW;AAAA,MAClC,OAAO,WAAW;AAAA,IACpB,CAAC;AACD,UAAM,UAAU,KAAK,QAAQ,mBAAmB;AAChD,UAAM,MAAM,GAAG,OAAO,GAAG,eAAe,IAAI,OAAO,SAAS,CAAC;AAC7D,WAAO,SAAS,OAAO;AAAA,EACzB;AAAA,EAEA,gBAAmC;AACjC,UAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAEzD,UAAM,gBAAgB,OAAO,IAAI,OAAO;AACxC,QAAI,eAAe;AACjB,aAAO,EAAE,MAAM,SAAS,QAAQ,gBAAgB;AAAA,IAClD;AAEA,UAAM,aAAa,OAAO,IAAI,OAAO;AACrC,QAAI,CAAC,YAAY;AACf,aAAO,EAAE,MAAM,SAAS,QAAQ,gBAAgB;AAAA,IAClD;AACA,UAAM,cAAc,eAAe,QAAQ,eAAe;AAC1D,QAAI,gBAAgB,QAAQ,gBAAgB,YAAY;AACtD,aAAO,EAAE,MAAM,SAAS,QAAQ,gBAAgB;AAAA,IAClD;AAEA,UAAM,YAAY,OAAO,IAAI,MAAM;AACnC,QAAI,CAAC,WAAW;AACd,aAAO,EAAE,MAAM,SAAS,QAAQ,eAAe;AAAA,IACjD;AAEA,UAAM,oBAAoB,eAAe,QAAQ,uBAAuB;AACxE,QAAI,CAAC,mBAAmB;AACtB,aAAO,EAAE,MAAM,SAAS,QAAQ,wBAAwB;AAAA,IAC1D;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,kBAAkB,SAAS;AAAA,MACjC,cAAc,aAAa,iBAAiB;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,SAAe;AACb,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAM,cAAgC;AACpC,SAAK,oBAAoB;AACzB,WAAiB,YAAY,KAAK,KAAK,MAAS;AAAA,EAClD;AAAA,EAEA,MAAM,gBACJ,QACmC;AACnC,SAAK,oBAAoB;AACzB,WAAiB,gBAAgB,KAAK,KAAK,QAAQ,MAAS;AAAA,EAC9D;AAAA,EAEA,MAAM,kBAAkB,IAAmC;AACzD,SAAK,oBAAoB;AACzB,WAAiB,kBAAkB,KAAK,KAAK,IAAI,MAAS;AAAA,EAC5D;AAAA,EAEA,MAAM,+BACJ,QACmC;AACnC,SAAK,oBAAoB;AACzB,WAAwB,+BAA+B,KAAK,KAAK,MAAM;AAAA,EACzE;AAAA,EAEA,MAAM,sBACJ,SACA,QAC6B;AAC7B,SAAK,oBAAoB;AACzB,WAAwB,sBAAsB,KAAK,KAAK,SAAS,MAAM;AAAA,EACzE;AAAA,EAEA,MAAM,oBACJ,SACA,eAC+B;AAC/B,SAAK,oBAAoB;AACzB,WAAwB;AAAA,MACtB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,oBACJ,SACA,WAC6B;AAC7B,SAAK,oBAAoB;AACzB,WAAwB,oBAAoB,KAAK,KAAK,SAAS,SAAS;AAAA,EAC1E;AAAA,EAEA,MAAM,uBACJ,SAC+C;AAC/C,SAAK,oBAAoB;AACzB,WAAuB,uBAAuB,KAAK,KAAK,SAAS,MAAS;AAAA,EAC5E;AAAA,EAEA,MAAM,yBACJ,SACkC;AAClC,SAAK,oBAAoB;AACzB,WAAuB,yBAAyB,KAAK,KAAK,OAAO;AAAA,EACnE;AAAA,EAEA,MAAM,WAAyB;AAC7B,SAAK,oBAAoB;AACzB,WAAc,SAAS,KAAK,GAAG;AAAA,EACjC;AAAA,EAEA,MAAM,eACJ,cACA,QAC6B;AAC7B,SAAK,oBAAoB;AACzB,WAAoB,eAAe,KAAK,KAAK,cAAc,MAAM;AAAA,EACnE;AAAA,EAEA,MAAM,eACJ,WACA,OACmB;AACnB,SAAK,oBAAoB;AACzB,WAAc,eAAe,KAAK,KAAK,WAAW,KAAK;AAAA,EACzD;AAAA,EAEA,kBAAkB,aAAgC;AAChD,UAAM,UAAU,KAAK,QAAQ,mBAAmB;AAChD,QAAI;AACJ,YAAQ,YAAY,MAAM;AAAA,MACxB,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,SAAS;AACP,cAAM,cAAqB,YAAY;AACvC;AAAA,MACF;AAAA,IACF;AACA,QAAI,SAAS,KAAM;AACnB,iBAAa,IAAI,IAAI,MAAM,OAAO,EAAE,SAAS,CAAC;AAAA,EAChD;AAAA,EAEA,iBAAuB;AACrB,iBAAa,sBAAsB;AAAA,EACrC;AAAA,EAEQ,sBAAsB;AAC5B,QAAI,KAAK,aAAa,MAAM,aAAa;AACvC,YAAM,IAAI,sBAAsB;AAAA,IAClC;AAAA,EACF;AACF;AAEA,SAAS,aAAa,KAAmB;AACvC,SAAO,KAAK,KAAK,UAAU,qBAAqB;AAClD;AAEO,SAAS,qBAAqB,QAAsC;AACzE,SAAO,IAAI,mBAAmB,MAAM;AACtC;;;A1D5dI;AAlDG,IAAM,sBAAkB,4BAA2C,IAAI;AAgBvE,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,eAAW,sBAAQ,MAAM,qBAAqB,MAAM,GAAG,CAAC,MAAM,CAAC;AAErE,8BAAU,MAAM;AACd,QAAI,cAAc;AAClB,QAAI,SAAS,aAAa,MAAM,WAAW;AACzC,eACG,KAAK,EACL,KAAK,MAAM;AACV,YAAI,CAAC,aAAa;AAChB,qBAAW,IAAI;AAAA,QACjB;AAAA,MACF,CAAC,EACA,MAAM,MAAM;AACX,YAAI,CAAC,aAAa;AAChB,qBAAW,IAAI;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACL,OAAO;AACL,iBAAW,IAAI;AAAA,IACjB;AAEA,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,YAAQ,sBAAQ,OAAO,EAAE,UAAU,QAAQ,IAAI,CAAC,UAAU,OAAO,CAAC;AAExE,SACE,4CAAC,gBAAgB,UAAhB,EAAyB,OACvB,UACH;AAEJ;AAYO,IAAM,mBAAmB;;;A2DnFhC,IAAAC,gBAA0D;;;ACbnD,IAAM,YAAY;;;ADgDd,IAAAC,sBAAA;AA5BX,IAAM,mBAAe,6BAAc,KAAK;AAuBjC,SAAS,mBAAmB,EAAE,SAAS,GAA4B;AACxE,QAAM,oBAAgB,0BAAW,YAAY;AAC7C,MAAI,eAAe;AAGjB,WAAO,6EAAG,UAAS;AAAA,EACrB;AAEA,SACE,8EASE;AAAA,iDAAC,UAAK,KAAI,cAAa,MAAK,gCAA+B;AAAA,IAC3D;AAAA,MAAC;AAAA;AAAA,QACC,KAAI;AAAA,QACJ,MAAK;AAAA,QACL,aAAY;AAAA;AAAA,IACd;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,KAAI;AAAA,QACJ,MAAK;AAAA;AAAA,IACP;AAAA,IASA,8CAAC,SAAI,WAAU,iBAAgB,OAAO,EAAE,SAAS,WAAW,GAC1D;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,YAAW;AAAA,UAEX,yBAAyB,EAAE,QAAQ,UAAU;AAAA;AAAA,MAC/C;AAAA,MACA,6CAAC,aAAa,UAAb,EAAsB,OAAO,MAAO,UAAS;AAAA,OAChD;AAAA,KACF;AAEJ;;;AE3FA,0BAAkC;;;ACwE3B,IAAM,cAAc;AAAA,EACzB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AACR;;;ACrFA,kBAAsC;AAK/B,SAAS,MAAM,QAAsB;AAC1C,aAAO,kBAAK,MAAM;AACpB;;;AF2CI,IAAAC,sBAAA;AAnCJ,IAAM,gBAGF;AAAA,EACF,MAAM;AAAA,IACJ,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,SAAS;AAAA,IACP,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA,IACL,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAAqB;AACnB,QAAM,EAAE,WAAW,MAAM,KAAK,IAAI,cAAc,OAAO;AAEvD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA,gBACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,4CAA4C,IAAI;AAAA,YAC9D,eAAY;AAAA;AAAA,QACd;AAAA,QAEF,6CAAC,OAAE,WAAW,GAAG,YAAY,SAAS,IAAI,GAAI,mBAAQ;AAAA;AAAA;AAAA,EACxD;AAEJ;;;AGjEA,IAAAC,uBAAkB;AAwBZ,IAAAC,sBAAA;AAfC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,cAAc,YAAY;AAAA,EAC1B;AACF,GAAqB;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,cAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA,uDAAC,0BAAE,WAAU,2BAA0B;AAAA;AAAA,EACzC;AAEJ;;;ACzBI,IAAAC,sBAAA;AAFG,SAAS,iBAAiB,OAAgC;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MACX,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,UAAS;AAAA,YACT,UAAS;AAAA,YACT,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA;AAAA,EACF;AAEJ;;;AC3BI,IAAAC,sBAAA;AAFG,SAAS,kBAAkB,EAAE,UAAU,GAA2B;AACvE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,qDAAC,UAAK,WAAW,GAAG,YAAY,SAAS,2BAA2B,GAAG,wBAEvE;AAAA,QACA,6CAAC,oBAAiB,WAAU,8BAA6B;AAAA;AAAA;AAAA,EAC3D;AAEJ;;;ACpBA,sCAAuC;AACvC,IAAAC,gBAAsE;AA4FhE,IAAAC,sBAAA;AAxFN,IAAM,qBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA;AAAA,QAEP,SACE;AAAA;AAAA;AAAA,QAGF,WACE;AAAA;AAAA;AAAA,QAGF,aACE;AAAA;AAAA,QAEF,OACE;AAAA;AAAA,QAEF,MAAM;AAAA;AAAA,QAEN,iBACE;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,SACE;AAAA,QACF,IAAI;AAAA,QACJ,MAAM;AAAA,MACR;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA;AAAA,QAEN,SAAS;AAAA,MACX;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,MAChB,EAAE,MAAM,MAAM,QAAQ,WAAW,WAAW,qBAAqB;AAAA,MACjE,EAAE,MAAM,WAAW,QAAQ,WAAW,WAAW,sBAAsB;AAAA,MACvE,EAAE,MAAM,MAAM,QAAQ,WAAW,WAAW,sBAAsB;AAAA,MAClE,EAAE,MAAM,QAAQ,QAAQ,WAAW,WAAW,qBAAqB;AAAA,IACrE;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAYA,IAAM,eAAW;AAAA,EACf,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,aAAa,YAAY;AAE/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT,eAAe,EAAE,SAAS,MAAM,QAAQ,UAAU,CAAC;AAAA,UACnD;AAAA,QACF;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACT,GAAG;AAAA,QAEH;AAAA,uBACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA;AAAA,UACd;AAAA,UAGD,aAAa,CAAC,aACb,6CAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,UAGhD,6CAAC,UAAK,WAAW,GAAG,aAAa,oBAAoB,GAClD,uBAAa,cAAc,cAAc,UAC5C;AAAA,UAEC,WAAW,CAAC,aACX,6CAAC,UAAK,WAAU,oBAAoB,mBAAQ;AAAA;AAAA;AAAA,IAEhD;AAAA,EAEJ;AACF;AAEA,SAAS,cAAc;;;AC3HnB,IAAAC,sBAAA;AAFG,SAAS,iBAAiB,OAAgC;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,MACX,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACAQ,IAAAC,sBAAA;AAjBD,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ;AACF,GAA8B;AAC5B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAY;AAAA,MACZ,WACE,6CAAC,oBAAiB,WAAU,sDAAqD;AAAA,MAEnF;AAAA,MACD;AAAA;AAAA,EAED;AAEJ;;;ACtCA,IAAAC,gBAA2B;AAapB,SAAS,cAAiC;AAC/C,QAAM,cAAU,0BAAW,eAAe;AAC1C,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI,kCAAkC;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,EACpB;AACF;AAEO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAC3D,YACE,UAAU,2GACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACwBU,IAAAC,uBAAA;AAtBH,SAAS,mBAAmB;AAAA,EACjC,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AACF,IAA6B,CAAC,GAAc;AAC1C,QAAM,EAAE,SAAS,IAAI,YAAY;AACjC,QAAM,eACJ,aACC,MAAM;AACL,SAAK,SAAS,WAAW;AAAA,EAC3B;AAEF,SACE,8CAAC,sBACC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA,mBACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA;AAAA,QACZ;AAAA,QAGF,+CAAC,SAAI,WAAU,+CACb;AAAA,wDAAC,QAAG,WAAW,GAAG,YAAY,IAAI,2BAA2B,GAAG,oCAEhE;AAAA,UACA,8CAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,yEAEnE;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAS;AAAA,YACT,WAAU;AAAA;AAAA,QACZ;AAAA,QAEC,UAAU,WACT;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAI;AAAA,YACJ,SAAQ;AAAA,YACR,WAAU;AAAA;AAAA,QACZ;AAAA,QAGF,8CAAC,qBAAkB,WAAU,gBAAe;AAAA;AAAA;AAAA,EAC9C,GACF;AAEJ;;;AClCI,IAAAC,uBAAA;AAxCJ,IAAM,qBAAqB,IAAI,KAAK,eAAe,SAAS;AAAA,EAC1D,OAAO;AAAA,EACP,MAAM;AACR,CAAC;AAEM,IAAM,cAAc;AAAA,EACzB,YAAY,CAAC,WAA+B;AAAA,IAC1C,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,mBAAmB,mBAAmB,OAAO,MAAM,QAAQ;AAAA,IAC3D,iBAAiB,MAAM,SACnB,mBAAmB,OAAO,MAAM,MAAM,IACtC;AAAA,EACN;AACF;AAgBO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,YAAY;AAElB,QAAM,cACJ,gFACE;AAAA,mDAAC,SAAI,WAAU,oKACZ;AAAA,YAAM,YACL;AAAA,QAAC;AAAA;AAAA,UACC,KAAK,MAAM;AAAA,UACX,KAAI;AAAA,UACJ,WAAU;AAAA;AAAA,MACZ,IAEA,8CAAC,SAAI,WAAU,0HAAyH;AAAA,MAE1I,8CAAC,SAAI,WAAU,oIAAmI;AAAA,MAElJ,8CAAC,SAAI,WAAU,yGACZ,gBAAM,UACL;AAAA,QAAC;AAAA;AAAA,UACC,KAAK,MAAM;AAAA,UACX,KAAI;AAAA,UACJ,WAAU;AAAA;AAAA,MACZ,IAEA,8CAAC,SAAI,WAAU,wJAAuJ,GAE1K;AAAA,OACF;AAAA,IAEC,MAAM,WACL;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT,YAAY;AAAA,UACZ;AAAA,QACF;AAAA,QAEC,gBAAM;AAAA;AAAA,IACT;AAAA,IAGF,+CAAC,SAAI,WAAU,oHACb;AAAA,qDAAC,SAAI,WAAU,+CACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,YAAY,SAAS,6BAA6B;AAAA,YACjE;AAAA;AAAA,QAED;AAAA,QACA,8CAAC,UAAK,WAAW,GAAG,YAAY,OAAO,2BAA2B,GAC/D,gBAAM,mBACT;AAAA,SACF;AAAA,MAEC,MAAM,mBACL,+CAAC,SAAI,WAAU,+CACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,YAAY,SAAS,6BAA6B;AAAA,YACjE;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,YAAY,OAAO,2BAA2B;AAAA,YAE3D,gBAAM;AAAA;AAAA,QACT;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAGF,QAAM,cAAc;AAAA,IAClB;AAAA,IACA;AAAA,IACA,WACE;AAAA,EACJ;AAEA,MAAI;AACJ,MAAI,SAAS;AACX,eACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,WAAW;AAAA,QACX;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ,OAAO;AACL,eAAW,8CAAC,SAAI,WAAW,aAAc,uBAAY;AAAA,EACvD;AAEA,QAAM,OAAO,qBACX,8CAAC,SAAI,WAAW,oBAAqB,oBAAS,IAE9C;AAGF,SAAO,8CAAC,sBAAoB,gBAAK;AACnC;;;ACzJA,IAAAC,gBAAoC;AAgCpC,IAAM,gBAAiC,EAAE,MAAM,UAAU;AAclD,SAAS,UAAU,UAA4B,CAAC,GAAoB;AACzE,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,EAAE,MAAM,aAAa,IAAI;AAC/B,QAAM,CAAC,aAAa,cAAc,QAAI;AAAA,IACpC,iBAAiB,SACb,EAAE,MAAM,WAAW,QAAQ,aAAa,IACxC;AAAA,EACN;AAEA,+BAAU,MAAM;AACd,QAAI,cAAc;AAGlB,QAAI,CAAC,SAAS;AACZ,UAAI,iBAAiB,QAAW;AAC9B,uBAAe,aAAa;AAAA,MAC9B;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,iBAAiB,QAAW;AAC9B,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,mBAAe,aAAa;AAC5B,aACG,YAAY,EACZ,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,aAAa;AAChB,uBAAe,EAAE,MAAM,WAAW,OAAO,CAAC;AAAA,MAC5C;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,uBAAe,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAC1C;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,YAAY,CAAC;AAEpC,SAAO,EAAE,YAAY;AACvB;;;ACxCQ,IAAAC,uBAAA;AA/CR,IAAM,sBAAsB;AAwB5B,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,IAAqB,CAAC,GAAc;AAClC,QAAM,EAAE,YAAY,IAAI,UAAU,EAAE,KAAK,CAAC;AAC1C,QAAM,OAAO,KAAK,IAAI,GAAG,cAAc,mBAAmB;AAE1D,MAAI,YAAY,SAAS,WAAW;AAClC,QAAI,SAAS;AACX,aAAO;AAAA,IACT;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAU;AAAA,QAEV,wDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,+BAEnE;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,YAAY,SAAS,SAAS;AAChC,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAEA,UAAM,eACJ,YAAY,WAAW,sBACnB,sCACA;AAEN,WACE;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAU;AAAA;AAAA,IACZ;AAAA,EAEJ;AAEA,MAAI,YAAY,OAAO,WAAW,GAAG;AACnC,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAU;AAAA,QAEV;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT,YAAY;AAAA,gBACZ;AAAA,cACF;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UACA,8CAAC,OAAE,WAAW,GAAG,YAAY,SAAS,6BAA6B,GAAG,yDAEtE;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,QAAM,eAAe,QAAQ,IAAI,cAAc,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;AAEpE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,GAAG,6CAA6C,SAAS;AAAA,UACpE,OAAO;AAAA,YACL,qBACE;AAAA,YACF,UAAU;AAAA,UACZ;AAAA,UAEC,sBAAY,OAAO,IAAI,CAAC,UACvB;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,YAAY,WAAW,KAAK;AAAA,cACnC,SAAS,eAAe,MAAM,aAAa,KAAK,IAAI;AAAA;AAAA,YAF/C,MAAM;AAAA,UAGb,CACD;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAcO,SAAS,WAAW,QAAyB,CAAC,GAAc;AACjE,SACE,8CAAC,sBACC,wDAAC,kBAAgB,GAAG,OAAO,GAC7B;AAEJ;;;AC3JA,IAAAC,gBAAyC;AAmEnC,IAAAC,uBAAA;AAzBN,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AACF,GAGc;AACZ,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAmB,MAAM;AAEnD,QAAM,SAAS,YAAY;AACzB,QAAI,CAAC,SAAU;AACf,aAAS,UAAU;AACnB,QAAI;AACF,YAAM,SAAS,OAAO,EAAE;AAIxB,eAAS,MAAM;AAAA,IACjB,QAAQ;AACN,eAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAEA,SACE,+CAAC,SAAI,WAAU,6GACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,OAAO;AAAA,QACd,WAAW;AAAA,UACT,YAAY;AAAA,UACZ;AAAA,QACF;AAAA,QAEC,iBAAO;AAAA;AAAA,IACV;AAAA,IAEC,YAAY,SACV,UAAU,eACT,+CAAC,SAAI,WAAU,mDACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,GAAG,YAAY,SAAS,6BAA6B;AAAA,UACjE;AAAA;AAAA,MAED;AAAA,MACA,8CAAC,YAAS,MAAK,MAAK,SAAQ,eAAc,SAAS,QAAQ,oBAE3D;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,SAAS,MAAM;AAAA,UAC/B;AAAA;AAAA,MAED;AAAA,OACF,IACE,UAAU,UACZ,+CAAC,SAAI,WAAU,mDACb;AAAA,oDAAC,UAAK,WAAW,GAAG,YAAY,SAAS,oBAAoB,GAAG,8BAEhE;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS,MAAM,SAAS,YAAY;AAAA,UACrC;AAAA;AAAA,MAED;AAAA,OACF,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,UAAU,UAAU;AAAA,QACpB,SAAS,MAAM,SAAS,YAAY;AAAA,QAEnC,oBAAU,aAAa,mBAAc;AAAA;AAAA,IACxC;AAAA,KAEN;AAEJ;AASO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT;AACF,GAAwC;AACtC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,+CAA+C,SAAS;AAAA,MAErE;AAAA,mBAAW,YACV,8CAAC,eAAY,SAAQ,QAAO,SAAQ,wCAAkC,IACpE,WAAW,UACb;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,SAAQ;AAAA;AAAA,QACV,IACE,QAAQ,WAAW,IACrB,8CAAC,eAAY,SAAQ,QAAO,SAAQ,6BAA4B,IAEhE,8CAAC,SAAI,WAAU,yEACZ,kBAAQ,IAAI,CAAC,WACZ;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA;AAAA;AAAA,UAFK,OAAO;AAAA,QAGd,CACD,GACH;AAAA,QAGD,SAAS,QAAQ,WAAW,aAC3B;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC/KA,IAAAC,gBAAiC;;;ACFjC,IAAAC,gBAAyD;;;ACmFzD,IAAM,oBACJ;AAIF,IAAM,iBAAsD,oBAAI,IAAI;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAID,IAAM,kBAAuD,oBAAI,IAAI;AAAA,EACnE;AAAA,EACA;AACF,CAAC;AAED,SAAS,UAAU,MAAsD;AACvE,SAAO,EAAE,MAAM,WAAW,CAAC,eAAe,IAAI,IAAI,EAAE;AACtD;AAOA,SAAS,cAA+C;AACtD,MAAI,OAAO,WAAW,YAAa,QAAO,EAAE,QAAQ,IAAI,KAAK,GAAG;AAChE,SAAO,EAAE,QAAQ,OAAO,SAAS,MAAM,KAAK,OAAO,SAAS,OAAO;AACrE;AAOA,SAAS,aAAa,OAAoC;AACxD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,OAAQ,MAAuD,UACjE;AACJ,SAAO,OAAO,MAAM,SAAS,WAAW,KAAK,OAAO;AACtD;AASA,SAAS,iBAAiB,OAAwC;AAChE,MAAI,iBAAiB,uBAAuB;AAC1C,WAAO,UAAU,mBAAmB;AAAA,EACtC;AACA,QAAM,OAAO,aAAa,KAAK;AAC/B,MACE,SAAS,UACT,gBAAgB,IAAI,IAA8B,GAClD;AACA,WAAO,UAAU,IAA8B;AAAA,EACjD;AACA,SAAO,UAAU,SAAS;AAC5B;AAOA,SAAS,gBACP,QACA,eACA,WACsC;AACtC,UAAQ,eAAe;AAAA,IACrB,KAAK;AACH,aAAO;AAAA,QACL,eAAe,OAAO;AAAA,QACtB,OAAO,OAAO;AAAA,QACd,eAAe;AAAA,QACf,GAAG,YAAY;AAAA,QACf,WAAW,aAAa;AAAA,MAC1B;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,eAAe,OAAO;AAAA,QACtB,OAAO,OAAO;AAAA,QACd,eAAe;AAAA,MACjB;AAAA,IACF,SAAS;AACP,YAAM,cAAqB;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAUA,eAAsB,0BACpB,QACkC;AAClC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,OAAO,CAAC,UAA8B,aAAa,KAAK;AAC9D,QAAM,YAAY,MAAM,cAAc,KAAK;AAG3C,OAAK,sBAAsB;AAC3B,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,SAAS;AAAA,MACzB,gBAAgB,QAAQ,iBAAiB,QAAQ,SAAS;AAAA,IAC5D;AAAA,EACF,SAAS,OAAO;AACd,WAAO,EAAE,MAAM,SAAS,OAAO,iBAAiB,KAAK,EAAE;AAAA,EACzD;AAGA,MAAI,UAAU,EAAG,QAAO,EAAE,MAAM,YAAY;AAG5C,OAAK,iBAAiB;AACtB,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,OAAO,YAAY,UAAU,OAAO;AAAA,EACxD,SAAS,OAAO;AAEd,QAAI,oBAAoB,KAAK,EAAE,SAAS,iBAAiB;AACvD,aAAO,EAAE,MAAM,SAAS,OAAO,UAAU,eAAe,EAAE;AAAA,IAC5D;AACA,WAAO,EAAE,MAAM,SAAS,OAAO,UAAU,SAAS,EAAE;AAAA,EACtD;AAGA,MAAI,UAAU,EAAG,QAAO,EAAE,MAAM,YAAY;AAG5C,OAAK,sBAAsB;AAC3B,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,sBAAsB,SAAS;AAAA,MAC5D;AAAA,MACA,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd;AAAA,IACF,CAAC;AACD,WAAO,EAAE,MAAM,WAAW,QAAQ;AAAA,EACpC,SAAS,OAAO;AACd,WAAO,EAAE,MAAM,SAAS,OAAO,iBAAiB,KAAK,EAAE;AAAA,EACzD;AACF;;;AD3LA,IAAM,YAAoC,EAAE,MAAM,QAAQ,OAAO,KAAK;AAEtE,IAAM,aAAqD;AAAA,EACzD,mBAAmB;AAAA,EACnB,eACE;AAAA,EACF,wBAAwB;AAAA,EACxB,qBACE;AAAA,EACF,SAAS;AACX;AAEA,SAAS,aAAa,OAGC;AACrB,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,SAAS,WAAW,MAAM,IAAI;AAAA,IAC9B,WAAW,MAAM;AAAA,EACnB;AACF;AAQO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,EAAE,SAAS,IAAI,YAAY;AACjC,QAAM,CAAC,OAAO,QAAQ,QAAI;AAAA,IAA6B,MACrD,SACI,EAAE,MAAM,SAAS,SAAS,OAAO,SAAS,MAAM,UAAU,IAC1D,EAAE,MAAM,eAAe;AAAA,EAC7B;AAKA,QAAM,cAAU,sBAAO,CAAC;AAMxB,+BAAU,MAAM;AAEd,YAAQ,WAAW;AACnB,QAAI,CAAC,OAAQ;AACb;AAAA,MACE,SACI,EAAE,MAAM,SAAS,SAAS,OAAO,SAAS,MAAM,UAAU,IAC1D,EAAE,MAAM,eAAe;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,QAAQ,QAAQ,OAAO,CAAC;AAK5B;AAAA,IACE,MAAM,MAAM;AACV,cAAQ,WAAW;AAAA,IACrB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,aAAS,2BAAY,MAAM;AAC/B,QAAI,CAAC,UAAU,MAAM,SAAS,QAAS;AAEvC,YAAQ,WAAW;AACnB,UAAM,MAAM,QAAQ;AAEpB,aAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS,OAAO;AAAA,MAChB,MAAM,EAAE,MAAM,UAAU;AAAA,IAC1B,CAAC;AAED,8BAA0B;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA,aAAa,MAAM,QAAQ,YAAY;AAAA,IACzC,CAAC,EAAE,KAAK,CAAC,WAAW;AAElB,UAAI,QAAQ,YAAY,IAAK;AAC7B,UAAI,OAAO,SAAS,WAAW;AAC7B,iBAAS,EAAE,MAAM,aAAa,SAAS,OAAO,QAAQ,CAAC;AAAA,MACzD,WAAW,OAAO,SAAS,SAAS;AAClC,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS,OAAO;AAAA,UAChB,MAAM,EAAE,MAAM,QAAQ,OAAO,aAAa,OAAO,KAAK,EAAE;AAAA,QAC1D,CAAC;AAAA,MACH;AAAA,IAEF,CAAC;AAAA,EACH,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,EAAE,OAAO,OAAO;AACzB;;;ADpFQ,IAAAC,uBAAA;AA5CD,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,EAAE,OAAO,OAAO,IAAI,iBAAiB;AAAA,IACzC;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAU,qBAAM;AAGtB,+BAAU,MAAM;AACd,QAAI,MAAM,SAAS,aAAa;AAC9B,oBAAc,MAAM,OAAO;AAC3B,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,MAAI,CAAC,UAAU,MAAM,SAAS,YAAa,QAAO;AAElD,SACE,8CAAC,SAAI,WAAU,uIACb;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAW;AAAA,MACX,mBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,uDAAC,SAAI,WAAU,0EACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI;AAAA,cACJ,WAAW,GAAG,YAAY,IAAI,2BAA2B;AAAA,cAC1D;AAAA;AAAA,UAED;AAAA,UACA,8CAAC,eAAY,SAAS,SAAS;AAAA,WACjC;AAAA,QAEC,MAAM,SAAS,kBACd,8CAAC,qBAAkB,kBAAoC;AAAA,QAExD,MAAM,SAAS,WACd;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM;AAAA,YACf,MAAM,MAAM;AAAA,YACZ;AAAA,YACA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;AAEA,SAAS,kBAAkB;AAAA,EACzB;AACF,GAEG;AACD,SACE,+CAAC,SAAI,WAAU,+CACb;AAAA,kDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,sFAEnE;AAAA,IACC,oBACC,8CAAC,YAAS,WAAS,MAAC,SAAS,kBAAkB,4BAE/C;AAAA,KAEJ;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,mBACJ,KAAK,SAAS,UAAU,KAAK,UAAU,QAAQ,CAAC,KAAK,MAAM;AAE7D,SACE,+CAAC,SAAI,WAAU,+CACb;AAAA,kDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,sHAGnE;AAAA,IAEA,+CAAC,SAAI,WAAU,oGACb;AAAA,oDAAC,UAAK,WAAW,GAAG,YAAY,OAAO,6BAA6B,GAAG,4BAEvE;AAAA,MACA,8CAAC,UAAK,WAAW,GAAG,YAAY,MAAM,2BAA2B,GAC9D,yBAAe,OAAO,GACzB;AAAA,OACF;AAAA,IAEC,KAAK,SAAS,UAAU,KAAK;AAAA;AAAA,IAG5B,8CAAC,SAAI,MAAK,SACR,wDAAC,eAAY,SAAQ,SAAQ,MAAI,MAAC,SAAS,KAAK,MAAM,SAAS,GACjE;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,WAAS;AAAA,QACT,SAAS;AAAA,QACT,WAAW,KAAK,SAAS;AAAA,QACzB,aAAY;AAAA,QAGZ,UAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,IAEC,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAS;AAAA,QACT,SAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK,SAAS;AAAA,QACzB;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;;;AGzMA,0BAAyB;AACzB,IAAAC,iBAAkD;;;ACHlD,IAAAC,gBAAyD;AAiCzD,IAAM,aAA4B,EAAE,MAAM,OAAO;AACjD,IAAMC,iBAA+B,EAAE,MAAM,UAAU;AAoBhD,SAAS,YACd,WACA,OACmB;AACnB,QAAM,EAAE,SAAS,IAAI,YAAY;AACjC,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAwB,UAAU;AAC5E,QAAM,sBAAkB,sBAAO,UAAU,IAAI;AAC7C,QAAM,qBAAiB,sBAAO,KAAK;AAEnC,+BAAU,MAAM;AACd,QAAI,CAAC,eAAe,SAAS;AAC3B,sBAAgB,UAAU,UAAU;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBAAa,2BAAY,YAAY;AACzC,qBAAiBA,cAAa;AAC9B,QAAI;AACF,YAAM,WAAW,MAAM,SAAS;AAAA,QAC9B;AAAA,QACA,gBAAgB;AAAA,MAClB;AACA,sBAAgB,UAAU;AAC1B,qBAAe,UAAU;AACzB,uBAAiB,EAAE,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC;AAC3D,aAAO,SAAS;AAAA,IAClB,SAAS,OAAO;AACd,YAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,uBAAiB,EAAE,MAAM,SAAS,OAAO,CAAC;AAC1C,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,CAAC;AAExB,SAAO,EAAE,eAAe,WAAW;AACrC;;;ADAQ,IAAAC,uBAAA;AAhDD,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyC;AACvC,QAAM,EAAE,eAAe,WAAW,IAAI,YAAY,WAAW,KAAK;AAClE,QAAM,iBAAa,uBAAO,KAAK;AAE/B,gCAAU,MAAM;AACd,QAAI,WAAW,QAAS;AACxB,eAAW,UAAU;AACrB,eAAW,EAAE,MAAM,MAAM;AAAA,IAEzB,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,gBAAgB,CAAC,MAAc,YAAqB;AACxD,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,sBAAc;AACd;AAAA,MACF,KAAK,mBAAmB;AACtB,cAAM,UACH,SAAkC,WAAW;AAChD,kBAAU,IAAI,MAAM,OAAO,CAAC;AAC5B;AAAA,MACF;AAAA,MACA;AACE;AAAA,IACJ;AAAA,EACF;AAEA,QAAM,cAAc,CAAC,UAAmB;AACtC,cAAU,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,oBAAoB,CAAC;AAAA,EAC5E;AAEA,MAAI,cAAc,SAAS,UAAU,cAAc,SAAS,WAAW;AACrE,WACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEA,wDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,8CAEnE;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,cAAc,SAAS,SAAS;AAClC,UAAM,eACJ,cAAc,WAAW,sBACrB,qCACA;AACN,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,+CAA+C,SAAS;AAAA,QAEtE;AAAA,wDAAC,eAAY,SAAQ,SAAQ,MAAI,MAAC,SAAS,cAAc;AAAA,UACxD,cAAc,WAAW,uBACxB;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM;AACb,2BAAW,EAAE,MAAM,MAAM;AAAA,gBAEzB,CAAC;AAAA,cACH;AAAA,cACD;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAI,WAAW,GAAG,kBAAkB,SAAS,GAC5C;AAAA,IAAC,oBAAAC;AAAA,IAAA;AAAA,MACC,aAAa,cAAc;AAAA,MAC3B,mBAAmB;AAAA,MACnB,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,MAAM,OAAO;AAAA,MACnD,SAAS,EAAE,gBAAgB,OAAO,mBAAmB,KAAK;AAAA,MAC1D,WAAW;AAAA,MACX,SAAS;AAAA;AAAA,EACX,GACF;AAEJ;;;AEtIA,IAAAC,uBAA6B;;;ACD7B,IAAAC,uBAA2C;AAuCvC,IAAAC,uBAAA;AA7BJ,IAAM,eAGF;AAAA,EACF,UAAU;AAAA,IACR,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,WAAW;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AACF;AAEO,SAAS,eAAe,EAAE,QAAQ,UAAU,GAAwB;AACzE,QAAM,EAAE,MAAM,YAAY,UAAU,IAAI,aAAa,MAAM;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,eAAY;AAAA;AAAA,EACd;AAEJ;;;ADuFQ,IAAAC,uBAAA;AAhHD,IAAM,qBAAqB;AAAA,EAChC,SAAS,MAA2C;AAClD,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;AAOO,IAAM,oBAAoB;AAAA,EAC/B,gBAAgB,QAAmD;AACjE,YAAQ,QAAQ;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,IACX;AAAA,EACF;AACF;AAGO,IAAM,kBAAkB;AAAA,EAC7B,OAAO,UAAoD;AACzD,QAAI,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,EAAG,QAAO;AAC1D,QAAI,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,WAAW,EAAG,QAAO;AAC5D,WAAO;AAAA,EACT;AACF;AAgBO,IAAM,oBAAoB;AAAA,EAC/B,WACE,KACA,YACA,OACA,aACA,YAAkC,CAAC,GAChB;AACnB,WAAO;AAAA,MACL,SAAS,mBAAmB,SAAS,IAAI,IAAI;AAAA,MAC7C,QAAQ,aACJ,kBAAkB,gBAAgB,WAAW,MAAM,IACnD;AAAA,MACJ;AAAA,MACA;AAAA,MACA,aAAa,IAAI,SAAS;AAAA,MAC1B,kBAAkB,UAAU,IAAI,CAAC,aAAa;AAAA,QAC5C,IAAI,QAAQ;AAAA,QACZ,SAAS,QAAQ;AAAA,QACjB,cAAc,eAAe,QAAQ,OAAO;AAAA,MAC9C,EAAE;AAAA,IACJ;AAAA,EACF;AACF;AAoBA,SAAS,uBAAuB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAIc;AACZ,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,UAAI,aAAa,KAAM,QAAO;AAC9B,aACE,8CAAC,YAAS,MAAK,MAAK,SAAS,UAAU,sBAEvC;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV;AAAA,IAEJ,KAAK;AACH,aAAO,8CAAC,eAAY,SAAQ,WAAU,SAAQ,sBAAqB;AAAA,IACrE,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SACE,qBAAqB,OACnB,2BAEA,gFAAE;AAAA;AAAA,YACuB;AAAA,YACvB;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YAAS;AAAA,aAEX;AAAA;AAAA,MAGN;AAAA,EAEN;AACF;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOc;AAKZ,MAAI,aAAa;AACf,WACE,gFACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,UAAU;AAAA,UACV,OAAO,YAAY;AAAA,UACnB,QAAQ;AAAA;AAAA,MACV;AAAA,MACC,WAAW,cACV;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV;AAAA,OAEJ;AAAA,EAEJ;AAGA,MAAI,WAAW,aAAa;AAC1B,UAAM,YAAY,iBAAiB,CAAC;AACpC,WACE,gFACG;AAAA,mBAAa,QACZ,8CAAC,YAAS,MAAK,MAAK,SAAQ,aAAY,SAAS,UAAU,2BAE3D;AAAA,MAKD,kBAAkB,YACjB;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV,IACE,kBAAkB,UACpB;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV,IAEA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAS,YAAY,UAAU,eAAe;AAAA;AAAA,MAChD;AAAA,OAEJ;AAAA,EAEJ;AAEA,MAAI,WAAW,YAAY;AACzB,WACE,gFACG;AAAA,mBAAa,QACZ,8CAAC,YAAS,MAAK,MAAK,SAAS,UAAU,4BAEvC;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAQ;AAAA;AAAA,MACV;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,aAAa,KAAM,QAAO;AAC9B,SACE,8CAAC,YAAS,MAAK,MAAK,SAAS,UAAU,4BAEvC;AAEJ;AAOO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SACE,8CAAC,sBACC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,iBAAe;AAAA,YACf,WAAU;AAAA,YAEV;AAAA,6DAAC,SAAI,WAAU,mDACb;AAAA,8DAAC,kBAAe,QAAQ,GAAG,QAAQ;AAAA,gBACnC;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW;AAAA,sBACT,YAAY;AAAA,sBACZ;AAAA,oBACF;AAAA,oBAEC,aAAG;AAAA;AAAA,gBACN;AAAA,iBACF;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,YAAY;AAAA,kBACd;AAAA,kBACA,eAAY;AAAA;AAAA,cACd;AAAA;AAAA;AAAA,QACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,WAAW,4BAA4B;AAAA,YACzC;AAAA,YAGA,wDAAC,SAAI,WAAU,2CACb,yDAAC,SAAI,WAAU,yEACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT,YAAY;AAAA,oBACZ;AAAA,kBACF;AAAA,kBAEC,aAAG;AAAA;AAAA,cACN;AAAA,cACC,GAAG,YAAY,iBACd;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAQ,GAAG;AAAA,kBACX;AAAA,kBACA;AAAA;AAAA,cACF,IAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAQ,GAAG;AAAA,kBACX,aAAa,GAAG;AAAA,kBAChB,kBAAkB,GAAG;AAAA,kBACrB;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,cACF;AAAA,eAEJ,GACF;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;;;AErWA,IAAAC,iBAA4D;;;ACA5D,IAAAC,iBAA0B;;;ACF1B,IAAAC,iBAAiD;AAmEjD,IAAMC,aAAuB,EAAE,MAAM,QAAQ,OAAO,KAAK;AACzD,IAAMC,iBAAkC,EAAE,MAAM,UAAU;AAC1D,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAS5B,IAAM,aAAsD;AAAA,EAC1D,eAAe;AAAA,EACf,KAAK;AAAA,EACL,sBAAsB;AAAA,EACtB,OAAO;AAAA,EACP,kBAAkB;AACpB;AAGA,SAAS,aAAa,MAAoB;AACxC,QAAM,QAAQ,OAAO,KAAK,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,QAAM,MAAM,OAAO,KAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,OAAO,OAAO,KAAK,YAAY,CAAC,EAAE,SAAS,GAAG,GAAG;AACvD,SAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI;AAChC;AASA,SAAS,kBAAkB,SAAyB;AAClD,QAAM,QAAQ,4BAA4B,KAAK,OAAO;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,CAAC,EAAE,MAAM,OAAO,GAAG,IAAI;AAC7B,SAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI;AAChC;AAMA,SAAS,cAAc,OAAwB;AAC7C,QAAM,QAAQ,8BAA8B,KAAK,KAAK;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,CAAC,EAAE,IAAI,IAAI,IAAI,IAAI;AACzB,QAAM,QAAQ,OAAO,EAAE;AACvB,QAAM,MAAM,OAAO,EAAE;AACrB,QAAM,OAAO,OAAO,IAAI;AACxB,QAAM,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG,GAAG;AAC1C,SACE,KAAK,YAAY,MAAM,QACvB,KAAK,SAAS,MAAM,QAAQ,KAC5B,KAAK,QAAQ,MAAM;AAEvB;AAEA,SAAS,eAAe,KAA6B;AACnD,QAAM,EAAE,QAAQ,MAAM,OAAO,WAAW,IAAI,IAAI;AAChD,QAAM,WAAW,CAAC,YAAY,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC5D,QAAM,mBAAmB,CAAC,QAAQ,UAAU,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAE5E,SAAO;AAAA,IACL,eAAe,IAAI,iBAAiB;AAAA;AAAA;AAAA,IAGpC,KAAK,kBAAkB,IAAI,eAAe,EAAE;AAAA,IAC5C,sBAAsB,IAAI,cAAc,QAAQ;AAAA,IAChD,OAAO,IAAI,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,KAAmC;AAC9D,SAAO;AAAA,IACL,MAAM,IAAI,iBAAiB,QAAQ;AAAA,IACnC,SAAS,IAAI,iBAAiB,WAAW;AAAA,EAC3C;AACF;AAEA,SAAS,iBAAiB,QAAoC;AAC5D,SAAO,OAAO,OAAO,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,KAAK,MAAM,EAAE;AAClE;AAOA,SAAS,mBACP,QACA,cACwB;AACxB,SAAO;AAAA,IACL,CAAC,WAAW,aAAa,GAAG,OAAO;AAAA,IACnC,CAAC,WAAW,GAAG,GAAG,OAAO;AAAA,IACzB,CAAC,WAAW,oBAAoB,GAAG,OAAO;AAAA,IAC1C,CAAC,WAAW,KAAK,GAAG,OAAO;AAAA,IAC3B,CAAC,WAAW,gBAAgB,GAAG,OAAO;AAAA,IACtC,MAAM,aAAa;AAAA,IACnB,SAAS,aAAa;AAAA,IACtB,WAAW,OAAO;AAAA,IAClB,MAAM,aAAa,oBAAI,KAAK,CAAC;AAAA,EAC/B;AACF;AAWO,SAAS,eAAe;AAAA,EAC7B;AACF,GAAgD;AAC9C,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA2BA,cAAa;AAElE,gCAAU,MAAM;AACd,QAAI,cAAc;AAElB,QAAI,CAAC,QAAQ;AACX,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ,eAASA,cAAa;AACtB,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,aAASA,cAAa;AACtB,aACG,SAAS,EACT,KAAK,CAAC,QAAQ;AACb,UAAI,YAAa;AACjB,UAAI,IAAI,SAAS,WAAW;AAC1B,iBAAS,EAAE,MAAM,aAAa,MAAMD,WAAU,CAAC;AAC/C;AAAA,MACF;AACA,YAAM,SAAS,eAAe,GAAG;AACjC,eAAS;AAAA,QACP,MAAM;AAAA,QACN;AAAA,QACA,cAAc,oBAAoB,GAAG;AAAA,QACrC,gBAAgB,CAAC,iBAAiB,MAAM;AAAA,QACxC,MAAMA;AAAA,MACR,CAAC;AAAA,IACH,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,YAAa;AACjB,eAAS;AAAA,QACP,MAAM;AAAA,QACN,QACE,iBAAiB,wBACb,sBACA;AAAA,MACR,CAAC;AAAA,IACH,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,MAAM,CAAC;AAE9B,QAAM,kBAAc;AAAA,IAClB,CAAC,OAAgC,UAAkB;AACjD;AAAA,QAAS,CAAC,SACR,KAAK,SAAS,YACV,EAAE,GAAG,MAAM,QAAQ,EAAE,GAAG,KAAK,QAAQ,CAAC,KAAK,GAAG,MAAM,EAAE,IACtD;AAAA,MACN;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,kBAAc,4BAAY,MAAM;AACpC;AAAA,MAAS,CAAC,SACR,KAAK,SAAS,WACV;AAAA,QACE,MAAM;AAAA,QACN,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK;AAAA,QACf,cAAc,KAAK;AAAA,QACnB,gBAAgB,KAAK;AAAA,MACvB,IACA;AAAA,IACN;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAa,4BAAY,MAAM;AACnC;AAAA,MAAS,CAAC,SACR,KAAK,SAAS,YACV;AAAA,QACE,MAAM;AAAA,QACN,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK;AAAA,QACnB,gBAAgB,KAAK;AAAA,QACrB,MAAMA;AAAA,MACR,IACA;AAAA,IACN;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAe,4BAAY,MAAM;AACrC;AAAA,MAAS,CAAC,SACR,KAAK,SAAS,YACV;AAAA,QACE,MAAM;AAAA,QACN,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK;AAAA,QACnB,gBAAgB,KAAK;AAAA,QACrB,MAAMA;AAAA,MACR,IACA;AAAA,IACN;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,aAAS,4BAAY,MAAM;AAC/B,QAAI,MAAM,SAAS,YAAY,MAAM,SAAS,YAAa;AAI3D,QACE,MAAM,SAAS,YACf,MAAM,OAAO,IAAI,KAAK,MAAM,MAC5B,CAAC,cAAc,MAAM,OAAO,GAAG,GAC/B;AACA,eAAS;AAAA,QACP,GAAG;AAAA,QACH,MAAM,EAAE,MAAM,QAAQ,OAAO,oBAAoB;AAAA,MACnD,CAAC;AACD;AAAA,IACF;AAEA,aAAS,EAAE,GAAG,OAAO,MAAM,EAAE,MAAM,UAAU,EAAE,CAAC;AAEhD,aACG;AAAA,MACC;AAAA,MACA,MAAM,SAAS,WACX,mBAAmB,MAAM,QAAQ,MAAM,YAAY,IACnD,CAAC;AAAA,IACP,EACC,KAAK,CAAC,eAAe;AACpB,eAAS,EAAE,MAAM,aAAa,WAAW,CAAC;AAAA,IAC5C,CAAC,EACA,MAAM,MAAM;AACX;AAAA,QAAS,CAAC,SACR,KAAK,SAAS,YAAY,KAAK,SAAS,cACpC,EAAE,GAAG,MAAM,MAAM,EAAE,MAAM,QAAQ,OAAO,oBAAoB,EAAE,IAC9D;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACL,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,EAAE,OAAO,aAAa,aAAa,YAAY,cAAc,OAAO;AAC7E;;;ADzQQ,IAAAE,uBAAA;AAzDR,IAAM,aAID;AAAA,EACH,EAAE,OAAO,iBAAiB,OAAO,kBAAkB;AAAA,EACnD,EAAE,OAAO,OAAO,OAAO,iBAAiB,aAAa,aAAa;AAAA,EAClE,EAAE,OAAO,wBAAwB,OAAO,yBAAyB;AAAA,EACjE,EAAE,OAAO,SAAS,OAAO,SAAS;AAAA,EAClC,EAAE,OAAO,oBAAoB,OAAO,oBAAoB;AAC1D;AAoBO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,EAAE,OAAO,aAAa,aAAa,YAAY,cAAc,OAAO,IACxE,eAAe,EAAE,OAAO,CAAC;AAG3B,gCAAU,MAAM;AACd,QAAI,MAAM,SAAS,aAAa;AAC9B,oBAAc,MAAM,UAAU;AAC9B,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,MAAI,CAAC,UAAU,MAAM,SAAS,YAAa,QAAO;AAElD,SACE,8CAAC,SAAI,WAAU,uIACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,uDAAC,SAAI,WAAU,0EACb;AAAA,wDAAC,2BAAwB,OAAc;AAAA,UACvC,8CAAC,eAAY,SAAS,SAAS;AAAA,WACjC;AAAA,QAEC,MAAM,SAAS,aAAa,8CAAC,iBAAc;AAAA,QAC3C,MAAM,SAAS,WAAW,8CAAC,eAAY,QAAQ,MAAM,QAAQ;AAAA,QAC7D,MAAM,SAAS,YACd;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,MAAM;AAAA,YACd,gBAAgB,MAAM;AAAA,YACtB,MAAM,MAAM;AAAA,YACZ;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QAED,MAAM,SAAS,aACd;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,MAAM;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QAED,MAAM,SAAS,eACd,8CAAC,kBAAe,MAAM,MAAM,MAAM,QAAgB;AAAA;AAAA;AAAA,EAEtD,GACF;AAEJ;AAEA,SAAS,wBAAwB;AAAA,EAC/B;AACF,GAEG;AACD,QAAM,QACJ,MAAM,SAAS,YACX,qBACA,MAAM,SAAS,WACb,wBACA,MAAM,SAAS,cACb,0BACA;AAEV,SACE,8CAAC,QAAG,WAAW,GAAG,YAAY,IAAI,2BAA2B,GAAI,iBAAM;AAE3E;AAEA,SAAS,gBAAgB;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAU;AAAA,MAET,qBAAW,IAAI,CAAC,EAAE,MAAM,MACvB;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,0DAAC,SAAI,WAAU,qFAAoF;AAAA,YACnG,8CAAC,SAAI,WAAU,qFAAoF;AAAA;AAAA;AAAA,QAJ9F;AAAA,MAKP,CACD;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AACF,GAEG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAI;AAAA,MACJ,SACE,WAAW,sBACP,2CACA;AAAA;AAAA,EAER;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,+CAAC,SAAI,WAAU,+CACb;AAAA,kDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,8FAGnE;AAAA,IAEC,kBACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAI;AAAA,QACJ,SAAQ;AAAA;AAAA,IACV;AAAA,IAGF,8CAAC,SAAI,WAAU,oGACZ,qBAAW,IAAI,CAAC,EAAE,OAAO,MAAM,MAC9B;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,YAAY,OAAO,6BAA6B;AAAA,cAE7D;AAAA;AAAA,UACH;AAAA,UACA,8CAAC,UAAK,WAAW,GAAG,YAAY,MAAM,2BAA2B,GAC9D,iBAAO,KAAK,KAAK,UACpB;AAAA;AAAA;AAAA,MAVK;AAAA,IAWP,CACD,GACH;AAAA,IAEA,8CAAC,OAAE,WAAW,GAAG,YAAY,SAAS,6BAA6B,GAAG,kMAItE;AAAA,IAEC,KAAK,SAAS,UAAU,KAAK,SAC5B,8CAAC,eAAY,SAAQ,SAAQ,MAAI,MAAC,SAAS,KAAK,OAAO;AAAA,IAGzD,+CAAC,SAAI,WAAU,+CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAS;AAAA,UACT,SAAS;AAAA,UACT,WAAW,KAAK,SAAS;AAAA,UACzB,aAAY;AAAA,UACb;AAAA;AAAA,MAED;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,WAAS;AAAA,UACT,SAAQ;AAAA,UACR,SAAS;AAAA,UACT,UAAU,KAAK,SAAS;AAAA,UACzB;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,+CAAC,SAAI,WAAU,+CACb;AAAA,kDAAC,SAAI,WAAU,oGACZ,qBAAW,IAAI,CAAC,EAAE,OAAO,OAAO,YAAY,MAC3C;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,YAAY,OAAO,6BAA6B;AAAA,cAE7D;AAAA;AAAA,UACH;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO,OAAO,KAAK;AAAA,cACnB;AAAA,cACA,UAAU,CAAC,MAAM,YAAY,OAAO,EAAE,OAAO,KAAK;AAAA,cAClD,WAAW;AAAA,gBACT,YAAY;AAAA,gBACZ;AAAA,cACF;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,MAjBK;AAAA,IAkBP,CACD,GACH;AAAA,IAEA,+CAAC,SAAI,WAAU,+CACb;AAAA,oDAAC,YAAS,WAAS,MAAC,SAAS,YAAY,2BAEzC;AAAA,MACA,8CAAC,YAAS,WAAS,MAAC,SAAQ,aAAY,SAAS,cAAc,oBAE/D;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AACF,GAGG;AACD,SACE,+CAAC,SAAI,WAAU,+CACb;AAAA,kDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,2LAInE;AAAA,IAEC,KAAK,SAAS,UAAU,KAAK,SAC5B,8CAAC,eAAY,SAAQ,SAAQ,MAAI,MAAC,SAAS,KAAK,OAAO;AAAA,IAGzD;AAAA,MAAC;AAAA;AAAA,QACC,WAAS;AAAA,QACT,SAAS;AAAA,QACT,WAAW,KAAK,SAAS;AAAA,QACzB,aAAY;AAAA,QACb;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;;;AE1TA,IAAAC,iBAAiD;AA4CjD,IAAMC,iBAA0C,EAAE,MAAM,UAAU;AAClE,IAAM,cAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,WAAW,CAAC;AACd;AAUO,SAAS,mBACd,SACA,eACA,UAAqC,CAAC,GACZ;AAC1B,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,EAAE,MAAM,UAAU,KAAK,IAAI;AACjC,QAAM,CAAC,gBAAgB,iBAAiB,QACtC;AAAA,IACE,SAAS,SAAY,EAAE,MAAM,WAAW,WAAW,KAAK,IAAIA;AAAA,EAC9D;AACF,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,CAAC;AAC1C,QAAM,cAAU,4BAAY,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/D,QAAM,iBAAa;AAAA,IACjB,OAAO,cAAmD;AACxD,YAAM,SAAS,oBAAoB,SAAS,SAAS;AACrD,cAAQ;AAAA,IACV;AAAA,IACA,CAAC,UAAU,SAAS,OAAO;AAAA,EAC7B;AAGA,gCAAU,MAAM;AACd,QAAI,cAAc;AAElB,QAAI,CAAC,SAAS;AAGZ;AAAA,QACE,SAAS,SAAY,EAAE,MAAM,WAAW,WAAW,KAAK,IAAI;AAAA,MAC9D;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ,UAAI,SAAS,QAAW;AACtB,0BAAkBA,cAAa;AAAA,MACjC;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,UAAa,aAAa,GAAG;AACxC,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,MAAM,cAAc;AAC5C,wBAAkB,EAAE,MAAM,SAAS,QAAQ,oBAAoB,CAAC;AAChE,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,sBAAkBA,cAAa;AAC/B,aACG,oBAAoB,SAAS,aAAa,EAC1C,KAAK,CAAC,cAAc;AACnB,UAAI,CAAC,aAAa;AAChB,0BAAkB,EAAE,MAAM,WAAW,UAAU,CAAC;AAAA,MAClD;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,0BAAkB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAC7C;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,SAAS,SAAS,eAAe,QAAQ,CAAC;AAEjE,SAAO,EAAE,gBAAgB,SAAS,WAAW;AAC/C;;;AC7IA,IAAAC,iBAAiD;AA+CjD,IAAMC,iBAAuC,EAAE,MAAM,UAAU;AAiBxD,SAAS,gBACd,SACA,UAAkC,CAAC,GACZ;AACvB,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,CAAC,mBAAmB,oBAAoB,QAC5C;AAAA,IACE,SAAS,SAAY,EAAE,MAAM,WAAW,GAAG,KAAK,IAAIA;AAAA,EACtD;AACF,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,CAAC;AAC1C,QAAM,cAAU,4BAAY,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;AAG/D,gCAAU,MAAM;AACd,QAAI,cAAc;AAElB,QAAI,CAAC,SAAS;AACZ,UAAI,SAAS,QAAW;AACtB,6BAAqBA,cAAa;AAAA,MACpC;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,UAAa,aAAa,GAAG;AACxC,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,aAAa,MAAM,cAAc;AAC5C,2BAAqB,EAAE,MAAM,SAAS,QAAQ,oBAAoB,CAAC;AACnE,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,yBAAqBA,cAAa;AAClC,YAAQ,IAAI;AAAA,MACV,SAAS,uBAAuB,OAAO;AAAA,MACvC,SAAS,yBAAyB,OAAO;AAAA,IAC3C,CAAC,EACE,KAAK,CAAC,CAAC,wBAAwB,QAAQ,MAAM;AAC5C,UAAI,CAAC,aAAa;AAChB,6BAAqB;AAAA,UACnB,MAAM;AAAA,UACN,cAAc;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,6BAAqB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAChD;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,SAAS,QAAQ,CAAC;AAEzC,SAAO,EAAE,mBAAmB,QAAQ;AACtC;;;AJ6BM,IAAAC,uBAAA;AA9HN,IAAM,sBAAsB,CAAC,gBAC3B,mBAAmB,SAAS,YAAY,IAAI,MAAM;AAEpD,IAAM,iBAAkD;AAAA,EACtD,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AACZ;AAEA,IAAM,uBAAwD;AAAA,EAC5D,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AACZ;AA0EA,IAAM,gCAAgC;AAEtC,IAAM,+BAA+B;AAErC,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAOA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AACF,GAGc;AACZ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAW;AAAA,MACX,cAAW;AAAA,MACX,WAAU;AAAA,MAEV,yDAAC,SAAI,WAAU,wMACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA;AAAA,QACZ;AAAA,QACC;AAAA,SACH;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,0BAA0B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,EAAE,SAAS,IAAI,YAAY;AACjC,QAAM,EAAE,mBAAmB,QAAQ,IAAI,gBAAgB,SAAS,EAAE,KAAK,CAAC;AACxE,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAwB,IAAI;AACtE,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,yBAAS,KAAK;AAC5D,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,KAAK;AAChE,QAAM,CAAC,wBAAwB,yBAAyB,QACtD,yBAA+B,IAAI;AACrC,QAAM,mBAAe,uBAAO,IAAI;AAEhC,gCAAU,MAAM;AACd,iBAAa,UAAU;AACvB,WAAO,MAAM;AACX,mBAAa,UAAU;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,CAAC;AAOL,QAAM,CAAC,sBAAsB,uBAAuB,QAAI,yBAAS,KAAK;AACtE,gCAAU,MAAM;AACd,QAAI,kBAAkB,SAAS,WAAW;AACxC;AAAA,SACG,kBAAkB,aAAa,QAAQ,KAAK,CAAC,GAAG;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,mBAAmB,QAAQ,CAAC;AAChC,QAAM;AAAA,IACJ;AAAA,IACA,SAAS;AAAA,IACT;AAAA,EACF,IAAI,mBAAmB,SAAS,UAAU;AAAA,IACxC,SAAS;AAAA,EACX,CAAC;AACD,QAAM,kBACJ,eAAe,SAAS,YAAY,eAAe,YAAY,CAAC;AAGlE,QAAM,gBACJ,eAAe,SAAS,UACpB,UACA,eAAe,SAAS,YACtB,YACA;AAER,QAAM,iBAAiB,OAAO,OAAe;AAC3C,UAAM,WAAW,qBAAqB,EAAE,CAAC;AAGzC,YAAQ;AAAA,EACV;AAEA,QAAM,sBACJ,gCAAgC,SAC5B,8BACA,CAAC,gBAA6B;AAC5B,QAAI,YAAY,SAAS,YAAY;AACnC,yBAAmB,IAAI;AACvB;AAAA,IACF;AAMA,SACG,YAAY,SAAS,qBACpB,YAAY,SAAS,yBACvB,WAAW,WACV,WAAW,QAAQ,qBAAqB,SACzC;AACA,2BAAqB,IAAI;AACzB;AAAA,IACF;AACA,aAAS,kBAAkB,WAAW;AAAA,EACxC;AACN,QAAM,mBACJ,6BAA6B,SACzB,2BACA,MAAM,SAAS,eAAe;AAMpC,QAAM,0BAA0B,CAC9B,eACA,uBACG;AACH,UAAM,YAAY;AAChB,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,aAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,cAAM,MAAM,6BAA6B;AACzC,YAAI,CAAC,aAAa,QAAS;AAC3B,YAAI;AACF,gBAAMC,YAAW,MAAM,SAAS,yBAAyB,OAAO;AAChE,gBAAM,UAAUA,UAAS,KAAK,CAAC,MAAM,EAAE,OAAO,aAAa,GAAG;AAC9D,cAAI,YAAY,UAAa,YAAY,mBAAoB;AAAA,QAC/D,SAAS,GAAG;AAAA,QAEZ;AAAA,MACF;AACA,UAAI,aAAa,SAAS;AACxB,kCAA0B,IAAI;AAC9B,gBAAQ;AAAA,MACV;AAAA,IACF,GAAG;AAAA,EACL;AAEA,MAAI,kBAAkB,SAAS,WAAW;AACxC,QAAI,QAAS,QAAO;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAU;AAAA,QAEV,wDAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAAG,qCAEnE;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,kBAAkB,SAAS,SAAS;AACtC,QAAI,kBAAkB,WAAW,qBAAqB;AACpD,aAAO,yBAAyB,SAC9B,uBAEA,8CAAC,sBAAmB;AAAA,IAExB;AACA,QAAI,MAAO,QAAO;AAClB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAI;AAAA,QACJ,SAAQ;AAAA,QACR,WAAU;AAAA;AAAA,IACZ;AAAA,EAEJ;AAEA,QAAM,EAAE,cAAc,wBAAwB,SAAS,IAAI;AAC3D,QAAM,eAAe,uBAAuB,QAAQ,KAAK,CAAC;AAC1D,QAAM,iBAAiB,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC5D,QAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,eAAe,IAAI,EAAE,EAAE,CAAC;AACtE,QAAM,wBAAwB,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1E,QAAM,kBACJ,gBAAgB,OAAO,cAAc;AAEvC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,uDAAC,SAAI,WAAU,+CACb;AAAA,wDAAC,QAAG,WAAW,GAAG,YAAY,IAAI,2BAA2B,GAC1D,iBACH;AAAA,UACA,8CAAC,OAAE,WAAW,GAAG,YAAY,MAAM,6BAA6B,GAC7D,uBACH;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,WAAU,yEACZ,uBAAa,IAAI,CAAC,KAAK,UAAU;AAChC,gBAAM,aAAa,sBAAsB,IAAI,IAAI,EAAE;AACnD,gBAAM,QAAQ,WAAW,SAAS,GAAG,IAAI,eAAe,IAAI,IAAI;AAChE,gBAAM,mBACH,iBAAiB,eAAe,GAAG,IAAI,SACxC,qBAAqB,IAAI,IAAI;AAK/B,gBAAM,qBACJ,YAAY,aAAa,UACzB,gCAAgC;AAElC,cAAI;AACJ,cAAI,wBAAwB,MAAM;AAChC,4BAAgB;AAAA,UAClB,WAAW,oBAAoB;AAC7B,4BAAgB,MAAM,0BAA0B,IAAI,EAAE;AAAA,UACxD,WAAW,qBAAqB;AAC9B,4BAAgB,MAAM,oBAAoB,GAAG;AAAA,UAC/C;AAEA,cAAI;AACJ,cAAI,qBAAqB,MAAM;AAC7B,oCAAwB;AAAA,UAC1B,WAAW,kBAAkB;AAC3B,oCAAwB,MAAM,iBAAiB,GAAG;AAAA,UACpD;AAIA,gBAAM,oBAAoB,oBAAoB,GAAG;AACjD,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,IAAI,kBAAkB;AAAA,gBACpB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,oBAAoB,kBAAkB,CAAC;AAAA,cACzC;AAAA,cACA,UAAU,kBAAkB;AAAA,cAC5B,UAAU,MACR,iBAAiB,CAAC,SAAU,SAAS,QAAQ,OAAO,KAAM;AAAA,cAE5D,UAAU;AAAA,cACV,gBAAgB,oBAAoB,iBAAiB;AAAA,cACrD,eAAe,oBAAoB,gBAAgB;AAAA,cACnD,kBAAkB;AAAA;AAAA,YAfb,IAAI;AAAA,UAgBX;AAAA,QAEJ,CAAC,GACH;AAAA,QAEC,oBAAoB,gBACnB;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAI;AAAA,YACJ,SAAQ;AAAA;AAAA,QACV;AAAA,QAGD,cACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAS;AAAA,YACT,UAAU,oBAAoB;AAAA,YAC9B,SAAS;AAAA,YACV;AAAA;AAAA,QAED;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,SAAS,MAAM,mBAAmB,KAAK;AAAA,YACvC,aAAa,MAAM,QAAQ;AAAA;AAAA,QAC7B;AAAA,QAEC,2BAA2B,QAC1B,8CAAC,uBAAoB,SAAS,MAAM,0BAA0B,IAAI,GAChE;AAAA,UAAC;AAAA;AAAA,YACC,WACE,6BAA6B,aAC7B,sBAAsB,IAAI,sBAAsB,GAAG;AAAA,YAErD,OACE,sBAAsB,IAAI,sBAAsB,GAAG,YACnD;AAAA,YAEF,QAAQ,6BAA6B;AAAA,YACrC,aAAa,MACX;AAAA,cACE;AAAA,cACA,sBAAsB,IAAI,sBAAsB,GAAG,UACjD;AAAA,YACJ;AAAA;AAAA,QAEJ,GACF;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,SAAS,MAAM,qBAAqB,KAAK;AAAA,YACzC;AAAA,YACA;AAAA,YACA,QAAQ,UAAU;AAAA,YAClB;AAAA,YACA,aAAa,MAAM;AACjB,sBAAQ;AACR,+BAAiB;AAAA,YACnB;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAsBO,SAAS,sBACd,OACW;AACX,SACE,8CAAC,sBACC,wDAAC,6BAA2B,GAAG,OAAO,GACxC;AAEJ;;;AK9fA,IAAAC,iBAA4C;AAmC5C,IAAMC,iBAAsC,EAAE,MAAM,UAAU;AASvD,SAAS,mBACd,SAC0B;AAC1B,QAAM,EAAE,iBAAiB,OAAO,QAAQ,IAAI;AAC5C,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAE1C,QAAM,CAAC,kBAAkB,mBAAmB,QAC1C,yBAA+BA,cAAa;AAE9C,QAAM,iBAAa,uBAAO,CAAC;AAE3B,gCAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,QAAS;AAC1B,UAAM,iBAAiB,EAAE,WAAW;AAEpC,UAAM,OAAO,YAAY;AACvB,UAAI;AACF,cAAM,cAAc,MAAM,SAAS,KAAK,eAAe;AAAA,UACrD;AAAA,UACA;AAAA,QACF,CAAC;AACD,YAAI,mBAAmB,WAAW,QAAS;AAC3C,4BAAoB,EAAE,MAAM,WAAW,YAAY,CAAC;AAAA,MACtD,QAAQ;AACN,YAAI,mBAAmB,WAAW,QAAS;AAC3C,4BAAoB,EAAE,MAAM,QAAQ,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,SAAK;AAEL,WAAO,MAAM;AACX,QAAE,WAAW;AAAA,IACf;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,iBAAiB,OAAO,OAAO,CAAC;AAEvD,SAAO,EAAE,iBAAiB;AAC5B;;;ACjFA,IAAAC,iBAA4C;AA8CrC,SAAS,aAAa,SAAkD;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,EACF,IAAI;AACJ,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAE1C,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA2B,IAAI;AACzD,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,IAAI;AAC/C,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,KAAK;AAEtD,QAAM,oBAAgB,uBAAO,KAAK;AAClC,QAAM,kBAAc,uBAAO,KAAK;AAChC,QAAM,iBAAa,uBAAO,CAAC;AAE3B,gCAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,SAAS;AACZ,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAM,iBAAiB,EAAE,WAAW;AACpC,kBAAc,UAAU;AAExB,UAAM,YAAY,YAAY;AAC5B,UAAI,wBAAwB,KAAM;AAClC,UAAI,cAAc,QAAS;AAC3B,oBAAc,UAAU;AAExB,UAAI,YAAY,SAAS;AACvB,wBAAgB,IAAI;AAAA,MACtB;AAEA,UAAI;AACF,cAAM,UAAU,MAAM,SAAS,KAAK,WAAW;AAAA,UAC7C;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ,QAAQ,YAAY;AAAA,QACtB,CAAC;AACD,YAAI,mBAAmB,WAAW,QAAS;AAE3C;AAAA,UACE,UAAU;AAAA,YACR;AAAA,YACA,YAAY;AAAA,YACZ;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,YAAY,SAAS;AACxB,sBAAY,UAAU;AACtB,uBAAa,KAAK;AAAA,QACpB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,YAAI,mBAAmB,WAAW,SAAS;AACzC,wBAAc,UAAU;AACxB,0BAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAEA,cAAU;AACV,UAAM,WAAW,YAAY,WAAW,cAAc;AACtD,WAAO,MAAM;AACX,oBAAc,QAAQ;AACtB,QAAE,WAAW;AACb,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,EAAE,OAAO,WAAW,aAAa;AAC1C;;;ACvIA,IAAAC,iBAA4C;AA2CrC,SAAS,qBACd,SAC4B;AAC5B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,EACF,IAAI;AACJ,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAE1C,QAAM,CAAC,UAAU,WAAW,QAAI,yBAE9B,oBAAI,IAAI,CAAC;AACX,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,IAAI;AAE/C,QAAM,iBAAa,uBAAO,CAAC;AAC3B,QAAM,oBAAgB,uBAAO,KAAK;AAIlC,QAAM,YAAY,OAAO,KAAK,GAAG;AAEjC,gCAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,SAAS;AACZ,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAM,UAAU,UAAU,MAAM,GAAG;AACnC,UAAM,iBAAiB,EAAE,WAAW;AACpC,kBAAc,UAAU;AACxB,QAAI,eAAe;AAEnB,mBAAe,gBAAgB;AAG7B,UAAI,cAAc,QAAS;AAC3B,oBAAc,UAAU;AACxB,UAAI,cAAc;AAChB,qBAAa,IAAI;AAAA,MACnB;AACA,YAAM,UAAU,MAAM,QAAQ;AAAA,QAC5B,QAAQ;AAAA,UAAI,CAAC,WACX,SAAS,MAAM,gBAAgB;AAAA,YAC7B,cAAc,eAAe,gBAAgB,QAAQ,KAAK;AAAA,YAC1D,OAAO;AAAA,YACP;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AACA,UAAI,mBAAmB,WAAW,QAAS;AAC3C,oBAAc,UAAU;AAExB,YAAM,OAAO,oBAAI,IAAqC;AACtD,cAAQ,QAAQ,CAAC,QAAQ,MAAM;AAC7B,cAAM,SAAS,QAAQ,CAAC;AACxB,aAAK;AAAA,UACH;AAAA,UACA,OAAO,WAAW,cAAc,OAAO,MAAM,UAAU;AAAA,QACzD;AAAA,MACF,CAAC;AACD,kBAAY,IAAI;AAChB,mBAAa,KAAK;AAClB,qBAAe;AAAA,IACjB;AAEA,kBAAc;AACd,UAAM,WAAW,YAAY,eAAe,cAAc;AAC1D,WAAO,MAAM;AACX,oBAAc,QAAQ;AACtB,QAAE,WAAW;AAAA,IACf;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,SAAS,OAAO,WAAW,gBAAgB,OAAO,CAAC;AAE1E,SAAO,EAAE,UAAU,UAAU;AAC/B;;;ACxHA,IAAAC,iBAAkC;AAgD3B,SAAS,iBAAiB,SAAwC;AACvE,QAAM,EAAE,SAAS,IAAI,YAAY;AAEjC,QAAM,2BAAuB,uBAAO,QAAQ,iBAAiB;AAC7D,QAAM,mBAAe,uBAAO,QAAQ,SAAS;AAC7C,QAAM,mBAAe,uBAAO,QAAQ,SAAS;AAE7C,uBAAqB,UAAU,QAAQ;AACvC,eAAa,UAAU,QAAQ;AAC/B,eAAa,UAAU,QAAQ;AAE/B,QAAM,4BAAwB,uBAAO,KAAK;AAE1C,gCAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,QAAI,CAAC,OAAO,IAAI,MAAM,KAAK,CAAC,OAAO,IAAI,OAAO,EAAG;AAEjD,QAAI,sBAAsB,QAAS;AAEnC,UAAM,cAAc,SAAS,cAAc;AAC3C,QAAI,YAAY,SAAS,SAAS;AAChC,WAAK,QAAQ,QAAQ,aAAa,QAAQ,YAAY,MAAM,CAAC,EAAE;AAAA,QAC7D,MAAM;AAAA,QAAC;AAAA,MACT;AACA;AAAA,IACF;AAEA,0BAAsB,UAAU;AAChC,QAAI,YAAY;AAEhB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,KAAK,MAAM,qBAAqB,QAAQ;AAAA,UAC5C,MAAM,YAAY;AAAA,UAClB,cAAc,YAAY;AAAA,QAC5B,CAAC;AAED,YAAI,UAAW;AAEf,YAAI,CAAC,IAAI;AACP,gCAAsB,UAAU;AAChC,gBAAM,aAAa,QAAQ,yBAAyB;AACpD;AAAA,QACF;AAEA,cAAM,SAAS,KAAK;AAEpB,YAAI,UAAW;AAEf,cAAM,aAAa,QAAQ;AAAA,MAC7B,QAAQ;AACN,YAAI,UAAW;AACf,8BAAsB,UAAU;AAChC,cAAM,aAAa,QAAQ,yBAAyB;AAAA,MACtD;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,kBAAY;AACZ,4BAAsB,UAAU;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AACf;;;AChHA,IAAAC,iBAAoC;AAiCpC,IAAMC,iBAAuC,EAAE,MAAM,UAAU;AAcxD,SAAS,gBACd,SACA,UAAkC,CAAC,GACZ;AACvB,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,CAAC,mBAAmB,oBAAoB,QAC5C;AAAA,IACE,SAAS,SACL,EAAE,MAAM,WAAW,aAAa,KAAK,IACrCA;AAAA,EACN;AAEF,gCAAU,MAAM;AACd,QAAI,cAAc;AAElB,QAAI,CAAC,SAAS;AACZ,UAAI,SAAS,QAAW;AACtB,6BAAqBA,cAAa;AAAA,MACpC;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,QAAW;AACtB,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,yBAAqBA,cAAa;AAClC,aACG,kBAAkB,OAAO,EACzB,KAAK,CAAC,gBAAgB;AACrB,UAAI,CAAC,aAAa;AAChB,6BAAqB,EAAE,MAAM,WAAW,YAAY,CAAC;AAAA,MACvD;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,6BAAqB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAChD;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,SAAS,IAAI,CAAC;AAErC,SAAO,EAAE,kBAAkB;AAC7B;;;ACtGA,IAAAC,iBAAoC;AAiCpC,IAAMC,iBAAyC,EAAE,MAAM,UAAU;AAe1D,SAAS,kBACd,SACA,UAAoC,CAAC,GACZ;AACzB,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,CAAC,qBAAqB,sBAAsB,QAChD;AAAA,IACE,SAAS,SACL,EAAE,MAAM,WAAW,gBAAgB,KAAK,IACxCA;AAAA,EACN;AAEF,gCAAU,MAAM;AACd,QAAI,cAAc;AAGlB,QAAI,CAAC,SAAS;AACZ,UAAI,SAAS,QAAW;AACtB,+BAAuBA,cAAa;AAAA,MACtC;AACA,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,SAAS,QAAW;AACtB,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,2BAAuBA,cAAa;AACpC,aAAS,UACN,oBAAoB,OAAO,EAC3B,KAAK,CAAC,mBAAmB;AACxB,UAAI,CAAC,aAAa;AAChB,+BAAuB,EAAE,MAAM,WAAW,eAAe,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,+BAAuB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAClD;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,SAAS,IAAI,CAAC;AAErC,SAAO,EAAE,oBAAoB;AAC/B;","names":["userAgent","import_viem","import_viem","import_react","import_jsx_runtime","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","LOADING_STATE","import_jsx_runtime","SumsubWebSdk","import_lucide_react","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_react","IDLE_SIGN","LOADING_STATE","import_jsx_runtime","import_react","LOADING_STATE","import_react","LOADING_STATE","import_jsx_runtime","statuses","import_react","LOADING_STATE","import_react","import_react","import_react","import_react","LOADING_STATE","import_react","LOADING_STATE"]}
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/CoinListProvider.tsx","../../src/shared/core/utils/crypto.ts","../../src/client/core/api/middleware/device-id.ts","../../src/shared/api/frontline/config.ts","../../src/shared/api/http-attributes.ts","../../src/client/core/api/middleware/user-agent.ts","../../src/shared/api/http.ts","../../src/shared/types/errors.ts","../../src/shared/core/observability/log-cause.ts","../../src/shared/core/observability/internal-logger.ts","../../src/shared/api/http-client.ts","../../src/shared/api/middleware/attach-session-middleware.ts","../../src/shared/api/middleware/idempotency-key.ts","../../src/shared/api/middleware/request-retry.ts","../../src/shared/api/middleware/session-renewal.ts","../../src/shared/api/authenticated-api-client.ts","../../src/client/core/api/api-client.ts","../../src/shared/types/oauth.ts","../../src/shared/core/auth/pkce.ts","../../src/client/core/auth/client-auth-namespace.ts","../../src/client/core/blockchain/wallet-error.ts","../../src/shared/core/blockchain/erc20/abi.ts","../../src/client/core/blockchain/erc20/approval.ts","../../src/shared/api/pagination.ts","../../src/shared/types/blockchain/core.ts","../../src/shared/core/blockchain/bps.ts","../../src/shared/types/blockchain/ui.ts","../../src/shared/core/blockchain/chain.ts","../../src/shared/types/providers/superstate/swap.ts","../../src/shared/api/frontline/providers/superstate/swap.ts","../../src/shared/core/blockchain/erc20/erc20-namespace.ts","../../src/shared/core/blockchain/formatters.ts","../../src/shared/core/blockchain/math.ts","../../src/shared/core/blockchain/token-registry.ts","../../src/shared/types/pagination.ts","../../src/shared/types/asset.ts","../../src/shared/types/offer.ts","../../src/shared/types/offer-detail.ts","../../src/shared/types/providers/coin-list/token-sale.ts","../../src/shared/api/frontline/providers/coin-list/token-sale.ts","../../src/shared/core/checkout/coin-list/token-sale-namespace.ts","../../src/shared/core/checkout/ondo/constants.ts","../../src/shared/core/checkout/ondo/math.ts","../../src/shared/types/trading.ts","../../src/shared/types/providers/ondo/ondo.ts","../../src/shared/api/frontline/providers/ondo/ondo.ts","../../src/shared/core/checkout/ondo/ondo-namespace.ts","../../src/shared/core/checkout/superstate/blockchain/abi.ts","../../src/shared/core/checkout/superstate/blockchain/math.ts","../../src/shared/core/checkout/superstate/blockchain/quote.ts","../../src/shared/core/checkout/superstate/blockchain/status.ts","../../src/shared/core/checkout/superstate/blockchain/swapped-event.ts","../../src/shared/core/checkout/superstate/constants.ts","../../src/shared/core/checkout/superstate/formatters.ts","../../src/shared/core/checkout/superstate/swap-namespace.ts","../../src/shared/api/frontline/offers.ts","../../src/shared/core/offers/offers-namespace.ts","../../src/shared/types/document-submission.ts","../../src/shared/api/frontline/documents.ts","../../src/shared/types/kyc.ts","../../src/shared/api/frontline/kyc.ts","../../src/shared/types/pii.ts","../../src/shared/api/frontline/pii.ts","../../src/shared/types/requirement.ts","../../src/shared/api/frontline/requirements.ts","../../src/shared/core/requirements/requirements-namespace.ts","../../src/shared/api/nabu/tokens.ts","../../src/shared/types/token-metadata.ts","../../src/shared/core/tokens/tokens-namespace.ts","../../src/shared/types/offer-option-address.ts","../../src/shared/types/wallet-ownership-challenge.ts","../../src/shared/api/frontline/wallet-connect.ts","../../src/shared/core/wallets/wallets-namespace.ts","../../src/shared/types/blockchain/wallet-error.ts","../../src/client/core/checkout/coin-list/token-sale-flows.ts","../../src/client/core/observability/flow-logging.ts","../../src/client/core/checkout/coin-list/client-token-sale-namespace.ts","../../src/shared/core/blockchain/address.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/utils/open-in-new-tab.ts","../../src/client/core/requirements/client-requirements-namespace.ts","../../src/client/core/support/client-support-namespace.ts","../../src/shared/api/nabu/config.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/design-system/logos/CoinListWordmark.tsx","../../src/client/components/design-system/PoweredByCoinList.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/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/OndoAmountView.tsx","../../src/client/components/checkout/ondo/buy/confirmation/OndoOrderConfirmed.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/OndoReviewView.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/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/buy/sidebar/OndoSidebarView.tsx","../../src/client/components/checkout/ondo/buy/wallet/OndoWalletSelectView.tsx","../../src/client/components/checkout/shared/selection/SelectableOptionRow.tsx","../../src/client/components/checkout/ondo/buy/OndoBuyCheckoutView.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/ondo/buy/useOndoBuyCheckoutViewModel.ts","../../src/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel.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/useOndoReviewViewModel.ts","../../src/client/hooks/checkout/ondo/shared/data/useOndoSwapTransaction.ts","../../src/client/hooks/checkout/ondo/shared/data/ondo-load-error.ts","../../src/client/ui/hooks/useCountdown.ts","../../src/client/hooks/checkout/ondo/buy/sidebar/useOndoSidebarViewModel.ts","../../src/client/hooks/checkout/ondo/buy/wallet/useOndoWalletSelectViewModel.ts","../../src/client/hooks/checkout/ondo/shared/data/useOndoPrice.ts","../../src/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus.ts","../../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/CheckoutContainer.tsx","../../src/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer.tsx","../../src/client/components/checkout/superstate/swap/SuperstateSwapCheckoutContainer.tsx","../../src/client/components/offers/grid/OfferCard.tsx","../../src/client/components/offers/grid/OffersGridView.tsx","../../src/client/hooks/offers/grid/useOffersGridViewModel.ts","../../src/client/hooks/offers/data/useOffers.ts","../../src/client/ui/format/date.ts","../../src/client/hooks/offers/grid/useOffersGridViewModel.types.ts","../../src/client/components/offers/grid/OffersGridContainer.tsx","../../src/client/components/requirements/checklist/ConnectedWalletList.tsx","../../src/client/components/requirements/checklist/RequirementItem.tsx","../../src/client/components/design-system/StepStatusIcon.tsx","../../src/client/components/requirements/checklist/RequirementsChecklistView.tsx","../../src/client/components/requirements/checklist/VerificationOverlay.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/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/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/checklist/useRequirementsChecklistViewModel.ts","../../src/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.types.ts","../../src/client/hooks/requirements/data/useOptionAddresses.ts","../../src/client/hooks/requirements/data/useRequirements.ts","../../src/client/components/requirements/checklist/RequirementsChecklistContainer.tsx","../../src/client/core/observability/pino-client-logger.ts","../../src/shared/core/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/tokens/data/useTokenMetadata.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\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/OndoAmountView';\nexport * from '@/client/components/checkout/ondo/buy/confirmation/OndoOrderConfirmed';\nexport * from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutContainer';\nexport * from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutView';\nexport * from '@/client/components/checkout/ondo/buy/review/OndoReviewView';\nexport * from '@/client/components/checkout/ondo/buy/sidebar/OndoSidebarView';\nexport * from '@/client/components/checkout/ondo/buy/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 {\n OfferCard,\n type Props as OfferCardProps,\n} from '@/client/components/offers/grid/OfferCard';\nexport * from '@/client/components/offers/grid/OffersGridContainer';\nexport * from '@/client/components/offers/grid/OffersGridView';\n// Components: requirements\nexport * from '@/client/components/requirements/checklist/ConnectedWalletList';\nexport * from '@/client/components/requirements/checklist/RequirementItem';\nexport * from '@/client/components/requirements/checklist/RequirementsChecklistContainer';\nexport * from '@/client/components/requirements/checklist/RequirementsChecklistView';\nexport * from '@/client/components/requirements/checklist/VerificationOverlay';\nexport * from '@/client/components/requirements/identity-verification/IdentityVerificationContainer';\nexport * from '@/client/components/requirements/identity-verification/IdentityVerificationView';\nexport * from '@/client/components/requirements/tax-document/TaxDocumentModalContainer';\nexport * from '@/client/components/requirements/tax-document/TaxDocumentModalView';\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/blockchain/erc20/approval';\nexport * from '@/client/core/blockchain/wallet-error';\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';\n// Observability: the `Logger` a host implements and hands to CoinListProvider,\n// plus the console implementation to start from.\nexport * from '@/client/core/observability/pino-client-logger';\nexport * from '@/client/core/requirements/client-requirements-namespace';\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 under `ondo/shared`\n// go out too, so a partner can compose their own viewmodel.\nexport * from '@/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/sidebar/useOndoSidebarViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/sidebar/useOndoSidebarViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\nexport * from '@/client/hooks/checkout/ondo/buy/wallet/useOndoWalletSelectViewModel';\nexport * from '@/client/hooks/checkout/ondo/buy/wallet/useOndoWalletSelectViewModel.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/useOndoSwapTransaction';\nexport * from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\n// Hooks: checkout (shared)\nexport * from '@/client/hooks/checkout/shared/checkout-ui.types';\nexport * from '@/client/hooks/checkout/shared/checkout-wallet.types';\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';\n// Hooks: requirements\nexport * from '@/client/hooks/requirements/checklist/useRequirementsChecklistViewModel';\nexport * from '@/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.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';\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/useErc20TokenBalances';\n// Hooks: tokens\nexport * from '@/client/hooks/tokens/data/useTokenMetadata';\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 '@/shared/api/http';\nexport * from '@/shared/types/blockchain/evm-wallet';\nexport * from '@/shared/types/blockchain/wallet-error';\nexport * from '@/shared/types/kyc';\nexport * from '@/shared/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 '@/shared/core/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 { RequestId } from '@/shared/types/logger';\nimport type { ClientCredentialsOAuth } from '@/shared/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 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 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 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 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 '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/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 '@/shared/api/http-attributes';\nimport type { QueryParamValues } from '@/shared/types/http';\nimport type { RequestId } from '@/shared/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","/**\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","import { apiErrorCode, HttpError } from '@/shared/api/http';\nimport {\n InvariantError,\n NotAuthenticatedError,\n NotImplementedError,\n ValidationError,\n} from '@/shared/types/errors';\nimport type { FrontlineEventId, LogCause } from '@/shared/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 four 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 `@/shared/api`, which `@/shared/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 NotAuthenticatedError) {\n return { type: 'not-authenticated' };\n }\n if (error instanceof NotImplementedError) {\n return { type: 'not-implemented' };\n }\n return { type: 'generic-error', name: errorName(error) };\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","import {\n classifyLogCause,\n describeErrorUnredacted,\n} from '@/shared/core/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 '@/shared/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 '@/shared/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/shared/api/http';\nimport { buildUrlWithQueryParams, makeRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n Logger,\n RequestId,\n UnredactedFields,\n} from '@/shared/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 response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) =>\n this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >,\n })) as HttpResponse<TResponse>;\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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport function attachSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): BeforeRequestMiddleware {\n return async (request: HttpRequest): Promise<HttpRequest> => {\n if (!Attributes.isProtected(request.attributes)) {\n return request;\n }\n\n let accessToken = await fetchAccessToken(false);\n if (!accessToken) {\n const clientCreds = Attributes.getClientCredentials(request.attributes);\n if (clientCreds) {\n accessToken = clientCreds;\n }\n }\n\n if (accessToken === null) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n Authorization: `Bearer ${accessToken.value}`,\n },\n };\n };\n}\n","import { HEADER_IDEMPOTENCY_KEY } from '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport { getUUIDv4 } from '@/shared/core/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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/shared/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 (!isRetryableStatus(response.status)) {\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 '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/shared/api/http-client';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport function renewSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\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(true);\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 '@/shared/api/http';\nimport { HttpError } from '@/shared/api/http';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\nimport { HttpClient } from '@/shared/api/http-client';\nimport { attachSessionMiddleware } from '@/shared/api/middleware/attach-session-middleware';\nimport { idempotencyKeyMiddleware } from '@/shared/api/middleware/idempotency-key';\nimport { requestRetryMiddleware } from '@/shared/api/middleware/request-retry';\nimport { renewSessionMiddleware } from '@/shared/api/middleware/session-renewal';\nimport type { Logger } from '@/shared/types/logger';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\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: (refresh: boolean) => Promise<OAuthAccessToken | null>,\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 '@/shared/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/shared/api/http';\nimport type { Logger } from '@/shared/types/logger';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\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 { Newtype } from '@/shared/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 '@/shared/core/utils/crypto';\nimport type {\n CodeChallenge as CodeChallengeType,\n CodeVerifier as CodeVerifierType,\n PKCEState as PKCEStateType,\n} from '@/shared/types/oauth';\nimport {\n type ClientId,\n CodeChallenge,\n CodeVerifier,\n PKCEState,\n type RedirectUri,\n} from '@/shared/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 '@/shared/api/frontline/config';\nimport { generatePKCEParams, type PKCEConfig } from '@/shared/core/auth/pkce';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Logger } from '@/shared/types/logger';\nimport { AuthorizationCode, CodeVerifier } from '@/shared/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 '@/shared/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/blockchain/wallet-error';\nimport { ERC20_ABI } from '@/shared/core/blockchain/erc20/abi';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport type {\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/shared/types/blockchain/wallet-error';\nimport type { TokenAllowance } from '@/shared/types/providers/superstate/swap';\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: TokenAllowance;\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.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.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 '@/shared/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 { InvariantError, ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type EthereumChain = 'ethereum_mainnet' | 'ethereum_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};\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\nexport const Chain = (value: string): Chain => {\n if (\n !Object.keys(ETHEREUM_CHAINS).includes(value) &&\n !Object.keys(SOLANA_CHAINS).includes(value)\n ) {\n throw new ValidationError(`Unsupported chain: \"${value}\"`);\n }\n return value as Chain;\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 }\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 {\n assertUint256,\n Bps,\n type Uint256,\n} from '@/shared/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 { Newtype } from '@/shared/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 { Hash } from 'viem';\nimport type { EthereumChain } from '@/shared/types/blockchain/core';\nimport { TxExplorerUrl } from '@/shared/types/blockchain/ui';\nimport { ValidationError } from '@/shared/types/errors';\n\n/**\n * The one EIP-155 table. `satisfies` makes a new {@link EthereumChain} a\n * compile error here until its id is added, which is what keeps both\n * directions below total.\n */\nconst CHAIN_IDS = {\n ethereum_mainnet: 1,\n ethereum_sepolia: 11155111,\n} as const satisfies Record<EthereumChain, number>;\n\nexport function getChainId(chain: EthereumChain): number {\n return CHAIN_IDS[chain];\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(CHAIN_IDS) as EthereumChain[];\n const chain = chains.find((c) => String(CHAIN_IDS[c]) === 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 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 default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n","import {\n EvmContractAddress,\n HexEncodedTransactionData,\n parseUint256,\n type Uint256,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/providers/superstate/swap';\n\n/**\n * Whether a wallet is authorized to interact with a given swap contract.\n */\nexport type SwapAuthorization = {\n authorized: boolean;\n};\n\nexport const SwapAuthorization = {\n fromDto: (dto: WalletAuthorizationDto): SwapAuthorization => ({\n authorized: dto.authorized,\n }),\n};\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 fromDto: (dto: SwapPreviewDto): SwapPreview => ({\n inputAmount: parseUint256(\n BigInt(dto.pay_input_amount),\n 'SwapPreview.pay_input_amount'\n ),\n fee: parseUint256(BigInt(dto.fee), 'SwapPreview.fee'),\n outputAmount: parseUint256(\n BigInt(dto.receive_output_amount),\n 'SwapPreview.receive_output_amount'\n ),\n }),\n};\n\n/**\n * The on-chain state of a swap contract.\n *\n * - `stopped`: non-zero when the contract is paused/halted.\n * - `swapLevel`: the current swap level/tier.\n */\nexport type SwapStatus = {\n stopped: Uint256;\n swapLevel: Uint256;\n};\n\nexport const SwapStatus = {\n fromDto: (dto: SwapStatusDto): SwapStatus => ({\n stopped: parseUint256(BigInt(dto.stopped), 'SwapStatus.stopped'),\n swapLevel: parseUint256(BigInt(dto.swap_level), 'SwapStatus.swap_level'),\n }),\n};\n\n// TODO: TokenAllowance and TokenBalance are generic ERC-20, not swap — move\n// them and their DTOs to /types/erc-20 alongside Erc20Namespace. Deferred:\n// it touches ~20 importers plus both barrels, so it wants its own PR.\n/**\n * The ERC-20 allowance an owner has granted a spender for a token.\n */\nexport type TokenAllowance = {\n allowance: Uint256;\n};\n\nexport const TokenAllowance = {\n fromDto: (dto: TokenAllowanceDto): TokenAllowance => ({\n allowance: parseUint256(BigInt(dto.allowance), 'TokenAllowance.allowance'),\n }),\n};\n\n/**\n * The raw ERC-20 balance an owner holds of a token (uint256).\n */\nexport type TokenBalance = {\n balance: Uint256;\n};\n\nexport const TokenBalance = {\n fromDto: (dto: TokenBalanceDto): TokenBalance => ({\n balance: parseUint256(BigInt(dto.balance), 'TokenBalance.balance'),\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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/shared/core/blockchain/erc20/erc20-namespace.types';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/shared/core/checkout/superstate/swap-namespace.types';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapOutputTokenDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/providers/superstate/swap';\nimport {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n TokenAllowance,\n TokenBalance,\n} from '@/shared/types/providers/superstate/swap';\n\nexport async function getSwapAuthorization(\n api: Sender,\n params: GetSwapAuthorizationParams\n): Promise<SwapAuthorization> {\n const dto = await api.send<WalletAuthorizationDto>({\n method: 'GET',\n url: '/v1/wallet/authorized',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n wallet_address: params.walletAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapAuthorization.fromDto(dto);\n}\n\nexport async function getSwapOutputToken(\n api: Sender,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const dto = await api.send<SwapOutputTokenDto>({\n method: 'GET',\n url: '/v1/swap/output-token',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return toErc20Asset(dto);\n}\n\nexport async function getSwapPreview(\n api: Sender,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const dto = await api.send<SwapPreviewDto>({\n method: 'GET',\n url: '/v1/swap/preview',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n input_token: params.inputToken,\n amount: params.amount.toString(),\n },\n attributes: Attributes.protected(),\n });\n return SwapPreview.fromDto(dto);\n}\n\nexport async function getSwapStatus(\n api: Sender,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const dto = await api.send<SwapStatusDto>({\n method: 'GET',\n url: '/v1/swap/status',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapStatus.fromDto(dto);\n}\n\nexport async function getTokenAllowance(\n api: Sender,\n params: GetTokenAllowanceParams\n): Promise<TokenAllowance> {\n const dto = await api.send<TokenAllowanceDto>({\n method: 'GET',\n url: '/v1/token/allowance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n spender: params.spender,\n },\n attributes: Attributes.protected(),\n });\n return TokenAllowance.fromDto(dto);\n}\n\nexport async function getTokenBalance(\n api: Sender,\n params: GetTokenBalanceParams\n): Promise<TokenBalance> {\n const dto = await api.send<TokenBalanceDto>({\n method: 'GET',\n url: '/v1/token/balance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n },\n attributes: Attributes.protected(),\n });\n return TokenBalance.fromDto(dto);\n}\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\nfunction toErc20Asset(dto: SwapOutputTokenDto): Erc20Asset {\n return {\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n };\n}\n","import {\n getTokenAllowance,\n getTokenBalance,\n} from '@/shared/api/frontline/providers/superstate/swap';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/shared/core/blockchain/erc20/erc20-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n TokenAllowance,\n TokenBalance,\n} from '@/shared/types/providers/superstate/swap';\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 */\nexport interface Erc20Namespace {\n /**\n * Reads the ERC-20 allowance an `owner` has granted a `spender`.\n */\n getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance>;\n\n /**\n * Reads the raw ERC-20 balance an `owner` holds of a token.\n */\n getBalance(params: GetTokenBalanceParams): Promise<TokenBalance>;\n}\n\nexport class Erc20NamespaceImpl implements Erc20Namespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ERC20');\n }\n\n async getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance> {\n return this.log.wrap('getAllowance', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getTokenAllowance(this.ctx.api, params);\n });\n }\n\n async getBalance(params: GetTokenBalanceParams): Promise<TokenBalance> {\n return this.log.wrap('getBalance', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getTokenBalance(this.ctx.api, params);\n });\n }\n}\n","import { formatUnits } from 'viem';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport { AssetDecimals } from '@/shared/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/shared/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\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 =\n maxFractionDigits !== undefined\n ? Math.min(maxFractionDigits, amount.decimals)\n : Math.min(2, amount.decimals);\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 const fraction =\n minFractionDigits === 0 ? '' : fractionPart.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 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 { parseUnits } from 'viem';\nimport {\n type AssetDecimals,\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/shared/types/blockchain/core';\nimport { ValidationError } from '@/shared/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 or missing digits on either side\n if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n const [, fraction = ''] = trimmed.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(trimmed, 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 {\n AssetDecimals,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type KnownAssetSymbol,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport { InvariantError } from '@/shared/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};\n\nconst USDT_ADDRESSES: TokenAddresses = {\n ethereum_mainnet: EvmContractAddress(\n '0xdac17f958d2ee523a2206206994597c13d831ec7'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x7169D38820dfd117C3FA1f22a697dBA58d90BA06'\n ),\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 contractAddress: (\n symbol: KnownAssetSymbol,\n chain: EthereumChain\n ): EvmContractAddress => {\n switch (symbol) {\n case 'USDC':\n return USDC_ADDRESSES[chain];\n case 'USDT':\n return USDT_ADDRESSES[chain];\n default:\n throw new InvariantError(`Unknown asset symbol: ${symbol}`);\n }\n },\n};\n","import type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { QueryParamValue } from '@/shared/types/http';\nimport type { Newtype } from '@/shared/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 data: dto.data.map(itemMapper),\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 '@/shared/types/dto/asset';\nimport type { Newtype } from '@/shared/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 { Chain, EvmContractAddress } from '@/shared/types/blockchain/core';\nimport type {\n OfferDto,\n OfferTokenDto,\n OfferTypeDto,\n} from '@/shared/types/dto/offer';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/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\nexport type Offer = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n startsAt: Date;\n endsAt: Date | null;\n tokens: OfferToken[];\n};\n\nexport const Offer = {\n fromDto: (dto: OfferDto): Offer => {\n // The same guard, and the same wording, as every array field in\n // `OfferDetail.fromDto`: a backend sending a non-array is a\n // `ValidationError` naming the field, which `classifyLogCause` maps to the\n // `validation` remedy. Left to `.map`, it would surface as a bare\n // `TypeError` classified `generic-error`, naming neither the field nor\n // whose fault it was.\n if (!Array.isArray(dto.tokens)) {\n throw new ValidationError(\n `Offer.tokens: expected an array, got ${typeof dto.tokens}`\n );\n }\n\n return {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n tokens: dto.tokens.map(OfferToken.fromDto),\n };\n },\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","import { notBlankStringOrNull } from '@/shared/core/utils/crypto';\nimport { Asset } from '@/shared/types/asset';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailTermDto,\n} from '@/shared/types/dto/offer-detail';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\nimport {\n OfferId,\n OfferSlug,\n OfferToken,\n type OfferType,\n} from '@/shared/types/offer';\n\nexport type OfferDetail = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n name: string;\n\n asset: Asset;\n fundingAssets: Asset[];\n tokens: OfferToken[];\n\n about: string | null;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n category: string;\n\n startsAt: Date;\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\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n if (!Array.isArray(dto.funding_assets)) {\n throw new ValidationError(\n `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`\n );\n }\n\n if (!Array.isArray(dto.options)) {\n throw new ValidationError(\n `OfferDetail.options: expected an array, got ${typeof dto.options}`\n );\n }\n\n if (!Array.isArray(dto.terms)) {\n throw new ValidationError(\n `OfferDetail.terms: expected an array, got ${typeof dto.terms}`\n );\n }\n\n if (!Array.isArray(dto.links)) {\n throw new ValidationError(\n `OfferDetail.links: expected an array, got ${typeof dto.links}`\n );\n }\n\n if (!Array.isArray(dto.faqs)) {\n throw new ValidationError(\n `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`\n );\n }\n\n if (!Array.isArray(dto.milestones)) {\n throw new ValidationError(\n `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`\n );\n }\n\n if (!Array.isArray(dto.tokens)) {\n throw new ValidationError(\n `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`\n );\n }\n\n return {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n name: dto.name,\n\n asset: Asset.fromDto(dto.asset),\n fundingAssets: dto.funding_assets.map(Asset.fromDto),\n tokens: dto.tokens.map(OfferToken.fromDto),\n\n about: notBlankStringOrNull(dto.about),\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n category: dto.category,\n\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: dto.faqs.map(FaqItem.fromDto),\n links: dto.links.map(Link.fromDto),\n milestones: dto.milestones.map(Milestone.fromDto),\n options: dto.options.map(OfferOption.fromDto),\n terms: dto.terms.map(TermItem.fromDto),\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 '@/shared/core/utils/crypto';\nimport { Asset, type AssetId } from '@/shared/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/shared/types/dto/providers/coin-list/token-sale';\nimport type { QueryParamValue } from '@/shared/types/http';\nimport type { Newtype } from '@/shared/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/shared/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/shared/types/offer-detail';\nimport { PaginationParams } from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { fetchAllPages } from '@/shared/api/pagination';\nimport type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { ParticipationDto } from '@/shared/types/dto/providers/coin-list/token-sale';\nimport type { OfferId } from '@/shared/types/offer';\nimport { PaginatedResponse } from '@/shared/types/pagination';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/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 '@/shared/api/frontline/providers/coin-list/token-sale';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { PaginatedResponse } from '@/shared/types/pagination';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/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: SharedNamespaceContext) {\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 { USDC_SYMBOL } from '@/shared/core/blockchain/token-registry';\nimport {\n DecimalString,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/types/collections';\n\n/**\n * The CoinList integration contract an Ondo swap is sent to, and therefore the\n * ERC-20 spender the user approves.\n *\n * It is a constant rather than a value read off the built transaction because\n * the approval has to happen *before* the transaction is built: the calldata\n * is only good for a minute, and an approval takes most of one to mine. The\n * built transaction's `tx.to` is checked against this before broadcasting, so a\n * stale constant fails loudly instead of sending a transaction that reverts on\n * `transferFrom`.\n *\n * Mainnet is absent, not zeroed: Ondo's production integration contract is not\n * deployed yet, and a zero address would be approved happily and revert only\n * later. Flows return `unsupported-chain` for a chain with no entry.\n *\n * The Sepolia entry is production's deployment. Beta has its own, so an SDK\n * pointed at beta fails `spender-mismatch` until ENG-1734 serves the address\n * off the offer.\n */\nconst ONDO_SWAP_CONTRACT_ADDRESSES: Partial<\n Record<EthereumChain, EvmContractAddress>\n> = {\n ethereum_sepolia: EvmContractAddress(\n '0x7014019ed51Edab984a71D30F2707D2dB2316A7A'\n ),\n};\n\n/** The Ondo integration contract on `chain`, or `null` where none is deployed. */\nexport function ondoSwapContractAddress(\n chain: EthereumChain\n): EvmContractAddress | null {\n return ONDO_SWAP_CONTRACT_ADDRESSES[chain] ?? null;\n}\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/**\n * How close to its deadline a built transaction stops being offerable.\n *\n * Placing an order is not instant - the wallet has to prompt, the user has to\n * confirm, and the transaction has to reach a node - so calldata with a second\n * left is one the contract will reject. Treating the last few seconds as\n * already expired turns a paid-for revert into a refresh button.\n */\nexport const ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5_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 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 {\n assertUint256,\n BlockchainAmount,\n type Uint256,\n} from '@/shared/types/blockchain/core';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { OndoSwapTransaction } from '@/shared/types/providers/ondo/ondo';\n\n/**\n * The price of one whole asset token in an Ondo swap transaction, in the\n * funding token's units.\n *\n * `POST /v1/ondo/swap/transaction` publishes no price. Frontline drops\n * Ninshubur's deliberately, because `GET /v1/ondo/swap/quote` already serves\n * one under that name at a different scale, and echoing both would leave a\n * caller to guess which was 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 `payInputAmount / 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 *\n * Denominated in the *funding* token's decimals, so it pairs with\n * `formattedUsdPrice` and with the fee and total rendered beside it.\n */\nexport function computeOndoPrice(\n transaction: Pick<\n OndoSwapTransaction,\n 'notionalValue' | 'receiveOutputAmount'\n >\n): BlockchainAmount {\n const { notionalValue, receiveOutputAmount } = transaction;\n\n // Unreachable through `OndoSwapTransaction.fromDto`, which rejects a\n // non-positive output at the boundary - frontline refuses to emit one. The\n // guard is here because this runs during render, where a RangeError from a\n // bare BigInt division would take the checkout down instead of a step.\n if (receiveOutputAmount.raw <= 0n) {\n throw new ValidationError(\n 'Ondo price: receiveOutputAmount must be greater than zero'\n );\n }\n\n // Scale the numerator by the asset's exponent so the quotient lands back in\n // the funding token's, which is the scale every other amount on the review\n // screen is in. Floor division: a price is truncated towards zero rather\n // than rounded, so the total it implies never overstates what was paid.\n const scaled =\n notionalValue.raw * 10n ** BigInt(receiveOutputAmount.decimals);\n const raw = scaled / receiveOutputAmount.raw;\n\n return BlockchainAmount({\n raw: assertPriceFits(raw),\n decimals: notionalValue.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 ValidationError(`Ondo price: out of uint256 bounds (${raw})`);\n }\n}\n","import type { Newtype } from '@/shared/types/newtype';\n\nexport type Ticker = Newtype<string, 'Ticker'>;\nexport const Ticker = (value: string): Ticker => value as Ticker;\n\nexport type OrderBookSide = 'buy' | 'sell';\n","import { chainFromId } from '@/shared/core/blockchain/chain';\nimport { blockchainAmountFromRawOrThrow } from '@/shared/core/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 '@/shared/types/blockchain/core';\nimport type {\n OndoQuoteDto,\n OndoSwapTransactionDto,\n OndoTradingStatusDto,\n} from '@/shared/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/shared/types/errors';\nimport { type OrderBookSide, Ticker } from '@/shared/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 that spends an attestation - see\n * {@link OndoSwapTransaction}.\n */\nexport type OndoQuote = {\n /** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */\n chain: EthereumChain;\n ticker: Ticker;\n /** Needed to approve or transfer the asset; the quote is the only source. */\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 an {@link OndoSwapTransaction}'s output: that one is\n * reported by whatever priced the quantity, the two sources are allowed to\n * disagree, and 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 * A signed, expiring buy: the calldata that fills it and the amounts it\n * commits to, from `buildSwapTransaction`.\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 * **It carries no identity.** No chain, ticker, asset or side: 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 asset, which the offer already does.\n *\n * It carries no price either. Divide {@link notionalValue} by\n * {@link receiveOutputAmount} - see `computeOndoPrice` - which is the price\n * this transaction actually fills at rather than an indicative one that has\n * since moved.\n */\nexport type OndoSwapTransaction = {\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 /** Gross amount the wallet pays, in the funding token's decimals. */\n payInputAmount: BlockchainAmount;\n /**\n * CoinList's cut of {@link payInputAmount}, in the same decimals. Taken off\n * the deposit rather than added on top, so the approval never has to cover\n * more than `payInputAmount`. Zero until ENG-1718 lands.\n */\n fee: BlockchainAmount;\n /**\n * `payInputAmount` less `fee`, in the same decimals: what Ondo priced.\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 * What the buyer receives, at the scale whatever priced the quantity\n * reported - not at the {@link OndoQuote}'s.\n */\n receiveOutputAmount: BlockchainAmount;\n};\n\nexport const OndoSwapTransaction = {\n fromDto: (dto: OndoSwapTransactionDto): OndoSwapTransaction => {\n // Read once each, so a mapper that reached for the wrong exponent on one\n // of the four amounts is a visible mistake rather than a plausible one.\n const inputDecimals = AssetDecimals(dto.pay_input_decimals);\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n return {\n tx: {\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n },\n expiresAt: parseExpiresAt(dto.expires_at),\n payInputAmount: blockchainAmountFromRawOrThrow({\n label: 'pay_input_amount',\n raw: dto.pay_input_amount,\n decimals: inputDecimals,\n }),\n fee: blockchainAmountFromRawOrThrow({\n label: 'fee',\n raw: dto.fee,\n decimals: inputDecimals,\n }),\n notionalValue: blockchainAmountFromRawOrThrow({\n label: 'notional_value',\n raw: dto.notional_value,\n decimals: inputDecimals,\n }),\n receiveOutputAmount: parseReceiveOutputAmount(\n dto.receive_output_amount,\n outputDecimals\n ),\n };\n },\n};\n\n/**\n * A transaction that yields nothing is not one to sign - the user would pay\n * the deposit and receive no asset - and frontline refuses to emit one\n * (`validate_number(:receive_output_amount, greater_than: 0)`). A zero here is\n * therefore a changed encoding, not a small order.\n *\n * Rejecting it at the boundary is also what lets `computeOndoPrice` divide by\n * it without a fallible result: the failure surfaces as the data hook's ERROR\n * state rather than as a division during render.\n */\nfunction parseReceiveOutputAmount(\n raw: string,\n decimals: AssetDecimals\n): BlockchainAmount {\n const amount = blockchainAmountFromRawOrThrow({\n label: 'receive_output_amount',\n raw,\n decimals,\n });\n if (amount.raw <= 0n) {\n throw new ValidationError(\n `receive_output_amount: must be greater than zero (\"${raw}\")`\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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { formatRawAmount } from '@/shared/core/blockchain/formatters';\nimport type {\n BuildOndoSwapTransactionParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport type {\n OndoQuoteDto,\n OndoSwapTransactionDto,\n OndoTradingStatusDto,\n} from '@/shared/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { QueryParamValues } from '@/shared/types/http';\nimport {\n OndoQuote,\n OndoSwapTransaction,\n OndoTradingStatus,\n} from '@/shared/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 buy: spends an attestation and returns\n * signed calldata with a deadline.\n *\n * `amount` goes out in **base units**, unlike `getOndoQuote`'s `token_amount`\n * which is in whole tokens: this number becomes the ERC-20 pull encoded into\n * the calldata, so it is the on-chain integer, not a human figure. Frontline\n * refuses zero, and refuses a wallet whose allowance does not cover it with a\n * 422 carrying `code: \"insufficient_allowance\"`.\n *\n * The response carries the scale of every amount on it, so nothing has to\n * travel alongside the request to read them back. `pay_input_decimals` is\n * nonetheless checked against the `amount` that was sent - see\n * {@link assertFundingScaleAgrees}.\n */\nexport async function buildOndoSwapTransaction(\n api: Sender,\n params: BuildOndoSwapTransactionParams\n): Promise<OndoSwapTransaction> {\n const dto = await api.send<OndoSwapTransactionDto>({\n method: 'POST',\n url: '/v1/ondo/swap/transaction',\n body: {\n symbol: params.symbol,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount.raw.toString(),\n },\n attributes: Attributes.protected(),\n });\n assertFundingScaleAgrees(dto, params);\n return OndoSwapTransaction.fromDto(dto);\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 funding token it resolves from the offer.\n * They should never differ - an approval on some other token reads as a zero\n * allowance, which frontline refuses before it signs anything - so a\n * disagreement here is a changed encoding rather than a user error, the same\n * reasoning `parseReceiveOutputAmount` rejects a zero output under.\n *\n * Worth the check because of where the value lands: `pay_input_amount` at the\n * wrong exponent renders the review screen's **Total** orders of magnitude out,\n * on the screen where the user commits money.\n */\nfunction assertFundingScaleAgrees(\n dto: OndoSwapTransactionDto,\n params: BuildOndoSwapTransactionParams\n): void {\n if (dto.pay_input_decimals !== params.amount.decimals) {\n throw new ValidationError(\n `pay_input_decimals: the swap was priced in ${dto.pay_input_decimals} decimals but the order was sized in ${params.amount.decimals}`\n );\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 buildOndoSwapTransaction,\n getOndoQuote,\n getOndoTradingStatus,\n} from '@/shared/api/frontline/providers/ondo/ondo';\nimport type {\n BuildOndoSwapTransactionParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n OndoQuote,\n OndoSwapTransaction,\n OndoTradingStatus,\n} from '@/shared/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. {@link buildSwapTransaction} is\n * not: budget one call per order placed, plus one per refresh the user asks\n * for.\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 getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;\n /**\n * Builds the buy for a specific wallet and amount: spends an attestation and\n * returns calldata to broadcast, valid until\n * {@link OndoSwapTransaction.expiresAt}.\n *\n * The wallet must have approved the swap contract to spend `amount` of the\n * offer's funding token first - frontline reads the allowance before asking\n * Ninshubur for anything, and rejects a short one with a 422 carrying\n * `code: \"insufficient_allowance\"`. See `prepareSwap` on the client\n * namespace, which approves and then builds, in that order.\n *\n * Buy-only, and the tokens are the offer's rather than the caller's to name.\n */\n buildSwapTransaction(\n params: BuildOndoSwapTransactionParams\n ): Promise<OndoSwapTransaction>;\n}\n\nexport class OndoNamespaceImpl implements OndoNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\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 buildSwapTransaction(\n params: BuildOndoSwapTransactionParams\n ): Promise<OndoSwapTransaction> {\n return this.log.wrap('buildSwapTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoSwapTransaction(this.ctx.api, params);\n });\n }\n}\n","export const SUPERSTATE_SWAP_ABI = [\n {\n type: 'function',\n name: 'authorized',\n inputs: [{ name: 'user', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'stopped',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'SWAP_LEVEL',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'preview',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Preview',\n components: [\n { name: 'input', type: 'uint256', internalType: 'uint256' },\n { name: 'fee', type: 'uint256', internalType: 'uint256' },\n { name: 'output', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'swap',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n { name: 'slip', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'tokenBalance',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputToken',\n inputs: [],\n outputs: [{ name: '', type: 'address', internalType: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputTokenBalance',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'setBps',\n inputs: [{ name: 'points', type: 'uint256', internalType: 'uint256' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'event',\n name: 'Swapped',\n inputs: [\n { name: 'user', type: 'address', indexed: true, internalType: 'address' },\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: '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 { name: 'to', type: 'address', indexed: true, internalType: 'address' },\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: 'InvalidAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InsufficientAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'SwapFailed',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n },\n] as const;\n","import { applyBps, BPS_DENOM } from '@/shared/core/blockchain/bps';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport {\n assertUint256,\n BlockchainAmount,\n Bps,\n} from '@/shared/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 '@/shared/types/blockchain/core';\nimport type { SwapPreview } from '@/shared/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 '@/shared/types/providers/superstate/swap';\n\n/**\n * Interprets the on-chain swap availability read from `stopped()` and\n * `SWAP_LEVEL()`.\n *\n * The contract tracks paused operations as a bitmask in `stopped`. The swap is\n * stopped when the SWAP_LEVEL flag is set:\n *\n * (stopped & SWAP_LEVEL) != 0 -> stopped (not active)\n */\nexport function isStopped(status: SwapStatus): boolean {\n return (status.stopped & status.swapLevel) !== 0n;\n}\n","import { parseEventLogs, type TransactionReceipt } from 'viem';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/checkout/superstate/blockchain/abi';\nimport {\n type AssetDecimals,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/shared/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 '@/shared/core/blockchain/token-registry';\nimport {\n Bps,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/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 Superstate swap contract on Ethereum Sepolia, and therefore the ERC-20\n * 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('0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557');\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/** The Superstate swap contract on `chain`, or `null` where none is deployed. */\nexport function superstateSwapContractAddress(\n chain: EthereumChain\n): EvmContractAddress | null {\n return SUPERSTATE_SWAP_CONTRACT_ADDRESSES[chain] ?? null;\n}\n","import {\n formattedUsdPrice,\n NA_AMOUNT_ASSET_UI,\n} from '@/shared/core/blockchain/formatters';\nimport { computePrice } from '@/shared/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport type { FormattedAmountAssetUi } from '@/shared/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 `@/shared/core/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 allowWallet,\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/shared/api/frontline/providers/superstate/swap';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/shared/core/checkout/superstate/swap-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Erc20Asset } from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n} from '@/shared/types/providers/superstate/swap';\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, checking token allowances, and proving/allow-listing wallet\n * ownership.\n */\nexport interface SuperstateSwapNamespace {\n /**\n * Checks whether a wallet is authorized to swap against the given contract.\n */\n getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization>;\n\n /**\n * Fetches a read-only quote for swapping `amount` of `inputToken`.\n */\n getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;\n\n /**\n * Reads the current on-chain state of a swap contract.\n */\n getStatus(params: SwapContractRef): Promise<SwapStatus>;\n\n /**\n * Reads the ERC-20 output token a swap contract pays out.\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 allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;\n}\n\nexport class SuperstateSwapNamespaceImpl implements SuperstateSwapNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'SUPERSTATE');\n }\n\n async getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization> {\n return this.log.wrap('getAuthorization', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapAuthorization(this.ctx.api, params);\n });\n }\n\n async getPreview(params: GetSwapPreviewParams): Promise<SwapPreview> {\n return this.log.wrap('getPreview', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapPreview(this.ctx.api, params);\n });\n }\n\n async getStatus(params: SwapContractRef): Promise<SwapStatus> {\n return this.log.wrap('getStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapStatus(this.ctx.api, params);\n });\n }\n\n async getOutputToken(params: SwapContractRef): Promise<Erc20Asset> {\n return this.log.wrap('getOutputToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapOutputToken(this.ctx.api, 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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { fetchAllPages } from '@/shared/api/pagination';\nimport type { OfferDto } from '@/shared/types/dto/offer';\nimport type { OfferDetailDto } from '@/shared/types/dto/offer-detail';\nimport type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport { Offer, type OfferId } from '@/shared/types/offer';\nimport { OfferDetail } from '@/shared/types/offer-detail';\nimport { PaginatedResponse, PaginationParams } from '@/shared/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.fromDto(pageDto, Offer.fromDto);\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 '@/shared/api/frontline/offers';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/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: SharedNamespaceContext) {\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 DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/shared/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/shared/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 '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { KycTokenDto } from '@/shared/types/dto/kyc';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport { KycToken } from '@/shared/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 '@/shared/types/dto/pii';\nimport type { Newtype } from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { PiiDto } from '@/shared/types/dto/pii';\nimport { Pii } from '@/shared/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 '@/shared/types/dto/requirement';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { Newtype } from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/shared/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { Requirement, RequirementStatusInfo } from '@/shared/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 '@/shared/api/frontline/documents';\nimport * as kycApi from '@/shared/api/frontline/kyc';\nimport * as piiApi from '@/shared/api/frontline/pii';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/shared/types/document-submission';\nimport type { KycLevelName, KycToken } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { Pii } from '@/shared/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/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: SharedNamespaceContext) {\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 { getAddress } from 'viem';\nimport { HttpError, type HttpResponse } from '@/shared/api/http';\nimport { HttpClient } from '@/shared/api/http-client';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/shared/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/shared/types/dto/nabu-token';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Logger } from '@/shared/types/logger';\nimport { TokenMetadata } from '@/shared/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 '@/shared/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuLogoDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/shared/types/dto/nabu-token';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/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 '@/shared/api/http-client';\nimport {\n createNabuApiClient,\n fetchAllTokensMetadata,\n fetchTokenMetadata,\n fetchTokensMetadata,\n} from '@/shared/api/nabu/tokens';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/shared/types/blockchain/core';\nimport type { Logger } from '@/shared/types/logger';\nimport type { TokenMetadata } from '@/shared/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 `SharedNamespaceContext`: 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 '@/shared/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/shared/types/dto/offer-option-address';\nimport type { Newtype } from '@/shared/types/newtype';\nimport type { OfferId } from '@/shared/types/offer';\nimport { OfferOptionId } from '@/shared/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 '@/shared/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/shared/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 '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { OfferOptionAddressDto } from '@/shared/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/shared/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/shared/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/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 '@/shared/api/frontline/wallet-connect';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/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: SharedNamespaceContext) {\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 `@/shared` 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/blockchain/erc20/approval';\nimport { formatRawAmount } from '@/shared';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport type { CoinListTokenSaleNamespace } from '@/shared/core/checkout/coin-list/token-sale-namespace';\nimport type { AssetId } from '@/shared/types/asset';\nimport type {\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/shared/types/blockchain/wallet-error';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport {\n Blockchain,\n type Participation,\n WalletAddress,\n} from '@/shared/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 const allowance = await erc20.getAllowance({\n tokenAddress: paymentTokenAddress,\n owner: wallet.address,\n spender: fundingContractAddress,\n chain,\n });\n currentAllowance = allowance.allowance;\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 '@/shared/core/observability/internal-logger';\nimport { describeErrorUnredacted } from '@/shared/core/observability/log-cause';\nimport {\n RedactedWalletError,\n type WalletError,\n} from '@/shared/types/blockchain/wallet-error';\nimport type { LogCause } from '@/shared/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: 'prepareSwap'` rather than matching a prefix.\n *\n * ```ts\n * withFlowLogging(this.log, 'prepareSwap', params.onProgress, (onProgress) =>\n * prepareOndoSwap({ ...params, onProgress, ondo: this, erc20: this.erc20 })\n * );\n * // INFO { scope: 'ONDO', flow: 'prepareSwap', msg: 'flow started' }\n * // INFO { scope: 'ONDO', flow: 'prepareSwap', phase: 'approving',\n * // msg: 'flow advanced' }\n * // ERROR { scope: 'ONDO', flow: 'prepareSwap',\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 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' }));\n\n try {\n const result = await run((phase) => {\n flowLog.info(() => ({ msg: 'flow advanced', fields: { phase } }));\n onProgress?.(phase);\n });\n logOutcome(flowLog, 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' }),\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(log: InternalLogger, outcome: FlowOutcome): void {\n switch (outcome.type) {\n case 'success':\n log.info(() => ({ msg: 'flow succeeded' }));\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 step: outcome.error.step,\n error: describeErrorUnredacted(outcome.error.cause),\n },\n }));\n log.error(() => ({\n msg: 'flow failed',\n 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/observability/flow-logging';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport {\n type CoinListTokenSaleNamespace,\n CoinListTokenSaleNamespaceImpl,\n} from '@/shared/core/checkout/coin-list/token-sale-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/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: SharedNamespaceContext,\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 params.onProgress,\n (onProgress) =>\n executeTokenSale({\n ...params,\n onProgress,\n erc20: this.erc20,\n tokenSale: this,\n })\n );\n }\n}\n","import { type Address, isAddressEqual } from 'viem';\n\n/**\n * Whether two EVM addresses name the same account or contract.\n *\n * Case-insensitive, because EIP-55 casing is a checksum rather than part of the\n * identity: the same address is equally itself checksummed, all-lowercase or\n * all-uppercase, and a backend is free to return whichever it likes. Comparing\n * with `===` rejects a matching address the moment the two sides disagree on\n * casing, which is a bug that only shows up in production and blames the wrong\n * thing when it does.\n *\n * Total: an address viem cannot parse is equal to nothing, itself included.\n * The callers are step-tagged flows that must not throw, and the address types\n * are unchecked casts over whatever the API returned, so a value that is not an\n * address at all is a case this has to answer rather than raise.\n */\nexport function isSameEvmAddress(a: Address, b: Address): boolean {\n try {\n return isAddressEqual(a, b);\n } catch {\n return false;\n }\n}\n","import type { Hash, TransactionReceipt } from 'viem';\nimport {\n type Erc20AllowanceError,\n type Erc20AllowancePhase,\n ensureErc20Allowance,\n} from '@/client/core/blockchain/erc20/approval';\nimport { classifyWalletError } from '@/client/core/blockchain/wallet-error';\nimport { apiErrorCode } from '@/shared/api/http';\nimport { isSameEvmAddress } from '@/shared/core/blockchain/address';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport { ondoSwapContractAddress } from '@/shared/core/checkout/ondo/constants';\nimport type { OndoNamespace } from '@/shared/core/checkout/ondo/ondo-namespace';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/shared/types/blockchain/wallet-error';\nimport type { OndoSwapTransaction } from '@/shared/types/providers/ondo/ondo';\n\n// ---------------------------------------------------------------------------\n// prepareOndoSwap\n// ---------------------------------------------------------------------------\n\n/**\n * Progress phases emitted by {@link prepareOndoSwap}, in the order they occur.\n * 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 {@link prepareOndoSwap} failed.\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\nexport type OndoSwapPreparationResult =\n | { type: 'success'; transaction: OndoSwapTransaction }\n | { type: 'error'; error: OndoSwapPreparationError };\n\nexport type PrepareOndoSwapParams = {\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 ERC-20 being spent, e.g. USDC on `chain`.\n *\n * Approval only - it is not sent to frontline, which resolves the funding\n * token from the offer. The two agreeing is what the allowance check on the\n * far side is confirming.\n */\n tokenAddress: EvmContractAddress;\n /** How much of `tokenAddress` to spend, in its base units. */\n amount: BlockchainAmount;\n onProgress?: (phase: OndoSwapPreparationPhase) => void;\n};\n\n/**\n * Gets an order ready to place: ensures the swap contract may pull `amount` of\n * `tokenAddress`, 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 is a constant ({@link ondoSwapContractAddress}) rather than the\n * `tx.to` the response returns; {@link executeOndoSwap} checks the two agree\n * before anything is broadcast.\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 prepareOndoSwap(\n params: PrepareOndoSwapParams\n): Promise<OndoSwapPreparationResult> {\n const {\n ondo,\n erc20,\n wallet,\n symbol,\n chain,\n tokenAddress,\n amount,\n onProgress,\n } = params;\n const emit = (phase: OndoSwapPreparationPhase) => onProgress?.(phase);\n\n // Step 0: Refuse a chain with no swap contract. Approving a zero address\n // would succeed and only revert later, at the user's expense.\n const spender = ondoSwapContractAddress(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 const transaction = await ondo.buildSwapTransaction({\n symbol,\n chain,\n walletAddress: wallet.address,\n amount,\n });\n return { type: 'success', transaction };\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` and `spender-mismatch` are refusals to broadcast rather than\n * failures of a broadcast: both would revert on chain and cost the user gas,\n * and both are fixed by building a fresh transaction.\n */\nexport type OndoSwapExecutionError =\n | { step: 'quote-expired' }\n | { step: 'spender-mismatch'; expected: EvmContractAddress }\n | { step: 'swap'; cause: WalletError }\n | { step: 'swap-reverted' };\n\nexport type OndoSwapExecutionResult =\n | { type: 'success'; txHash: Hash; transaction: OndoSwapTransaction }\n | { type: 'error'; error: OndoSwapExecutionError };\n\nexport type ExecuteOndoSwapParams = {\n wallet: EvmWallet;\n /**\n * The transaction to fill, from {@link prepareOndoSwap} or\n * `ondo.buildSwapTransaction`.\n */\n transaction: OndoSwapTransaction;\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: broadcasts the calldata Ondo encoded and waits\n * for it to mine.\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 * Two checks run first, both of which would otherwise surface as a reverted\n * transaction the user paid for: it must not have expired (its deadline is\n * encoded in the calldata), and its `to` must be the contract the approval\n * named, since anything else cannot pull the funds.\n */\nexport async function executeOndoSwap(\n params: ExecuteOndoSwapParams\n): Promise<OndoSwapExecutionResult> {\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 0b: Refuse calldata pointing somewhere other than the contract the\n // user approved - it could not pull the funds, so it can only revert.\n // Compared case-insensitively: Ondo promises no particular casing, and a\n // checksum disagreement here would reject every order after the user had\n // already paid for the approval and spent an attestation on the build.\n //\n // Frontline runs the same check against its own configured contract. This\n // one is not redundant: it catches the case frontline cannot see, where the\n // SDK's `ondoSwapContractAddress` has drifted from that config, so the\n // approval went to a contract the calldata does not name.\n const spender = ondoSwapContractAddress(chain);\n if (spender === null || !isSameEvmAddress(transaction.tx.to, spender)) {\n return {\n type: 'error',\n error: {\n step: 'spender-mismatch',\n expected: spender ?? transaction.tx.to,\n },\n };\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 OndoSwapExecutionResult,\n type OndoSwapPreparationResult,\n type PrepareOndoSwapParams,\n prepareOndoSwap,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport { withFlowLogging } from '@/client/core/observability/flow-logging';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport {\n type OndoNamespace,\n OndoNamespaceImpl,\n} from '@/shared/core/checkout/ondo/ondo-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\n\n/**\n * The Ondo namespace plus the two halves of placing an order, which need a\n * wallet and so cannot live on the shared namespace.\n *\n * They are two calls rather than one because the flow is two user decisions:\n * the buyer commits to an amount (approving the spend), reviews firm numbers,\n * and only then places the order. Bundling them would mean approving and\n * filling behind a single button, and would burn most of the transaction's\n * ~60-second life on the approval.\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`, then builds the transaction\n * that spends it. Returns a step-tagged result rather than throwing.\n */\n prepareSwap(\n params: Omit<PrepareOndoSwapParams, 'ondo' | 'erc20'>\n ): Promise<OndoSwapPreparationResult>;\n /**\n * Broadcasts a built transaction and waits for it to mine, refusing one that\n * has expired or points at an unexpected contract. Returns a step-tagged\n * result rather than throwing.\n */\n executeSwap(params: ExecuteOndoSwapParams): Promise<OndoSwapExecutionResult>;\n}\n\nexport class ClientOndoNamespaceImpl\n extends OndoNamespaceImpl\n implements ClientOndoNamespace\n{\n constructor(\n ctx: SharedNamespaceContext,\n private readonly erc20: Erc20Namespace\n ) {\n super(ctx);\n }\n\n prepareSwap(\n params: Omit<PrepareOndoSwapParams, 'ondo' | 'erc20'>\n ): Promise<OndoSwapPreparationResult> {\n return withFlowLogging(\n this.log,\n 'prepareSwap',\n params.onProgress,\n (onProgress) =>\n prepareOndoSwap({\n ...params,\n onProgress,\n ondo: this,\n erc20: this.erc20,\n })\n );\n }\n\n executeSwap(params: ExecuteOndoSwapParams): Promise<OndoSwapExecutionResult> {\n return withFlowLogging(\n this.log,\n 'executeSwap',\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/blockchain/erc20/approval';\nimport { classifyWalletError } from '@/client/core/blockchain/wallet-error';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/checkout/superstate/blockchain/abi';\nimport {\n computePrice,\n computeSlip,\n} from '@/shared/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport { isStopped } from '@/shared/core/checkout/superstate/blockchain/status';\nimport { decodeSwappedOutputAmount } from '@/shared/core/checkout/superstate/blockchain/swapped-event';\nimport type { SuperstateSwapNamespace } from '@/shared/core/checkout/superstate/swap-namespace';\nimport type { WalletsNamespace } from '@/shared/core/wallets/wallets-namespace';\nimport {\n BlockchainAmount,\n type Bps,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { WalletError } from '@/shared/types/blockchain/wallet-error';\nimport type { OfferId } from '@/shared/types/offer';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapStatus,\n} from '@/shared/types/providers/superstate/swap';\nimport type { WalletOwnershipChallenge } from '@/shared/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 | { 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 is stopped (paused). Run before\n // any approval so the user never signs a tx that the swap would revert.\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 (isStopped(status)) {\n return { type: 'error', error: { step: 'swap-stopped' } };\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 auth: SwapAuthorization;\n try {\n auth = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (auth.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: SwapAuthorization;\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.authorized) {\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/observability/flow-logging';\nimport type { Erc20Namespace } from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport {\n type SuperstateSwapNamespace,\n SuperstateSwapNamespaceImpl,\n} from '@/shared/core/checkout/superstate/swap-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport type { WalletsNamespace } from '@/shared/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: SharedNamespaceContext,\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 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 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/utils/open-in-new-tab';\nimport {\n COINLIST_BASE_URL,\n VERIFY_IDENTITY_ACCREDITATION_PATH,\n VERIFY_IDENTITY_PATH,\n WALLET_PATH,\n} from '@/shared/api/frontline/config';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type RequirementsNamespace,\n RequirementsNamespaceImpl,\n} from '@/shared/core/requirements/requirements-namespace';\nimport type { Requirement } from '@/shared/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: SharedNamespaceContext,\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/utils/open-in-new-tab';\nimport { SUPPORT_NEW_TICKET_URL } from '@/shared/api/frontline/config';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Logger } from '@/shared/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 { ApiClient } from '@/client/core/api/api-client';\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 '@/shared/api/frontline/config';\nimport { NABU_BASE_URL } from '@/shared/api/nabu/config';\nimport {\n type Erc20Namespace,\n Erc20NamespaceImpl,\n} from '@/shared/core/blockchain/erc20/erc20-namespace';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type OffersNamespace,\n OffersNamespaceImpl,\n} from '@/shared/core/offers/offers-namespace';\nimport {\n type TokensNamespace,\n TokensNamespaceImpl,\n} from '@/shared/core/tokens/tokens-namespace';\nimport {\n type WalletsNamespace,\n WalletsNamespaceImpl,\n} from '@/shared/core/wallets/wallets-namespace';\nimport type { Config } from '@/shared/types/config';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport interface ClientConfig extends Config {\n /**\n * The SDK user must provide this function. It is responsible for fetching a\n * valid {@link OAuthAccessToken}, or **null** for logged-out users. If your\n * backend is in TypeScript, it is recommended to use\n * `CoinListServer#auth.getAccessToken` from `@/server/core/coinlist-server`.\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: `prepareSwap` (approve, then commit a firm\n * quote) and `executeSwap` (broadcast it).\n *\n * The reads are free to poll while the user edits an order. `prepareSwap` 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 init(): Promise<AuthState>;\n}\n\nclass CoinListClientImpl implements CoinListClient {\n /** Cached access token: undefined = loading, null = no token, AccessToken = logged in */\n private _accessToken: OAuthAccessToken | null | undefined = undefined;\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 this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl || PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n this.fetchAccessToken.bind(this),\n logger\n );\n const ctx: SharedNamespaceContext = {\n api: this.api,\n logger,\n ensureUserAuthenticated: async () => this.ensureAuthenticated(),\n };\n this.auth = new ClientAuthNamespaceImpl(_config, {\n getState: () => this.getAuthState(),\n clearAccessToken: () => {\n this._accessToken = null;\n },\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 await this.fetchAccessToken(true);\n return this.getAuthState();\n }\n\n async fetchAccessToken(refresh: boolean): Promise<OAuthAccessToken | null> {\n if (!refresh && this._accessToken !== undefined) return this._accessToken;\n\n try {\n const accessToken = await this._config.getAccessToken();\n this._accessToken = accessToken;\n return accessToken;\n } catch (_) {\n this._accessToken = null;\n return null;\n }\n }\n\n private getAuthState(): AuthState {\n if (this._accessToken === undefined) {\n return 'unknown';\n }\n return this._accessToken !== null ? 'logged-in' : 'logged-out';\n }\n\n private ensureAuthenticated() {\n if (this.getAuthState() !== '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 * `@/shared/core/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 '@/shared/core/observability/internal-logger';\nimport type { Logger } from '@/shared/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 → OfferCard, 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.2.1 | 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-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--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}}}@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-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}@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}}: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}.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}}@layer components;@layer utilities{.clcosdk\\\\:pointer-events-none{pointer-events:none}.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:calc(var(--clcosdk-spacing) * 0)}.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\\\\:-bottom-0\\\\.5{bottom:calc(var(--clcosdk-spacing) * -.5)}.clcosdk\\\\:bottom-full{bottom:100%}.clcosdk\\\\:left-1\\\\/2{left:50%}.clcosdk\\\\:z-50{z-index:50}.clcosdk\\\\:order-1{order:1}.clcosdk\\\\:order-2{order:2}.clcosdk\\\\:mt-2{margin-top:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:mt-4{margin-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:mb-2{margin-bottom:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:mb-6{margin-bottom:calc(var(--clcosdk-spacing) * 6)}.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-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-full{width:100%;height:100%}.clcosdk\\\\:h-1{height:calc(var(--clcosdk-spacing) * 1)}.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-28{height:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\\\:h-52{height:calc(var(--clcosdk-spacing) * 52)}.clcosdk\\\\:h-\\\\[18px\\\\]{height:18px}.clcosdk\\\\:h-\\\\[54px\\\\]{height:54px}.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:calc(var(--clcosdk-spacing) * 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-\\\\[2\\\\.4rem\\\\]{min-height:2.4rem}.clcosdk\\\\:min-h-screen{min-height:100vh}.clcosdk\\\\:w-1{width:calc(var(--clcosdk-spacing) * 1)}.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-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-\\\\[448px\\\\]{width:448px}.clcosdk\\\\:w-auto{width:auto}.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-\\\\[22rem\\\\]{max-width:22rem}.clcosdk\\\\:max-w-\\\\[28rem\\\\]{max-width:28rem}.clcosdk\\\\:max-w-\\\\[30rem\\\\]{max-width:30rem}.clcosdk\\\\:max-w-\\\\[760px\\\\]{max-width:760px}.clcosdk\\\\:max-w-\\\\[1200px\\\\]{max-width:1200px}.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:calc(var(--clcosdk-spacing) * 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\\\\: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\\\\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.clcosdk\\\\:grid-cols-2{grid-template-columns:repeat(2,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-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\\\\:gap-1{gap:calc(var(--clcosdk-spacing) * 1)}.clcosdk\\\\:gap-1\\\\.5{gap:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:gap-2{gap:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:gap-5{gap:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:gap-8{gap:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:gap-\\\\[5px\\\\]{gap:5px}: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-border>:not(:last-child)){border-color:var(--color-border)}: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-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-dashed{--tw-border-style:dashed;border-style:dashed}.clcosdk\\\\:border-accent\\\\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-accent\\\\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.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,.clcosdk\\\\:border-border\\\\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-border\\\\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.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-success-border{border-color:var(--color-success-border)}.clcosdk\\\\:border-warning-border{border-color:var(--color-warning-border)}.clcosdk\\\\:border-t-transparent{border-top-color:#0000}.clcosdk\\\\:bg-accent\\\\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:bg-accent\\\\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.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-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-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:bg-\\\\[image\\\\:var\\\\(--btn-primary-gradient\\\\)\\\\]{background-image:var(--btn-primary-gradient)}.clcosdk\\\\:from-surface{--tw-gradient-from:var(--color-surface);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:via-section{--tw-gradient-via:var(--color-section);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:via-transparent{--tw-gradient-via:transparent;--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:to-background{--tw-gradient-to:var(--color-background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:var(--color-overlay)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:color-mix(in oklab, var(--color-overlay) 35%, transparent)}}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:object-contain{object-fit:contain}.clcosdk\\\\:object-cover{object-fit:cover}.clcosdk\\\\:p-0{padding:calc(var(--clcosdk-spacing) * 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-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:calc(var(--clcosdk-spacing) * 1)}.clcosdk\\\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pt-14{padding-top:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:pr-4{padding-right:calc(var(--clcosdk-spacing) * 4)}.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-\\\\[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-\\\\[110\\\\%\\\\]{--tw-leading:110%;line-height:110%}.clcosdk\\\\:leading-\\\\[120\\\\%\\\\]{--tw-leading:120%;line-height:120%}.clcosdk\\\\:leading-\\\\[125\\\\%\\\\]{--tw-leading:125%;line-height:125%}.clcosdk\\\\:leading-\\\\[130\\\\%\\\\]{--tw-leading:130%;line-height:130%}.clcosdk\\\\:leading-\\\\[135\\\\%\\\\]{--tw-leading:135%;line-height:135%}.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\\\\.12px\\\\]{--tw-tracking:.12px;letter-spacing:.12px}.clcosdk\\\\:tracking-\\\\[0\\\\.28px\\\\]{--tw-tracking:.28px;letter-spacing:.28px}.clcosdk\\\\:break-words{overflow-wrap:break-word}.clcosdk\\\\:whitespace-nowrap{white-space:nowrap}.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-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\\\\: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-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f62e);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-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f640);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-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#0000002e);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-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#00000040);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-\\\\[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-all{transition-property:all;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\\\\:ease-in-out{--tw-ease:var(--clcosdk-ease-in-out);transition-timing-function:var(--clcosdk-ease-in-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\\\\:opacity-100:is(:where(.clcosdk\\\\:group):hover *){opacity:1}}.clcosdk\\\\:placeholder\\\\:text-text-disabled::placeholder{color:var(--color-text-disabled)}@media (hover:hover){.clcosdk\\\\:hover\\\\:-translate-y-0\\\\.5:hover{--tw-translate-y:calc(var(--clcosdk-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\\\:hover\\\\:border-divider:hover{border-color:var(--color-divider)}.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\\\\:hover\\\\:shadow-\\\\[0px_14px_32px_-10px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.35\\\\)\\\\]:hover{--tw-shadow:0px 14px 32px -10px var(--tw-shadow-color,#00000059);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-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-accent-focus:focus-visible{--tw-ring-color:var(--color-accent-focus)}.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-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:calc(var(--clcosdk-spacing) * 0)}}@media (min-width:40rem){.clcosdk\\\\:sm\\\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:48rem){.clcosdk\\\\:md\\\\:order-1{order:1}.clcosdk\\\\:md\\\\:order-2{order:2}.clcosdk\\\\:md\\\\:hidden{display:none}.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-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-card{border-radius:24px}.clcosdk\\\\:md\\\\:rounded-dialog{border-radius:32px}.clcosdk\\\\:md\\\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:md\\\\:px-6{padding-inline:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:md\\\\:px-8{padding-inline:calc(var(--clcosdk-spacing) * 8)}}@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-gradient-position{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-via-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:100%}@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}@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.subhead, text)}>{content}</p>\n </div>\n );\n}\n","/**\n * CoinList Sale SDK — Typography Tokens\n *\n * Scale based on design system.\n * fontSize in px, lineHeight as percentage string, fontWeight as number.\n * Use the cn() Tailwind classes where possible, these values\n * are for programmatic access or non-Tailwind contexts.\n */\n\nexport const typeScale = {\n hero: {\n fontSize: 64,\n lineHeight: '110%',\n fontWeight: 600,\n },\n display: {\n fontSize: 48,\n lineHeight: '110%',\n fontWeight: 600,\n },\n h1: {\n fontSize: 36,\n lineHeight: '120%',\n fontWeight: 600,\n },\n h2: {\n fontSize: 28,\n lineHeight: '125%',\n fontWeight: 600,\n },\n h3: {\n fontSize: 22,\n lineHeight: '130%',\n fontWeight: 600,\n },\n h4: {\n fontSize: 18,\n lineHeight: '135%',\n fontWeight: 500,\n },\n body: {\n fontSize: 16,\n lineHeight: '150%',\n fontWeight: 400,\n },\n bodyMedium: {\n fontSize: 16,\n lineHeight: '150%',\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: 400,\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-[110%] clcosdk:font-semibold',\n display: 'clcosdk:text-[48px] clcosdk:leading-[110%] clcosdk:font-semibold',\n h1: 'clcosdk:text-[36px] clcosdk:leading-[120%] clcosdk:font-semibold',\n h2: 'clcosdk:text-[28px] clcosdk:leading-[125%] clcosdk:font-semibold',\n h3: 'clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-semibold',\n h4: 'clcosdk:text-[18px] clcosdk:leading-[135%] clcosdk:font-medium',\n body: 'clcosdk:text-[16px] clcosdk:leading-[150%] 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.\n bodyMedium: 'clcosdk:text-[16px] clcosdk:leading-[150%] 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 data: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-normal',\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","import type { SVGProps } from 'react';\n\nexport function CoinListWordmark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"638\"\n height=\"125\"\n viewBox=\"0 0 638 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M68.7724 123.966C74.8226 124.172 80.7696 123.519 86.5104 121.799C97.4076 118.531 106.551 112.58 113.942 103.947C113.942 103.947 113.942 103.947 113.908 103.912C111.879 102.193 109.851 100.507 107.857 98.8218L105.829 97.1363C105.451 96.8268 105.107 96.5172 104.729 96.2076C103.939 95.5197 103.148 94.8662 102.323 94.2126C95.3107 98.8562 87.6104 101.539 79.1196 101.883C74.8569 102.055 70.6287 101.642 66.5036 100.507C59.5252 98.6154 53.2688 95.1757 48.2499 89.7755C39.1059 79.938 35.8745 68.1743 38.2465 55.0348C39.7246 46.9172 43.4373 40.0723 49.1093 34.5C47.9061 34.7408 46.703 35.016 45.5342 35.3943C36.5277 38.2148 29.6181 43.6839 24.6336 51.6639C20.6803 58.0273 18.5834 64.9411 18.3428 72.4739C18.2053 76.7047 18.4803 80.7979 19.4428 84.7879C22.5023 97.2395 29.3087 107.043 39.6903 114.335H39.7934V114.403C40.1372 114.644 40.4809 114.919 40.8247 115.16C49.2812 120.801 58.5971 123.691 68.7724 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M72.2101 89.052C68.1881 90.8406 64.0286 91.8725 59.6973 92.2165C64.9912 95.209 70.8007 96.688 77.1259 96.8256C79.1885 96.86 81.251 96.6536 83.4167 96.3097C88.745 95.4841 93.6951 93.5579 98.3015 90.7374C93.9358 87.057 89.6044 83.4109 85.2386 79.7305C81.526 83.6861 77.1946 86.8506 72.2101 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M66.9848 0.241609C66.4348 0.276006 65.8848 0.344799 65.3691 0.413592C70.663 1.4111 75.7851 3.13093 80.6321 5.71068C90.0511 10.7326 97.3732 17.9215 102.289 27.4494L104.936 25.1448C107.652 22.7714 110.368 20.3981 113.084 18.0247C106.655 11.1797 99.092 6.15784 90.223 3.06214C84.3103 0.998336 78.2601 -0.0335643 72.0381 0.000832319C70.388 0.000832319 68.7036 0.138419 66.9848 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M25.4242 107.871C17.4833 97.9988 13.1519 86.7167 13.2207 73.818C13.2207 67.317 14.5614 61.0568 17.1396 55.1062C20.9553 46.2662 26.9711 39.1805 35.4276 34.2962C43.3685 29.687 51.9968 27.8984 61.1752 29.2743C70.5943 30.7189 78.3976 35.2249 84.6541 42.2762C84.6541 42.2762 84.8603 42.5514 84.9634 42.6546C85.8916 41.8291 86.8541 41.0035 87.7823 40.178L88.9167 39.1805C89.8792 38.355 90.8417 37.4951 91.8043 36.6696C94.0043 34.7434 96.17 32.8515 98.3357 30.9253C94.1075 22.223 87.7479 15.55 79.3258 10.8377C69.3911 5.26541 58.7002 3.54557 47.3904 5.02463C41.7528 5.78136 36.3557 7.50119 31.1993 10.0465C13.702 18.7145 1.08597 36.532 0.0546833 58.4771C-0.117196 62.0887 0.123436 65.7348 0.673452 69.3464C2.04849 78.3239 5.34859 86.4759 10.6425 93.8368C14.7676 99.5123 19.6834 104.19 25.3898 107.871H25.4242Z\"\n fill=\"currentColor\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M366.034 58.1654C366.034 46.8145 375.178 37.665 386.419 37.665C397.66 37.665 406.804 46.8145 406.804 58.1654V99.3727H420.727V58.1654C420.727 39.1785 405.395 23.7344 386.419 23.7344C367.444 23.7344 352.112 39.1785 352.112 58.1654V99.3727H366.034V58.1654ZM278.616 38.1466C265.141 38.1466 254.244 49.0503 254.244 62.5338C254.244 76.0173 265.141 86.9211 278.616 86.9211C292.092 86.9211 302.989 76.0173 302.989 62.5338C302.989 49.0503 292.092 38.1466 278.616 38.1466ZM240.321 62.5338C240.321 41.3799 257.475 24.2159 278.616 24.2159C299.757 24.2159 316.911 41.3799 316.911 62.5338C316.911 83.6878 299.757 100.852 278.616 100.852C257.475 100.852 240.321 83.6878 240.321 62.5338ZM208.386 38.2154C195.082 37.9402 184.048 48.5 183.738 61.8115C183.463 75.123 194.017 86.1643 207.32 86.4739C215.192 86.6459 222.274 82.9998 226.812 77.2212L237.777 85.8204C230.662 94.9011 219.455 100.645 207.011 100.37C186.007 99.923 169.335 82.5183 169.782 61.5019C170.229 40.4856 187.623 23.8032 208.627 24.2503C219.524 24.4911 229.287 29.3066 236.059 36.8051L225.712 46.1266C221.415 41.3455 215.227 38.3186 208.317 38.1466L208.386 38.2154ZM340.527 25.2134V99.3727H326.605V25.2134H340.527ZM508.282 25.2134H494.36V99.8542H508.282V25.2134ZM483.154 99.8542H448.846C439.221 99.8542 431.452 92.0462 431.452 82.4495V25.2134H445.374V82.4495C445.374 84.3757 446.921 85.9236 448.846 85.9236H483.154V99.8542ZM583.772 25.2134H567.856H542.83C530.661 25.2134 520.933 35.1885 520.933 47.2273C520.933 59.2661 530.661 69.2412 542.83 69.2412H552.421C556.821 69.2412 560.396 72.8184 560.396 77.1868V77.9435C560.396 82.3463 556.821 85.8892 552.421 85.8892H520.451V99.8198H552.421C564.522 99.8198 574.319 90.0168 574.319 77.9091V77.1524C574.319 65.0448 564.522 55.2417 552.421 55.2417H542.83C538.499 55.2417 534.855 51.6301 534.855 47.1585C534.855 42.6869 538.499 39.0753 542.83 39.0753H574.319H583.772C591.472 39.0753 597.694 45.3011 597.694 53.0059V99.3039H611.617V53.0059C611.617 37.6306 599.138 25.1446 583.772 25.1446V25.2134ZM637.021 39.1441H609.038V25.2134H637.021V39.1441Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","import { CoinListWordmark } from '@/client/components/design-system/logos/CoinListWordmark';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface PoweredByCoinListProps {\n className?: string;\n}\n\nexport function PoweredByCoinList({ className }: PoweredByCoinListProps) {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-[5px] clcosdk:text-text-secondary',\n className\n )}\n >\n <span className={cn(typeClasses.caption, 'clcosdk:tracking-[0.12px]')}>\n Powered by\n </span>\n <CoinListWordmark className=\"clcosdk:h-3 clcosdk:w-auto\" />\n </div>\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 { PoweredByCoinList } from '@/client/components/design-system/PoweredByCoinList';\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\n <PoweredByCoinList className=\"clcosdk:mt-4\" />\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, 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, naming what is being typed —\n * Superstate's `$`, Ondo's `USDC`.\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 unit label\n * beside it, which is what a token symbol is — `USDC 1,000` is a quantity\n * and its unit, and painting them alike makes the symbol look like a digit.\n */\n prefixTone?: 'primary' | 'muted';\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 led by what it\n * is denominated in, and a trailing action.\n *\n * What names the denomination is a slot rather than a prop, because it is not\n * always the asset being paid: Ondo leads with the input token's symbol,\n * Superstate with a `$`, because its field is dollar-denominated and the\n * stablecoin funding it is chosen separately.\n */\nexport function CheckoutAmountInput({\n label,\n value,\n onChange,\n placeholder,\n invalid = false,\n disabled = false,\n prefix,\n prefixTone = 'primary',\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\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 <div className=\"clcosdk:flex clcosdk:min-w-0 clcosdk:flex-1 clcosdk:items-center clcosdk:gap-1\">\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 <input\n id={inputId}\n // Text, not `number`: the browser sanitizes a number field's value,\n // so a mid-edit `\"1.\"` can reach `onChange` as `\"\"`. The caller\n // owns parsing and validation, and needs the string it was typed 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) => onChange(event.target.value)}\n // Fills the row rather than sizing to its own text: sizing to the\n // content made an empty field one character wide, so most of what\n // looks like the field could not be clicked or typed into. The\n // denomination leads instead, so it stays against the number\n // without the input having to hug its own text.\n className={cn(\n typeClasses.h4,\n 'clcosdk:w-full clcosdk:min-w-0 clcosdk:flex-1 clcosdk:bg-transparent',\n 'clcosdk:outline-none clcosdk:font-medium clcosdk:placeholder:text-text-disabled',\n toneClass\n )}\n />\n </div>\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. That is the normal case today — the SDK ships no icon\n * registry — so it 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 OndoAmountUiEvent,\n OndoAmountUiState,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel.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 OndoAmountViewProps {\n state: OndoAmountUiState;\n onEvent: (event: OndoAmountUiEvent) => 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 OndoAmountView(props: OndoAmountViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoAmountViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoAmountViewBody({\n state,\n onEvent,\n className,\n}: OndoAmountViewProps): 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<OndoAmountUiState, { type: 'active' }>;\n onEvent: (event: OndoAmountUiEvent) => 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 prefix={selectedAsset?.symbol}\n prefixTone=\"muted\"\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: OndoAmountUiEvent) => 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<OndoAmountUiState, { type: 'complete' }>;\n onEvent: (event: OndoAmountUiEvent) => 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 '@/shared/types/blockchain/core';\n\nconst TITLE = 'Order confirmed';\nconst SHARES_RECEIVED_CAPTION = '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 OndoOrderConfirmed({\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={\n <AssetSummaryRow\n asset={state.outputAsset}\n value={state.outputAmount}\n caption={SHARES_RECEIVED_CAPTION}\n />\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<OndoOrderConfirmedUiState, { type: 'visible' }>\n): CheckoutDetailRowUi[] {\n return [\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 {header}\n </>\n )}\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 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 because the two screens that use it disagree\n * about what belongs there — the sidebar shows a price over a market status,\n * the confirmation dialog a quantity over `shares received` — and a screen with\n * nothing to say on the right passes neither.\n */\nexport function AssetSummaryRow({\n asset,\n iconSize = 48,\n value,\n caption,\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: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 {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 <div\n className={cn(\n typeClasses.h4,\n 'clcosdk:text-right 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:text-right 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 OndoQuoteStatusUi,\n OndoReviewUiEvent,\n OndoReviewUiState,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel.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 OndoReviewViewProps {\n state: OndoReviewUiState;\n onEvent: (event: OndoReviewUiEvent) => 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 OndoReviewView(props: OndoReviewViewProps): ReactNode {\n return (\n <CoinListStyleScope>\n <OndoReviewViewBody {...props} />\n </CoinListStyleScope>\n );\n}\n\nfunction OndoReviewViewBody({\n state,\n onEvent,\n className,\n}: OndoReviewViewProps): 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<OndoReviewUiState, { type: 'active' }>;\n onEvent: (event: OndoReviewUiEvent) => 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: OndoQuoteStatusUi;\n onEvent: (event: OndoReviewUiEvent) => 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: OndoReviewUiEvent) => 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","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/buy/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 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: 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-6 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-4 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/buy/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';\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';\n\nexport interface OndoWalletSelectViewProps {\n state: OndoWalletSelectUiState;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\n className?: string;\n}\n\n/**\n * Step 1 of the Ondo checkout. Pure: the wallets arrive already shaped, 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 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 className,\n}: OndoWalletSelectViewProps): 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<OndoWalletSelectUiState, { type: 'active' }>;\n onEvent: (event: OndoWalletSelectUiEvent) => void;\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 { OndoAmountView } from '@/client/components/checkout/ondo/buy/amount/OndoAmountView';\nimport { OndoOrderConfirmed } from '@/client/components/checkout/ondo/buy/confirmation/OndoOrderConfirmed';\nimport { OndoReviewView } from '@/client/components/checkout/ondo/buy/review/OndoReviewView';\nimport { OndoSidebarView } from '@/client/components/checkout/ondo/buy/sidebar/OndoSidebarView';\nimport { OndoWalletSelectView } from '@/client/components/checkout/ondo/buy/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 * 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 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 <OndoAmountView state={state.amount} onEvent={onEvent} />\n <OndoReviewView 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 <OndoOrderConfirmed state={state.orderConfirmed} onEvent={onEvent} />\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 { 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 `$` goes in `CheckoutAmountInput`'s\n * `prefix` slot — where Ondo puts the symbol of the token it charges. Nothing\n * here is submitted: confirming 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 '@/shared/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={\n <AssetSummaryRow\n asset={state.asset}\n caption={`Issued by ${state.issuer}`}\n />\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<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 '@/shared/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-6 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 {\n type OndoAmountStepInput,\n useOndoAmountViewModel,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel';\nimport {\n type OndoOrderPlaced,\n type OndoReviewStepInput,\n useOndoReviewViewModel,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel';\nimport { useOndoSidebarViewModel } from '@/client/hooks/checkout/ondo/buy/sidebar/useOndoSidebarViewModel';\nimport type {\n OndoBuyCheckoutUiEvent,\n OndoBuyCheckoutUiState,\n OndoOrderConfirmedUiState,\n} from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel.types';\nimport {\n type OndoWalletSelectStepInput,\n useOndoWalletSelectViewModel,\n} from '@/client/hooks/checkout/ondo/buy/wallet/useOndoWalletSelectViewModel';\nimport { useOndoPrice } from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nimport { useOndoTradingStatus } from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\nimport { CheckoutAssetUi } from '@/client/hooks/checkout/shared/checkout-ui.types';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport { getNetworkName, txExplorerUrl } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/shared/core/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport {\n DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE,\n ONDO_POLL_INTERVAL_MS,\n} from '@/shared/core/checkout/ondo/constants';\nimport { computeOndoPrice } from '@/shared/core/checkout/ondo/math';\nimport type { OndoQuoteSize } from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport {\n type AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type EthereumChain,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\nimport type {\n OndoSwapTransaction,\n OndoTradingStatus,\n} from '@/shared/types/providers/ondo/ondo';\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 `prepareSwap` when the amount was confirmed. */\n transaction: OndoSwapTransaction;\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: OfferDetail;\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, so the\n * hook can be called unconditionally beside other providers' viewmodels.\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 * There is no flow-level error state. Every failure belongs to a region: a\n * price that will not load leaves the panel's corner unavailable, and an order\n * that will not go through is reported on the review step, next to the button\n * that caused it.\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 const [orderConfirmed, setOrderConfirmed] =\n useState<OndoOrderConfirmedUiState>({ type: 'hidden' });\n\n const { state: priceState } = useOndoPrice({\n symbol: ondoSymbol,\n side: 'buy',\n size: priceSize(step),\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled,\n });\n\n const { state: tradingStatusState } = useOndoTradingStatus({\n symbol: ondoSymbol,\n side: 'buy',\n pollIntervalMs: ONDO_POLL_INTERVAL_MS,\n enabled,\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 } = useOndoAmountViewModel(\n {\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 // 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\n const { state: reviewState, onEvent: onReviewEvent } = useOndoReviewViewModel(\n {\n stepInput: reviewStepInput(step),\n ondoSymbol,\n chain,\n offer,\n onComplete: (order) => {\n setOrderConfirmed(\n toOrderConfirmedUi({ order, chain, locale, offer, ondoSymbol })\n );\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\n const { state: sidebarState } = useOndoSidebarViewModel({\n offer,\n ondoSymbol,\n chain,\n priceState,\n tradingStatusState,\n });\n\n const state: OndoBuyCheckoutUiState = {\n wallet: walletState,\n amount: amountState,\n review: reviewState,\n sidebar: sidebarState,\n 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({ type: 'hidden' });\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): OndoAmountStepInput {\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): OndoReviewStepInput {\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}: {\n order: OndoOrderPlaced;\n chain: EthereumChain;\n locale: string;\n offer: OfferDetail;\n ondoSymbol: AssetSymbol;\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 }),\n outputAmount: assetAmount(\n formatAmount(order.transaction.receiveOutputAmount, locale),\n ondoSymbol\n ),\n totalCost: assetAmount(\n formatAmount(order.transaction.payInputAmount, locale),\n inputSymbol\n ),\n pricePerShare: formattedUsdPrice(\n computeOndoPrice(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 OndoAmountUiEvent,\n OndoAmountUiState,\n} from '@/client/hooks/checkout/ondo/buy/amount/useOndoAmountViewModel.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 { getNetworkName } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n shortenAddress,\n} from '@/shared/core/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/shared/core/blockchain/math';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport { ONDO_SUPPORTED_INPUT_ASSETS } from '@/shared/core/checkout/ondo/constants';\nimport {\n type AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type DecimalString,\n type EthereumChain,\n EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type {\n OndoSwapTransaction,\n OndoTradingStatus,\n} from '@/shared/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 OndoAmountConfirmed = {\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n transaction: OndoSwapTransaction;\n};\n\nexport type OndoAmountStepInput =\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 UseOndoAmountViewModelOptions {\n stepInput: OndoAmountStepInput;\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 /** Called once the approval has mined and the transaction has been built. */\n onComplete: (confirmed: OndoAmountConfirmed) => void;\n /** Called when the user reopens this step from a later one. */\n onEdit: () => void;\n}\n\nexport interface UseOndoAmountViewModelResult {\n state: OndoAmountUiState;\n onEvent: (event: OndoAmountUiEvent) => 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 useOndoAmountViewModel({\n stepInput,\n ondoSymbol,\n chain,\n onComplete,\n onEdit,\n}: UseOndoAmountViewModelOptions): UseOndoAmountViewModelResult {\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: `OndoSwapTransaction` 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: 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 = (): OndoAmountUiState => {\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.prepareSwap({\n wallet: stepInput.wallet,\n symbol: ondoSymbol,\n chain,\n tokenAddress: TOKEN_REGISTRY.contractAddress(selectedAsset, 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: OndoAmountUiEvent) => {\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 OndoAmountValidation =\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}): OndoAmountValidation {\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 '@/shared/types/blockchain/core';\nimport { AssetIconUrl } from '@/shared/types/blockchain/ui';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\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 comes from an offer\n * and carries its own artwork, which is why `CheckoutAssetUi.fromErc20` still\n * 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 * Frontline publishes a missing logo as an empty string rather than omitting\n * the field, so the absent case has to be recognised rather than merely\n * falsy-checked into a `\"\"` that renders as a broken image. Every consumer\n * wants the same answer, and writing the convention out at each of them is how\n * 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 === '' ? null : AssetIconUrl(offer.logoUrl);\n}\n","import { offerIconUrl } from '@/client/ui/format/asset-icon';\nimport type {\n AssetSymbol,\n Erc20Asset,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type {\n AssetIconUrl,\n FormattedAmountAssetUi,\n ShortenedWalletAddress,\n} from '@/shared/types/blockchain/ui';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\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. The SDK ships no icon\n * registry — `TOKEN_REGISTRY` carries none and only `Offer.logoUrl` supplies\n * one — so absence is the common case, not an edge case, and `AssetIcon`\n * 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 a\n * token does not carry one - the SDK ships no icon registry, and the only\n * source is the offer being bought. Which is also why it defaults to `null`:\n * the input 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 * only icon the SDK has, 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 * 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 { symbol, networkName }: { symbol: AssetSymbol; networkName: string }\n ): CheckoutAssetUi => ({\n name: offer.name,\n symbol,\n iconUrl: offerIconUrl(offer),\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` while the balance is still loading and if the fetch fails —\n * the balance hook swallows errors and the last known value stands in. The\n * loading half is visible to the user only through the step's CTA, which\n * stays disabled until a balance has arrived.\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 { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/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 * has an entry once a fetch settles (`bigint` on success, `null` on failure).\n * Assets that were not requested are absent.\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. A poll tick is skipped while the\n * previous fetch is still in flight. `assets` is compared by contents, so\n * passing an inline array does 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 coinlist.erc20.getBalance({\n tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),\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 next.set(\n symbol,\n result.status === 'fulfilled' ? result.value.balance : null\n );\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, useState } from 'react';\nimport type { Hash } from 'viem';\nimport type {\n OndoSwapExecutionError,\n OndoSwapExecutionPhase,\n} from '@/client/core/checkout/ondo/ondo-flows';\nimport type {\n OndoQuoteStatusUi,\n OndoReviewUiEvent,\n OndoReviewUiState,\n} from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel.types';\nimport type { OndoLoadErrorReason } from '@/client/hooks/checkout/ondo/shared/data/ondo-load-error';\nimport {\n type LoadOndoSwapTransactionState,\n useOndoSwapTransaction,\n} from '@/client/hooks/checkout/ondo/shared/data/useOndoSwapTransaction';\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 { getNetworkName } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formattedUsdPrice,\n shortenAddress,\n} from '@/shared/core/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport { ONDO_QUOTE_EXPIRY_THRESHOLD_MS } from '@/shared/core/checkout/ondo/constants';\nimport { computeOndoPrice } from '@/shared/core/checkout/ondo/math';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n EthereumChain,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\nimport type { OndoSwapTransaction } from '@/shared/types/providers/ondo/ondo';\n\nexport type OndoReviewStepInput =\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 transaction `prepareSwap` 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?: OndoSwapTransaction;\n };\n\n/**\n * A filled order, as the confirmation dialog needs it.\n *\n * It names no asset. The transaction does not carry one, and rebuilding an\n * `Erc20Asset` here would mean inventing a `decimals` - the quote's answers\n * for a different quantity, and the transaction's is a scale rather than a\n * property of the token. A host that wants to know what was bought has the\n * `offer` and `ondoSymbol` it passed in.\n */\nexport type OndoOrderPlaced = {\n txHash: Hash;\n transaction: OndoSwapTransaction;\n /** What the buyer paid, in the input asset. */\n amount: BlockchainAmount;\n inputAsset: StablecoinSymbol;\n wallet: EvmWallet;\n};\n\nexport interface UseOndoReviewViewModelOptions {\n stepInput: OndoReviewStepInput;\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 only icon.\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: OfferDetail;\n /** Called once the swap has mined. */\n onComplete: (order: OndoOrderPlaced) => void;\n}\n\nexport interface UseOndoReviewViewModelResult {\n state: OndoReviewUiState;\n onEvent: (event: OndoReviewUiEvent) => 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, and a quote inside\n * {@link ONDO_QUOTE_EXPIRY_THRESHOLD_MS} of its deadline is treated as already\n * gone: placing an order is not instant, and a transaction that arrives after\n * the deadline reverts at the user's expense.\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 useOndoReviewViewModel({\n stepInput,\n ondoSymbol,\n chain,\n offer,\n onComplete,\n}: UseOndoReviewViewModelOptions): UseOndoReviewViewModelResult {\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 } = useOndoSwapTransaction({\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: isActive,\n });\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') setError(null);\n }, [stepInput.type]);\n\n const transaction =\n transactionState.type === 'CONTENT' ? transactionState.transaction : null;\n const secondsLeft = useCountdown({ until: transaction?.expiresAt ?? null });\n const quoteStatus = toQuoteStatusUi(transactionState, secondsLeft);\n\n const uiState = (): OndoReviewUiState => {\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<OndoReviewStepInput, { type: 'active' }>,\n built: OndoSwapTransaction\n ): Extract<OndoReviewUiState, { 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 }),\n outputAmount: assetAmount(\n formatAmount(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(computeOndoPrice(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.payInputAmount, 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 if (stepInput.type !== 'active' || transaction === null || phase !== null) {\n return;\n }\n if (quoteStatus.type !== 'valid') return;\n\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 setError(executionErrorMessage(result.error));\n return;\n }\n onComplete({\n txHash: result.txHash,\n transaction: result.transaction,\n amount: stepInput.amount,\n inputAsset: stepInput.inputAsset,\n wallet: stepInput.wallet,\n });\n };\n\n const refreshQuote = () => {\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: OndoReviewUiEvent) => {\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: LoadOndoSwapTransactionState,\n secondsLeft: number | null\n): OndoQuoteStatusUi {\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 || isTooCloseToExpiry(secondsLeft)) {\n return { type: 'expired' };\n }\n return { type: 'valid', expiresInLabel: expiresInLabel(secondsLeft) };\n}\n\n/**\n * A quote with only seconds left is one the order cannot reach in time: the\n * wallet has to prompt, the user has to confirm, and the transaction has to\n * travel. Calling those seconds expired turns a paid-for revert into a button.\n */\nfunction isTooCloseToExpiry(secondsLeft: number): boolean {\n return secondsLeft * 1000 <= ONDO_QUOTE_EXPIRY_THRESHOLD_MS;\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 '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 'spender-mismatch':\n return 'This quote does not match the approval you gave. Get a new one.';\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 { BuildOndoSwapTransactionParams } from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport type { OndoSwapTransaction } from '@/shared/types/providers/ondo/ondo';\n\n/**\n * The state of the built transaction 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 transaction may\n * still be good, and a failed refresh is fixed by refreshing again.\n */\nexport type LoadOndoSwapTransactionState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: OndoLoadErrorReason }\n | {\n type: 'CONTENT';\n transaction: OndoSwapTransaction;\n isRefreshing: boolean;\n /** Why the last refresh failed; `null` when the transaction is fresh. */\n refreshError: OndoLoadErrorReason | null;\n };\n\nexport interface UseOndoSwapTransactionOptions {\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: BuildOndoSwapTransactionParams | null;\n /**\n * A transaction the caller already holds, typically the one `prepareSwap`\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?: OndoSwapTransaction;\n /** When false, the hook does not fetch. */\n enabled: boolean;\n}\n\nexport interface UseOndoSwapTransactionResult {\n state: LoadOndoSwapTransactionState;\n /** Builds a fresh transaction for the same order. Spends an attestation. */\n refetch: () => void;\n}\n\n/**\n * Holds the firm, expiring transaction a review step places an order against,\n * 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 transaction 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 * transaction: 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 * Buy-only, like the endpoint behind it - the funding token goes in and the\n * asset comes out, both resolved from the offer. It sits beside the two\n * side-parameterised polls rather than under `buy/` because a sell will reach\n * for the same seam, and moving it then is cheaper than forking it now.\n */\nexport function useOndoSwapTransaction(\n options: UseOndoSwapTransactionOptions\n): UseOndoSwapTransactionResult {\n const { request, data, enabled } = options;\n const { coinlist, isReady } = useCoinList();\n const log = useLogger('useOndoSwapTransaction');\n\n const [state, setState] = useState<LoadOndoSwapTransactionState>(() =>\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 sibling\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.buildSwapTransaction(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 `prepareSwap` 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 - `prepareSwap` 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: BuildOndoSwapTransactionParams): 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 { NotAuthenticatedError } from '@/shared/types/errors';\n\n/**\n * Why an Ondo read failed, in the only two 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. Everything else collapses\n * 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 = 'not-authenticated' | 'generic-error';\n\nexport function ondoLoadErrorReason(error: unknown): OndoLoadErrorReason {\n return error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : '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 type {\n OndoSidebarPriceUi,\n OndoSidebarUiState,\n} from '@/client/hooks/checkout/ondo/buy/sidebar/useOndoSidebarViewModel.types';\nimport type { LoadOndoPriceState } from '@/client/hooks/checkout/ondo/shared/data/useOndoPrice';\nimport type { LoadOndoTradingStatusState } from '@/client/hooks/checkout/ondo/shared/data/useOndoTradingStatus';\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 '@/shared/core/blockchain/chain';\nimport { formattedUsdPrice } from '@/shared/core/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/shared/core/blockchain/math';\nimport {\n AssetDecimals,\n type AssetSymbol,\n type BlockchainAmount,\n type DecimalString,\n type EthereumChain,\n} from '@/shared/types/blockchain/core';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\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: OfferDetail;\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 /** 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 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 }),\n // No frontline endpoint carries any of these today, and the detail list\n // drops a null row rather than dashing it.\n issuer: null,\n tickerSymbol: null,\n isin: null,\n assetType: null,\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/buy/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 '@/shared/core/blockchain/chain';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/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 { 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 '@/shared/core/checkout/ondo/constants';\nimport type { OndoQuoteSize } from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport {\n AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n DecimalString,\n} from '@/shared/types/blockchain/core';\nimport type { OndoQuote } from '@/shared/types/providers/ondo/ondo';\nimport type { OrderBookSide } from '@/shared/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.prepareSwap`.\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 '@/shared/core/checkout/ondo/constants';\nimport type { AssetSymbol } from '@/shared/types/blockchain/core';\nimport type { OndoTradingStatus } from '@/shared/types/providers/ondo/ondo';\nimport type { OrderBookSide } from '@/shared/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\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","'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 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 { offerIconUrl } from '@/client/ui/format/asset-icon';\nimport { getNetworkName, txExplorerUrl } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formattedUsdPrice,\n shortenAddress,\n usdAmount,\n} from '@/shared/core/blockchain/formatters';\nimport { TOKEN_REGISTRY, USDC } from '@/shared/core/blockchain/token-registry';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport {\n DEFAULT_AMOUNT_TO_COMPUTE_PRICE,\n SUPERSTATE_ISSUER_NAME,\n SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n SWAP_POLL_INTERVAL_MS,\n superstateSwapContractAddress,\n} from '@/shared/core/checkout/superstate/constants';\nimport {\n BlockchainAmount,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { AssetIconUrl } from '@/shared/types/blockchain/ui';\nimport type { OfferDetail } from '@/shared/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: OfferDetail;\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, so the\n * hook can be called unconditionally beside other providers' viewmodels.\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 const assetIconUrl = offerIconUrl(offer);\n\n const [step, setStep] = useState<SuperstateSwapStep>({ type: 'wallet' });\n const [orderConfirmed, setOrderConfirmed] =\n useState<SuperstateOrderConfirmedUiState>({ type: 'hidden' });\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 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 { inputAmount, inputTokenAddress } = quoteInput(step, chain);\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(\n toOrderConfirmedUi({ order, chain, locale, assetIconUrl })\n );\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 orderConfirmed,\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({ type: 'hidden' });\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 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: TOKEN_REGISTRY.contractAddress(\n SUPERSTATE_SUPPORTED_INPUT_ASSETS[0],\n chain\n ),\n };\n case 'review':\n return {\n inputAmount: step.amount,\n inputTokenAddress: TOKEN_REGISTRY.contractAddress(\n step.inputAsset,\n chain\n ),\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 issuer: SUPERSTATE_ISSUER_NAME,\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 { getNetworkName } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatRawAmount,\n shortenAddress,\n usdAmount,\n} from '@/shared/core/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/shared/core/blockchain/math';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport {\n SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n SWAP_POLL_INTERVAL_MS,\n} from '@/shared/core/checkout/superstate/constants';\nimport {\n type AssetDecimals,\n type AssetSymbol,\n BlockchainAmount,\n type EthereumChain,\n EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/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 '@/shared/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 '@/shared/core/checkout/superstate/blockchain/quote';\nimport { SWAP_POLL_INTERVAL_MS } from '@/shared/core/checkout/superstate/constants';\nimport type {\n AssetDecimals,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/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 { getNetworkName } from '@/shared/core/blockchain/chain';\nimport {\n assetAmount,\n formatAmount,\n formatBpsAsPercent,\n shortenAddress,\n usdAmount,\n} from '@/shared/core/blockchain/formatters';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport { computeSlip } from '@/shared/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport {\n DEFAULT_SLIPPAGE_BPS,\n SLIPPAGE_OPTIONS_BPS,\n} from '@/shared/core/checkout/superstate/constants';\nimport { formattedPricePerShare } from '@/shared/core/checkout/superstate/formatters';\nimport {\n BlockchainAmount,\n type Bps,\n type Erc20Asset,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { AssetIconUrl } from '@/shared/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 /** The offer's logo, which is the only icon the output asset has. */\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 inputTokenAddress: TOKEN_REGISTRY.contractAddress(\n stepInput.inputAsset,\n chain\n ),\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-stopped':\n return 'Swapping is currently paused. Please check back soon.';\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","'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 { getNetworkName } from '@/shared/core/blockchain/chain';\nimport {\n formatAmount,\n NA_AMOUNT_ASSET_UI,\n usdAmount,\n} from '@/shared/core/blockchain/formatters';\nimport { parseBlockchainAmount } from '@/shared/core/blockchain/math';\nimport { TOKEN_REGISTRY, USDC } from '@/shared/core/blockchain/token-registry';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport {\n SUPERSTATE_ISSUER_NAME,\n SUPERSTATE_SUPPORTED_INPUT_ASSETS,\n} from '@/shared/core/checkout/superstate/constants';\nimport { formattedPricePerShare } from '@/shared/core/checkout/superstate/formatters';\nimport {\n AssetSymbol,\n type Erc20Asset,\n type EthereumChain,\n} from '@/shared/types/blockchain/core';\nimport type {\n AssetIconUrl,\n FormattedAmountAssetUi,\n} from '@/shared/types/blockchain/ui';\nimport type { OfferDetail } from '@/shared/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: OfferDetail;\n /** The chain the token lives on, which names the network row. */\n chain: EthereumChain;\n /** The offer's logo — the only icon the output asset has. */\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 has to\n * come from the offer regardless: the SDK ships no icon registry, and an\n * `Erc20Asset` carries none.\n */\nfunction assetUi(\n offer: OfferDetail,\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 '@/shared/core/blockchain/chain';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type {\n EthereumChain,\n EvmContractAddress,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { EvmWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/shared/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 { OndoBuyCheckoutView } from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutView';\nimport { SuperstateSwapCheckoutView } from '@/client/components/checkout/superstate/swap/SuperstateSwapCheckoutView';\nimport type { OndoOrderPlaced } from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel';\nimport { useOndoBuyCheckoutViewModel } from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel';\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 {\n AssetSymbol,\n EthereumChain,\n} from '@/shared/types/blockchain/core';\nimport type { OfferType } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\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 * Nothing here is per-offer. It is per-*integration*, so a host builds it once\n * and passes the same object for every offer it renders.\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 * Must be total. Ondo's viewmodel is called for every offer - React hooks\n * cannot be called conditionally - so this runs for Superstate and\n * token-sale offers too, where its result is passed to a viewmodel that is\n * `enabled: false` and never reads it. Throwing on an offer you do not\n * recognise would take down a checkout Ondo has no part in; return anything.\n */\n symbol: (offer: OfferDetail) => AssetSymbol;\n /** Fired once an Ondo swap has mined. The dialog shows either way. */\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: OfferDetail) => 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': { symbol: (offer) => AssetSymbol(offer.asset.code) },\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 every\n * provider, for a checkout that is mounted 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 * Every provider's viewmodel is called on every render, because React hooks\n * cannot be called conditionally. Only the one matching `offer.type` is\n * `enabled`, so the other providers fetch nothing and run no timers — that\n * `enabled` flag is why every checkout viewmodel has one.\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\n *\n * `offer` and `chain` are read as fixed for the lifetime of the mount. Each\n * provider's viewmodel owns a step machine — which wallet was authorized, how\n * much is being spent — and that progress is bound to the offer it was made\n * against: a Superstate wallet authorization is allow-listed per offer, and an\n * ERC-20 approval is granted per chain. Changing either prop in place would\n * carry a completed step from one offer onto another, so the container does not\n * try to; a swap could also land mid-execution, between an approval and the\n * broadcast it was granted for, which is worse than not switching at all.\n *\n * **To render a different offer or chain, remount rather than reassign** — give\n * the container a `key` that changes with them:\n *\n * ```tsx\n * <CheckoutContainer\n * key={`${offer.id}:${chain}`}\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 */\nexport function CheckoutContainer({\n offer,\n chain,\n wallets,\n config,\n enabled = true,\n className,\n}: CheckoutContainerProps): ReactNode {\n const ondo = useOndoBuyCheckoutViewModel({\n offer,\n ondoSymbol: config['ondo::swap'].symbol(offer),\n chain,\n wallets,\n enabled: enabled && offer.type === 'ondo::swap',\n onOrderConfirmed: config['ondo::swap'].onOrderConfirmed,\n });\n\n const superstate = useSuperstateSwapCheckoutViewModel({\n offer,\n chain,\n wallets,\n enabled: enabled && offer.type === 'superstate::swap',\n onOrderConfirmed: config['superstate::swap'].onOrderConfirmed,\n });\n\n return renderOffer(offer.type, {\n ondo: () => (\n <OndoBuyCheckoutView\n state={ondo.state}\n onEvent={ondo.onEvent}\n className={className}\n />\n ),\n superstate: () => (\n <SuperstateSwapCheckoutView\n state={superstate.state}\n onEvent={superstate.onEvent}\n className={className}\n />\n ),\n tokenSale: () => config['coinlist::token_sale'].render(offer),\n });\n}\n\n/**\n * Picks the branch for an offer type.\n *\n * Split out so the dispatch is one exhaustive `switch` over `OfferType` with\n * nothing else in it — the hooks above have to run first regardless of which\n * branch wins, and interleaving them made it easy to misread that as a\n * conditional call.\n */\nfunction renderOffer(\n type: OfferType,\n branches: {\n ondo: () => ReactNode;\n superstate: () => ReactNode;\n tokenSale: () => ReactNode;\n }\n): ReactNode {\n switch (type) {\n case 'ondo::swap':\n return branches.ondo();\n case 'superstate::swap':\n return branches.superstate();\n case 'coinlist::token_sale':\n return branches.tokenSale();\n default: {\n // A new offer type without a case here is a compile error.\n const exhaustive: never = type;\n return exhaustive;\n }\n }\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { OndoBuyCheckoutView } from '@/client/components/checkout/ondo/buy/OndoBuyCheckoutView';\nimport type { OndoOrderPlaced } from '@/client/hooks/checkout/ondo/buy/review/useOndoReviewViewModel';\nimport { useOndoBuyCheckoutViewModel } from '@/client/hooks/checkout/ondo/buy/useOndoBuyCheckoutViewModel';\nimport type { CheckoutWalletSelection } from '@/client/hooks/checkout/shared/checkout-wallet.types';\nimport type {\n AssetSymbol,\n EthereumChain,\n} from '@/shared/types/blockchain/core';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\n\nexport interface OndoBuyCheckoutContainerProps {\n /** The offer being bought: names the asset and supplies its logo. */\n offer: OfferDetail;\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, which is what\n * `CheckoutContainer` uses to call each provider's checkout unconditionally.\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 { 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 '@/shared/types/blockchain/core';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\n\nexport interface SuperstateSwapCheckoutContainerProps {\n /** The offer being bought: names the asset, the window and the minimum. */\n offer: OfferDetail;\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, which is what\n * `CheckoutContainer` uses to call each provider's checkout unconditionally.\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","'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 { OfferCardUi } from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\n\nexport interface Props {\n offer: OfferCardUi;\n /** Optional click handler. When provided, the card renders as interactive. */\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 * Offer card. Self-scoped: renders fully styled on its own, with no\n * `CoinListStyleScope` needed. Also composed by {@link OffersGrid}.\n */\nexport function OfferCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: Props): ReactNode {\n const cardLabel = 'Open offer details';\n\n const cardContent = (\n <>\n <div className=\"clcosdk:relative clcosdk:mb-6 clcosdk:h-52 clcosdk:w-full clcosdk:overflow-hidden clcosdk:rounded-2xl clcosdk:border clcosdk:border-border/60 clcosdk:bg-section\">\n {offer.bannerUrl ? (\n <img\n src={offer.bannerUrl}\n alt=\"Offer banner\"\n className=\"clcosdk:h-full clcosdk:w-full clcosdk:object-cover\"\n />\n ) : (\n <div className=\"clcosdk:h-full clcosdk:w-full clcosdk:bg-gradient-to-br clcosdk:from-surface clcosdk:via-section clcosdk:to-background\" />\n )}\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:bg-gradient-to-b clcosdk:from-transparent clcosdk:via-transparent clcosdk:to-overlay/35\" />\n\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:p-6\">\n {offer.logoUrl ? (\n <img\n src={offer.logoUrl}\n alt=\"Offer logo\"\n className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:object-cover clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.25)]\"\n />\n ) : (\n <div className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.18)]\" />\n )}\n </div>\n </div>\n\n {offer.tagline && (\n <p\n className={cn(\n typeClasses.h3,\n 'clcosdk:min-h-[2.4rem] clcosdk:text-text-primary'\n )}\n >\n {offer.tagline}\n </p>\n )}\n\n <div className=\"clcosdk:mt-4 clcosdk:grid clcosdk:grid-cols-2 clcosdk:gap-5 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Starts\n </span>\n <span className={cn(typeClasses.label, 'clcosdk:text-text-primary')}>\n {offer.formattedStartsAt}\n </span>\n </div>\n\n {offer.formattedEndsAt && (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Ends\n </span>\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-primary')}\n >\n {offer.formattedEndsAt}\n </span>\n </div>\n )}\n </div>\n </>\n );\n\n const baseClasses = cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-[28rem] clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-left clcosdk:shadow-card clcosdk:transition-all clcosdk:duration-200',\n className,\n onClick &&\n 'clcosdk:cursor-pointer clcosdk:hover:-translate-y-0.5 clcosdk:hover:border-divider clcosdk:hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-accent-focus clcosdk:focus-visible:ring-offset-2'\n );\n\n let cardNode: ReactNode;\n if (onClick) {\n cardNode = (\n <button\n type=\"button\"\n aria-label={cardLabel}\n className={baseClasses}\n onClick={onClick}\n >\n {cardContent}\n </button>\n );\n } else {\n cardNode = <div className={baseClasses}>{cardContent}</div>;\n }\n\n const card = containerClassName ? (\n <div className={containerClassName}>{cardNode}</div>\n ) : (\n cardNode\n );\n\n return <CoinListStyleScope>{card}</CoinListStyleScope>;\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 { OfferCard } from '@/client/components/offers/grid/OfferCard';\nimport type {\n OfferCardUi,\n OffersGridUiEvent,\n OffersGridUiState,\n} from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\n\nconst DEFAULT_MAX_COLUMNS = 3;\n\nexport interface OffersGridViewProps {\n state: OffersGridUiState;\n onEvent: (event: OffersGridUiEvent) => void;\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}\n\n/**\n * Renders every state of the offers grid. Pure: it holds no state, fetches\n * nothing, and reports clicks through `onEvent`.\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: OfferCardUi[];\n interactive: boolean;\n onEvent: (event: OffersGridUiEvent) => void;\n maxColumns?: number;\n className?: string;\n containerClassName?: string;\n}): ReactNode {\n const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);\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('clcosdk:grid clcosdk:w-full clcosdk:gap-6', className)}\n style={{\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 20rem), 1fr))',\n maxWidth: maxGridWidth,\n }}\n >\n {offers.map((offer) => (\n <OfferCard\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 {\n OfferCardUi,\n type OffersGridUiEvent,\n type OffersGridUiState,\n} from '@/client/hooks/offers/grid/useOffersGridViewModel.types';\nimport { useLocale } from '@/client/hooks/shared/useLocale';\nimport type { Offer } from '@/shared/types/offer';\n\nexport interface UseOffersGridViewModelOptions {\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer#offers.list()`).\n * When provided, the client-side fetch is skipped entirely.\n */\n data?: Offer[];\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, formats them for the cards,\n * and resolves a clicked card back to its domain offer for the host callback.\n */\nexport function useOffersGridViewModel(\n options: UseOffersGridViewModelOptions = {}\n): UseOffersGridViewModelResult {\n const { data, onOfferClick } = options;\n const { offersState } = useOffers({ data });\n const locale = useLocale();\n\n const state = useMemo<OffersGridUiState>(\n () => toUiState(offersState, locale, onOfferClick !== undefined),\n [offersState, locale, 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 locale: string,\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 return {\n type: 'content',\n offers: offersState.offers.map((offer) =>\n OfferCardUi.fromDomain(offer, locale)\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 '@/shared/types/errors';\nimport type { Offer } from '@/shared/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\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.\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 } = 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 // 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, serverOffers, log]);\n\n return { offersState };\n}\n","/**\n * Date presentation helpers.\n *\n * Every function takes an explicit `locale`, the way\n * `@/shared/core/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","import { formatMonthYear } from '@/client/ui/format/date';\nimport type { Offer, OfferId } from '@/shared/types/offer';\n\nexport type OffersGridUiState =\n | { type: 'loading' }\n | { type: 'error'; message: string }\n | { type: 'empty' }\n | {\n type: 'content';\n offers: OfferCardUi[];\n /** Cards render as buttons only when the host passed `onOfferClick`. */\n interactive: boolean;\n };\n\nexport type OffersGridUiEvent = {\n type: 'ON_OFFER_CLICK';\n offerId: OfferId;\n};\n\n/**\n * An offer as an offer card renders it: dates already formatted, nothing left\n * to decide at render time.\n */\nexport type OfferCardUi = {\n id: OfferId;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n formattedStartsAt: string;\n formattedEndsAt: string | null;\n};\n\nexport const OfferCardUi = {\n fromDomain: (offer: Offer, locale: string): OfferCardUi => ({\n id: offer.id,\n tagline: offer.tagline,\n bannerUrl: offer.bannerUrl,\n logoUrl: offer.logoUrl,\n formattedStartsAt: formatMonthYear(offer.startsAt, locale),\n formattedEndsAt: offer.endsAt\n ? formatMonthYear(offer.endsAt, locale)\n : null,\n }),\n};\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { OffersGridView } from '@/client/components/offers/grid/OffersGridView';\nimport { useOffersGridViewModel } from '@/client/hooks/offers/grid/useOffersGridViewModel';\nimport type { Offer } from '@/shared/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 * Offers pre-fetched on the server (e.g. via `CoinListServer#offers.list()`).\n * When provided, the component uses this data as-is and skips the client-side\n * fetch entirely.\n */\n data?: Offer[];\n}\n\n/**\n * Displays a responsive grid of offers, backed by\n * {@link useOffersGridViewModel}.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip the\n * client-side fetch entirely. Uses the `loading` / `error` / `emptyState` slots\n * when provided; otherwise renders the standard fallbacks. Cards are\n * interactive only when `onOfferClick` is 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 ...viewProps\n}: OffersGridContainerProps = {}): ReactNode {\n const { state, onEvent } = useOffersGridViewModel({ data, onOfferClick });\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/checklist/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 { 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/checklist/ConnectedWalletList';\nimport type {\n ConnectedWalletUi,\n RequirementItemUi,\n RequirementStatus,\n WalletsStatus,\n} from '@/client/hooks/requirements/checklist/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\nfunction VerificationActionZone({\n status,\n onAction,\n onContactSupport,\n}: {\n status: RequirementStatus;\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\" onClick={onAction}>\n Continue\n </ClButton>\n );\n case 'pending':\n return (\n <AlertBanner\n variant=\"warning\"\n content=\"Under review. We'll notify you when complete.\"\n />\n );\n case 'completed':\n return <AlertBanner variant=\"success\" content=\"Identity verified.\" />;\n case 'rejected':\n return (\n <AlertBanner\n variant=\"error\"\n content={\n onContactSupport === null ? (\n 'Verification rejected.'\n ) : (\n <>\n Verification rejected.{' '}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"clcosdk:underline\"\n >\n Contact support\n </button>\n .\n </>\n )\n }\n />\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 size=\"sm\" variant=\"secondary\" onClick={onAction}>\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\" 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\" 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}: 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:flex clcosdk:h-14 clcosdk:w-full 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 className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4\">\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:text-text-secondary'\n )}\n >\n {ui.description}\n </p>\n {ui.variant === 'verification' ? (\n <VerificationActionZone\n status={ui.status}\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 { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { RequirementItem } from '@/client/components/requirements/checklist/RequirementItem';\nimport type {\n RequirementsChecklistUiEvent,\n RequirementsChecklistUiState,\n} from '@/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.types';\n\nexport interface RequirementsChecklistViewProps {\n state: RequirementsChecklistUiState;\n onEvent: (event: RequirementsChecklistUiEvent) => void;\n /** Optional loading slot. */\n loading?: ReactNode;\n /** Optional error slot. */\n error?: ReactNode;\n /**\n * Rendered when the user is not authenticated. Nothing is rendered when\n * omitted; `RequirementsChecklistContainer` passes a connected sign-in card.\n */\n unauthenticatedState?: ReactNode;\n className?: string;\n}\n\n/**\n * Renders the requirements checklist: its header, one row per requirement, the\n * eligibility banner and the continue action. Pure: the rows arrive already\n * shaped in `state`, and every 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 unauthenticatedState,\n className,\n}: RequirementsChecklistViewProps): ReactNode {\n switch (state.type) {\n case 'loading':\n return loading ?? <LoadingState />;\n case 'not-authenticated':\n return unauthenticatedState ?? null;\n case 'error':\n return (\n error ?? (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Unable to load requirements right now. Please try again.\"\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n )\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 <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n {state.description}\n </p>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {state.items.map((row) => (\n <RequirementItem\n key={row.id}\n ui={row.item}\n expanded={row.expanded}\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 {state.ineligible && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"You are not eligible to participate.\"\n />\n )}\n\n {state.continueAction && (\n <ClButton\n fullWidth\n disabled={!state.continueAction.enabled}\n onClick={() => onEvent({ type: 'ON_CONTINUE' })}\n >\n Continue\n </ClButton>\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 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 requirements...\n </p>\n </output>\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 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 '@/shared/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 '@/shared/types/errors';\nimport type { KycLevelName } from '@/shared/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 '@/shared/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 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 '@/shared/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 '@/shared/types/document-submission';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Pii } from '@/shared/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 '@/shared/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, 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 '@/shared/core/blockchain/formatters';\nimport type { ConnectWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/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 '@/shared/types/blockchain/core';\nimport type { ConnectWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/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/blockchain/wallet-error';\nimport type { WalletsNamespace } from '@/shared/core/wallets/wallets-namespace';\nimport type { ConnectWallet } from '@/shared/types/blockchain/evm-wallet';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletChallengeType,\n WalletOwnershipChallenge,\n} from '@/shared/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 `@/shared/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 '@/shared/types/blockchain/evm-wallet';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/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 {\n ChecklistStatus,\n RequirementItemUi,\n type RequirementsChecklistUiEvent,\n type RequirementsChecklistUiState,\n type RequirementsVerificationUi,\n RequirementVariant,\n type WalletsStatus,\n} from '@/client/hooks/requirements/checklist/useRequirementsChecklistViewModel.types';\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 { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { ConnectWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { OfferOptionAddressId } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/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 /** 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: 'KYC Verification',\n external_wallet: 'External Wallet',\n whitelisted_wallet: 'Whitelisted Wallet',\n jurisdiction: 'Jurisdiction Check',\n accreditation: 'Accreditation',\n document: 'Document',\n};\n\nconst DEFAULT_DESCRIPTIONS: Record<RequirementType, string> = {\n kyc_approved: 'Complete Know Your Customer verification.',\n external_wallet: 'Connect an external wallet.',\n whitelisted_wallet: 'Connect a whitelisted wallet.',\n jurisdiction: 'Confirm your jurisdiction eligibility.',\n accreditation: 'Verify your accreditation status.',\n document: 'Confirm your Tax Documents.',\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 */\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 identityVerificationOptions,\n } = options;\n const log = useLogger('useRequirementsChecklistViewModel');\n\n const { coinlist } = useCoinList();\n const { requirementsState, refetch } = useRequirements(offerId, { data });\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: 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' };\n case 'ERROR':\n return requirementsState.reason === 'not-authenticated'\n ? { type: 'not-authenticated' }\n : { type: 'error' };\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 { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\n\nexport type RequirementsChecklistUiState =\n | { type: 'loading' }\n | { type: 'not-authenticated' }\n | { type: 'error' }\n | {\n type: 'content';\n title: string;\n description: string;\n items: RequirementsChecklistItemUi[];\n ineligible: boolean;\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};\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: statusInfo\n ? RequirementStatus.fromStatusValue(statusInfo.status)\n : 'required',\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 };\n },\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","import { useCallback, useEffect, useState } from 'react';\nimport { useLogger } from '@/client/hooks/shared/useLogger';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/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 '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/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\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 *\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 } = 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 (!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, offerId, fetchKey, log]);\n\n return { requirementsState, refetch };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListSignInCardContainer } from '@/client/components/auth/CoinListSignInCardContainer';\nimport { RequirementsChecklistView } from '@/client/components/requirements/checklist/RequirementsChecklistView';\nimport { VerificationOverlay } from '@/client/components/requirements/checklist/VerificationOverlay';\nimport { IdentityVerificationContainer } from '@/client/components/requirements/identity-verification/IdentityVerificationContainer';\nimport { TaxDocumentModalContainer } from '@/client/components/requirements/tax-document/TaxDocumentModalContainer';\nimport { ConnectWalletModalContainer } from '@/client/components/requirements/wallet/ConnectWalletModalContainer';\nimport { useRequirementsChecklistViewModel } from '@/client/hooks/requirements/checklist/useRequirementsChecklistViewModel';\nimport type { RequirementsData } from '@/client/hooks/requirements/data/useRequirements';\nimport type { ConnectWallet } from '@/shared/types/blockchain/evm-wallet';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { Requirement } from '@/shared/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 * Rendered when the user is not authenticated. Defaults to\n * {@link CoinListSignInCardContainer}, which prompts the user to sign in and starts\n * the CoinList OAuth flow. Pass `null` to render nothing.\n */\n unauthenticatedState?: ReactNode;\n /** Optional error slot. */\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 * 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.\n *\n * When the user is not authenticated, renders a sign-in card instead of the\n * checklist - without fetching. Pass `unauthenticatedState` to customize that\n * state, or `null` to render nothing.\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 unauthenticatedState,\n className,\n ...options\n}: RequirementsChecklistContainerProps): ReactNode {\n const { state, onEvent } = useRequirementsChecklistViewModel(options);\n\n return (\n <>\n <RequirementsChecklistView\n state={state}\n onEvent={onEvent}\n loading={loading}\n error={error}\n unauthenticatedState={\n // The sign-in default lives here, not in the View: it is a connected\n // component, and a View must render from what it is handed.\n unauthenticatedState !== undefined ? (\n unauthenticatedState\n ) : (\n <CoinListSignInCardContainer />\n )\n }\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 '@/shared/core/observability/pino-logger';\nimport type { Logger, PinoLoggerOptions } from '@/shared/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 '@/shared/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 `@/shared`\n * stays pino-free and the `./shared` 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 * `@/shared` 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 '@/shared/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 '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { Participation } from '@/shared/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\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.\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 } = 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 // 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, 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 '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/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\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.\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 } = 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 (!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, offerId, data, log]);\n\n return { offerDetailsState };\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 '@/shared/types/blockchain/core';\nimport type { TokenMetadata } from '@/shared/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"],"mappings":"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","names":["import_react","userAgent","requestId","emit","import_viem","import_viem","import_viem","import_viem","emit","import_viem","emit","emit","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_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","subtitle","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","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_lucide_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","TITLE","detailRows","import_lucide_react","import_react","import_jsx_runtime","import_jsx_runtime","TITLE","ActiveView","CompletedView","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","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","DESCRIPTION","EMBEDDED_WALLET_LABEL","EXTERNAL_WALLET_LABEL","ActiveView","CompletedView","ExternalWalletRow","EmbeddedWalletRow","WalletGlyph","DisconnectControl","import_jsx_runtime","ERROR_TITLE","ERROR_DESCRIPTION","ErrorView","import_react","import_react","import_react","import_react","import_react","import_react","phaseMessage","MARKET_CLOSED","import_react","error","import_react","size","import_react","LOADING","import_react","import_react","NO_WALLET","INVALID_AMOUNT","AMOUNT_ZERO","toInputAssetUi","import_react","import_react","import_react","phaseMessage","executionErrorMessage","import_react","CONNECT_FAILED","resolveWallet","toEmbeddedWalletUi","toExternalWalletUi","toConfirmedWalletUi","phaseMessage","error","findEmbedded","walletStepInput","amountStepInput","reviewStepInput","toOrderConfirmedUi","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_react","LOADING_STATE","import_jsx_runtime","import_react","import_jsx_runtime","import_lucide_react","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","LoadingState","import_jsx_runtime","import_jsx_runtime","SumsubWebSdk","import_react","import_react","LOADING_STATE","NOT_AUTHENTICATED_MESSAGE","GENERIC_ERROR_MESSAGE","import_jsx_runtime","import_jsx_runtime","import_react","import_react","LOADING_STATE","NOT_AUTHENTICATED_MESSAGE","GENERIC_ERROR_MESSAGE","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","import_jsx_runtime","import_react","import_react","LOADING_STATE","import_react","LOADING_STATE","import_react","LOADING_STATE"]}