@coinlist-co/react 0.10.0 → 0.10.1
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.
- package/dist/{chunk-GSSAB4K5.js → chunk-AQVCOWOV.js} +163 -69
- package/dist/chunk-AQVCOWOV.js.map +1 -0
- package/dist/{chunk-7BJ2HAG7.js → chunk-TBU3EBNM.js} +2 -2
- package/dist/{chunk-TUZKKFNW.js → chunk-UOHD7US2.js} +53 -34
- package/dist/chunk-UOHD7US2.js.map +1 -0
- package/dist/client/index.cjs +292 -295
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +5 -4
- package/dist/client/index.js.map +1 -1
- package/dist/{collections-ZYLKp8JB.d.ts → collections-Bv1Oxzu_.d.ts} +1 -1
- package/dist/{collections-CJ24dOda.d.cts → collections-DDyxbOPZ.d.cts} +1 -1
- package/dist/{requirement-CDi5NJI8.d.cts → requirement-oVZA1INj.d.cts} +5 -1
- package/dist/{requirement-CDi5NJI8.d.ts → requirement-oVZA1INj.d.ts} +5 -1
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +3 -5
- package/dist/server/index.js.map +1 -1
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.d.cts +4 -4
- package/dist/shared/index.d.ts +4 -4
- package/dist/shared/index.js +12 -92
- package/dist/shared/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-AAER5LOL.js +0 -22
- package/dist/chunk-AAER5LOL.js.map +0 -1
- package/dist/chunk-GSSAB4K5.js.map +0 -1
- package/dist/chunk-TUZKKFNW.js.map +0 -1
- /package/dist/{chunk-7BJ2HAG7.js.map → chunk-TBU3EBNM.js.map} +0 -0
|
@@ -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/participation.ts","../../src/client/core/blockchain/token-sale-flow.ts","../../src/shared/api/frontline/participations.ts","../../src/shared/core/token-sale-namespace.ts","../../src/client/core/client-token-sale-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/api/frontline/offers.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/erc20-namespace.ts","../../src/shared/types/oauth.ts","../../src/shared/pkce.ts","../../src/shared/types/errors.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/shared/core/blockchain/formatters.ts","../../src/shared/types/blockchain/ui.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/shared/core/blockchain/swap/constants.ts","../../src/shared/core/blockchain/swap/quote.ts","../../src/client/hooks/swap/useSwapTokenBalances.ts","../../src/shared/core/blockchain/token-registry.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 { 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 /** Raw base-unit amount to participate with (e.g. `\"100000000\"` for 100 USDC with 6 decimals). */\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 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 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 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: amount.raw.toString(),\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 { 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 {\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 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 { 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 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 {\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 { 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","/**\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 { 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","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 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","'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 { 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 { 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 {\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 { 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;;;AC5DO,IAAM,kBAAkB,CAAC,UAAkB;AAK3C,IAAM,aAAa,CAAC,UAAkB;AAKtC,IAAM,gBAAgB,CAAC,UAAyB;AA0DhD,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;;;AC5CA,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;AAI/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,OAAO,IAAI,SAAS;AAAA,MAC5B;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;;;AC3KA,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;;;ACvDO,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;;;AC1BO,IAAM,qBAAqB;AAAA,EAChC,SAAS,CAAC,SAAoD;AAAA,IAC5D,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,EAChB;AACF;;;ACVA,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;;;ACbO,IAAM,WAAW;AAAA,EACtB,SAAS,CAAC,SAAgC;AAAA,IACxC,OAAO,IAAI;AAAA,EACb;AACF;;;ACbA,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;;;ACxCO,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;;;AClEA,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;;;ACDO,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;;;ACnDA,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;;;ACAO,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;;;ACrDO,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;;;ACzCO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACE,UAAU,mEACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;AC+CO,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;;;ArD5dI;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;;;AsDnFhC,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;;;AEpLA,IAAAC,eAA4B;;;ACsBrB,IAAM,yBAAyB,CAAC,UACrC;AAGK,IAAM,yBAAyB,CAAC,UACrC;;;ADVK,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;AA4JO,IAAM,qBACX,uBAAuB,GAAG;AAE5B,IAAM,sBAAsB,cAAc,CAAC;;;AHxFnC,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;;;AKzMA,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;;;ACKrC,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;;;AFQO,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;;;AGvIA,IAAAC,iBAA4C;;;ACSrC,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;;;AD1BO,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;;;AExHA,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_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_viem","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/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":"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","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"]}
|