@coinlist-co/react 0.11.1-rc.e102bdb → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/{chunk-7CTH4KPU.js → chunk-6CQHDASY.js} +648 -620
  2. package/dist/chunk-6CQHDASY.js.map +1 -0
  3. package/dist/{chunk-UZUQALFY.js → chunk-F6WGUKZC.js} +9 -9
  4. package/dist/chunk-F6WGUKZC.js.map +1 -0
  5. package/dist/{chunk-LSPZETDH.js → chunk-ZFBEI3BW.js} +131 -134
  6. package/dist/chunk-ZFBEI3BW.js.map +1 -0
  7. package/dist/client/index.cjs +1489 -1346
  8. package/dist/client/index.cjs.map +1 -1
  9. package/dist/client/index.d.cts +395 -254
  10. package/dist/client/index.d.ts +395 -254
  11. package/dist/client/index.js +852 -739
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/{collections-BBI_XydI.d.cts → collections-DOm9VKVm.d.cts} +1 -1
  14. package/dist/{collections-BrX9rRWc.d.ts → collections-aCv-Wr2a.d.ts} +1 -1
  15. package/dist/{config-CMl1bR3F.d.cts → config-DIaFzrMW.d.cts} +56 -13
  16. package/dist/{config-CMl1bR3F.d.ts → config-DIaFzrMW.d.ts} +56 -13
  17. package/dist/server/index.cjs +262 -236
  18. package/dist/server/index.cjs.map +1 -1
  19. package/dist/server/index.d.cts +4 -4
  20. package/dist/server/index.d.ts +4 -4
  21. package/dist/server/index.js +3 -3
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/{shared → universal}/index.cjs +948 -919
  24. package/dist/universal/index.cjs.map +1 -0
  25. package/dist/{shared → universal}/index.d.cts +566 -536
  26. package/dist/{shared → universal}/index.d.ts +566 -536
  27. package/dist/{shared → universal}/index.js +9 -5
  28. package/package.json +23 -17
  29. package/dist/chunk-7CTH4KPU.js.map +0 -1
  30. package/dist/chunk-LSPZETDH.js.map +0 -1
  31. package/dist/chunk-UZUQALFY.js.map +0 -1
  32. package/dist/shared/index.cjs.map +0 -1
  33. /package/dist/{shared → universal}/index.js.map +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/shared/index.ts","../../src/shared/api/http-attributes.ts","../../src/shared/api/http.ts","../../src/shared/api/pagination.ts","../../src/shared/core/utils/crypto.ts","../../src/shared/types/oauth.ts","../../src/shared/core/auth/pkce.ts","../../src/shared/types/errors.ts","../../src/shared/types/blockchain/core.ts","../../src/shared/core/blockchain/bps.ts","../../src/shared/types/blockchain/ui.ts","../../src/shared/core/blockchain/chain.ts","../../src/shared/core/blockchain/erc20/abi.ts","../../src/shared/types/providers/superstate/swap.ts","../../src/shared/api/frontline/providers/superstate/swap.ts","../../src/shared/core/observability/log-cause.ts","../../src/shared/core/observability/internal-logger.ts","../../src/shared/core/blockchain/erc20/erc20-namespace.ts","../../src/shared/core/blockchain/formatters.ts","../../src/shared/core/blockchain/math.ts","../../src/shared/core/blockchain/token-registry.ts","../../src/shared/types/pagination.ts","../../src/shared/types/asset.ts","../../src/shared/types/offer.ts","../../src/shared/types/offer-detail.ts","../../src/shared/types/providers/coin-list/token-sale.ts","../../src/shared/api/frontline/providers/coin-list/token-sale.ts","../../src/shared/core/checkout/coin-list/token-sale-namespace.ts","../../src/shared/core/checkout/ondo/constants.ts","../../src/shared/core/checkout/ondo/math.ts","../../src/shared/types/trading.ts","../../src/shared/types/providers/ondo/ondo.ts","../../src/shared/api/frontline/providers/ondo/ondo.ts","../../src/shared/core/checkout/ondo/ondo-namespace.ts","../../src/shared/core/checkout/superstate/blockchain/abi.ts","../../src/shared/core/checkout/superstate/blockchain/math.ts","../../src/shared/core/checkout/superstate/blockchain/quote.ts","../../src/shared/core/checkout/superstate/blockchain/status.ts","../../src/shared/core/checkout/superstate/blockchain/swapped-event.ts","../../src/shared/core/checkout/superstate/constants.ts","../../src/shared/core/checkout/superstate/formatters.ts","../../src/shared/core/checkout/superstate/swap-namespace.ts","../../src/shared/api/frontline/offers.ts","../../src/shared/core/offers/offers-namespace.ts","../../src/shared/types/document-submission.ts","../../src/shared/api/frontline/documents.ts","../../src/shared/types/kyc.ts","../../src/shared/api/frontline/kyc.ts","../../src/shared/types/pii.ts","../../src/shared/api/frontline/pii.ts","../../src/shared/types/requirement.ts","../../src/shared/api/frontline/requirements.ts","../../src/shared/core/requirements/requirements-namespace.ts","../../src/shared/api/nabu/tokens.ts","../../src/shared/api/frontline/config.ts","../../src/shared/api/http-client.ts","../../src/shared/types/token-metadata.ts","../../src/shared/core/tokens/tokens-namespace.ts","../../src/shared/types/offer-option-address.ts","../../src/shared/types/wallet-ownership-challenge.ts","../../src/shared/api/frontline/wallet-connect.ts","../../src/shared/core/wallets/wallets-namespace.ts","../../src/shared/types/blockchain/wallet-error.ts","../../src/shared/types/oauth-session.ts","../../src/shared/types/user.ts"],"sourcesContent":["/** biome-ignore-all lint/plugin: one of the three barrels - the only files that may hold export clauses, and the only index files. */\n/**\n * `HttpError` and its reader only, rather than the whole module: `makeRequest`\n * and the request builder are internal machinery. The error is public because\n * it is what every API call rejects with when the backend refuses a request,\n * and without the class there is no way to catch a 4xx by type.\n * `apiErrorCode` comes with it because catching by type is only half of it -\n * telling two 422s apart takes the code inside the body.\n */\nexport {\n apiErrorCode,\n HttpError,\n type HttpResponse,\n} from '@/shared/api/http';\nexport * from '@/shared/api/pagination';\nexport * from '@/shared/core/auth/pkce';\nexport * from '@/shared/core/blockchain/bps';\nexport * from '@/shared/core/blockchain/chain';\nexport * from '@/shared/core/blockchain/erc20/abi';\nexport * from '@/shared/core/blockchain/erc20/erc20-namespace';\nexport * from '@/shared/core/blockchain/erc20/erc20-namespace.types';\nexport * from '@/shared/core/blockchain/formatters';\nexport * from '@/shared/core/blockchain/math';\nexport * from '@/shared/core/blockchain/token-registry';\nexport * from '@/shared/core/checkout/coin-list/token-sale-namespace';\nexport * from '@/shared/core/checkout/ondo/constants';\nexport * from '@/shared/core/checkout/ondo/math';\nexport * from '@/shared/core/checkout/ondo/ondo-namespace';\nexport * from '@/shared/core/checkout/ondo/ondo-namespace.types';\nexport * from '@/shared/core/checkout/superstate/blockchain/abi';\nexport * from '@/shared/core/checkout/superstate/blockchain/math';\nexport * from '@/shared/core/checkout/superstate/blockchain/quote';\nexport * from '@/shared/core/checkout/superstate/blockchain/status';\nexport * from '@/shared/core/checkout/superstate/blockchain/swapped-event';\nexport * from '@/shared/core/checkout/superstate/constants';\nexport * from '@/shared/core/checkout/superstate/formatters';\nexport * from '@/shared/core/checkout/superstate/swap-namespace';\nexport * from '@/shared/core/checkout/superstate/swap-namespace.types';\nexport * from '@/shared/core/offers/offers-namespace';\nexport * from '@/shared/core/requirements/requirements-namespace';\nexport * from '@/shared/core/tokens/tokens-namespace';\nexport * from '@/shared/core/wallets/wallets-namespace';\nexport * from '@/shared/types/asset';\nexport * from '@/shared/types/blockchain/core';\nexport * from '@/shared/types/blockchain/evm-wallet';\nexport * from '@/shared/types/blockchain/ui';\nexport * from '@/shared/types/blockchain/wallet-error';\nexport * from '@/shared/types/collections';\nexport * from '@/shared/types/config';\nexport * from '@/shared/types/document-submission';\nexport * from '@/shared/types/dto/pagination';\nexport * from '@/shared/types/errors';\nexport * from '@/shared/types/http';\nexport * from '@/shared/types/kyc';\nexport * from '@/shared/types/logger';\nexport * from '@/shared/types/oauth';\nexport * from '@/shared/types/oauth-session';\nexport * from '@/shared/types/offer';\nexport * from '@/shared/types/offer-detail';\nexport * from '@/shared/types/offer-option-address';\nexport * from '@/shared/types/pagination';\nexport * from '@/shared/types/pii';\nexport * from '@/shared/types/providers/coin-list/token-sale';\nexport * from '@/shared/types/providers/ondo/ondo';\nexport * from '@/shared/types/providers/superstate/swap';\nexport * from '@/shared/types/requirement';\nexport * from '@/shared/types/token-metadata';\nexport * from '@/shared/types/trading';\nexport * from '@/shared/types/user';\nexport * from '@/shared/types/wallet-ownership-challenge';\n","import type { RequestId } from '@/shared/types/logger';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\n\nexport type HttpRequestAttributes = {\n /**\n * Correlates the log lines of one logical request. Minted by\n * {@link HttpClient} on the first attempt and carried onto every retry and\n * post-renewal re-send by {@link concat}, which is what lets a reader tell\n * three attempts of one request from three separate requests.\n */\n requestId?: RequestId;\n protected?: boolean;\n userAgent?: boolean;\n idempotencyKey?: boolean;\n /** Zero-based attempt index: 0 = first request, 1 = first retry, etc. */\n retryAttempt?: number;\n renewAttempted?: boolean;\n clientCredentials?: ClientCredentialsOAuth;\n};\n\nexport type Attributes = Readonly<HttpRequestAttributes>;\n\nconst empty: Attributes = {};\n\nconst concat = (left: Attributes, right: Attributes): Attributes => ({\n ...left,\n ...right,\n});\n\nconst concatAll = (...items: Attributes[]): Attributes => {\n let result = empty;\n for (const item of items) {\n result = concat(result, item);\n }\n return result;\n};\n\nconst protectedRequest = (): Attributes => ({ protected: true });\nconst userAgent = (): Attributes => ({ userAgent: true });\nconst idempotencyKey = (): Attributes => ({\n idempotencyKey: true,\n});\n\nconst clientCredentials = (\n credentials: ClientCredentialsOAuth | undefined\n): Attributes => ({\n clientCredentials: credentials,\n});\n/** Returns attributes with the given retry attempt (zero-based). */\nconst retryAttempt = (attempt: number): Attributes => ({\n retryAttempt: attempt,\n});\nconst renewAttempted = (value: boolean): Attributes => ({\n renewAttempted: value,\n});\n\nconst requestId = (id: RequestId): Attributes => ({ requestId: id });\n\nconst getRequestId = (attrs?: HttpRequestAttributes): RequestId | null =>\n attrs?.requestId ?? null;\n\nconst isProtected = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.protected === true;\nconst needUserAgent = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.userAgent === true;\nconst isIdempotent = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.idempotencyKey === true;\nconst getRetryAttempt = (attrs?: HttpRequestAttributes): number =>\n attrs?.retryAttempt ?? 0;\nconst wasRenewAttempted = (attrs?: HttpRequestAttributes): boolean =>\n attrs?.renewAttempted === true;\nconst getClientCredentials = (\n attrs?: HttpRequestAttributes\n): ClientCredentialsOAuth | undefined => attrs?.clientCredentials;\n\nexport const Attributes = {\n empty,\n concat,\n concatAll,\n protected: protectedRequest,\n isProtected,\n userAgent,\n needUserAgent,\n idempotencyKey,\n isIdempotent,\n retryAttempt,\n getRetryAttempt,\n renewAttempted,\n wasRenewAttempted,\n clientCredentials,\n getClientCredentials,\n requestId,\n getRequestId,\n} as const;\n","import {\n Attributes,\n type HttpRequestAttributes,\n} from '@/shared/api/http-attributes';\nimport type { QueryParamValues } from '@/shared/types/http';\nimport type { RequestId } from '@/shared/types/logger';\n\nexport type HttpClientConfig = {\n baseUrl: string;\n /**\n * The frontline `X-API-Version` header. Omit for clients against other\n * backends (e.g. the token registry): a version header they don't know\n * would also force a CORS preflight the CDN cannot answer.\n */\n xApiVersion?: string;\n};\n\nexport type HttpRequest<TBody = unknown> =\n | {\n method: 'GET';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'POST';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n body: TBody;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'DELETE';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n };\nexport type HttpResponse<TBody = unknown> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody | null;\n /**\n * The id of the request that produced this response, stamped by\n * {@link HttpClient} so that whoever turns a non-2xx into an\n * {@link HttpError} can carry it without threading the request alongside.\n * Absent when the response did not come from an `HttpClient`.\n */\n requestId?: RequestId;\n};\n\nexport class HttpError<TBody = unknown> extends Error {\n readonly response: HttpResponse<TBody>;\n\n constructor(response: HttpResponse<TBody>) {\n super(`Request failed with ${response.status} status`);\n this.name = 'HttpError';\n this.response = response;\n }\n\n /**\n * Correlates this failure with the `[HTTP]` log lines for the same request,\n * which carry the method, the URL, the duration and every retry. `null` when\n * the response did not come from an {@link HttpClient}.\n *\n * Worth quoting in a bug report: it is what makes a log excerpt readable.\n */\n get requestId(): RequestId | null {\n return this.response.requestId ?? null;\n }\n}\n\n/**\n * The machine-readable `code` frontline attaches to an error, or `null` for\n * anything else - a non-HTTP failure, or an error body that carries only a\n * message.\n *\n * Frontline answers a failure with `{ type, message, code?, errors?,\n * event_id? }`, and `code` is the only part of it meant to be branched on:\n * `message` is prose that may be reworded, and `type` distinguishes\n * `invalid_request_error` from `api_error` without saying which one.\n *\n * Reach for this only where a code has a distinct remedy the user can act on.\n * Mapping the whole vocabulary would couple the SDK to strings frontline does\n * not version; falling back to a generic failure is the right default.\n */\nexport function apiErrorCode(error: unknown): string | null {\n if (!(error instanceof HttpError)) return null;\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const code: unknown = (body as { code?: unknown }).code;\n return typeof code === 'string' ? code : null;\n}\n\nexport async function makeRequest<TResponse = unknown>(\n request: HttpRequest\n): Promise<HttpResponse<TResponse>> {\n const headers: Record<string, string> = {\n Accept: 'application/json',\n ...(request.method === 'POST' && request.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(request.headers ?? {}),\n };\n\n const init: RequestInit = {\n method: request.method,\n headers,\n ...(request.redirect !== undefined ? { redirect: request.redirect } : {}),\n };\n\n if (request.method === 'POST' && request.body !== undefined) {\n init.body = JSON.stringify(request.body);\n }\n\n const response = await fetch(\n buildUrlWithQueryParams(request.url, request.queryParams),\n init\n );\n const responseHeaders = headersToRecord(response.headers);\n\n if (response.status === 204 || response.status === 205) {\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n await response.text();\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n const text = await response.text();\n let body: TResponse | null;\n try {\n body = text ? (JSON.parse(text) as TResponse) : null;\n } catch (_) {\n // A non-JSON body (an HTML error page from a CDN, proxy, or load\n // balancer) would otherwise surface as a bare SyntaxError with the status\n // lost. Throw the full response instead, so callers can classify the\n // failure by status and still see what the server actually sent.\n throw new HttpError({\n status: response.status,\n headers: responseHeaders,\n body: text,\n });\n }\n\n return {\n status: response.status,\n body,\n headers: responseHeaders,\n };\n}\n\n/**\n * The URL as `fetch` will see it, query string included.\n *\n * Exported for {@link HttpClient}'s `debug` request line, which renders the\n * request exactly as sent. Every other log line carries {@link HttpRequest.url}\n * alone - the query holds wallet addresses, chains and amounts, and `debug` is\n * the only level allowed to see them.\n */\nexport function buildUrlWithQueryParams(\n url: string,\n queryParams?: Record<string, QueryParamValues>\n): string {\n if (!queryParams) {\n return url;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) {\n continue;\n }\n searchParams.append(key, String(item));\n }\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const queryString = searchParams.toString();\n if (!queryString) {\n return url;\n }\n\n return url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`;\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key.toLowerCase()] = value;\n });\n return record;\n}\n\nfunction concatAttributes(\n request: HttpRequest,\n attrs: Attributes\n): HttpRequest {\n const nextAttributes = Attributes.concat(\n request.attributes ?? Attributes.empty,\n attrs\n );\n const nextRequest: typeof request = {\n ...request,\n attributes: nextAttributes,\n };\n return nextRequest;\n}\n\nexport const Request = {\n concatAttributes,\n};\n","import type {\n Cursor,\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/types/pagination';\n\n/**\n * Walks every page of a cursor-paginated endpoint and returns the flattened\n * result.\n *\n * Lives in the API layer rather than beside `PaginationParams` because it\n * drives requests: it is the auto-paginating half that `list()` is built on,\n * while the params and the response envelope are domain models the client and\n * the server both name.\n */\nexport async function fetchAllPages<\n A,\n P extends PaginationParams = PaginationParams,\n>(\n fetchPage: (params: P) => Promise<PaginatedResponse<A>>,\n baseParams?: Omit<P, keyof PaginationParams>\n): Promise<A[]> {\n const items: A[] = [];\n let cursor: Cursor | null = null;\n\n do {\n const params = {\n ...(baseParams ?? {}),\n after: cursor ?? undefined,\n } as P;\n const page = await fetchPage(params);\n items.push(...page.data);\n cursor = page.startingAfter;\n } while (cursor);\n\n return items;\n}\n","/**\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","import type { Newtype } from '@/shared/types/newtype';\n\nexport type AuthorizationCode = Newtype<string, 'AuthorizationCode'>;\nexport const AuthorizationCode = (value: string): AuthorizationCode =>\n value as AuthorizationCode;\n\nexport type CodeVerifier = Newtype<string, 'CodeVerifier'>;\nexport const CodeVerifier = (value: string): CodeVerifier =>\n value as CodeVerifier;\n\nexport type CodeChallenge = Newtype<string, 'CodeChallenge'>;\nexport const CodeChallenge = (value: string): CodeChallenge =>\n value as CodeChallenge;\n\nexport type PKCEState = Newtype<string, 'PKCEState'>;\nexport const PKCEState = (value: string) => value as PKCEState;\n\nexport type RedirectUri = Newtype<string, 'RedirectUri'>;\nexport const RedirectUri = (value: string): RedirectUri => value as RedirectUri;\n\nexport type ClientId = Newtype<string, 'ClientId'>;\nexport const ClientId = (value: string): ClientId => value as ClientId;\n\nexport type ClientSecret = Newtype<string, 'ClientSecret'>;\nexport const ClientSecret = (value: string): ClientSecret =>\n value as ClientSecret;\n","import {\n arrayBufferToBase64Url,\n generateSecureRandomBase64Url,\n sha256,\n} from '@/shared/core/utils/crypto';\nimport type {\n CodeChallenge as CodeChallengeType,\n CodeVerifier as CodeVerifierType,\n PKCEState as PKCEStateType,\n} from '@/shared/types/oauth';\nimport {\n type ClientId,\n CodeChallenge,\n CodeVerifier,\n PKCEState,\n type RedirectUri,\n} from '@/shared/types/oauth';\n\nexport type PKCEParams = {\n clientId: ClientId;\n responseType: 'code';\n redirectUri: RedirectUri;\n codeChallenge: CodeChallengeType;\n codeChallengeMethod: 'S256';\n state: PKCEStateType;\n codeVerifier: CodeVerifierType;\n};\n\nexport type PKCEConfig = {\n clientId: ClientId;\n redirectUri: RedirectUri;\n};\n\n/**\n * Generates PKCE parameters for an OAuth2 authorization code flow.\n * Pure crypto — no React, no DOM beyond Web Crypto API. Safe to use\n * in server-side code and Next.js middleware.\n */\nexport async function generatePKCEParams(\n config: PKCEConfig\n): Promise<PKCEParams> {\n const state = generateSecureRandomBase64Url(32);\n const codeVerifier = generateSecureRandomBase64Url(32);\n const codeChallengeRaw = await sha256(codeVerifier);\n const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);\n\n return {\n clientId: config.clientId,\n responseType: 'code',\n redirectUri: config.redirectUri,\n codeChallenge: CodeChallenge(codeChallenge),\n codeChallengeMethod: 'S256',\n state: PKCEState(state),\n codeVerifier: CodeVerifier(codeVerifier),\n };\n}\n","/**\n * Error thrown when a feature or code path is not yet implemented.\n */\nexport class NotImplementedError extends Error {\n constructor(message = 'Not implemented yet') {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\n/**\n * Error thrown when accessing a feature that requires authentication\n * without being authenticated.\n */\nexport class NotAuthenticatedError extends Error {\n constructor(\n message = 'The user is not authenticated. Go through the OAuth flow first!'\n ) {\n super(message);\n this.name = 'NotAuthenticatedError';\n }\n}\n\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Error thrown when the SDK computes something impossible: a value outside\n * uint256 after its own arithmetic, a symbol missing from a registry the SDK\n * itself ships. Distinct from {@link ValidationError}, which means the backend\n * sent a shape the SDK does not understand.\n *\n * The two have different remedies, which is the whole reason they are separate\n * types: a {@link ValidationError} is worth reporting to CoinList, an\n * `InvariantError` is an SDK bug worth reporting against the SDK.\n */\nexport class InvariantError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvariantError';\n }\n}\n\n/**\n * Error thrown when an arithmetic operation has no answer to give: a division\n * by zero, or a result that falls outside the range its type can represent.\n *\n * Distinct from {@link ValidationError}, which says a value arrived malformed.\n * A `MathError` says every operand was well-formed and the operation on them\n * still has no result, so the two are worth catching apart: one points at the\n * response, the other at the arithmetic we asked for.\n */\nexport class MathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MathError';\n }\n}\n","import {\n InvariantError,\n MathError,\n ValidationError,\n} from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type EthereumChain =\n | 'ethereum_mainnet'\n | 'ethereum_sepolia'\n | 'base_mainnet'\n | 'base_sepolia';\n\n/**\n * The exhaustive chain set: a new {@link EthereumChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const ETHEREUM_CHAINS: Record<EthereumChain, true> = {\n ethereum_mainnet: true,\n ethereum_sepolia: true,\n base_mainnet: true,\n base_sepolia: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const EthereumChain = (value: string): EthereumChain => {\n if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Ethereum chain: \"${value}\"`);\n }\n return value as EthereumChain;\n};\n\nexport type SolanaChain = 'solana_mainnet' | 'solana_devnet';\n\n/**\n * The exhaustive chain set: a new {@link SolanaChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const SOLANA_CHAINS: Record<SolanaChain, true> = {\n solana_mainnet: true,\n solana_devnet: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const SolanaChain = (value: string): SolanaChain => {\n if (!Object.keys(SOLANA_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Solana chain: \"${value}\"`);\n }\n return value as SolanaChain;\n};\n\nexport type Chain = EthereumChain | SolanaChain;\n\nexport const Chain = (value: string): Chain => {\n if (\n !Object.keys(ETHEREUM_CHAINS).includes(value) &&\n !Object.keys(SOLANA_CHAINS).includes(value)\n ) {\n throw new ValidationError(`Unsupported chain: \"${value}\"`);\n }\n return value as Chain;\n};\n\n/**\n * Protocol a wallet binding is scoped to. EVM-only for now: an EVM address\n * binds once per option regardless of which EVM chain proved ownership.\n * Frontline's enum also has `:solana`, but we don't handle Solana bindings yet,\n * so this stays `'ethereum'` until Solana support lands.\n */\nexport type WalletProtocol = 'ethereum';\n\n/**\n * EVM addresses keep a `0x${string}` base so they stay assignable to the\n * `0x${string}` shapes that on-chain libraries (viem/wagmi) expect. We only\n * drop the runtime `0x` narrowing: values are trusted at the boundary and\n * branded via the constructor.\n */\nexport type EvmWalletAddress = Newtype<`0x${string}`, 'EvmWalletAddress'>;\nexport const EvmWalletAddress = (value: string): EvmWalletAddress =>\n value as EvmWalletAddress;\n\nexport type EvmContractAddress = Newtype<`0x${string}`, 'EvmContractAddress'>;\nexport const EvmContractAddress = (value: string): EvmContractAddress =>\n value as EvmContractAddress;\n\n/**\n * What uniquely identifies a token: the chain it is deployed on plus its\n * contract address. Never a symbol, which can collide across issuers.\n */\nexport type TokenIdentifier = {\n /** The chain the token contract is deployed on. */\n chain: EthereumChain;\n /**\n * The token's contract address, in any casing — consumers that need the\n * EIP-55 form (e.g. the token registry routes) checksum it themselves.\n */\n address: EvmContractAddress;\n};\n\nexport type HexEncodedTransactionData = Newtype<\n `0x${string}`,\n 'HexEncodedTransactionData'\n>;\nexport const HexEncodedTransactionData = (\n value: string\n): HexEncodedTransactionData => value as HexEncodedTransactionData;\n\n/**\n * A transaction the backend has already encoded for us — the caller only\n * broadcasts it. Used by the flows that hand a wallet a ready-made `to`/`data`\n * pair (allow-listing a wallet, an Ondo swap) rather than encoding a contract\n * call themselves.\n */\nexport type Tx = {\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n};\n\n/**\n * The largest exponent whose power of ten still fits a uint256: 10^77 fits,\n * 10^78 does not.\n *\n * The bound is arithmetic rather than a token standard's. ERC-20 reports\n * `decimals()` as a `uint8`, so 255 is what a contract *can* say, but every\n * {@link AssetDecimals} in this codebase is paired with a {@link Uint256} raw\n * by construction, and scaling by anything past this leaves that pairing\n * unrepresentable. A value between 78 and 255 would therefore pass a\n * standard-faithful check and then break the first multiplication it reached.\n */\nexport const MAX_ASSET_DECIMALS = 77;\n\n/**\n * How many decimal places one whole token divides into.\n *\n * Validated, unlike its neighbours here — {@link Uint256} is a bare `bigint`\n * with a separate {@link assertUint256} guard, and {@link DecimalString} casts\n * unchecked. The asymmetry is deliberate and follows the value's provenance:\n * an `AssetDecimals` used to come only from literals and the token registry,\n * but backends now publish exponents of their own (`asset_decimals` on an Ondo\n * quote, both scales on a built swap), and those feed `10n ** BigInt(d)`\n * during render. Guarding at construction is what keeps a fractional or\n * unbounded exponent from surfacing as a `RangeError` mid-render — or, at\n * 10^200, as a hung tab — instead of as the failed state the screen has.\n *\n * See docs/ADR-7-VALIDATED-NEWTYPES.md.\n *\n * @throws ValidationError on a non-integer, a negative, or anything above\n * {@link MAX_ASSET_DECIMALS}.\n */\nexport type AssetDecimals = Newtype<number, 'AssetDecimals'>;\nexport const AssetDecimals = (value: number): AssetDecimals => {\n if (!Number.isInteger(value)) {\n throw new ValidationError(`Asset decimals must be an integer: ${value}`);\n }\n if (value < 0 || value > MAX_ASSET_DECIMALS) {\n throw new ValidationError(\n `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`\n );\n }\n return value as AssetDecimals;\n};\n\nexport const STABLE_DECIMALS = AssetDecimals(6);\n\n/**\n * A non-negative decimal number the backend sent as a string, kept unscaled.\n *\n * Reach for it when a response gives you a number but not the decimals to\n * scale it by, or gives you one it has already applied. Inventing an exponent\n * for either is how a display ends up orders of magnitude out.\n *\n * Contrast {@link BlockchainAmount}, which pairs a raw uint256 with the\n * decimals it is denominated in and so is only constructible when you know\n * both. Arithmetic on a `DecimalString` needs a decimal library we\n * deliberately do not ship.\n */\nexport type DecimalString = Newtype<string, 'DecimalString'>;\nexport const DecimalString = (value: string): DecimalString =>\n value as DecimalString;\n\nexport const MAX_UINT_256 = 2n ** 256n - 1n;\n\n/**\n * A non-negative integer within uint256 bounds. Kept unbranded (a plain\n * `bigint`) so raw on-chain amounts flow in without ceremony; bounds are\n * enforced where it matters (see {@link combineAmounts}).\n */\nexport type Uint256 = bigint;\n\n/**\n * Asserts a computed bigint falls within uint256 bounds. Use at on-chain\n * arithmetic boundaries (bps math, price computation) where the SDK's own\n * arithmetic could underflow below zero or overflow above 2^256-1.\n *\n * Throws {@link InvariantError}, because reaching it means the SDK computed\n * something no chain could represent. **For a value that came off the wire,\n * use {@link parseUint256} instead**: the backend sending an unrepresentable\n * number is a {@link ValidationError}, and the two have different remedies.\n */\nexport const assertUint256 = (value: bigint): Uint256 => {\n if (isUint256(value)) return value;\n throw new InvariantError(`Value out of uint256 bounds: ${value}`);\n};\n\n/**\n * {@link assertUint256} at a wire boundary: the same bounds check, reported as\n * a {@link ValidationError} against the named field, because a value out of\n * range here is the backend's, not the SDK's.\n *\n * `label` names the field the way a DTO mapper's other failures do, so a log\n * line says which one - `SwapPreview.pay_input_amount`, not `a number`.\n */\nexport const parseUint256 = (value: bigint, label: string): Uint256 => {\n if (isUint256(value)) return value;\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n};\n\nconst isUint256 = (value: bigint): boolean =>\n value >= 0n && value <= MAX_UINT_256;\n\nexport type BlockchainAmount = Newtype<\n { raw: Uint256; decimals: AssetDecimals },\n 'BlockchainAmount'\n>;\n\n/**\n * Constructs a {@link BlockchainAmount} and exposes arithmetic helpers.\n * TypeScript has no operator overloading, so use `BlockchainAmount.add(a, b)`\n * instead of `+`/`-`/`*`/`/` on the objects directly.\n */\nexport const BlockchainAmount = Object.assign(\n (value: { raw: Uint256; decimals: AssetDecimals }): BlockchainAmount =>\n value as BlockchainAmount,\n {\n add: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x + y),\n sub: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x - y),\n mul: multiplyAmounts,\n div: divideAmounts,\n }\n);\n\n/**\n * `a * b`, denominated in `a`'s decimals - a price times a quantity, an amount\n * times a rate.\n *\n * The exact inverse of {@link divideAmounts}, and it reads the same way round:\n * the answer stays in `a`'s scale and `b`'s divides back out, so the two\n * compose - `mul(div(a, b), b)` is `a` again, short only what truncation took.\n * That is what makes `price x quantity` land in the currency the price was\n * quoted in rather than at some product of two exponents no token uses.\n *\n * The multiplication happens *before* the division by `10^b.decimals`, so the\n * full precision of both operands survives into the one rounding at the end.\n * Like `div` it truncates towards zero on both signs, which is the safe\n * direction for money: a total is never inflated past what the parts hold.\n *\n * Total - unlike `div`, there is nothing here to reject. The scale it divides\n * by is a power of ten, never zero, and a product is not bounds-checked for\n * the same reason a quotient is not: whether one past uint256 is a corrupt\n * response or an expected magnitude belongs to the caller.\n */\nfunction multiplyAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n const product = a.raw * b.raw;\n return BlockchainAmount({\n raw: product / 10n ** BigInt(b.decimals),\n decimals: a.decimals,\n });\n}\n\n/**\n * `a / b`, denominated in `a`'s decimals - a price, a ratio, a rate.\n *\n * Unlike {@link combineAmounts}, the two operands may be at different scales,\n * and usually are: dividing dollars by shares is the point of the operation,\n * and the two tokens rarely share an exponent. `b`'s scale divides back out -\n * the numerator is scaled by `10^b.decimals` *before* the division, so nothing\n * is lost to integer truncation early and the quotient lands in `a`'s scale,\n * which is the one the amounts it is rendered beside are in.\n *\n * Truncates towards zero on both signs, which is what BigInt division already\n * does and the safe direction for money: the total a price implies never\n * exceeds, in magnitude, the amount that actually moved.\n *\n * A zero divisor is the only rejection. The quotient is deliberately *not*\n * bounds-checked the way {@link combineAmounts} checks a sum: scaling the\n * numerator carries even legal pairs past uint256 (a maximal amount over a\n * single base unit), and whether that reads as a corrupt response or an\n * expected magnitude is the caller's to judge - see `computeOndoBuyPrice` and\n * `computeOndoSellPrice`, which bounds-check the price they build out of this.\n *\n * @throws MathError when `b` is zero. `add` and `sub` throw a bare `Error`\n * because a scale mismatch is a programming error caught in review; a zero\n * divisor arrives from a server response and is divided by during render, so\n * it is a named failure a screen can catch and map to a failed state.\n */\nfunction divideAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n if (b.raw === 0n) {\n throw new MathError('Cannot divide a BlockchainAmount by zero');\n }\n\n const scaled = a.raw * 10n ** BigInt(b.decimals);\n return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });\n}\n\n/**\n * Combine two amounts with a raw-bigint `op`. Both operands must share the\n * same `decimals` — adding/subtracting differently-scaled amounts is a\n * programming error, so we throw rather than silently producing garbage.\n * The result is bounds-checked, so an underflow (negative `raw`) or uint256\n * overflow is rejected.\n */\nfunction combineAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount,\n op: (x: bigint, y: bigint) => bigint\n): BlockchainAmount {\n if (a.decimals !== b.decimals) {\n throw new InvariantError(\n 'Cannot combine BlockchainAmounts with different decimals: ' +\n `${a.decimals} vs ${b.decimals}`\n );\n }\n const raw = op(a.raw, b.raw);\n if (raw < 0n || raw > MAX_UINT_256) {\n throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);\n }\n return BlockchainAmount({ raw, decimals: a.decimals });\n}\n\nexport type AssetSymbol = Newtype<string, 'AssetSymbol'>;\nexport const AssetSymbol = (value: string): AssetSymbol => value as AssetSymbol;\n\n/**\n * A stablecoin symbol is an {@link AssetSymbol} narrowed to the coins we\n * support. It shares the `AssetSymbol` brand so it stays assignable to it.\n */\nexport type StablecoinSymbol = Newtype<'USDC' | 'USDT', 'AssetSymbol'>;\nexport const StablecoinSymbol = (value: 'USDC' | 'USDT'): StablecoinSymbol =>\n value as StablecoinSymbol;\n\nexport type KnownAssetSymbol = StablecoinSymbol;\nexport const KnownAssetSymbol = StablecoinSymbol;\n\nexport type Erc20Asset = {\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n};\n\nexport type Bps = Newtype<bigint, 'Bps'>;\nexport const Bps = (value: bigint): Bps => value as Bps;\n","import {\n assertUint256,\n Bps,\n type Uint256,\n} from '@/shared/types/blockchain/core';\n\n/** Basis-point denominator: 10_000 bps = 100%. */\nexport const BPS_DENOM: Bps = Bps(10_000n);\n\n/**\n * Applies a basis-point fraction to an amount, flooring the result.\n * `floor((amount × bps) / BPS_DENOM)`. The result is bounds-checked, so an\n * overflow (bps far above BPS_DENOM) or a negative product is rejected.\n */\nexport function applyBps(amount: Uint256, bps: Bps): Uint256 {\n return assertUint256((amount * bps) / BPS_DENOM);\n}\n","import type { Newtype } from '@/shared/types/newtype';\n\nexport type FormattedAmountUi = Newtype<string, 'FormattedAmountUi'>;\nexport const FormattedAmountUi = (value: string): FormattedAmountUi =>\n value as FormattedAmountUi;\n\nexport type FormattedPercentUi = Newtype<string, 'FormattedPercentUi'>;\nexport const FormattedPercentUi = (value: string): FormattedPercentUi =>\n value as FormattedPercentUi;\n\nexport type TxExplorerUrl = Newtype<string, 'TxExplorerUrl'>;\nexport const TxExplorerUrl = (value: string): TxExplorerUrl =>\n value as TxExplorerUrl;\n\n/**\n * A wallet address shortened for display (e.g. `0x1234…5678`). Keeps a\n * `0x${string}` base but drops the runtime `0x` narrowing.\n */\nexport type ShortenedWalletAddress = Newtype<\n `0x${string}`,\n 'ShortenedWalletAddress'\n>;\nexport const ShortenedWalletAddress = (value: string): ShortenedWalletAddress =>\n value as ShortenedWalletAddress;\n\nexport type FormattedAmountAssetUi = Newtype<string, 'FormattedAmountAssetUi'>;\nexport const FormattedAmountAssetUi = (value: string): FormattedAmountAssetUi =>\n value as FormattedAmountAssetUi;\n\nexport type AssetIconUrl = Newtype<string, 'AssetIconUrl'>;\nexport const AssetIconUrl = (value: string): AssetIconUrl =>\n value as AssetIconUrl;\n","import type { Hash } from 'viem';\nimport type { EthereumChain } from '@/shared/types/blockchain/core';\nimport { TxExplorerUrl } from '@/shared/types/blockchain/ui';\nimport { ValidationError } from '@/shared/types/errors';\n\n/**\n * The one EIP-155 table. `satisfies` makes a new {@link EthereumChain} a\n * compile error here until its id is added, which is what keeps both\n * directions below total.\n */\nconst CHAIN_IDS = {\n ethereum_mainnet: 1,\n ethereum_sepolia: 11155111,\n base_mainnet: 8453,\n base_sepolia: 84532,\n} as const satisfies Record<EthereumChain, number>;\n\nexport function getChainId(chain: EthereumChain): number {\n return CHAIN_IDS[chain];\n}\n\n/**\n * Resolves an EIP-155 chain id to the chain the SDK names it by — the inverse\n * of {@link getChainId}, for backends that report a bare `chain_id`.\n *\n * @throws ValidationError on an unrecognised id. Defaulting to mainnet would\n * let a testnet response read as a live one.\n */\nexport function chainFromId(chainId: string): EthereumChain {\n const chains = Object.keys(CHAIN_IDS) as EthereumChain[];\n const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);\n if (!chain) {\n throw new ValidationError(`Unsupported EIP-155 chain id: \"${chainId}\"`);\n }\n return chain;\n}\n\nexport function getNetworkName(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'Ethereum';\n case 'ethereum_sepolia':\n return 'Ethereum Sepolia';\n case 'base_mainnet':\n return 'Base';\n case 'base_sepolia':\n return 'Base Sepolia';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n\nexport function txExplorerUrl(\n chain: EthereumChain,\n txHash: Hash\n): TxExplorerUrl {\n return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);\n}\n\nfunction explorerBaseUrl(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'https://etherscan.io';\n case 'ethereum_sepolia':\n return 'https://sepolia.etherscan.io';\n case 'base_mainnet':\n return 'https://basescan.org';\n case 'base_sepolia':\n return 'https://sepolia-explorer.base.org';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n","/**\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 {\n EvmContractAddress,\n HexEncodedTransactionData,\n parseUint256,\n type Uint256,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/providers/superstate/swap';\n\n/**\n * Whether a wallet is authorized to interact with a given swap contract.\n */\nexport type SwapAuthorization = {\n authorized: boolean;\n};\n\nexport const SwapAuthorization = {\n fromDto: (dto: WalletAuthorizationDto): SwapAuthorization => ({\n authorized: dto.authorized,\n }),\n};\n\n/**\n * A read-only quote for a swap: how much goes in, the protocol fee, and how\n * much would come out. All amounts are raw on-chain integers (uint256).\n */\nexport type SwapPreview = {\n inputAmount: Uint256;\n fee: Uint256;\n outputAmount: Uint256;\n};\n\nexport const SwapPreview = {\n fromDto: (dto: SwapPreviewDto): SwapPreview => ({\n inputAmount: parseUint256(\n BigInt(dto.pay_input_amount),\n 'SwapPreview.pay_input_amount'\n ),\n fee: parseUint256(BigInt(dto.fee), 'SwapPreview.fee'),\n outputAmount: parseUint256(\n BigInt(dto.receive_output_amount),\n 'SwapPreview.receive_output_amount'\n ),\n }),\n};\n\n/**\n * The on-chain state of a swap contract.\n *\n * - `stopped`: non-zero when the contract is paused/halted.\n * - `swapLevel`: the current swap level/tier.\n */\nexport type SwapStatus = {\n stopped: Uint256;\n swapLevel: Uint256;\n};\n\nexport const SwapStatus = {\n fromDto: (dto: SwapStatusDto): SwapStatus => ({\n stopped: parseUint256(BigInt(dto.stopped), 'SwapStatus.stopped'),\n swapLevel: parseUint256(BigInt(dto.swap_level), 'SwapStatus.swap_level'),\n }),\n};\n\n// TODO: TokenAllowance and TokenBalance are generic ERC-20, not swap — move\n// them and their DTOs to /types/erc-20 alongside Erc20Namespace. Deferred:\n// it touches ~20 importers plus both barrels, so it wants its own PR.\n/**\n * The ERC-20 allowance an owner has granted a spender for a token.\n */\nexport type TokenAllowance = {\n allowance: Uint256;\n};\n\nexport const TokenAllowance = {\n fromDto: (dto: TokenAllowanceDto): TokenAllowance => ({\n allowance: parseUint256(BigInt(dto.allowance), 'TokenAllowance.allowance'),\n }),\n};\n\n/**\n * The raw ERC-20 balance an owner holds of a token (uint256).\n */\nexport type TokenBalance = {\n balance: Uint256;\n};\n\nexport const TokenBalance = {\n fromDto: (dto: TokenBalanceDto): TokenBalance => ({\n balance: parseUint256(BigInt(dto.balance), 'TokenBalance.balance'),\n }),\n};\n\n/**\n * The backend's response to an allow-wallet request. Either the caller must\n * broadcast an on-chain transaction to complete allow-listing, or nothing is\n * required because the wallet is already allowed.\n */\nexport type AllowWalletResponse =\n | {\n action: 'broadcast_transaction';\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n }\n | {\n action: 'none';\n alreadyAllowed: boolean;\n };\n\nexport const AllowWalletResponse = {\n fromDto: (dto: AllowWalletResponseDto): AllowWalletResponse => {\n switch (dto.action) {\n case 'broadcast_transaction':\n return {\n action: 'broadcast_transaction',\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n };\n case 'none':\n return {\n action: 'none',\n alreadyAllowed: dto.already_allowed,\n };\n default: {\n const _exhaustive: never = dto;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/shared/core/blockchain/erc20/erc20-namespace.types';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/shared/core/checkout/superstate/swap-namespace.types';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n} from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapOutputTokenDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/shared/types/dto/providers/superstate/swap';\nimport {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n TokenAllowance,\n TokenBalance,\n} from '@/shared/types/providers/superstate/swap';\n\nexport async function getSwapAuthorization(\n api: Sender,\n params: GetSwapAuthorizationParams\n): Promise<SwapAuthorization> {\n const dto = await api.send<WalletAuthorizationDto>({\n method: 'GET',\n url: '/v1/wallet/authorized',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n wallet_address: params.walletAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapAuthorization.fromDto(dto);\n}\n\nexport async function getSwapOutputToken(\n api: Sender,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const dto = await api.send<SwapOutputTokenDto>({\n method: 'GET',\n url: '/v1/swap/output-token',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return toErc20Asset(dto);\n}\n\nexport async function getSwapPreview(\n api: Sender,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const dto = await api.send<SwapPreviewDto>({\n method: 'GET',\n url: '/v1/swap/preview',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n input_token: params.inputToken,\n amount: params.amount.toString(),\n },\n attributes: Attributes.protected(),\n });\n return SwapPreview.fromDto(dto);\n}\n\nexport async function getSwapStatus(\n api: Sender,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const dto = await api.send<SwapStatusDto>({\n method: 'GET',\n url: '/v1/swap/status',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapStatus.fromDto(dto);\n}\n\nexport async function getTokenAllowance(\n api: Sender,\n params: GetTokenAllowanceParams\n): Promise<TokenAllowance> {\n const dto = await api.send<TokenAllowanceDto>({\n method: 'GET',\n url: '/v1/token/allowance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n spender: params.spender,\n },\n attributes: Attributes.protected(),\n });\n return TokenAllowance.fromDto(dto);\n}\n\nexport async function getTokenBalance(\n api: Sender,\n params: GetTokenBalanceParams\n): Promise<TokenBalance> {\n const dto = await api.send<TokenBalanceDto>({\n method: 'GET',\n url: '/v1/token/balance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n },\n attributes: Attributes.protected(),\n });\n return TokenBalance.fromDto(dto);\n}\n\nexport async function allowWallet(\n api: Sender,\n params: AllowWalletParams\n): Promise<AllowWalletResponse> {\n const dto = await api.send<AllowWalletResponseDto>({\n method: 'POST',\n url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,\n body: {\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n },\n attributes: Attributes.protected(),\n });\n return AllowWalletResponse.fromDto(dto);\n}\n\nfunction toErc20Asset(dto: SwapOutputTokenDto): Erc20Asset {\n return {\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n };\n}\n","import { apiErrorCode, HttpError } from '@/shared/api/http';\nimport {\n InvariantError,\n MathError,\n NotAuthenticatedError,\n NotImplementedError,\n ValidationError,\n} from '@/shared/types/errors';\nimport type { FrontlineEventId, LogCause } from '@/shared/types/logger';\n\n/**\n * Classifies anything thrown inside the SDK into a {@link LogCause}.\n *\n * The SDK's **only** structured classification of a thrown error. It reaches\n * `warn` as well as `error`, since a recoverable failure is no less worth\n * naming than a fatal one.\n *\n * An `instanceof` chain rather than a pattern match, for the same reason\n * `classifyWalletError` is one: these are classes, not an ADT, so there is no\n * tag to match on. The chain is ordered most specific first and ends in\n * `generic-error`, which is total - a host-supplied lambda may throw anything\n * at all, a string included.\n *\n * Everything it returns is safe above `'debug'`, and the chain itself is the\n * opt-in list: only the five SDK-authored error classes named below reach an\n * arm carrying a `message`, because only those messages were written by the\n * SDK. Everything else contributes its class name and nothing more, since its\n * message and its fields are host-authored. {@link describeErrorUnredacted} is\n * where those go. A new error type has to be added here deliberately, which is\n * the moment to ask whether its message is SDK-authored all the way down;\n * defaulting to \"safe\" is how the leak ADR-8 replaced happened.\n *\n * Lives at Level 1 rather than beside {@link LogCause} because classifying an\n * {@link HttpError} means importing `@/shared/api`, which `@/shared/types` may\n * not do (`data.yaml#domain-models-dont-reach-the-api-layer`).\n */\nexport function classifyLogCause(error: unknown): LogCause {\n if (error instanceof HttpError) {\n return httpCause(error);\n }\n if (error instanceof ValidationError) {\n return { type: 'validation', message: error.message };\n }\n if (error instanceof InvariantError) {\n return { type: 'invariant', message: error.message };\n }\n if (error instanceof MathError) {\n return { type: 'math', message: error.message };\n }\n if (error instanceof NotAuthenticatedError) {\n return { type: 'not-authenticated' };\n }\n if (error instanceof NotImplementedError) {\n return { type: 'not-implemented' };\n }\n return { type: 'generic-error', name: errorName(error) };\n}\n\n/**\n * A one-line rendering of a thrown error **verbatim**, message included.\n *\n * Unredacted, and therefore `'debug'` only: every caller puts the result in a\n * {@link DebugEvent} field, which the level check has already admitted. Always\n * called inside an event lambda, so it never runs below the level.\n *\n * The difference from {@link classifyLogCause} is one word - `message` - and\n * it is the whole safety boundary. A viem `BaseError.message` embeds the\n * transaction's `from`, `to`, `value` and calldata; a host's `getAccessToken`\n * may throw `new Error('token abc123 rejected')`. Neither is something the SDK\n * can vouch for.\n *\n * A rendered string rather than the error object, because an `Error`'s `name`,\n * `message` and `stack` are all non-enumerable: handed to a structured sink as\n * an object it serialises to `{}`.\n */\nexport function describeErrorUnredacted(error: unknown): string {\n if (error instanceof HttpError) {\n return describeHttpErrorRedacted(error);\n }\n if (error instanceof Error) {\n return `${error.name}: ${error.message}`;\n }\n return `thrown non-error: ${stringifyUnredacted(error)}`;\n}\n\n/**\n * Renders a value for a log field without ever throwing. A DTO holding a\n * `bigint`, or a params object the host made circular, must not turn a log\n * line into a second failure.\n *\n * Unredacted by construction - it stringifies whatever it is handed - so every\n * call site must be a `'debug'` one.\n */\nexport function stringifyUnredacted(value: unknown): string {\n if (value === undefined) return '';\n try {\n // `JSON.stringify` answers `undefined` for a function or a symbol, which\n // a params object can legitimately hold - an `onProgress` callback, say.\n return (\n JSON.stringify(value, (_key, item: unknown) =>\n typeof item === 'bigint' ? `${item}` : item\n ) ?? String(value)\n );\n } catch (_) {\n return '<unserializable>';\n }\n}\n\n/**\n * The status and frontline's code. Server-authored, so it is the same string\n * at every level rather than two renderings of one failure.\n */\nfunction describeHttpErrorRedacted(error: HttpError): string {\n const code = apiErrorCode(error);\n const status = error.response.status;\n return code === null\n ? `HttpError ${status}`\n : `HttpError ${status} (${code})`;\n}\n\n/**\n * The class name of an unrecognised throw, which is all of it that the SDK may\n * repeat above `'debug'`. A thrown non-error has no class worth naming, so its\n * `typeof` stands in.\n */\nfunction errorName(error: unknown): string {\n return error instanceof Error ? error.name : `non-error ${typeof error}`;\n}\n\n/**\n * The status and the two identifiers, and nothing else. The body stays out:\n * this value reaches `Logger.error`, which runs at every level a host would\n * enable in production, and a response body is a `'debug'`-only disclosure.\n * `requestId` is what leads back to it.\n */\nfunction httpCause(error: HttpError): LogCause {\n return {\n type: 'http',\n requestId: error.requestId,\n status: error.response.status,\n code: apiErrorCode(error),\n eventId: apiErrorEventId(error),\n };\n}\n\n/**\n * Frontline stamps a failure with `event_id`, the id its own logs are keyed\n * by. It is the single most useful thing to quote when raising a ticket, which\n * is why it is pulled out of the body rather than left for a reader to find.\n *\n * Private, unlike `apiErrorCode`: nothing branches on it, so it is a logging\n * detail rather than public API.\n */\nfunction apiErrorEventId(error: HttpError): FrontlineEventId | null {\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const eventId: unknown = (body as { event_id?: unknown }).event_id;\n return typeof eventId === 'string' ? (eventId as FrontlineEventId) : null;\n}\n","import {\n classifyLogCause,\n describeErrorUnredacted,\n} from '@/shared/core/observability/log-cause';\nimport type {\n DebugEvent,\n LogBinding,\n LogBindings,\n LogCause,\n Logger,\n LogLevel,\n LogScope,\n SafeEvent,\n SafeFields,\n UnredactedFields,\n} from '@/shared/types/logger';\n\n/**\n * Wraps the host's {@link Logger}, or its absence, into the thing SDK code\n * actually calls.\n *\n * Three jobs, the first two of which exist so that no call site anywhere in\n * the SDK ever branches on whether logging is on:\n *\n * 1. **Absence is normalised away.** No logger yields {@link noopInternalLogger},\n * whose methods do nothing and whose `wrap` still runs the wrapped work.\n * 2. **The level is checked here, once per call.** Below the level, the\n * event lambda is never invoked and no {@link LogCause} is built. That is\n * the whole reason events are lambdas: expensive debug detail costs nothing\n * in production.\n * 3. **The safety boundary is enforced here.** `'debug'` is the unredacted\n * level; `info`, `warn` and `error` carry only what the SDK authored and\n * what the server minted. {@link InternalLogger.failure} and\n * {@link InternalLogger.warning} render an error twice - verbatim onto a\n * `debug` line, classified onto theirs - rather than once, so that a host\n * running at `'debug'` may still forward `error` to a tracker unchanged.\n *\n * The scope and the accumulated {@link LogBindings} are stamped here, so a\n * call site names only what happened. That is also why call sites hand over an\n * {@link InternalSafeEvent} rather than a finished {@link SafeEvent}: nothing\n * should have to know its own scope twice.\n *\n * ```ts\n * const log = internalLogger(ctx.logger, 'ONDO');\n * log.child({ flow: 'review' }).failure(\n * () => ({ msg: 'quote refresh failed' }),\n * error\n * );\n * // { scope: 'ONDO', flow: 'review', cause: { type: 'http', status: 410, ... },\n * // msg: 'quote refresh failed' }\n * ```\n */\nexport function internalLogger(\n logger: Logger | null | undefined,\n scope: LogScope\n): InternalLogger {\n return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;\n}\n\n/**\n * The logging surface SDK code uses. Never exported to hosts: they implement\n * {@link Logger}, which is deliberately smaller.\n */\nexport type InternalLogger = {\n /**\n * A logger narrowed by one more {@link LogBinding}, which every line it\n * emits carries as its own field.\n */\n child(binding: LogBinding): InternalLogger;\n\n /**\n * The unredacted level. Request and response bodies, full URLs, headers,\n * operation params and raw thrown errors belong here and **only** here.\n */\n debug(event: () => InternalDebugEvent): void;\n\n info(event: () => InternalSafeEvent): void;\n warn(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a failure whose cause is already known, or has none. Prefer\n * {@link failure}, which classifies a thrown error for you.\n */\n error(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a thrown error, classifying it into a {@link LogCause}. Prefer\n * this over `error` at a `catch`: classification only happens when the level\n * admits it.\n *\n * The `error` line names the error's class but never its message, since an\n * error the SDK did not author may say anything at all. The verbatim\n * rendering goes onto a paired `debug` line instead.\n *\n * For a failure the SDK recovers from, use {@link warning} instead. An\n * `error` line a host cannot act on is worse than no line at all: it trains\n * them to ignore the ones that matter.\n */\n failure(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * {@link failure} for trouble that did not break anything: a poll tick that\n * failed while the last value still stands, a retried request.\n *\n * Carries the classified {@link LogCause} exactly as `failure` does. The two\n * differ in level and in nothing else, because what separates them is\n * whether anything actually broke - not how much is known about it.\n */\n warning(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * Runs one namespace operation with logging around it: the call and its\n * params at `debug`, and any throw at `error` with the cause classified.\n * Every line carries `op` as a binding.\n *\n * **The params never reach the `error` line.** They routinely hold the\n * things this SDK must not put in front of a production error tracker - an\n * app bearer token, a document's signing fields, a wallet signature - and\n * the `debug` line plus the request id is how you get them back. The type\n * says so: `params` is `unknown`, which is not a {@link SafeFields} value.\n *\n * Always rethrows. Logging observes behaviour, it never changes it.\n */\n wrap<T>(op: string, params: unknown, run: () => Promise<T>): Promise<T>;\n};\n\n/**\n * What a call site hands to `info`, `warn`, `error`, `failure` or `warning` -\n * a {@link SafeEvent} minus the scope and bindings the logger stamps itself.\n */\nexport type InternalSafeEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: SafeFields;\n readonly cause?: LogCause;\n};\n\n/** What a call site hands to `debug`. Its fields accept anything. */\nexport type InternalDebugEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: UnredactedFields;\n};\n\n/** Each level admits itself and everything above it in this table. */\nconst LEVEL_RANK: Record<LogLevel, number> = {\n none: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction scopedLogger(\n logger: Logger,\n scope: LogScope,\n bindings: LogBindings\n): InternalLogger {\n const admits = (level: LogLevel): boolean =>\n LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];\n\n const safe = (event: InternalSafeEvent): SafeEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n ...(event.cause === undefined ? {} : { cause: event.cause }),\n });\n\n const unredacted = (event: InternalDebugEvent): DebugEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n });\n\n const self: InternalLogger = {\n child: (binding) =>\n scopedLogger(logger, scope, { ...bindings, ...binding }),\n\n debug: (event) => {\n if (admits('debug')) logger.debug(() => unredacted(event()));\n },\n\n info: (event) => {\n if (admits('info')) logger.info(() => safe(event()));\n },\n\n warn: (event) => {\n if (admits('warn')) logger.warn(() => safe(event()));\n },\n\n error: (event) => {\n if (admits('error')) logger.error(() => safe(event()));\n },\n\n failure: (event, error) => {\n // Two lines rather than one, and deliberately in this order: the `error`\n // line stays safe at every level, so a host running `'debug'` in beta\n // can still pipe `error` to Sentry without leaking what `debug` shows.\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('error')) logger.error(() => safe(classified(event(), error)));\n },\n\n warning: (event, error) => {\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('warn')) logger.warn(() => safe(classified(event(), error)));\n },\n\n wrap: async (op, params, run) => {\n const opLog = self.child({ op });\n opLog.debug(() => ({ msg: 'call', fields: { params } }));\n try {\n return await run();\n } catch (error) {\n opLog.failure(() => ({ msg: 'call failed' }), error);\n throw error;\n }\n },\n };\n\n return self;\n}\n\n/**\n * The same event with the thrown error rendered **verbatim** - for the\n * `'debug'` line, and nowhere else.\n */\nfunction verbatim(\n event: InternalSafeEvent,\n error: unknown\n): InternalDebugEvent {\n return {\n msg: event.msg,\n fields: { ...event.fields, error: describeErrorUnredacted(error) },\n };\n}\n\n/**\n * The same event with the thrown error classified into a {@link LogCause}\n * - safe at `'warn'` and `'error'`.\n *\n * An explicit `cause` on the event wins: a call site that already knows what\n * went wrong knows better than the classifier.\n */\nfunction classified(\n event: InternalSafeEvent,\n error: unknown\n): InternalSafeEvent {\n return { ...event, cause: event.cause ?? classifyLogCause(error) };\n}\n\n/**\n * What every SDK codepath gets when the host supplied no logger. `wrap` still\n * runs the work it is given; everything else is inert.\n *\n * There is no `console` fallback here or anywhere else in the SDK: a host who\n * supplied no logger gets silence, not a default destination they did not\n * choose.\n */\nexport const noopInternalLogger: InternalLogger = {\n child: () => noopInternalLogger,\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n failure: () => undefined,\n warning: () => undefined,\n wrap: (_op, _params, run) => run(),\n};\n","import {\n getTokenAllowance,\n getTokenBalance,\n} from '@/shared/api/frontline/providers/superstate/swap';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/shared/core/blockchain/erc20/erc20-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n TokenAllowance,\n TokenBalance,\n} from '@/shared/types/providers/superstate/swap';\n\n/**\n * Generic ERC-20 reads shared across on-chain flows (swap, token sale): the\n * allowance an owner has granted a spender, and the raw token balance an owner\n * holds. These are plain token reads, not tied to any single product flow.\n */\nexport interface Erc20Namespace {\n /**\n * Reads the ERC-20 allowance an `owner` has granted a `spender`.\n */\n getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance>;\n\n /**\n * Reads the raw ERC-20 balance an `owner` holds of a token.\n */\n getBalance(params: GetTokenBalanceParams): Promise<TokenBalance>;\n}\n\nexport class Erc20NamespaceImpl implements Erc20Namespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ERC20');\n }\n\n async getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance> {\n return this.log.wrap('getAllowance', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getTokenAllowance(this.ctx.api, params);\n });\n }\n\n async getBalance(params: GetTokenBalanceParams): Promise<TokenBalance> {\n return this.log.wrap('getBalance', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getTokenBalance(this.ctx.api, params);\n });\n }\n}\n","import { formatUnits } from 'viem';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport { AssetDecimals } from '@/shared/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/shared/types/blockchain/ui';\n\nexport function shortenAddress(\n address: EvmWalletAddress\n): ShortenedWalletAddress {\n const short =\n address.length > 10\n ? `${address.slice(0, 6)}…${address.slice(-4)}`\n : address;\n return ShortenedWalletAddress(short);\n}\n\nexport type FormatAmountOptions = {\n maxFractionDigits?: AssetDecimals;\n};\n\nexport function formatAmount(\n amount: BlockchainAmount,\n locale: string,\n options?: FormatAmountOptions\n): FormattedAmountUi {\n const decimal = formatRawAmount(amount);\n let [integerPart, fractionPart = ''] = decimal.split('.');\n\n const maxFractionDigits = options?.maxFractionDigits;\n const minFractionDigits =\n maxFractionDigits !== undefined\n ? Math.min(maxFractionDigits, amount.decimals)\n : Math.min(2, amount.decimals);\n\n if (\n maxFractionDigits !== undefined &&\n fractionPart.length > maxFractionDigits\n ) {\n ({ integerPart, fractionPart } = roundFractionHalfUp(\n integerPart,\n fractionPart,\n maxFractionDigits\n ));\n }\n\n const fraction =\n minFractionDigits === 0 ? '' : fractionPart.padEnd(minFractionDigits, '0');\n\n const integerFormatted = BigInt(integerPart).toLocaleString(locale);\n if (minFractionDigits === 0 && fraction === '') {\n return FormattedAmountUi(integerFormatted);\n }\n\n const decimalSeparator =\n new Intl.NumberFormat(locale)\n .formatToParts(1.1)\n .find((p) => p.type === 'decimal')?.value ?? '.';\n\n return FormattedAmountUi(`${integerFormatted}${decimalSeparator}${fraction}`);\n}\n\n/**\n * Rounds a decimal split into `integerPart`/`fractionPart` strings half-up to\n * `maxFractionDigits`, carrying into the integer part when needed (via BigInt,\n * so precision is preserved beyond `Number.MAX_SAFE_INTEGER`).\n *\n * Precondition: `integerPart` must be non-negative (guaranteed here because\n * `BlockchainAmount.raw` is a `Uint256`). A negative integer part would carry\n * in the wrong direction (toward +∞ instead of away from zero).\n */\nfunction roundFractionHalfUp(\n integerPart: string,\n fractionPart: string,\n maxFractionDigits: number\n): { integerPart: string; fractionPart: string } {\n if (fractionPart.length <= maxFractionDigits) {\n return { integerPart, fractionPart };\n }\n\n if (maxFractionDigits === 0) {\n const roundUp = fractionPart[0] >= '5';\n const integer = BigInt(integerPart) + (roundUp ? 1n : 0n);\n return { integerPart: integer.toString(), fractionPart: '' };\n }\n\n const trimmed = fractionPart.slice(0, maxFractionDigits);\n if (fractionPart[maxFractionDigits] < '5') {\n return { integerPart, fractionPart: trimmed };\n }\n\n const digits = trimmed.split('').map((digit) => Number.parseInt(digit, 10));\n let carry = 1;\n for (let i = digits.length - 1; i >= 0 && carry > 0; i -= 1) {\n const sum = digits[i] + carry;\n if (sum === 10) {\n digits[i] = 0;\n carry = 1;\n } else {\n digits[i] = sum;\n carry = 0;\n }\n }\n\n return {\n integerPart:\n carry > 0 ? (BigInt(integerPart) + 1n).toString() : integerPart,\n fractionPart: digits.join(''),\n };\n}\n\nexport function formatRawAmount(amount: BlockchainAmount): string {\n return formatUnits(amount.raw, amount.decimals);\n}\n\n/**\n * Formats a {@link BlockchainAmount} using compact notation (e.g. `1.37B`,\n * `5M`). Compact notation only surfaces a couple of significant decimals, so\n * the bigint → number narrowing here is intentional and safe: full precision\n * is deliberately dropped in favour of a human-readable summary value.\n */\nexport function formatCompactAmount(\n amount: BlockchainAmount,\n locale: string\n): FormattedAmountUi {\n const value = Number(formatRawAmount(amount));\n const formatted = new Intl.NumberFormat(locale, {\n notation: 'compact',\n maximumFractionDigits: 2,\n }).format(value);\n return FormattedAmountUi(formatted);\n}\n\nexport function formatBpsAsPercent(\n bps: Bps,\n locale: string\n): FormattedPercentUi {\n const whole = bps / 100n;\n const fraction = bps % 100n;\n const wholeFormatted = whole.toLocaleString(locale);\n const decimalSeparator =\n new Intl.NumberFormat(locale)\n .formatToParts(1.1)\n .find((p) => p.type === 'decimal')?.value ?? '.';\n\n if (fraction === 0n) {\n return FormattedPercentUi(`${wholeFormatted}%`);\n }\n\n const fractionFormatted = fraction\n .toString()\n .padStart(2, '0')\n .replace(/0+$/, '');\n\n return FormattedPercentUi(\n `${wholeFormatted}${decimalSeparator}${fractionFormatted}%`\n );\n}\n\nexport function usdAmount(amount: FormattedAmountUi): FormattedAmountAssetUi {\n return FormattedAmountAssetUi(`$${amount}`);\n}\n\nexport function assetAmount(\n amount: FormattedAmountUi,\n symbol: AssetSymbol\n): FormattedAmountAssetUi {\n return FormattedAmountAssetUi(`${amount} ${symbol}`);\n}\n\n/** Placeholder shown when an amount is unavailable (e.g. a loading quote). */\nexport const NA_AMOUNT_ASSET_UI: FormattedAmountAssetUi =\n FormattedAmountAssetUi('-');\n\nconst USD_FRACTION_DIGITS = AssetDecimals(2);\n\n/**\n * Formats a USD amount capped at 2 fractional digits, falling back to the\n * {@link NA_AMOUNT_ASSET_UI} placeholder when the amount is absent.\n */\nexport function formattedUsdPrice(\n amount: BlockchainAmount | null,\n locale: string\n): FormattedAmountAssetUi {\n if (!amount) return NA_AMOUNT_ASSET_UI;\n return usdAmount(\n formatAmount(amount, locale, { maxFractionDigits: USD_FRACTION_DIGITS })\n );\n}\n","import { parseUnits } from 'viem';\nimport {\n type AssetDecimals,\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/shared/types/blockchain/core';\nimport { ValidationError } from '@/shared/types/errors';\n\n/** A typed, i18n-agnostic reason a raw amount string failed to parse. */\nexport type AmountParseErrorReason =\n | { type: 'empty' }\n | { type: 'negative' }\n | { type: 'invalid-format' }\n | { type: 'too-many-decimals'; maxDecimals: AssetDecimals }\n /** Scaled up by `decimals`, the amount no longer fits a uint256. */\n | { type: 'overflow' };\n\nexport type AmountParseResult =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; reason: AmountParseErrorReason };\n\n/**\n * Wraps a raw uint256 base-unit string — what Ondo and the on-chain reads\n * return (\"100000000\" is 100 USDC, not 100 wei-of-nothing) — in a\n * {@link BlockchainAmount} at the given decimals. The value is already scaled,\n * so `decimals` is only the unit tag that travels with it.\n *\n * Distinct from {@link parseBlockchainAmount}, which takes a *human decimal*\n * string and scales it up. Feeding a raw amount to that one silently\n * multiplies it by 10^decimals — pick by what the backend sends, not by which\n * one is closer at hand.\n *\n * @throws ValidationError when the string is not a non-negative uint256\n * integer. A backend that regresses to decimal strings fails loudly here\n * rather than truncating.\n */\nexport function blockchainAmountFromRawOrThrow({\n label,\n raw,\n decimals,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n}): BlockchainAmount {\n const trimmed = raw.trim();\n // BigInt('') is 0n, not an error — an absent amount must not read as zero.\n if (trimmed === '') {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n let value: bigint;\n try {\n // BigInt() rejects \"0.5\", \"abc\" and \"1e18\" by throwing SyntaxError.\n value = BigInt(trimmed);\n } catch {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n try {\n return BlockchainAmount({ raw: assertUint256(value), decimals });\n } catch {\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n }\n}\n\n/**\n * Parses a user-entered decimal string into a {@link BlockchainAmount} at the\n * given token decimals. Rejects scientific notation, negatives, malformed\n * input, more fractional digits than the token supports, and amounts that\n * scale past uint256 — surfacing a typed {@link AmountParseErrorReason} so\n * callers own the display copy.\n */\nexport function parseBlockchainAmount(\n amount: string,\n decimals: AssetDecimals\n): AmountParseResult {\n const trimmed = amount.trim();\n if (trimmed === '') return { valid: false, reason: { type: 'empty' } };\n if (trimmed.startsWith('-')) {\n return { valid: false, reason: { type: 'negative' } };\n }\n // viem accepts \"1e18\" as scientific notation — reject it explicitly\n if (/[eE]/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // reject bare decimal point or missing digits on either side\n if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n const [, fraction = ''] = trimmed.split('.');\n if (fraction.length > decimals) {\n return {\n valid: false,\n reason: { type: 'too-many-decimals', maxDecimals: decimals },\n };\n }\n try {\n // parseUnits is unbounded: a long enough input scales past uint256, which\n // no on-chain amount can hold. Reporting it as valid would send a\n // truncated or reverting value to a contract.\n const raw = parseUnits(trimmed, decimals);\n if (raw > MAX_UINT_256) {\n return { valid: false, reason: { type: 'overflow' } };\n }\n return {\n valid: true,\n amount: BlockchainAmount({ raw, decimals }),\n };\n } catch {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n}\n","import {\n AssetDecimals,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n type KnownAssetSymbol,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport { InvariantError } from '@/shared/types/errors';\n\nexport const USDC_SYMBOL: StablecoinSymbol = StablecoinSymbol('USDC');\nexport const USDC: Erc20Asset = {\n name: 'USD Coin',\n symbol: USDC_SYMBOL,\n decimals: AssetDecimals(6),\n};\n\nexport const USDT_SYMBOL: StablecoinSymbol = StablecoinSymbol('USDT');\nexport const USDT: Erc20Asset = {\n name: 'Tether USD',\n symbol: USDT_SYMBOL,\n decimals: AssetDecimals(6),\n};\n\n/** ERC-20 contract addresses for a supported stablecoin, keyed by chain. */\ntype TokenAddresses = Record<EthereumChain, EvmContractAddress>;\n\nconst USDC_ADDRESSES: TokenAddresses = {\n ethereum_mainnet: EvmContractAddress(\n '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'\n ),\n base_mainnet: EvmContractAddress(\n '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'\n ),\n base_sepolia: EvmContractAddress(\n '0x036CbD53842c5426634e7929541eC2318f3dCF7e'\n ),\n};\n\n/**\n * USDT is not deployed on every chain the SDK models: Tether publishes no\n * Base Sepolia token. The table stays total, with that one absence an\n * explicit `null`, so a new {@link EthereumChain} is still a compile error\n * here until the author decides whether USDT exists on it — the same\n * exhaustiveness the rest of the chain model relies on. A lookup then\n * answers the honest `null` rather than calling a fake address.\n */\nconst USDT_ADDRESSES: Record<EthereumChain, EvmContractAddress | null> = {\n ethereum_mainnet: EvmContractAddress(\n '0xdac17f958d2ee523a2206206994597c13d831ec7'\n ),\n ethereum_sepolia: EvmContractAddress(\n '0x7169D38820dfd117C3FA1f22a697dBA58d90BA06'\n ),\n base_mainnet: EvmContractAddress(\n '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2'\n ),\n base_sepolia: null,\n};\n\n/** Lookups for the stablecoins the SDK's swap flows support out of the box. */\nexport const TOKEN_REGISTRY = {\n erc20: (symbol: KnownAssetSymbol): Erc20Asset => {\n switch (symbol) {\n case 'USDC':\n return USDC;\n case 'USDT':\n return USDT;\n default:\n throw new InvariantError(`Unknown asset symbol: ${symbol}`);\n }\n },\n /**\n * USDC's contract on `chain`. USDC is deployed on every chain the SDK\n * models, so the table is total and the answer is never `null`.\n */\n usdcAddress: (chain: EthereumChain): EvmContractAddress =>\n USDC_ADDRESSES[chain],\n /**\n * USDT's contract on `chain`, or `null` where Tether publishes none —\n * Base Sepolia today. The honest answer, never a fake address a balance\n * read would call.\n */\n usdtAddress: (chain: EthereumChain): EvmContractAddress | null =>\n USDT_ADDRESSES[chain],\n};\n","import type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { QueryParamValue } from '@/shared/types/http';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type Cursor = Newtype<string, 'Cursor'>;\nexport const Cursor = (value: string) => value as Cursor;\n\n/**\n * Cursor-based pagination input used when requesting paginated API resources.\n * Set `after` or `before` to navigate relative to a known cursor, and `limit`\n * to control the maximum number of returned items.\n */\nexport interface PaginationParams {\n before?: Cursor;\n after?: Cursor;\n limit?: number;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n startingAfter: Cursor | null;\n startingBefore: Cursor | null;\n}\n\nexport const PaginatedResponse = {\n fromDto: <A, B>(\n dto: PaginatedResponseDto<A>,\n itemMapper: (item: A) => B\n ): PaginatedResponse<B> => ({\n data: dto.data.map(itemMapper),\n startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,\n startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null,\n }),\n};\n\nexport const PaginationParams = {\n toQueryParams: (\n params: PaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams: Record<string, QueryParamValue> = {};\n if (params.after) {\n queryParams.starting_after = params.after;\n }\n if (params.before) {\n queryParams.starting_before = params.before;\n }\n if (params.limit) {\n queryParams.limit = params.limit;\n }\n return queryParams;\n },\n};\n","import type { AssetDto } from '@/shared/types/dto/asset';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type AssetId = Newtype<string, 'AssetId'>;\nexport const AssetId = (value: string) => value as AssetId;\n\nexport type AssetCode = Newtype<string, 'AssetCode'>;\nexport const AssetCode = (value: string) => value as AssetCode;\n\nexport type Asset = {\n id: AssetId;\n code: AssetCode;\n name: string;\n fractionalDigits: number;\n};\n\nexport const Asset = {\n fromDto: (dto: AssetDto): Asset => ({\n id: AssetId(dto.id),\n code: AssetCode(dto.code),\n name: dto.name,\n fractionalDigits: dto.fractional_digits,\n }),\n};\n","import { Chain, EvmContractAddress } from '@/shared/types/blockchain/core';\nimport type {\n OfferDto,\n OfferTokenDto,\n OfferTypeDto,\n} from '@/shared/types/dto/offer';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type OfferId = Newtype<string, 'OfferId'>;\nexport const OfferId = (value: string) => value as OfferId;\n\nexport type OfferSlug = Newtype<string, 'OfferSlug'>;\nexport const OfferSlug = (value: string) => value as OfferSlug;\n\nexport type OfferType = OfferTypeDto;\n\nexport type Offer = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n startsAt: Date;\n endsAt: Date | null;\n tokens: OfferToken[];\n};\n\nexport const Offer = {\n fromDto: (dto: OfferDto): Offer => {\n // The same guard, and the same wording, as every array field in\n // `OfferDetail.fromDto`: a backend sending a non-array is a\n // `ValidationError` naming the field, which `classifyLogCause` maps to the\n // `validation` remedy. Left to `.map`, it would surface as a bare\n // `TypeError` classified `generic-error`, naming neither the field nor\n // whose fault it was.\n if (!Array.isArray(dto.tokens)) {\n throw new ValidationError(\n `Offer.tokens: expected an array, got ${typeof dto.tokens}`\n );\n }\n\n return {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n tokens: dto.tokens.map(OfferToken.fromDto),\n };\n },\n};\n\nexport type TokenRole = 'funding' | 'distribution' | 'swap';\n\nexport type OfferToken = {\n role: TokenRole;\n chain: Chain;\n address: EvmContractAddress;\n};\n\nexport const OfferToken = {\n fromDto: (dto: OfferTokenDto): OfferToken => ({\n role: dto.role,\n chain: Chain(dto.chain),\n address: EvmContractAddress(dto.address),\n }),\n};\n","import { notBlankStringOrNull } from '@/shared/core/utils/crypto';\nimport { Asset } from '@/shared/types/asset';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailTermDto,\n} from '@/shared/types/dto/offer-detail';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\nimport {\n OfferId,\n OfferSlug,\n OfferToken,\n type OfferType,\n} from '@/shared/types/offer';\n\nexport type OfferDetail = {\n id: OfferId;\n slug: OfferSlug;\n type: OfferType;\n name: string;\n\n asset: Asset;\n fundingAssets: Asset[];\n tokens: OfferToken[];\n\n about: string | null;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n category: string;\n\n startsAt: Date;\n endsAt: Date | null;\n\n faqs: FaqItem[];\n links: Link[];\n milestones: Milestone[];\n options: OfferOption[];\n terms: TermItem[];\n};\n\nexport type OfferOptionId = Newtype<string, 'OfferOptionId'>;\nexport const OfferOptionId = (value: string) => value as OfferOptionId;\n\nexport type OfferOptionSlug = Newtype<string, 'OfferOptionSlug'>;\nexport const OfferOptionSlug = (value: string) => value as OfferOptionSlug;\n\nexport type OfferOption = {\n id: OfferOptionId;\n slug: OfferOptionSlug;\n bidIncrement: number | null;\n floorPriceUsd: number | null;\n minimumPurchaseUsd: number | null;\n priceUsd: string | null;\n saleAgreementUrl: string | null;\n totalTokenSupply: number | null;\n};\n\nexport type FaqItem = {\n question: string | null;\n answer: string | null;\n};\n\nexport type TermItem = {\n key: string | null;\n value: string | null;\n};\n\nexport type Milestone = {\n name: string | null;\n schedule: string | null;\n status: 'completed' | 'active' | 'upcoming';\n};\n\nexport type Link = {\n label: string | null;\n url: string | null;\n};\n\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n if (!Array.isArray(dto.funding_assets)) {\n throw new ValidationError(\n `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`\n );\n }\n\n if (!Array.isArray(dto.options)) {\n throw new ValidationError(\n `OfferDetail.options: expected an array, got ${typeof dto.options}`\n );\n }\n\n if (!Array.isArray(dto.terms)) {\n throw new ValidationError(\n `OfferDetail.terms: expected an array, got ${typeof dto.terms}`\n );\n }\n\n if (!Array.isArray(dto.links)) {\n throw new ValidationError(\n `OfferDetail.links: expected an array, got ${typeof dto.links}`\n );\n }\n\n if (!Array.isArray(dto.faqs)) {\n throw new ValidationError(\n `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`\n );\n }\n\n if (!Array.isArray(dto.milestones)) {\n throw new ValidationError(\n `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`\n );\n }\n\n if (!Array.isArray(dto.tokens)) {\n throw new ValidationError(\n `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`\n );\n }\n\n return {\n id: OfferId(dto.id),\n slug: OfferSlug(dto.slug),\n type: dto.type,\n name: dto.name,\n\n asset: Asset.fromDto(dto.asset),\n fundingAssets: dto.funding_assets.map(Asset.fromDto),\n tokens: dto.tokens.map(OfferToken.fromDto),\n\n about: notBlankStringOrNull(dto.about),\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n category: dto.category,\n\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: dto.faqs.map(FaqItem.fromDto),\n links: dto.links.map(Link.fromDto),\n milestones: dto.milestones.map(Milestone.fromDto),\n options: dto.options.map(OfferOption.fromDto),\n terms: dto.terms.map(TermItem.fromDto),\n };\n },\n};\n\nexport const OfferOption = {\n fromDto: (dto: OfferDetailOptionDto): OfferOption => ({\n id: OfferOptionId(dto.id),\n slug: OfferOptionSlug(dto.slug),\n bidIncrement: dto.bid_increment,\n floorPriceUsd: dto.floor_price_usd,\n minimumPurchaseUsd: dto.minimum_purchase_usd,\n priceUsd: dto.price_usd,\n saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),\n totalTokenSupply: dto.total_token_supply,\n }),\n};\n\nexport const FaqItem = {\n fromDto: (dto: OfferDetailFaqDto): FaqItem => ({\n question: notBlankStringOrNull(dto.question),\n answer: notBlankStringOrNull(dto.answer),\n }),\n};\n\nexport const Link = {\n fromDto: (dto: OfferDetailLinkDto): Link => ({\n label: notBlankStringOrNull(dto.label),\n url: notBlankStringOrNull(dto.url),\n }),\n};\n\nexport const TermItem = {\n fromDto: (dto: OfferDetailTermDto): TermItem => ({\n key: notBlankStringOrNull(dto.key),\n value: notBlankStringOrNull(dto.value),\n }),\n};\n\nexport const Milestone = {\n fromDto: (dto: OfferDetailMilestoneDto): Milestone => ({\n name: notBlankStringOrNull(dto.name),\n schedule: notBlankStringOrNull(dto.schedule),\n status: dto.status,\n }),\n};\n","import { notBlankStringOrNull } from '@/shared/core/utils/crypto';\nimport { Asset, type AssetId } from '@/shared/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/shared/types/dto/providers/coin-list/token-sale';\nimport type { QueryParamValue } from '@/shared/types/http';\nimport type { Newtype } from '@/shared/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/shared/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/shared/types/offer-detail';\nimport { PaginationParams } from '@/shared/types/pagination';\n\n/** Unique identifier for a participation. */\nexport type ParticipationId = Newtype<string, 'ParticipationId'>;\n/** Casts a string into a typed {@link ParticipationId}. */\nexport const ParticipationId = (value: string) => value as ParticipationId;\n\n/** Blockchain identifier for where a participation is funded. */\nexport type Blockchain = Newtype<string, 'Blockchain'>;\n/** Casts a string into a typed {@link Blockchain}. */\nexport const Blockchain = (value: string) => value as Blockchain;\n\n/** Wallet address used for a participation. */\nexport type WalletAddress = Newtype<`0x${string}`, 'WalletAddress'>;\n/** Casts a `0x`-prefixed string into a typed {@link WalletAddress}. */\nexport const WalletAddress = (value: `0x${string}`) => value as WalletAddress;\n\n/** Possible participation lifecycle states returned by the API. */\nexport type ParticipationStatus = ParticipationStatusDto;\n\n/** Domain model for a participation returned by CoinList APIs. */\nexport type Participation = {\n /** Unique participation id. */\n id: ParticipationId;\n /** Parent offer id. */\n offerId: OfferIdType;\n /** Selected offer option id. */\n offerOptionId: OfferOptionIdType;\n /** Current processing status. */\n status: ParticipationStatus;\n /** Raw participation amount from API. */\n amount: string;\n /** Human-readable formatted amount from API. */\n displayAmount: string;\n /** Asset metadata for the participation amount. */\n asset: Asset;\n /** Funding chain identifier. */\n chain: Blockchain;\n /** Creation timestamp, if returned by API. */\n insertedAt: Date | null;\n /** Last update timestamp, if returned by API. */\n updatedAt: Date | null;\n /** Wallet used for participation, blank values normalized to null. */\n walletAddress: WalletAddress | null;\n};\n\n/** Parameters required to create a new participation. */\nexport type CreateParticipationParams = {\n /** Offer to participate in. */\n offerId: OfferIdType;\n /** Offer option selected for participation. */\n offerOptionId: OfferOptionIdType;\n /** Blockchain for funding. */\n chain: Blockchain;\n /** Wallet address that funds the participation. */\n walletAddress: WalletAddress;\n /**\n * Decimal token amount to participate with (e.g. `\"100\"` for 100 USDC), NOT\n * raw base units. The backend rescales this by the asset's decimals to verify\n * it against the on-chain approval allowance.\n */\n amount: string;\n /** Funding asset id. */\n assetId: AssetId;\n /**\n * Hash of the ERC-20 `approve()` transaction covering this participation.\n * Required: the backend verifies it on-chain (sender, token, spender, and\n * approved amount) before confirming the participation.\n */\n approvalTransactionHash: string;\n};\n\n/** Pagination params for listing participations, with an optional offer filter. */\nexport interface ParticipationsPaginationParams extends PaginationParams {\n offerId?: OfferIdType;\n}\n\nexport const ParticipationsPaginationParams = {\n toQueryParams: (\n params: ParticipationsPaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams = PaginationParams.toQueryParams(params);\n if (params.offerId) {\n queryParams['filters[0][field]'] = 'offer_id';\n queryParams['filters[0][op]'] = '==';\n queryParams['filters[0][value]'] = params.offerId;\n }\n return queryParams;\n },\n};\n\nexport const Participation = {\n /** Maps API DTO shape into the SDK participation domain model. */\n fromDto: (dto: ParticipationDto): Participation => {\n const walletAddress = notBlankStringOrNull(dto.wallet_address);\n return {\n id: ParticipationId(dto.id),\n offerId: OfferId(dto.offer_id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n status: dto.status,\n amount: dto.amount,\n displayAmount: dto.amount_string,\n asset: Asset.fromDto(dto.asset),\n chain: Blockchain(dto.chain),\n insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,\n updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,\n walletAddress: walletAddress\n ? WalletAddress(walletAddress as `0x${string}`)\n : null,\n };\n },\n};\n\nexport const CreateParticipationParams = {\n /** Maps participation creation params into API DTO payload. */\n toDto: (params: CreateParticipationParams): CreateParticipationDto => ({\n offer_id: params.offerId,\n offer_option_id: params.offerOptionId,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount,\n asset_id: params.assetId,\n approval_transaction_hash: params.approvalTransactionHash,\n }),\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { fetchAllPages } from '@/shared/api/pagination';\nimport type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { ParticipationDto } from '@/shared/types/dto/providers/coin-list/token-sale';\nimport type { OfferId } from '@/shared/types/offer';\nimport { PaginatedResponse } from '@/shared/types/pagination';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/providers/coin-list/token-sale';\n\nexport async function fetchParticipations(\n api: Sender,\n offerId?: OfferId\n): Promise<Participation[]> {\n return fetchAllPages<Participation, ParticipationsPaginationParams>(\n (params) => fetchParticipationsPage(api, params),\n { offerId }\n );\n}\n\nexport async function fetchParticipationsPage(\n api: Sender,\n params: ParticipationsPaginationParams\n): Promise<PaginatedResponse<Participation>> {\n const pageDto = await api.send<PaginatedResponseDto<ParticipationDto>>({\n method: 'GET',\n url: '/v1/participations',\n queryParams: ParticipationsPaginationParams.toQueryParams(params),\n attributes: Attributes.protected(),\n });\n return PaginatedResponse.fromDto(pageDto, Participation.fromDto);\n}\n\nexport async function fetchParticipation(\n api: Sender,\n id: ParticipationId\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'GET',\n url: `/v1/participations/${id}`,\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n\nexport async function createParticipation(\n api: Sender,\n params: CreateParticipationParams\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'POST',\n url: '/v1/participations',\n body: CreateParticipationParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n","import * as participationsApi from '@/shared/api/frontline/providers/coin-list/token-sale';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { PaginatedResponse } from '@/shared/types/pagination';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/providers/coin-list/token-sale';\n\n/**\n * Read/write operations for token sales: listing and reading the current user's\n * participations, and recording a new one. The on-chain execution flow\n * (`executeTokenSale`) is layered on top of this in the client-side namespace.\n */\nexport interface CoinListTokenSaleNamespace {\n /**\n * Fetches all participations by iterating through every paginated response,\n * optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n list(offerId?: OfferId): Promise<Participation[]>;\n\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n\n /**\n * Fetches a participation by id.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n get(id: ParticipationId): Promise<Participation>;\n\n /**\n * Records a participation with CoinList.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n}\n\nexport class CoinListTokenSaleNamespaceImpl\n implements CoinListTokenSaleNamespace\n{\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'TOKEN_SALE');\n }\n\n async list(offerId?: OfferId): Promise<Participation[]> {\n return this.log.wrap('list', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipations(this.ctx.api, offerId);\n });\n }\n\n async listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipationsPage(this.ctx.api, params);\n });\n }\n\n async get(id: ParticipationId): Promise<Participation> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipation(this.ctx.api, id);\n });\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n return this.log.wrap('createParticipation', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.createParticipation(this.ctx.api, params);\n });\n }\n}\n","import { USDC_SYMBOL } from '@/shared/core/blockchain/token-registry';\nimport {\n DecimalString,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/types/collections';\n\n/**\n * The CoinList integration contract an Ondo swap is sent to, and therefore the\n * ERC-20 spender the user approves.\n *\n * It is a constant rather than a value read off the built transaction because\n * the approval has to happen *before* the transaction is built: the calldata\n * is only good for a minute, and an approval takes most of one to mine. The\n * built transaction's `tx.to` is checked against this before broadcasting, so a\n * stale constant fails loudly instead of sending a transaction that reverts on\n * `transferFrom`.\n *\n * Mainnet is absent, not zeroed: Ondo's production integration contract is not\n * deployed yet, and a zero address would be approved happily and revert only\n * later. Flows return `unsupported-chain` for a chain with no entry.\n *\n * The Sepolia entry is production's deployment. Beta has its own, so an SDK\n * pointed at beta fails `spender-mismatch` until ENG-1734 serves the address\n * off the offer.\n */\nconst ONDO_SWAP_CONTRACT_ADDRESSES: Partial<\n Record<EthereumChain, EvmContractAddress>\n> = {\n ethereum_sepolia: EvmContractAddress(\n '0x7014019ed51Edab984a71D30F2707D2dB2316A7A'\n ),\n};\n\n/** The Ondo integration contract on `chain`, or `null` where none is deployed. */\nexport function ondoSwapContractAddress(\n chain: EthereumChain\n): EvmContractAddress | null {\n return ONDO_SWAP_CONTRACT_ADDRESSES[chain] ?? null;\n}\n\n/**\n * How often the Ondo checkout refreshes what it is allowed to poll: the market\n * status and the indicative price. Both are free - neither spends an\n * attestation - so this is paced for a price the user can trust rather than\n * for cost.\n *\n * A built transaction is deliberately not on this timer. Building spends an\n * attestation, so it happens once per order and once per refresh the user\n * asks for.\n */\nexport const ONDO_POLL_INTERVAL_MS = 15_000;\n\n/**\n * How close to its deadline a built transaction stops being offerable.\n *\n * Placing an order is not instant - the wallet has to prompt, the user has to\n * confirm, and the transaction has to reach a node - so calldata with a second\n * left is one the contract will reject. Treating the last few seconds as\n * already expired turns a paid-for revert into a refresh button.\n */\nexport const ONDO_QUOTE_EXPIRY_THRESHOLD_MS = 5_000;\n\n/**\n * The order size the sidebar prices against before the user names one.\n *\n * Ondo prices by size, so some amount has to be sent. $1,000 is a plausible\n * order rather than a token one: a size so small that Ondo's minimum rejects\n * it would leave the panel permanently blank.\n *\n * Named distinctly from `DEFAULT_AMOUNT_TO_COMPUTE_PRICE` in the swap\n * constants, which is a raw `bigint` of USDC base units for a different\n * endpoint. Both barrels are flat, so two constants of the same name could not\n * coexist - and they mean different things anyway.\n */\nexport const DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE = DecimalString('1000');\n\n/**\n * The coin an Ondo sell settles into, for display only.\n *\n * The scale of every amount on a built transaction comes off the response, so\n * this names the token and never sizes it - `receive_output_decimals` is the\n * only authority on how many decimals the proceeds are counted in, and the two\n * are allowed to disagree.\n *\n * Named apart from {@link ONDO_SUPPORTED_INPUT_ASSETS} rather than read out of\n * it, though both are USDC today. On a buy USDC is what the user funds with\n * and one of a list that may grow; on a sell it is what they settle into and\n * there is one of it. Reading `ONDO_SUPPORTED_INPUT_ASSETS[0]` here would make\n * the sell screen quietly follow whichever funding coin happened to be listed\n * first.\n */\nexport const ONDO_SETTLEMENT_ASSET: StablecoinSymbol = USDC_SYMBOL;\n\n/**\n * The order size the sidebar prices a sell against before the user names one.\n *\n * Sells are quoted by token amount rather than by notional: the fee comes out\n * of dollars, and Ondo's price is size-aware, so a buy's quantity depends on\n * the quote being asked for while a sell is sized by what the user already\n * holds. One whole share is a size Ondo will price - small enough to be\n * plausible for any asset, large enough that Ondo's minimum does not reject it\n * and leave the panel permanently blank.\n *\n * The buy counterpart is {@link DEFAULT_ONDO_AMOUNT_TO_COMPUTE_PRICE}, which\n * is a dollar figure for the same reason in reverse.\n */\nexport const DEFAULT_ONDO_SELL_TOKENS_TO_COMPUTE_PRICE = 1;\n\n/**\n * The coins an Ondo buy can be funded with, in display order, with the first\n * preselected.\n *\n * USDC alone today: it is what the Sepolia integration contract accepts. The\n * amount step renders a single entry as a plain card and two or more as a\n * picker, so adding one here is all it takes.\n */\nexport const ONDO_SUPPORTED_INPUT_ASSETS: NonEmptyArray<StablecoinSymbol> = [\n USDC_SYMBOL,\n];\n","import {\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n type Uint256,\n} from '@/shared/types/blockchain/core';\nimport { MathError } from '@/shared/types/errors';\nimport type {\n OndoBuyTransaction,\n OndoSellOutcome,\n OndoSellTransaction,\n} from '@/shared/types/providers/ondo/ondo';\n\n/**\n * The price of one whole asset token in a built Ondo purchase, in the funding\n * token's units - USD per share.\n *\n * Neither builder publishes a price. Frontline drops Ninshubur's deliberately,\n * because `GET /v1/ondo/swap/quote` already serves one under that name at a\n * different scale, and echoing both would leave a caller to guess which was\n * which.\n *\n * Dividing the two amounts the response *does* carry is better than reading\n * the indicative one anyway: it is the price this transaction fills at, rather\n * than a poll that has since moved and was struck against a different size.\n *\n * **Fee-exclusive.** `notionalValue` is the deposit after CoinList's fee comes\n * off, so this is the price Ondo filled at, not the buyer's all-in cost per\n * token - that would be `spendInputAmount / receiveOutputAmount`, and it is\n * higher. Fee-exclusive is what the review screen wants, because it renders\n * the fee on its own line: price x quantity, plus fee, comes to the total.\n * Making this all-in would double-count the fee against that breakdown.\n *\n * The two are equal until ENG-1718 turns a fee on, which frontline rejects\n * today. They diverge the moment it does, so the choice is load-bearing rather\n * than academic.\n */\nexport function computeOndoBuyPrice(\n transaction: OndoBuyTransaction\n): BlockchainAmount {\n const { notionalValue, receiveOutputAmount } = transaction;\n return pricePerShare({\n usd: notionalValue,\n shares: receiveOutputAmount,\n });\n}\n\n/**\n * The price of one whole asset token in a built Ondo sale, in the settlement\n * token's units - USD per share, the same thing\n * {@link computeOndoBuyPrice} answers with the ratio inverted.\n *\n * **Fee-exclusive, and it takes arithmetic to be so.** `expected.quantity` is\n * published already net of `expected.fee`, so the proceeds are added back\n * before dividing: what comes out is the price Ondo filled at, which is the\n * buy arm's meaning rather than a second one. That is what lets one review row\n * render on either screen, and what keeps the sell breakdown honest - the fee\n * sits on its own line beside this, and a net price would count it twice.\n *\n * Read against {@link OndoSellTransaction.expected} alone. The `minimum` arm\n * describes the same trade at a different outcome, and pricing that one would\n * answer \"the worst price this could fill at\", which no screen asks for.\n *\n * The two readings coincide while frontline forces the fee to zero, which it\n * does today. They diverge the day ENG-1718 lands.\n */\nexport function computeOndoSellPrice(\n transaction: OndoSellTransaction\n): BlockchainAmount {\n const { expected, spendInputAmount } = transaction;\n return pricePerShare({\n usd: grossProceeds(expected),\n shares: spendInputAmount,\n });\n}\n\n/**\n * What Ondo returned before CoinList took its cut: the published quantity with\n * the fee charged on it added back.\n *\n * Bounded before the addition rather than after. The two amounts are parsed\n * independently, each a uint256 in its own right, so nothing in the mapper\n * stops their sum leaving the range - and `BlockchainAmount.add` answers an\n * out-of-range sum with an `InvariantError`, which says the SDK's own\n * arithmetic went wrong. It did not: a gross that no uint256 can hold is a\n * corrupt response, the same kind of thing {@link assertPriceFits} reports, and\n * it has to say so here rather than take the checkout down mid-render.\n *\n * The addition itself is still `BlockchainAmount.add`, so the two amounts\n * disagreeing about their scale stays an `InvariantError`. That one really is\n * internal: `OndoSellTransaction.fromDto` reads both off\n * `receive_output_decimals`.\n */\nfunction grossProceeds(expected: OndoSellOutcome): BlockchainAmount {\n const raw = expected.quantity.raw + expected.fee.raw;\n if (raw > MAX_UINT_256) {\n throw new MathError(`Ondo sell proceeds: out of uint256 bounds (${raw})`);\n }\n return BlockchainAmount.add(expected.quantity, expected.fee);\n}\n\n/**\n * USD per whole share, in the USD amount's decimals.\n *\n * Both prices bottom out here so the scaling, the rounding and the bound are\n * written once: whichever side the amounts came off, a price is one dollar\n * amount divided by one asset amount.\n *\n * {@link BlockchainAmount.div} owns the arithmetic - it scales the numerator\n * by the asset's exponent so the quotient lands back in the funding token's,\n * truncates towards zero so the total a price implies never overstates what\n * was paid, and refuses a zero share quantity rather than dividing by it.\n * That last guard is unreachable through either `fromDto`, which rejects a\n * non-positive amount on both sides of the trade at the boundary - both of\n * them, because which one lands in the denominator here flips with the\n * direction. It matters because this runs during render, where a bare BigInt\n * division would take the checkout down with a RangeError instead of failing\n * one step.\n *\n * What is Ondo's rather than every amount's is the uint256 bound: `div`\n * deliberately does not check one, because scaling can carry a legal pair out\n * of range, and here that can only mean a corrupt response.\n */\nfunction pricePerShare({\n usd,\n shares,\n}: {\n usd: BlockchainAmount;\n shares: BlockchainAmount;\n}): BlockchainAmount {\n const price = BlockchainAmount.div(usd, shares);\n return BlockchainAmount({\n raw: assertPriceFits(price.raw),\n decimals: price.decimals,\n });\n}\n\n/**\n * A price past uint256 needs an output amount of a few base units against a\n * notional no real balance holds. It cannot come off the wire, so it is a\n * corrupt response rather than an expensive order.\n */\nfunction assertPriceFits(raw: bigint): Uint256 {\n try {\n return assertUint256(raw);\n } catch {\n throw new MathError(`Ondo price: out of uint256 bounds (${raw})`);\n }\n}\n","import type { Newtype } from '@/shared/types/newtype';\n\nexport type Ticker = Newtype<string, 'Ticker'>;\nexport const Ticker = (value: string): Ticker => value as Ticker;\n\nexport type OrderBookSide = 'buy' | 'sell';\n","import { chainFromId } from '@/shared/core/blockchain/chain';\nimport { blockchainAmountFromRawOrThrow } from '@/shared/core/blockchain/math';\nimport {\n AssetDecimals,\n AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n HexEncodedTransactionData,\n type Tx,\n} from '@/shared/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoSwapDtoCore,\n OndoTradingStatusDto,\n} from '@/shared/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/shared/types/errors';\nimport { type OrderBookSide, Ticker } from '@/shared/types/trading';\n\n/**\n * Whether an Ondo asset can be traded right now.\n *\n * The caps only mean anything while trading is open, so they live on the\n * `tradable` branch. They stay {@link DecimalString} rather than\n * {@link BlockchainAmount} because the response carries no `asset_decimals`:\n * there is no honest exponent to attach, and the USD caps arrive with more\n * fractional digits than a stablecoin has decimals.\n *\n * Each cap is independently nullable even when tradable — Ondo may open an\n * asset for trading without publishing every limit.\n *\n * `side` is carried through from the response rather than dropped: the whole\n * status describes one side, so a buy and a sell status are otherwise\n * indistinguishable once a caller holds both.\n */\nexport type OndoTradingStatus =\n | {\n type: 'tradable';\n side: OrderBookSide;\n /** Largest order in whole tokens. */\n grossMaxTokens: DecimalString | null;\n /** Largest order in USD. */\n grossMaxNotionalValue: DecimalString | null;\n /** USD cap for the session the market is currently in. */\n grossMaxActiveNotionalValue: DecimalString | null;\n }\n | {\n type: 'not-tradable';\n side: OrderBookSide;\n };\n\nexport const OndoTradingStatus = {\n fromDto: (dto: OndoTradingStatusDto): OndoTradingStatus => {\n if (!dto.tradable) return { type: 'not-tradable', side: dto.side };\n return {\n type: 'tradable',\n side: dto.side,\n grossMaxTokens: decimalOrNull(dto.gross_max_tokens),\n grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),\n grossMaxActiveNotionalValue: decimalOrNull(\n dto.gross_max_active_notional_value\n ),\n };\n },\n};\n\nconst decimalOrNull = (value: string | null): DecimalString | null =>\n value === null ? null : DecimalString(value);\n\n/**\n * An indicative price for an Ondo asset, free to poll while the user edits an\n * order.\n *\n * **No CoinList fee is applied to the quantity or the price.** Ondo prices\n * exactly the amount asked for. A CoinList approval is fee-inclusive, so\n * sizing a quote against one without netting the fee first overstates what the\n * user receives. Showing a gross/net breakdown needs a CoinList swap\n * contract's `preview`, and no such contract exists for Ondo yet.\n *\n * The quote carries no transaction to broadcast and no expiry. Building one is\n * a separate endpoint per side that spends an attestation - see\n * {@link OndoBuyTransaction} and {@link OndoSellTransaction}.\n */\nexport type OndoQuote = {\n /** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */\n chain: EthereumChain;\n ticker: Ticker;\n /**\n * Needed to approve or transfer the asset; the quote is the only source.\n *\n * **Resolved on Ethereum mainnet**, like everything else on this quote, and\n * therefore not necessarily the contract the swap pulls from on the chain\n * the order executes on. Frontline resolves that one per chain and publishes\n * it nowhere, so on a testnet these are two different tokens. Tracked\n * against the frontline stack that follows ENG-1756.\n */\n assetAddress: EvmContractAddress;\n /**\n * The asset as the quote resolves it, from frontline's own catalogue.\n *\n * Its `decimals` scale {@link tokenBaseUnits} and nothing else. They are\n * **not** the scale of a built transaction's spend or output: those are\n * reported by whatever priced them, the sources are allowed to disagree, and\n * only the one that produced a number answers for it.\n */\n asset: Erc20Asset;\n side: OrderBookSide;\n tokenBaseUnits: BlockchainAmount;\n /**\n * USD price of one whole token. Unscaled because Ondo has already scaled it,\n * and by USDon's 18 decimals rather than the stablecoin's 6 — re-scaling it\n * by either would be wrong.\n */\n price: DecimalString;\n};\n\nexport const OndoQuote = {\n fromDto: (dto: OndoQuoteDto): OndoQuote => {\n const assetDecimals = AssetDecimals(dto.asset_decimals);\n return {\n chain: chainFromId(dto.chain_id),\n ticker: Ticker(dto.ticker),\n assetAddress: EvmContractAddress(dto.asset_address),\n asset: {\n name: dto.ticker,\n symbol: AssetSymbol(dto.symbol),\n decimals: assetDecimals,\n },\n side: dto.side,\n tokenBaseUnits: blockchainAmountFromRawOrThrow({\n label: 'tokenBaseUnits',\n raw: dto.token_base_units,\n decimals: assetDecimals,\n }),\n price: DecimalString(dto.price),\n };\n },\n};\n\n/**\n * The half of a built swap that both sides share: the calldata, its deadline,\n * and what the wallet parts with.\n *\n * There is deliberately **no union over the two sides**. Each is built by its\n * own endpoint and its own namespace method, so a caller never holds one\n * without knowing which it is, and a union would only re-pose a question the\n * call site had already answered. What is genuinely common lives here, and\n * {@link executeOndoSwap} takes this rather than either arm - broadcasting\n * knows nothing about the direction of the trade.\n *\n * `side` is not on this type but on each arm, as a literal the SDK authors\n * from the method that was called. The wire stopped echoing one when the\n * endpoint split, and it is still worth carrying: `OndoOrderPlaced` is a union\n * the SDK builds from both, and that union needs a tag.\n */\nexport type OndoSwapTransactionCore = {\n /**\n * Broadcast as-is. The `to` is the swap contract, which is also the ERC-20\n * spender the user must have approved.\n */\n tx: Tx;\n /**\n * When the calldata stops being accepted. A transaction broadcast after this\n * reverts, so callers must compare against it before signing.\n */\n expiresAt: Date;\n /**\n * Gross amount the wallet spends, in the decimals of the token this side\n * spends: the funding token on a buy, the asset on a sell.\n *\n * The same field at two scales, which is the whole reason the two sides are\n * two types. It is also what the approval has to cover.\n */\n spendInputAmount: BlockchainAmount;\n};\n\n/**\n * A signed, expiring purchase: a funding token in, an exact quantity of the\n * asset out.\n *\n * Distinct from {@link OndoQuote} in three ways that matter: it costs an\n * attestation to obtain, it expires, and it carries a {@link Tx} the wallet\n * broadcasts verbatim. Treat it as single-use - once broadcast (or once\n * `expiresAt` passes) it is spent, and a new one must be built.\n *\n * **The quantity is attested and exact, with no floor beneath it.** That is\n * what separates it from an {@link OndoSellTransaction}, which commits to a\n * range: nothing here is an estimate.\n *\n * **It carries no other identity.** No chain, ticker or asset: the endpoint\n * publishes none of them, and inventing them from the request would assert\n * what the server resolved rather than report it. What it does publish is the\n * scale of every amount on it, so a caller needs nothing alongside it to read\n * the numbers - only to name the assets, which the offer already does.\n *\n * It carries no price either. See `computeOndoBuyPrice`, which derives it from\n * the amounts the response does carry - the price this transaction fills at,\n * rather than an indicative one that has since moved.\n */\nexport type OndoBuyTransaction = OndoSwapTransactionCore & {\n side: 'buy';\n /**\n * CoinList's cut, in `spendInputAmount`'s decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Taken at execution rather than added on top, so the approval never has to\n * cover more than `spendInputAmount`.\n */\n fee: BlockchainAmount;\n /**\n * `spendInputAmount` less `fee`, in the same decimals: what Ondo priced, and\n * the numerator of the fill price.\n *\n * Read from the response rather than subtracted here. Whether the fee comes\n * off the deposit or goes on top of it is the server's definition to change,\n * and a client that derives this cannot notice when it does.\n */\n notionalValue: BlockchainAmount;\n /**\n * Quantity of the asset the wallet receives, at the scale whatever priced it\n * reported - not at the {@link OndoQuote}'s `asset.decimals`.\n */\n receiveOutputAmount: BlockchainAmount;\n};\n\nexport const OndoBuyTransaction = {\n fromDto: (dto: OndoBuyDto): OndoBuyTransaction => {\n // Read once each, so a mapper that reached for the wrong exponent on one\n // of the amounts is a visible mistake rather than a plausible one.\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'buy',\n fee: blockchainAmountFromRawOrThrow({\n label: 'fee',\n raw: dto.fee,\n decimals: spendDecimals,\n }),\n notionalValue: blockchainAmountFromRawOrThrow({\n label: 'notional_value',\n raw: dto.notional_value,\n decimals: spendDecimals,\n }),\n receiveOutputAmount: parsePositiveAmount({\n label: 'receive_output_amount',\n raw: dto.receive_output_amount,\n decimals: outputDecimals,\n // A transaction that yields nothing is not one to sign - the user\n // would pay the deposit and receive no asset - and frontline refuses\n // to emit one. A zero here is a changed encoding, not a small order.\n // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`\n // divide by it without a fallible result: the failure surfaces as the\n // data hook's ERROR state rather than as a division during render.\n reason: 'a buy that yields nothing is not fillable',\n }),\n };\n },\n};\n\n/**\n * One end of the range a sale commits to: what arrives, and what CoinList took\n * to get it there.\n *\n * The two travel together because they are charged against each other -\n * `quantity` is already **net** of `fee` - and because the pair a caller wants\n * is always both halves of the same outcome. Grouping them is what makes\n * \"the expected quantity, less the fee at the floor\" unrepresentable rather\n * than merely wrong.\n */\nexport type OndoSellOutcome = {\n /** What the wallet receives at this outcome, net of {@link fee}. */\n quantity: BlockchainAmount;\n /**\n * CoinList's cut at this outcome, in the same decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Already deducted from {@link quantity} rather than charged on top of it.\n */\n fee: BlockchainAmount;\n};\n\n/**\n * A signed, expiring sale: the asset in, a settlement coin out, somewhere\n * between two published outcomes.\n *\n * Single-use and expiring for the same reasons as an {@link OndoBuyTransaction},\n * and obtained the same way - one endpoint, one attestation.\n *\n * **A sale commits to a range, not a quantity.** Ondo settles through USDon\n * before converting to the settlement token, so {@link expected} is what to\n * expect and {@link minimum} is what the calldata enforces. A screen that\n * shows only the first presents a firm-looking number the contract may\n * legitimately fill below.\n *\n * There is deliberately no counterpart to a buy's `notionalValue`. A sale\n * commits on the output side, so frontline reports no fee-exclusive input and\n * refuses to relate numbers Ninshubur did not relate. What it does relate is\n * each quantity to the fee beside it, which is why {@link OndoSellOutcome}\n * pairs them.\n *\n * One thing this type cannot see: the floor signed into `tx.data` is gross of\n * the fee, so a caller decoding the calldata finds a larger number than\n * `minimum.quantity`. Both are correct; `minimum.quantity` is what the wallet\n * actually receives.\n */\nexport type OndoSellTransaction = OndoSwapTransactionCore & {\n side: 'sell';\n /** What the sale is expected to return. An expectation, not a guarantee. */\n expected: OndoSellOutcome;\n /**\n * The floor the calldata enforces. A fill below it reverts on chain, so this\n * - not {@link expected} - is what a seller is actually guaranteed.\n */\n minimum: OndoSellOutcome;\n};\n\nexport const OndoSellTransaction = {\n fromDto: (dto: OndoSellDto): OndoSellTransaction => {\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n // One exponent for all four amounts below, unlike a buy where the fee\n // follows the spend. A sale takes its cut from the coin it settles in.\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n const expectedQuantity = parsePositiveAmount({\n label: 'expected_quantity',\n raw: dto.expected_quantity,\n decimals: outputDecimals,\n reason: 'a sale that yields nothing is not fillable',\n });\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'sell',\n expected: {\n quantity: expectedQuantity,\n fee: blockchainAmountFromRawOrThrow({\n label: 'expected_fee',\n raw: dto.expected_fee,\n decimals: outputDecimals,\n }),\n },\n minimum: {\n quantity: parseMinimumQuantity(\n dto.minimum_quantity,\n outputDecimals,\n expectedQuantity\n ),\n fee: blockchainAmountFromRawOrThrow({\n label: 'minimum_fee',\n raw: dto.minimum_fee,\n decimals: outputDecimals,\n }),\n },\n };\n },\n};\n\n/**\n * The three fields both responses carry, mapped once.\n *\n * `spendDecimals` is passed in rather than read here because a buy also\n * denominates its `fee` and `notionalValue` in it, so reading it twice would\n * leave two places to get wrong.\n */\nfunction parseSwapCore(\n dto: OndoSwapDtoCore,\n spendDecimals: AssetDecimals\n): OndoSwapTransactionCore {\n return {\n tx: {\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n },\n expiresAt: parseExpiresAt(dto.expires_at),\n spendInputAmount: parsePositiveAmount({\n label: 'spend_input_amount',\n raw: dto.spend_input_amount,\n decimals: spendDecimals,\n // A transaction that takes nothing from the wallet is not one to sign:\n // it would settle one leg of a trade and skip the other. Frontline\n // refuses an `amount` of zero whichever way the trade runs, so this is a\n // changed encoding rather than a small order.\n //\n // Guarded on both sides rather than on the sale alone, because which\n // amount becomes the divisor in the price flips with the direction: a\n // guard placed by that would be a rule about the arithmetic rather than\n // about the trade.\n reason: 'a swap that spends nothing is not fillable',\n }),\n };\n}\n\n/**\n * The floor under a sale's proceeds, refused when it cannot be one.\n *\n * A floor above the amount it is a floor on cannot be filled: the calldata\n * would revert on every outcome. Frontline validates both bounds\n * (`minimum <= expected`, and `> 0`), so either is a changed encoding rather\n * than a tight quote.\n *\n * Rejecting them at the boundary is what lets the review screen render the\n * pair without deciding what to do when they contradict each other - the\n * failure surfaces as the data hook's ERROR state instead.\n */\nfunction parseMinimumQuantity(\n raw: string,\n decimals: AssetDecimals,\n expectedQuantity: BlockchainAmount\n): BlockchainAmount {\n const amount = parsePositiveAmount({\n label: 'minimum_quantity',\n raw,\n decimals,\n reason: 'a floor of zero guarantees nothing',\n });\n if (amount.raw > expectedQuantity.raw) {\n throw new ValidationError(\n `minimum_quantity: must not exceed expected_quantity (\"${raw}\" > \"${expectedQuantity.raw}\")`\n );\n }\n return amount;\n}\n\n/**\n * An amount the trade cannot proceed without, refused at zero.\n *\n * `reason` says what the zero would have meant, so the message names the trade\n * rather than the field alone - the same field is a deposit on one side and a\n * quantity of shares on the other.\n */\nfunction parsePositiveAmount({\n label,\n raw,\n decimals,\n reason,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n reason: string;\n}): BlockchainAmount {\n const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });\n if (amount.raw <= 0n) {\n throw new ValidationError(\n `${label}: must be greater than zero (\"${raw}\") - ${reason}`\n );\n }\n return amount;\n}\n\n/**\n * A transaction whose expiry cannot be read is not safely fillable - the\n * deadline is encoded in the calldata either way, so broadcasting against an\n * unknown one only spends gas on a revert. Fail here instead.\n */\nfunction parseExpiresAt(value: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n throw new ValidationError(`expires_at: not a date (\"${value}\")`);\n }\n return date;\n}\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { formatRawAmount } from '@/shared/core/blockchain/formatters';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport type { BlockchainAmount } from '@/shared/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoTradingStatusDto,\n} from '@/shared/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { QueryParamValues } from '@/shared/types/http';\nimport {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/shared/types/providers/ondo/ondo';\n\nexport async function getOndoTradingStatus(\n api: Sender,\n params: GetOndoTradingStatusParams\n): Promise<OndoTradingStatus> {\n const dto = await api.send<OndoTradingStatusDto>({\n method: 'GET',\n url: '/v1/ondo/swap/trading-status',\n queryParams: { symbol: params.symbol, side: params.side },\n attributes: Attributes.protected(),\n });\n return OndoTradingStatus.fromDto(dto);\n}\n\nexport async function getOndoQuote(\n api: Sender,\n params: GetOndoQuoteParams\n): Promise<OndoQuote> {\n const dto = await api.send<OndoQuoteDto>({\n method: 'GET',\n url: '/v1/ondo/swap/quote',\n queryParams: {\n symbol: params.symbol,\n side: params.side,\n duration: params.duration,\n ...sizeParam(params),\n },\n attributes: Attributes.protected(),\n });\n return OndoQuote.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a purchase: spends an attestation and\n * returns signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the funding token**, unlike\n * `getOndoQuote`'s `token_amount` which is in whole tokens: this number\n * becomes the ERC-20 pull encoded into the calldata, so it is the on-chain\n * integer, not a human figure. Frontline refuses zero, and refuses a wallet\n * whose allowance on that token does not cover it with a 422 carrying\n * `code: \"insufficient_allowance\"`.\n *\n * The body carries no `side`. It used to, optional on the wire and defaulting\n * to `buy`, which is exactly the silent default the endpoint split removed:\n * the path is now what says which trade to sign and which token's allowance to\n * read, and a request cannot lose it.\n */\nexport async function buildOndoBuy(\n api: Sender,\n params: BuildOndoBuyParams\n): Promise<OndoBuyTransaction> {\n const dto = await api.send<OndoBuyDto>({\n method: 'POST',\n url: '/v1/ondo/swap/buy',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'purchase',\n });\n return OndoBuyTransaction.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a sale: spends an attestation and returns\n * signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the asset**, which is the one thing\n * that makes this materially different from {@link buildOndoBuy} rather than a\n * mirror of it. The same integer means something 1e12 different on the two\n * sides, so an order sized in the funding token's units and posted here is not\n * a rejected request but a wrong one.\n *\n * Frontline reads the allowance on the **asset** before asking Ninshubur for\n * anything - a sale delivers it, so the swap contract pulls it with\n * `transferFrom` - and refuses a short one with a 422 carrying\n * `code: \"insufficient_allowance\"` and a message naming that address.\n */\nexport async function buildOndoSell(\n api: Sender,\n params: BuildOndoSellParams\n): Promise<OndoSellTransaction> {\n const dto = await api.send<OndoSellDto>({\n method: 'POST',\n url: '/v1/ondo/swap/sell',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'sale',\n // The two answers come from two chains, so on a testnet they can disagree\n // for a reason that is neither the caller's nor a corrupt response. Say so,\n // or a QA run reads as a puzzle rather than a diagnosis.\n note:\n 'the quote resolves the asset on Ethereum mainnet while the swap ' +\n 'executes on the chain requested, so these disagree until frontline ' +\n 'serves a chain-scoped quote',\n });\n return OndoSellTransaction.fromDto(dto);\n}\n\n/**\n * The four fields both endpoints take, spelled the same way for both.\n *\n * `amount` is the only one whose meaning forks, and it forks in the *token*\n * rather than in the encoding - a uint256 decimal string either way.\n */\nfunction swapBody(\n params: BuildOndoBuyParams | BuildOndoSellParams\n): Record<string, string> {\n return {\n symbol: params.symbol,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount.raw.toString(),\n };\n}\n\n/**\n * Refuses a response denominated in a different scale than the request was.\n *\n * The two are independent resolutions of the same token: the caller sized\n * `amount` in the coin it chose and approved, while frontline reads\n * `decimals()` on-chain from the token the side spends, which it resolves from\n * the offer. On a purchase they should never differ - an approval on some\n * other token reads as a zero allowance, which frontline refuses before it\n * signs anything - so a disagreement is a changed encoding rather than a user\n * error, the same reasoning the mapper rejects a zero amount under.\n *\n * Worth the check because of where the value lands: `spend_input_amount` at\n * the wrong exponent renders the review screen's committed amount orders of\n * magnitude out, on the screen where the user commits money.\n */\nfunction assertSpendScaleAgrees({\n published,\n sized,\n trade,\n note,\n}: {\n published: number;\n sized: BlockchainAmount;\n trade: 'purchase' | 'sale';\n note?: string;\n}): void {\n if (published === sized.decimals) return;\n const because = note === undefined ? '' : ` - ${note}`;\n throw new ValidationError(\n `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`\n );\n}\n\n/**\n * `token_amount` is in **whole tokens**, unlike the response's\n * `token_base_units` — Ondo names both `tokenAmount`, 1e18 apart. Hence the\n * unscale on the way out.\n *\n * The size is checked at runtime because the types do not cover it: TypeScript\n * rejects an object carrying *neither*, but against a union of object types it\n * accepts one carrying *both*, and a JavaScript caller gets no check at all.\n */\nfunction sizeParam(\n params: GetOndoQuoteParams\n): Record<string, QueryParamValues> {\n const tokenAmount = 'tokenAmount' in params ? params.tokenAmount : undefined;\n const notionalValue =\n 'notionalValue' in params ? params.notionalValue : undefined;\n\n if (tokenAmount !== undefined) {\n if (notionalValue !== undefined) {\n throw new ValidationError(\n 'An Ondo quote takes tokenAmount or notionalValue, not both'\n );\n }\n return { token_amount: formatRawAmount(tokenAmount) };\n }\n if (notionalValue === undefined) {\n throw new ValidationError(\n 'An Ondo quote must be sized by tokenAmount or notionalValue'\n );\n }\n return { notional_value: notionalValue };\n}\n","import {\n buildOndoBuy,\n buildOndoSell,\n getOndoQuote,\n getOndoTradingStatus,\n} from '@/shared/api/frontline/providers/ondo/ondo';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/shared/core/checkout/ondo/ondo-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/shared/types/providers/ondo/ondo';\n\n/**\n * Ondo swap reads, plus the write that turns one into a fillable transaction.\n *\n * The two reads are free to poll - neither spends an attestation, so a client\n * may call them while the user edits an order. The two builders are not:\n * budget one call per order placed, plus one per refresh the user asks for.\n *\n * **One builder per side, mirroring the endpoints.** A purchase and a sale\n * agree on how to broadcast and on nothing else: a purchase commits to an\n * exact quantity, a sale to a range with a floor beneath it, and `amount` is\n * the funding token on one and the asset on the other. A single method taking\n * a `side` would have to return a union the caller then re-narrows, having\n * already decided which trade it was placing.\n *\n * **No CoinList fee is applied to a read quote, and no read discloses one.**\n * Ondo prices exactly the amount passed. A CoinList approval is fee-inclusive,\n * so sizing a quote against a user's approval without subtracting the fee\n * first overstates what they receive. A built transaction carries the fee\n * explicitly, and it is zero until one lands (ENG-1718).\n *\n * Every method requires `AuthState === 'logged-in'` and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface OndoNamespace {\n getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus>;\n getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;\n /**\n * Builds a purchase for a specific wallet and deposit: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoBuyTransaction.expiresAt}.\n *\n * The wallet must have approved the swap contract to spend `amount` of the\n * offer's **funding token** first. Frontline reads that allowance before\n * asking Ninshubur for anything, and rejects a short one with a 422 carrying\n * `code: \"insufficient_allowance\"`. See `prepareBuy` on the client\n * namespace, which approves and then builds, in that order.\n *\n * The tokens themselves are the offer's rather than the caller's to name.\n */\n buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;\n /**\n * Builds a sale for a specific wallet and quantity: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoSellTransaction.expiresAt}.\n *\n * The approval this one needs is on the **asset**, not on a stablecoin - a\n * sale delivers the asset, so the swap contract pulls it with `transferFrom`\n * exactly as it pulls the deposit on a purchase. Same 422 when it is short,\n * with a message naming that address. See `prepareSell` on the client\n * namespace.\n *\n * Returns a range rather than a quantity: Ondo settles through USDon before\n * converting to the settlement token, so disclose\n * {@link OndoSellTransaction.minimum} and not only `expected`.\n */\n buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction>;\n}\n\nexport class OndoNamespaceImpl implements OndoNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ONDO');\n }\n\n async getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus> {\n return this.log.wrap('getTradingStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoTradingStatus(this.ctx.api, params);\n });\n }\n\n async getQuote(params: GetOndoQuoteParams): Promise<OndoQuote> {\n return this.log.wrap('getQuote', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoQuote(this.ctx.api, params);\n });\n }\n\n async buildBuyTransaction(\n params: BuildOndoBuyParams\n ): Promise<OndoBuyTransaction> {\n return this.log.wrap('buildBuyTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoBuy(this.ctx.api, params);\n });\n }\n\n async buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction> {\n return this.log.wrap('buildSellTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoSell(this.ctx.api, params);\n });\n }\n}\n","export const SUPERSTATE_SWAP_ABI = [\n {\n type: 'function',\n name: 'authorized',\n inputs: [{ name: 'user', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'stopped',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'SWAP_LEVEL',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'preview',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Preview',\n components: [\n { name: 'input', type: 'uint256', internalType: 'uint256' },\n { name: 'fee', type: 'uint256', internalType: 'uint256' },\n { name: 'output', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'swap',\n inputs: [\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n { name: 'slip', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'tokenBalance',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputToken',\n inputs: [],\n outputs: [{ name: '', type: 'address', internalType: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputTokenBalance',\n inputs: [],\n outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [{ name: 'token', type: 'address', internalType: 'address' }],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n { name: 'inputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'feeSum', type: 'uint256', internalType: 'uint256' },\n { name: 'outputSum', type: 'uint256', internalType: 'uint256' },\n { name: 'count', type: 'uint256', internalType: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n { name: 'amount', type: 'uint256', internalType: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'setBps',\n inputs: [{ name: 'points', type: 'uint256', internalType: 'uint256' }],\n outputs: [{ name: '', type: 'bool', internalType: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'event',\n name: 'Swapped',\n inputs: [\n { name: 'user', type: 'address', indexed: true, internalType: 'address' },\n {\n name: 'inputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'outputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'inputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'outputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Transferred',\n inputs: [\n { name: 'to', type: 'address', indexed: true, internalType: 'address' },\n {\n name: 'token',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'error',\n name: 'InvalidAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InsufficientAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'SwapFailed',\n inputs: [\n { name: 'user', type: 'address', internalType: 'address' },\n { name: 'token', type: 'address', internalType: 'address' },\n ],\n },\n] as const;\n","import { applyBps, BPS_DENOM } from '@/shared/core/blockchain/bps';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport {\n assertUint256,\n BlockchainAmount,\n Bps,\n} from '@/shared/types/blockchain/core';\n\n/**\n * Price of 1 output token in USD, assuming the input token is a $1 stablecoin.\n *\n * `raw_price = inputTokenAmount.raw × 10^outputDecimals ÷ outputTokenAmount.raw`\n *\n * The multiplication happens before the division so we never lose precision to\n * integer truncation early. This mirrors standard fixed-point practice on-chain.\n * Returned decimals match the input token decimals (always the stablecoin's 6).\n */\nexport function computePrice({\n inputTokenAmount,\n outputTokenAmount,\n}: SwapQuote): BlockchainAmount | null {\n if (outputTokenAmount.raw === 0n) return null;\n\n const scale = 10n ** BigInt(outputTokenAmount.decimals);\n const raw = assertUint256(\n (inputTokenAmount.raw * scale) / outputTokenAmount.raw\n );\n\n return BlockchainAmount({ raw, decimals: inputTokenAmount.decimals });\n}\n\n/**\n * Applies slippage to an amount, returning the minimum acceptable amount:\n * `amount × (BPS_DENOM − slippage) / BPS_DENOM`. Throws when `slippage` exceeds\n * `BPS_DENOM` (the retained fraction would be negative).\n */\nexport function computeSlip(\n amount: BlockchainAmount,\n slippage: Bps\n): BlockchainAmount {\n const retained = Bps(assertUint256(BPS_DENOM - slippage));\n const slipRaw = applyBps(amount.raw, retained);\n return BlockchainAmount({ raw: slipRaw, decimals: amount.decimals });\n}\n","import {\n type AssetDecimals,\n BlockchainAmount,\n} from '@/shared/types/blockchain/core';\nimport type { SwapPreview } from '@/shared/types/providers/superstate/swap';\n\n/**\n * A read-only quote for a swap as domain amounts: how much goes in, the\n * protocol fee, and how much would come out. Derived from the raw\n * {@link SwapPreview} the swap contract returns.\n */\nexport type SwapQuote = {\n inputTokenAmount: BlockchainAmount;\n fee: BlockchainAmount;\n outputTokenAmount: BlockchainAmount;\n};\n\nexport const SwapQuote = {\n /**\n * Assembles a {@link SwapQuote} from a raw contract {@link SwapPreview}. The\n * input and fee are denominated in the input token; the output in the output\n * token.\n */\n fromPreview: (\n preview: SwapPreview,\n inputDecimals: AssetDecimals,\n outputDecimals: AssetDecimals\n ): SwapQuote => ({\n inputTokenAmount: BlockchainAmount({\n raw: preview.inputAmount,\n decimals: inputDecimals,\n }),\n fee: BlockchainAmount({ raw: preview.fee, decimals: inputDecimals }),\n outputTokenAmount: BlockchainAmount({\n raw: preview.outputAmount,\n decimals: outputDecimals,\n }),\n }),\n};\n","import type { SwapStatus } from '@/shared/types/providers/superstate/swap';\n\n/**\n * Interprets the on-chain swap availability read from `stopped()` and\n * `SWAP_LEVEL()`.\n *\n * The contract tracks paused operations as a bitmask in `stopped`. The swap is\n * stopped when the SWAP_LEVEL flag is set:\n *\n * (stopped & SWAP_LEVEL) != 0 -> stopped (not active)\n */\nexport function isStopped(status: SwapStatus): boolean {\n return (status.stopped & status.swapLevel) !== 0n;\n}\n","import { parseEventLogs, type TransactionReceipt } from 'viem';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/checkout/superstate/blockchain/abi';\nimport {\n type AssetDecimals,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/shared/types/blockchain/core';\n\n/**\n * Decodes the confirmed output amount from the `Swapped` event in a swap\n * transaction receipt.\n *\n * Returns `null` when the event is absent or the amount is not a valid uint256\n * so callers can fall back to the quote's expected output — the swap already\n * confirmed on-chain, so a missing/undecodable event should not fail the flow.\n */\nexport function decodeSwappedOutputAmount(\n receipt: TransactionReceipt,\n outputDecimals: AssetDecimals\n): BlockchainAmount | null {\n try {\n const [swapped] = parseEventLogs({\n abi: SUPERSTATE_SWAP_ABI,\n eventName: 'Swapped',\n logs: receipt.logs,\n });\n if (!swapped) return null;\n\n const raw = swapped.args.outputAmount;\n if (raw < 0n || raw > MAX_UINT_256) return null;\n return BlockchainAmount({ raw, decimals: outputDecimals });\n } catch {\n // Undecodable log (ABI mismatch / malformed) — fall back to the\n // quote. The swap already confirmed on-chain, so never fail here.\n return null;\n }\n}\n","import { USDC_SYMBOL } from '@/shared/core/blockchain/token-registry';\nimport {\n Bps,\n type EthereumChain,\n EvmContractAddress,\n type StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/types/collections';\n\n/**\n * Who issues the asset a Superstate swap pays out.\n *\n * A constant rather than a field off the offer: no frontline endpoint carries\n * an issuer, and every offer this checkout serves is Superstate's by\n * definition — `CheckoutContainer` routes here on `superstate::swap` alone.\n */\nexport const SUPERSTATE_ISSUER_NAME = 'Superstate';\n\n/**\n * The coins a Superstate swap can be funded with, in display order, with the\n * first preselected.\n *\n * USDC alone today: it is what the deployed swap contract accepts. The amount\n * step renders a single entry as a plain card and two or more as a picker, so\n * adding one here is all it takes.\n */\nexport const SUPERSTATE_SUPPORTED_INPUT_ASSETS: NonEmptyArray<StablecoinSymbol> =\n [USDC_SYMBOL];\n\n/** Poll interval for refreshing on-chain swap quotes and balances. */\nexport const SWAP_POLL_INTERVAL_MS = 15_000;\n\n/**\n * Notional input used to derive a display price-per-share when the user has\n * not yet entered an amount (1 USDC at 6 decimals).\n */\nexport const DEFAULT_AMOUNT_TO_COMPUTE_PRICE = 1_000_000n;\n\n/** Slippage tolerances offered in the review step, in basis points. */\nexport const SLIPPAGE_OPTIONS_BPS: Bps[] = [25n, 50n, 100n, 200n, 500n].map(\n (n) => Bps(n)\n);\n\n/** Default slippage tolerance (0.5%). */\nexport const DEFAULT_SLIPPAGE_BPS: Bps = Bps(50n);\n\n/**\n * The Superstate swap contract on Ethereum Sepolia, and therefore the ERC-20\n * spender the user approves there.\n *\n * Exported in its own right for a partner driving `coinlist.superstate.execute`\n * at Level 1, where the contract is an explicit parameter.\n */\nexport const SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA: EvmContractAddress =\n EvmContractAddress('0x84f8e9a6C9Cc12fe911259372EfCa5582C4ae557');\n\n/**\n * The Superstate swap contract per chain.\n *\n * Mainnet is absent, not zeroed: the production address is not finalized\n * upstream, and a zero address would be approved happily and revert only later.\n * A chain with no entry has no checkout — `useSuperstateSwapCheckoutViewModel`\n * reports it as the flow-level error rather than quoting against nothing.\n */\nconst SUPERSTATE_SWAP_CONTRACT_ADDRESSES: Partial<\n Record<EthereumChain, EvmContractAddress>\n> = {\n ethereum_sepolia: SUPERSTATE_SWAP_CONTRACT_ADDRESS_SEPOLIA,\n};\n\n/** The Superstate swap contract on `chain`, or `null` where none is deployed. */\nexport function superstateSwapContractAddress(\n chain: EthereumChain\n): EvmContractAddress | null {\n return SUPERSTATE_SWAP_CONTRACT_ADDRESSES[chain] ?? null;\n}\n","import {\n formattedUsdPrice,\n NA_AMOUNT_ASSET_UI,\n} from '@/shared/core/blockchain/formatters';\nimport { computePrice } from '@/shared/core/checkout/superstate/blockchain/math';\nimport type { SwapQuote } from '@/shared/core/checkout/superstate/blockchain/quote';\nimport type { FormattedAmountAssetUi } from '@/shared/types/blockchain/ui';\n\n/**\n * Formats a quote's implied price per output token as a USD amount.\n *\n * Lives with the provider rather than in `@/shared/core/blockchain/formatters`\n * because {@link SwapQuote} and {@link computePrice} are Superstate's: the\n * shared formatters stay provider-agnostic.\n */\nexport function formattedPricePerShare(\n quote: SwapQuote | null,\n locale: string\n): FormattedAmountAssetUi {\n if (!quote) return NA_AMOUNT_ASSET_UI;\n return formattedUsdPrice(computePrice(quote), locale);\n}\n","import {\n allowWallet,\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/shared/api/frontline/providers/superstate/swap';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/shared/core/checkout/superstate/swap-namespace.types';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Erc20Asset } from '@/shared/types/blockchain/core';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n} from '@/shared/types/providers/superstate/swap';\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, checking token allowances, and proving/allow-listing wallet\n * ownership.\n */\nexport interface SuperstateSwapNamespace {\n /**\n * Checks whether a wallet is authorized to swap against the given contract.\n */\n getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization>;\n\n /**\n * Fetches a read-only quote for swapping `amount` of `inputToken`.\n */\n getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;\n\n /**\n * Reads the current on-chain state of a swap contract.\n */\n getStatus(params: SwapContractRef): Promise<SwapStatus>;\n\n /**\n * Reads the ERC-20 output token a swap contract pays out.\n */\n getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;\n\n /**\n * Submits a signed wallet-ownership challenge to allow-list the wallet for\n * an offer, identified by its offer id. Obtain the challenge from\n * `WalletsNamespace.createOwnershipChallenge`.\n */\n allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;\n}\n\nexport class SuperstateSwapNamespaceImpl implements SuperstateSwapNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'SUPERSTATE');\n }\n\n async getAuthorization(\n params: GetSwapAuthorizationParams\n ): Promise<SwapAuthorization> {\n return this.log.wrap('getAuthorization', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapAuthorization(this.ctx.api, params);\n });\n }\n\n async getPreview(params: GetSwapPreviewParams): Promise<SwapPreview> {\n return this.log.wrap('getPreview', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapPreview(this.ctx.api, params);\n });\n }\n\n async getStatus(params: SwapContractRef): Promise<SwapStatus> {\n return this.log.wrap('getStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapStatus(this.ctx.api, params);\n });\n }\n\n async getOutputToken(params: SwapContractRef): Promise<Erc20Asset> {\n return this.log.wrap('getOutputToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getSwapOutputToken(this.ctx.api, params);\n });\n }\n\n async allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse> {\n return this.log.wrap('allowWallet', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return allowWallet(this.ctx.api, params);\n });\n }\n}\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport { fetchAllPages } from '@/shared/api/pagination';\nimport type { OfferDto } from '@/shared/types/dto/offer';\nimport type { OfferDetailDto } from '@/shared/types/dto/offer-detail';\nimport type { PaginatedResponseDto } from '@/shared/types/dto/pagination';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport { Offer, type OfferId } from '@/shared/types/offer';\nimport { OfferDetail } from '@/shared/types/offer-detail';\nimport { PaginatedResponse, PaginationParams } from '@/shared/types/pagination';\n\nexport async function fetchOffers(\n api: Sender,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Offer[]> {\n return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));\n}\n\nexport async function fetchOffersPage(\n api: Sender,\n params: PaginationParams,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<PaginatedResponse<Offer>> {\n const queryParams = PaginationParams.toQueryParams(params);\n const pageDto = await api.send<PaginatedResponseDto<OfferDto>>({\n method: 'GET',\n url: '/v1/offers',\n queryParams,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return PaginatedResponse.fromDto(pageDto, Offer.fromDto);\n}\n\nexport async function fetchOfferDetails(\n api: Sender,\n id: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<OfferDetail> {\n const dto = await api.send<OfferDetailDto>({\n method: 'GET',\n url: `/v1/offers/${id}`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return OfferDetail.fromDto(dto);\n}\n","import * as offersApi from '@/shared/api/frontline/offers';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/types/pagination';\n\n/**\n * Reads over CoinList's offers: the catalogue a user can browse, and the full\n * detail of a single offer.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise. On the server, the same reads are\n * additionally available with an app-level token — see\n * `ServerOffersNamespace`.\n */\nexport interface OffersNamespace {\n /**\n * Fetches every offer, iterating through all pages. Prefer {@link listPage}\n * when you render a paginated list yourself.\n */\n list(): Promise<Offer[]>;\n\n /**\n * Fetches a single page of offers. Pass the previous response's\n * `startingAfter` as `after` to advance.\n */\n listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n\n /**\n * Fetches the full detail of one offer, including its options. Note this\n * returns {@link OfferDetail} — a richer model than the {@link Offer}\n * summaries {@link list} returns.\n */\n get(id: OfferId): Promise<OfferDetail>;\n}\n\nexport class OffersNamespaceImpl implements OffersNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'OFFERS');\n }\n\n async list(): Promise<Offer[]> {\n return this.log.wrap('list', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOffers(this.ctx.api, undefined);\n });\n }\n\n async listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOffersPage(this.ctx.api, params, undefined);\n });\n }\n\n async get(id: OfferId): Promise<OfferDetail> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return offersApi.fetchOfferDetails(this.ctx.api, id, undefined);\n });\n }\n}\n","import type {\n DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/shared/types/dto/document-submission';\n\n/** Document types that can be signed via {@link CoinListClient.submitDocument}. */\nexport type DocumentType = 'tax_certification';\n\n/** Signing-state machine status for a document submission. */\nexport type DocumentSubmissionStatus = DocumentSubmissionStatusDto;\n\n/** The tax form derived from the entity's kind (individual vs company/trust). */\nexport type DocumentFormType = DocumentFormTypeDto;\n\n/** Result of starting (or resuming) a document signing submission. */\nexport type DocumentSubmission = {\n status: DocumentSubmissionStatus;\n formType: DocumentFormType;\n};\n\nexport const DocumentSubmission = {\n fromDto: (dto: DocumentSubmissionDto): DocumentSubmission => ({\n status: dto.status,\n formType: dto.form_type,\n }),\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/shared/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/shared/types/dto/document-submission';\n\n/**\n * Starts (or resumes) a document signing submission for the given type.\n *\n * `fields` are signing-form values keyed by the document's DocuSeal field\n * names (e.g. `\"Full Name\"`, `\"Permanent Address\"`) and are forwarded\n * verbatim to Passport to pre-fill the document. They are not validated or\n * persisted by Frontline.\n */\nexport async function submitDocument(\n api: Sender,\n documentType: DocumentType,\n fields: Record<string, string>\n): Promise<DocumentSubmission> {\n const dto = await api.send<DocumentSubmissionDto>({\n method: 'POST',\n url: `/v1/documents/${documentType}/submission`,\n body: fields,\n attributes: Attributes.protected(),\n });\n return DocumentSubmission.fromDto(dto);\n}\n","import type { KycTokenDto } from '@/shared/types/dto/kyc';\n\n/**\n * Sumsub verification level name. Determines which screens the Sumsub WebSDK\n * shows (levels are configured in the Sumsub dashboard). The backend\n * prescribes the level (and whether the applicant must be reset first) in the\n * requirement statuses response — clients never compute levels themselves.\n */\nexport type KycLevelName = string;\n\n/** Short-lived Sumsub WebSDK access token scoped to the current user. */\nexport type KycToken = {\n token: string;\n};\n\nexport const KycToken = {\n fromDto: (dto: KycTokenDto): KycToken => ({\n token: dto.token,\n }),\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { KycTokenDto } from '@/shared/types/dto/kyc';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport { KycToken } from '@/shared/types/kyc';\n\nexport async function createKycToken(\n api: Sender,\n levelName?: KycLevelName,\n reset?: boolean\n): Promise<KycToken> {\n const dto = await api.send<KycTokenDto>({\n method: 'POST',\n url: '/v1/kyc-token',\n body: {\n ...(levelName === undefined ? {} : { level_name: levelName }),\n ...(reset === undefined ? {} : { reset }),\n },\n attributes: Attributes.protected(),\n });\n return KycToken.fromDto(dto);\n}\n","import type {\n PiiAddressDto,\n PiiDto,\n PiiJurisdictionDto,\n PiiKindDto,\n} from '@/shared/types/dto/pii';\nimport type { Newtype } from '@/shared/types/newtype';\n\n/** Whether the PII belongs to an individual or a company/trust entity. */\nexport type PiiKind = PiiKindDto;\n\n/** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */\nexport type Iso2CountryCode = Newtype<string, 'Iso2CountryCode'>;\nexport const Iso2CountryCode = (value: string) => value as Iso2CountryCode;\n\n/** Jurisdiction derived from the entity's address country. */\nexport type PiiJurisdiction = {\n iso2: Iso2CountryCode;\n name: string | null;\n};\n\nexport const PiiJurisdiction = {\n fromDto: (dto: PiiJurisdictionDto): PiiJurisdiction => ({\n iso2: Iso2CountryCode(dto.iso_2),\n name: dto.name,\n }),\n};\n\n/** Permanent address on file for the entity. */\nexport type PiiAddress = {\n street: string | null;\n city: string | null;\n state: string | null;\n postalCode: string | null;\n country: string | null;\n};\n\nexport const PiiAddress = {\n fromDto: (dto: PiiAddressDto): PiiAddress => ({\n street: dto.street,\n city: dto.city,\n state: dto.state,\n postalCode: dto.postal_code,\n country: dto.country,\n }),\n};\n\n/**\n * The current user's PII, used to pre-fill tax forms such as the W-8BEN.\n * Fields the entity hasn't provided are `null`.\n */\nexport type Pii = {\n kind: PiiKind;\n fullLegalName: string | null;\n dateOfBirth: string | null;\n jurisdiction: PiiJurisdiction | null;\n taxId: string | null;\n permanentAddress: PiiAddress;\n};\n\nexport const Pii = {\n fromDto: (dto: PiiDto): Pii => ({\n kind: dto.kind,\n fullLegalName: dto.full_legal_name,\n dateOfBirth: dto.date_of_birth,\n jurisdiction: dto.jurisdiction\n ? PiiJurisdiction.fromDto(dto.jurisdiction)\n : null,\n taxId: dto.tax_id,\n permanentAddress: PiiAddress.fromDto(dto.permanent_address),\n }),\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { PiiDto } from '@/shared/types/dto/pii';\nimport { Pii } from '@/shared/types/pii';\n\nexport async function fetchPii(api: Sender): Promise<Pii> {\n const dto = await api.send<PiiDto>({\n method: 'GET',\n url: '/v1/pii',\n attributes: Attributes.protected(),\n });\n return Pii.fromDto(dto);\n}\n","import type {\n RequirementActionNeededReasonDto,\n RequirementDto,\n RequirementStatusesDto,\n RequirementStatusValueDto,\n RequirementTypeDto,\n} from '@/shared/types/dto/requirement';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type RequirementId = Newtype<string, 'RequirementId'>;\nexport const RequirementId = (value: string) => value as RequirementId;\n\nexport type RequirementType = RequirementTypeDto;\nexport type RequirementStatusValue = RequirementStatusValueDto;\nexport type RequirementActionNeededReason = RequirementActionNeededReasonDto;\n\nexport type Requirement = {\n id: RequirementId;\n type: RequirementType;\n details: Record<string, unknown> | null;\n};\n\nexport const Requirement = {\n fromDto: (dto: RequirementDto): Requirement => ({\n id: RequirementId(dto.id),\n type: dto.type,\n details: dto.details,\n }),\n};\n\nexport type RequirementStatusInfo = {\n id: RequirementId;\n status: RequirementStatusValue;\n /** Why the requirement needs action (KYC-backed requirements only). */\n action: RequirementActionNeededReason | null;\n /**\n * The Sumsub verification level that resolves this requirement, prescribed\n * by the backend. Present exactly when an inline Sumsub flow can be started.\n */\n kycLevel?: KycLevelName;\n /**\n * Whether the Sumsub applicant must be reset before starting the flow\n * (redoing an already-approved level, e.g. to update stale PII). Forward to\n * the kyc-token request as-is.\n */\n kycReset?: boolean;\n};\n\nexport const RequirementStatusInfo = {\n fromStatusesDto: (dto: RequirementStatusesDto): RequirementStatusInfo[] =>\n Object.entries(dto.statuses).map(([id, value]) =>\n typeof value === 'string'\n ? { id: RequirementId(id), status: value, action: null }\n : {\n id: RequirementId(id),\n status: value.status,\n action: value.action ?? null,\n kycLevel: value.kyc_level,\n kycReset: value.kyc_reset,\n }\n ),\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/shared/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/shared/types/oauth-session';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { Requirement, RequirementStatusInfo } from '@/shared/types/requirement';\n\nexport async function fetchOfferRequirements(\n api: Sender,\n offerId: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Record<OfferOptionId, Requirement[]>> {\n const response = await api.send<OfferRequirementsDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return Object.fromEntries(\n Object.entries(response.options).map(([optionId, list]) => [\n optionId,\n list.data.map(Requirement.fromDto),\n ])\n );\n}\n\nexport async function fetchRequirementStatuses(\n api: Sender,\n offerId: OfferId\n): Promise<RequirementStatusInfo[]> {\n const response = await api.send<RequirementStatusesDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements/statuses`,\n attributes: Attributes.protected(),\n });\n return RequirementStatusInfo.fromStatusesDto(response);\n}\n","import * as documentsApi from '@/shared/api/frontline/documents';\nimport * as kycApi from '@/shared/api/frontline/kyc';\nimport * as piiApi from '@/shared/api/frontline/pii';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/shared/types/document-submission';\nimport type { KycLevelName, KycToken } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { Pii } from '@/shared/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\n\nexport type CreateKycTokenParams = {\n /**\n * Sumsub verification level to run. Defaults to the backend's standard\n * level.\n */\n levelName?: KycLevelName;\n /**\n * Resets the Sumsub applicant first, so an already-approved level can be\n * executed again (e.g. to update stale PII). Pass the `kycReset` value from\n * the requirement status, and never on mid-flow token refreshes.\n */\n reset?: boolean;\n};\n\nexport type SubmitDocumentParams = {\n /** Currently only `tax_certification` (W-8BEN / W-8BEN-E). */\n documentType: DocumentType;\n /**\n * Signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to pre-fill the document.\n */\n fields: Record<string, string>;\n};\n\n/**\n * Everything a user must satisfy before they can participate in an offer:\n * reading the checklist and its live statuses, and the operations that satisfy\n * individual requirements — identity verification (KYC) and tax-document\n * signing.\n *\n * Wallet requirements (`external_wallet`, `whitelisted_wallet`) are satisfied\n * through `WalletsNamespace` instead, since wallet proofs are also used\n * outside the requirements flow.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface RequirementsNamespace {\n /**\n * Fetches the requirements for every option of an offer, grouped by option\n * id. This is the definition of the checklist; {@link statuses} tells you\n * where the user stands against it.\n */\n forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;\n\n /**\n * Fetches the current user's status for each requirement of an offer.\n */\n statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n\n /**\n * Creates a short-lived Sumsub WebSDK access token so an identity\n * verification (KYC) flow can be started, e.g. by the `IdentityVerification`\n * component.\n */\n createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;\n\n /**\n * Fetches the current user's PII, used to pre-fill tax forms such as the\n * W-8BEN. Fields the entity hasn't provided are `null`.\n */\n getPii(): Promise<Pii>;\n\n /**\n * Starts (or resumes) a document signing submission.\n */\n submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;\n}\n\nexport class RequirementsNamespaceImpl implements RequirementsNamespace {\n protected readonly log: InternalLogger;\n\n constructor(protected readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'REQUIREMENTS');\n }\n\n async forOffer(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchOfferRequirements(\n this.ctx.api,\n offerId,\n undefined\n );\n });\n }\n\n async statuses(offerId: OfferId): Promise<RequirementStatusInfo[]> {\n return this.log.wrap('statuses', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.ctx.api, offerId);\n });\n }\n\n async createKycToken(params?: CreateKycTokenParams): Promise<KycToken> {\n return this.log.wrap('createKycToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return kycApi.createKycToken(\n this.ctx.api,\n params?.levelName,\n params?.reset\n );\n });\n }\n\n async getPii(): Promise<Pii> {\n return this.log.wrap('getPii', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return piiApi.fetchPii(this.ctx.api);\n });\n }\n\n async submitDocument(\n params: SubmitDocumentParams\n ): Promise<DocumentSubmission> {\n return this.log.wrap('submitDocument', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return documentsApi.submitDocument(\n this.ctx.api,\n params.documentType,\n params.fields\n );\n });\n }\n}\n","import { getAddress } from 'viem';\nimport { HttpError, type HttpResponse } from '@/shared/api/http';\nimport { HttpClient } from '@/shared/api/http-client';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/shared/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/shared/types/dto/nabu-token';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Logger } from '@/shared/types/logger';\nimport { TokenMetadata } from '@/shared/types/token-metadata';\n\n/**\n * An {@link HttpClient} against the token registry rather than frontline: no\n * `X-API-Version` (the registry doesn't know it, and the extra header would\n * force a CORS preflight the static CDN cannot answer) and no session\n * middleware (the registry is public).\n */\nexport function createNabuApiClient(\n baseUrl: string,\n logger: Logger | null = null\n): HttpClient {\n return new HttpClient({ baseUrl }, {}, logger);\n}\n\n/**\n * Fetches one token's display metadata from the registry.\n *\n * Returns `null` when the registry does not list the token: the registry is\n * curated, so \"not listed\" is a domain answer, not a failure. The deployment\n * signals it as either a 404 or — Cloudflare Pages' fallback for unknown\n * routes — a 2xx serving its HTML inspection page, so both map to `null`.\n * Everything else throws: a non-2xx status is an {@link HttpError} carrying\n * the registry's response, including a 5xx whose body is an HTML error page.\n */\nexport async function fetchTokenMetadata(\n client: HttpClient,\n token: TokenIdentifier\n): Promise<TokenMetadata | null> {\n // The registry's canonical route uses the EIP-55 checksummed address:\n // lowercase costs a redirect round-trip and wrong mixed casing 404s.\n const address = checksummed(token.address);\n let response: HttpResponse<NabuTokenDto>;\n try {\n response = await client.send<NabuTokenDto>({\n method: 'GET',\n url: `/${token.chain}/token/${address}`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n return null;\n }\n throw error;\n }\n\n if (response.status === 404) {\n return null;\n }\n assertOk(response);\n if (response.body === null) {\n // Not a \"not listed\" signal — those are the 404 and the HTML fallback. A\n // 2xx with a zero-length body is a broken deploy or a mangling\n // intermediary, and mapping it to null would hide a listed token.\n throw new ValidationError(\n `Token registry returned an empty body for token \"${address}\" on \"${token.chain}\"`\n );\n }\n return TokenMetadata.fromDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches all available tokens the registry lists for `chain`, in a single\n * request against the chain snapshot — fetching N tokens one by one would\n * cost N round-trips for a catalogue that arrives whole anyway.\n *\n * Unlike {@link fetchTokenMetadata}, a missing snapshot throws rather than\n * mapping to an empty answer: the registry publishes a snapshot for every\n * chain it knows, so its absence is a deployment problem — and an invented\n * `[]` would render as \"no metadata\" without anyone noticing.\n */\nexport async function fetchTokensMetadata(\n client: HttpClient,\n chain: EthereumChain\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuChainAssetsDto>;\n try {\n response = await client.send<NabuChainAssetsDto>({\n method: 'GET',\n url: `/${chain}/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n `Token registry returned non-JSON for the \"${chain}\" snapshot`\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n `Token registry returned an empty \"${chain}\" snapshot`\n );\n }\n return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches every token the registry lists, across all chains, in a single\n * request against the complete snapshot — the cheapest way to resolve a\n * multi-chain catalogue: one download regardless of how many assets or\n * chains it spans.\n *\n * Chains outside the SDK's type surface (e.g. Solana) are skipped rather\n * than failing the whole snapshot. As with the per-chain snapshot, a missing\n * or empty response throws: the registry always publishes `/assets.json`, so\n * its absence is a deployment problem, not an empty catalogue.\n */\nexport async function fetchAllTokensMetadata(\n client: HttpClient\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuRegistryDto>;\n try {\n response = await client.send<NabuRegistryDto>({\n method: 'GET',\n url: `/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n 'Token registry returned non-JSON for the complete snapshot'\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n 'Token registry returned an empty complete snapshot'\n );\n }\n return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);\n}\n\n/**\n * The registry's deployment answers routes that have no static file with its\n * HTML inspection page and a 2xx status. `makeRequest` surfaces any non-JSON\n * body as an {@link HttpError} carrying the status, so \"2xx but not JSON\" is\n * precisely the registry's \"no such file\" signal — while a non-2xx with an\n * HTML body (a CDN 502/503 page, a proxy block page) keeps its status and\n * stays an outage for the caller to see, never a domain answer.\n */\nfunction isRegistryHtmlFallback(error: unknown): boolean {\n return (\n error instanceof HttpError &&\n error.response.status >= 200 &&\n error.response.status < 300\n );\n}\n\nfunction assertOk(response: HttpResponse<unknown>): void {\n if (response.status < 200 || response.status >= 300) {\n // The full response, never a stripped one: HttpError is public API and\n // callers classify failures off `response.body` (e.g. a 429 vs a 502).\n throw new HttpError(response);\n }\n}\n\nfunction checksummed(address: string): string {\n try {\n return getAddress(address);\n } catch (_) {\n throw new ValidationError(`Invalid EVM contract address: \"${address}\"`);\n }\n}\n","export const PUBLIC_API_BASE_URL = 'https://api.coinlist.co';\nexport const HEADER_API_VERSION = 'X-API-Version';\nexport const HEADER_USER_AGENT = 'User-Agent';\nexport const HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';\nexport const API_VERSION = '2025-10-17';\n\nexport const COINLIST_BASE_URL = 'https://coinlist.co';\nexport const OAUTH_PAGE_PATH = '/oauth/authorize';\n\nexport const SUPPORT_NEW_TICKET_URL =\n 'https://support.coinlist.co/support/tickets/new';\n\nexport const VERIFY_IDENTITY_PATH = '/verify-identity';\nexport const VERIFY_IDENTITY_ACCREDITATION_PATH =\n '/verify-identity/accreditation_full';\nexport const WALLET_PATH = '/wallet';\n","import { HEADER_API_VERSION } from '@/shared/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/shared/api/http';\nimport { buildUrlWithQueryParams, makeRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n Logger,\n RequestId,\n UnredactedFields,\n} from '@/shared/types/logger';\n\nexport type BeforeRequestMiddleware = (\n request: HttpRequest\n) => Promise<HttpRequest>;\n\nexport type AfterRequestMiddleware = (args: {\n request: HttpRequest;\n response: HttpResponse<unknown>;\n retry: (request?: HttpRequest) => Promise<HttpResponse<unknown>>;\n}) => Promise<HttpResponse<unknown>>;\n\nexport type HttpClientMiddleware = {\n beforeRequest?: BeforeRequestMiddleware[];\n afterRequest?: AfterRequestMiddleware[];\n};\n\nexport type HttpClientOptions = {\n /**\n * Mints the id that correlates one request's log lines. Injected so specs\n * can assert on log output, the same reason\n * {@link createRequestRetryMiddleware} takes a `delayFn`; defaults to a\n * short random string.\n */\n makeRequestId?: () => RequestId;\n};\n\n/**\n * Logging lives here rather than in a middleware pair so that every client\n * built on `HttpClient` reports by construction - the frontline client, the\n * token registry client, and whatever comes next. A middleware would have to\n * be remembered per client, and could not time a request or see one that threw\n * before producing a response.\n */\nexport class HttpClient {\n private readonly log: InternalLogger;\n private readonly makeRequestId: () => RequestId;\n\n constructor(\n readonly config: HttpClientConfig,\n readonly middleware: HttpClientMiddleware = {},\n logger: Logger | null = null,\n options: HttpClientOptions = {}\n ) {\n this.log = internalLogger(logger, 'HTTP');\n this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;\n }\n\n async send<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n return this.runRequestWithAfterMiddleware<TResponse>(request);\n }\n\n /**\n * Runs beforeRequest, executeRequest, then the full afterRequest middleware\n * chain. Used by send() and by the retry() callback so that when a\n * middleware calls retry(), the retried response also goes through all\n * afterRequest middleware (e.g. session renewal, retry). Middleware\n * must use request.attributes.retryAttempt (or similar) to avoid infinite\n * recursion when they trigger retries.\n */\n private async runRequestWithAfterMiddleware<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const preparedRequest = await this.runBeforeRequestMiddleware(\n this.withClientDefaults(request)\n );\n let response = await this.executeRequest<TResponse>(preparedRequest);\n\n for (const middleware of this.middleware.afterRequest ?? []) {\n response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) =>\n this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >,\n })) as HttpResponse<TResponse>;\n }\n\n return response;\n }\n\n private withClientDefaults(request: HttpRequest): HttpRequest {\n const url = this.resolveUrl(request.url);\n const headers = {\n ...(request.headers ?? {}),\n ...(this.config.xApiVersion !== undefined\n ? { [HEADER_API_VERSION]: this.config.xApiVersion }\n : {}),\n };\n\n return {\n ...request,\n url,\n headers,\n // Only when absent: a retry or a post-renewal re-send arrives with the\n // first attempt's id already on it, and keeping it is the whole point.\n attributes:\n Attributes.getRequestId(request.attributes) === null\n ? Attributes.concat(\n request.attributes ?? Attributes.empty,\n Attributes.requestId(this.makeRequestId())\n )\n : request.attributes,\n };\n }\n\n /**\n * Resolves a request URL against the client's baseUrl.\n *\n * @internal Public only for testing. Do not use in application code; use\n * {@link HttpClient.send} with a path and the client will resolve the URL.\n */\n resolveUrl(url: string): string {\n // If already absolute, use as-is.\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n // Otherwise append path to baseUrl so base path (e.g. /api) is preserved.\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const path = url.startsWith('/') ? url : `/${url}`;\n return base + path;\n }\n\n private async runBeforeRequestMiddleware(\n initialRequest: HttpRequest\n ): Promise<HttpRequest> {\n let request = initialRequest;\n for (const middleware of this.middleware.beforeRequest ?? []) {\n request = await middleware(request);\n }\n\n return request;\n }\n\n /**\n * One physical attempt, logged as one line.\n *\n * A non-2xx is a `warn` rather than an `error` because the wire does not\n * know whether it is a failure: the retry middleware may turn a 503 into a\n * success, and the token registry reads a 404 as \"not listed\". The namespace\n * above decides, and logs the `error` when it does.\n */\n private async executeRequest<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const requestId = Attributes.getRequestId(request.attributes);\n const log = requestId === null ? this.log : this.log.child({ requestId });\n const attempt = Attributes.getRetryAttempt(request.attributes) + 1;\n const startedAt = Date.now();\n\n log.debug(() => ({\n msg: 'request sent',\n fields: describeRequestUnredacted(request),\n }));\n\n try {\n const response = await makeRequest<TResponse>(request);\n const elapsed = Date.now() - startedAt;\n const outcome = () => ({\n msg: 'request completed',\n fields: {\n ...identifyRequest(request),\n 'http.response.status_code': response.status,\n duration_ms: elapsed,\n attempt,\n },\n });\n\n if (response.status >= 200 && response.status < 300) {\n log.info(outcome);\n } else {\n log.warn(outcome);\n }\n log.debug(() => ({\n msg: 'response received',\n fields: { body: response.body },\n }));\n\n return requestId === null ? response : { ...response, requestId };\n } catch (error) {\n const elapsed = Date.now() - startedAt;\n // `warning`, not two hand-written lines: it renders the error verbatim\n // at `'debug'` and classified at `'warn'`, which is the pairing this\n // used to spell out by hand.\n log.warning(\n () => ({\n msg: 'request threw',\n fields: {\n ...identifyRequest(request),\n duration_ms: elapsed,\n attempt,\n },\n }),\n error\n );\n throw error;\n }\n }\n}\n\n/**\n * How a request is named on every line above `'debug'`.\n *\n * `server.address` and `url.path` rather than OpenTelemetry's `url.full`, and\n * that is a deliberate deviation from the convention the rest of these keys\n * follow. `url.full` is defined to carry the query string, and frontline reads\n * take `chain`, `wallet_address` and `amount` as query parameters - so the\n * standard key would put host data on the levels this SDK keeps redacted.\n * The full URL appears at `'debug'` and nowhere else.\n *\n * `HttpRequest.url` carries no query to begin with - {@link makeRequest}\n * appends it on the way to `fetch` - so the split is about naming rather than\n * about stripping anything.\n */\nfunction identifyRequest(request: HttpRequest): {\n 'http.request.method': string;\n 'server.address': string | null;\n 'url.path': string;\n} {\n const { host, path } = splitUrl(request.url);\n return {\n 'http.request.method': request.method,\n 'server.address': host,\n 'url.path': path,\n };\n}\n\n/**\n * The host and the path of an absolute URL, separately, because OpenTelemetry\n * names them separately and because only the path is worth grouping on.\n *\n * Never throws: it runs inside an event lambda, and the {@link Logger}\n * contract says nothing the SDK hands over may turn a log line into a second\n * failure. A URL `URL` refuses is reported as it stands, which is safe either\n * way - `HttpRequest.url` never carries a query string.\n */\nfunction splitUrl(url: string): { host: string | null; path: string } {\n try {\n const parsed = new URL(url);\n return { host: parsed.host, path: parsed.pathname };\n } catch (_) {\n return { host: null, path: url };\n }\n}\n\n/**\n * Eight base36 characters. Short enough to read at the head of every line and\n * wide enough that two concurrent requests in one session will not collide.\n * Deliberately not a counter: a module-level counter would be global mutable\n * state shared by every client in the process.\n */\nfunction defaultMakeRequestId(): RequestId {\n return Math.random().toString(36).slice(2, 10).padEnd(8, '0') as RequestId;\n}\n\n/**\n * The request as sent - full URL, headers and body verbatim. `debug` is\n * documented as unredacted: it exists to reproduce a bug, and a redacted\n * `Authorization` is exactly what you need when the bug is that the wrong\n * token went out.\n *\n * The query string appears here and nowhere else, under `url.full`. Every\n * other line names the request through {@link identifyRequest}, whose\n * `url.path` has none - which is why those lines are safe above `debug`.\n * Rendering the sent URL here is what makes a `wallet_address`, a `chain` or\n * an `amount` reproducible at all.\n *\n * The values are handed over as they stand rather than stringified: a\n * {@link DebugEvent} accepts anything, and the logger implementation is what\n * guarantees a `bigint` or a cycle cannot fail to render.\n */\nfunction describeRequestUnredacted(request: HttpRequest): UnredactedFields {\n return {\n 'http.request.method': request.method,\n 'url.full': buildUrlWithQueryParams(request.url, request.queryParams),\n headers: request.headers,\n ...(request.method === 'POST' ? { body: request.body } : {}),\n };\n}\n\n/**\n * Structural interface satisfied by both {@link AuthenticatedApiClient} and\n * {@link ApiClient}. Used by the shared frontline API functions so they can\n * be called from either the client or server without any browser dependencies.\n */\nexport interface Sender {\n send<T>(request: HttpRequest): Promise<T>;\n}\n","import {\n AssetDecimals,\n AssetSymbol,\n EthereumChain,\n EvmContractAddress,\n type TokenIdentifier,\n} from '@/shared/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuLogoDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/shared/types/dto/nabu-token';\nimport { ValidationError } from '@/shared/types/errors';\nimport type { Newtype } from '@/shared/types/newtype';\n\n/**\n * An absolute URL to a logo image in the token registry. Registry image URLs\n * are content-fingerprinted and served immutable, so a value is safe to cache\n * for as long as you hold it.\n */\nexport type TokenLogoUrl = Newtype<string, 'TokenLogoUrl'>;\nexport const TokenLogoUrl = (value: string): TokenLogoUrl =>\n value as TokenLogoUrl;\n\nexport type TokenLogoImage = {\n url: TokenLogoUrl;\n width: number;\n height: number;\n};\n\n/**\n * `VECTOR` is a single SVG. `RASTER` has webp variants at 32/64/128/256/512px\n * widths (never wider than the original): use the smallest one that covers\n * your render size, or `original` if none does.\n */\nexport type TokenLogo =\n | { kind: 'VECTOR'; url: TokenLogoUrl }\n | { kind: 'RASTER'; original: TokenLogoImage; variants: TokenLogoImage[] };\n\nexport const TokenLogo = {\n /** `baseUrl` is the registry origin; registry URLs are root-relative. */\n fromDto: (dto: NabuLogoDto, baseUrl: string): TokenLogo =>\n dto.kind === 'VECTOR'\n ? { kind: 'VECTOR', url: resolveLogoUrl(dto.url, baseUrl) }\n : {\n kind: 'RASTER',\n original: logoImageFromDto(dto.original, baseUrl),\n variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl)),\n },\n};\n\n/**\n * Display metadata for one token, from CoinList's public token registry.\n *\n * Keyed by `(chain, address)` — never by symbol, which can collide. The\n * registry is curated: a token missing from it is an expected answer, not an\n * error, so lookups return `null` rather than throwing.\n */\nexport type TokenMetadata = {\n identifier: TokenIdentifier;\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n logo: TokenLogo;\n /** Dark-theme logo; `null` when the registry configures none. */\n logoDark: TokenLogo | null;\n};\n\nexport const TokenMetadata = {\n /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */\n fromDto: (dto: NabuTokenDto, baseUrl: string): TokenMetadata => {\n assertSupportedSchemaVersion(dto.schema_version);\n return {\n identifier: {\n chain: EthereumChain(dto.chain),\n address: EvmContractAddress(dto.address),\n },\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n logo: TokenLogo.fromDto(dto.logo, baseUrl),\n logoDark:\n dto.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(dto.logo_dark, baseUrl),\n };\n },\n\n /**\n * Maps the complete registry snapshot to every token it lists across the\n * chains this SDK models, skipping native coins and chains outside\n * {@link EthereumChain} (e.g. Solana) rather than failing on them — the\n * registry may serve chains ahead of the SDK's type surface.\n */\n fromRegistryDto: (dto: NabuRegistryDto, baseUrl: string): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return dto.chains.flatMap((chainDto) => {\n let chain: EthereumChain;\n try {\n chain = EthereumChain(chainDto.chain);\n } catch {\n return [];\n }\n return tokensOfChain(chain, chainDto.assets, baseUrl);\n });\n },\n\n /**\n * Maps a chain snapshot to the tokens it lists, skipping the chain's native\n * coin (`kind: 'COIN'`, no contract address).\n */\n fromChainAssetsDto: (\n dto: NabuChainAssetsDto,\n baseUrl: string\n ): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);\n },\n};\n\n/** The token rows of one chain's asset list, skipping the native coin. */\nfunction tokensOfChain(\n chain: EthereumChain,\n assets: NabuChainAssetsDto['assets'],\n baseUrl: string\n): TokenMetadata[] {\n return assets\n .filter((asset) => asset.kind === 'TOKEN' && asset.address !== undefined)\n .map((asset) => ({\n identifier: {\n chain,\n // The filter above cannot narrow `address` for the type checker.\n address: EvmContractAddress(asset.address as string),\n },\n name: asset.name,\n symbol: AssetSymbol(asset.symbol),\n decimals: AssetDecimals(asset.decimals),\n logo: TokenLogo.fromDto(asset.logo, baseUrl),\n logoDark:\n asset.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(asset.logo_dark, baseUrl),\n }));\n}\n\n/**\n * The registry bumps schema_version only on breaking changes, so mapping a\n * newer schema with this code would produce silent garbage — fail instead.\n */\nfunction assertSupportedSchemaVersion(version: number): void {\n if (version !== 1) {\n throw new ValidationError(\n `Unsupported token registry schema_version: ${version}`\n );\n }\n}\n\nconst logoImageFromDto = (\n dto: { url: string; width: number; height: number },\n baseUrl: string\n): TokenLogoImage => ({\n url: resolveLogoUrl(dto.url, baseUrl),\n width: dto.width,\n height: dto.height,\n});\n\nconst resolveLogoUrl = (url: string, baseUrl: string): TokenLogoUrl =>\n TokenLogoUrl(\n url.startsWith('http') ? url : `${baseUrl.replace(/\\/$/, '')}${url}`\n );\n","import type { HttpClient } from '@/shared/api/http-client';\nimport {\n createNabuApiClient,\n fetchAllTokensMetadata,\n fetchTokenMetadata,\n fetchTokensMetadata,\n} from '@/shared/api/nabu/tokens';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/shared/types/blockchain/core';\nimport type { Logger } from '@/shared/types/logger';\nimport type { TokenMetadata } from '@/shared/types/token-metadata';\n\n/**\n * Token display metadata — name, symbol, decimals, and logos — from\n * CoinList's public token registry, keyed by {@link TokenIdentifier} (the\n * same chain + address pairs `Offer.tokens` carries).\n *\n * Unlike the other namespaces, this one is public: no method requires an\n * authenticated user, and nothing here touches the CoinList API — reads go to\n * the registry's CDN.\n */\nexport interface TokensNamespace {\n /**\n * Fetches metadata for one token. Returns `null` when the registry does not\n * list the token — the registry is curated, so callers must fall back to\n * their own display defaults rather than treat this as an error.\n */\n get(token: TokenIdentifier): Promise<TokenMetadata | null>;\n\n /**\n * Fetches every token the registry lists, in one request: the complete\n * snapshot with no `chain`, or one chain's snapshot with it. Prefer this\n * over calling {@link get} in a loop when displaying a catalogue — two\n * hundred tokens across three chains is still a single download.\n *\n * The complete snapshot spans every chain the registry knows; tokens on\n * chains this SDK does not model (e.g. Solana) are left out of the result.\n *\n * Unlike {@link get}, a missing snapshot throws rather than returning `[]`:\n * the registry always publishes the complete snapshot and one per chain it\n * knows, so an absence is a deployment problem, not an empty catalogue.\n */\n list(chain?: EthereumChain): Promise<TokenMetadata[]>;\n}\n\nexport class TokensNamespaceImpl implements TokensNamespace {\n private readonly api: HttpClient;\n private readonly log: InternalLogger;\n\n /**\n * Takes the registry origin rather than a `SharedNamespaceContext`: the\n * registry is unauthenticated and on its own host, so the frontline sender\n * and the auth check would both be dead weight here.\n */\n constructor(baseUrl: string, logger: Logger | null = null) {\n this.api = createNabuApiClient(baseUrl, logger);\n this.log = internalLogger(logger, 'TOKENS');\n }\n\n get(token: TokenIdentifier): Promise<TokenMetadata | null> {\n return this.log.wrap('get', token, () =>\n fetchTokenMetadata(this.api, token)\n );\n }\n\n list(chain?: EthereumChain): Promise<TokenMetadata[]> {\n return this.log.wrap('list', chain, () =>\n chain === undefined\n ? fetchAllTokensMetadata(this.api)\n : fetchTokensMetadata(this.api, chain)\n );\n }\n}\n","import type { Hex } from 'viem';\nimport {\n type EthereumChain,\n EvmWalletAddress,\n type WalletProtocol,\n} from '@/shared/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/shared/types/dto/offer-option-address';\nimport type { Newtype } from '@/shared/types/newtype';\nimport type { OfferId } from '@/shared/types/offer';\nimport { OfferOptionId } from '@/shared/types/offer-detail';\n\n/** Unique identifier for a proven wallet binding on an offer option. */\nexport type OfferOptionAddressId = Newtype<string, 'OfferOptionAddressId'>;\n/** Casts a string into a typed {@link OfferOptionAddressId}. */\nexport const OfferOptionAddressId = (value: string) =>\n value as OfferOptionAddressId;\n\n/**\n * A user's external wallet, proven via a wallet-ownership challenge and bound\n * to an offer option. Returned by the `/v1/offers/:offer_id/addresses` resource.\n */\nexport type OfferOptionAddress = {\n /** Unique binding id. */\n id: OfferOptionAddressId;\n /** Offer option the wallet is bound to. */\n offerOptionId: OfferOptionId;\n /** The connected external wallet address. */\n address: EvmWalletAddress;\n /**\n * Protocol the binding is scoped to. An EVM address binds once per option\n * regardless of which EVM chain proved ownership.\n */\n protocol: WalletProtocol;\n /** When the binding was created. */\n createdAt: Date;\n};\n\n/** Parameters required to connect a proven external wallet to an offer option. */\nexport type ConnectExternalWalletParams = {\n /** Offer the option belongs to. */\n offerId: OfferId;\n /** Offer option to bind the wallet to. */\n offerOptionId: OfferOptionId;\n /** External wallet address that was proven. */\n walletAddress: EvmWalletAddress;\n /** Chain the ownership was proven on. */\n chain: EthereumChain;\n /** Signature of the wallet-ownership challenge message. */\n signature: Hex;\n};\n\nexport const OfferOptionAddress = {\n /** Maps the API DTO into the SDK offer-option-address domain model. */\n fromDto: (dto: OfferOptionAddressDto): OfferOptionAddress => ({\n id: OfferOptionAddressId(dto.id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n address: EvmWalletAddress(dto.address),\n protocol: dto.protocol,\n createdAt: new Date(dto.created_at),\n }),\n};\n\nexport const ConnectExternalWalletParams = {\n /** Maps connect-wallet params into the API DTO payload. */\n toDto: (\n params: ConnectExternalWalletParams\n ): CreateOfferOptionAddressDto => ({\n offer_option_id: params.offerOptionId,\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n }),\n};\n","import type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/shared/types/dto/wallet-ownership-challenge';\n\n/**\n * A single-use ownership challenge returned by `POST /v1/wallet-ownership`.\n * The consumer signs {@link message} with their wallet, then submits the\n * signature to connect the wallet to an offer option.\n */\nexport type WalletOwnershipChallenge = {\n /** The message the wallet must sign. */\n message: string;\n /** When the challenge expires and can no longer be consumed. */\n expiresAt: Date;\n};\n\n/** Fields common to every wallet-ownership challenge request. */\ntype WalletOwnershipChallengeParamsBase = {\n /** Wallet address to prove ownership of. */\n walletAddress: EvmWalletAddress;\n /** Chain the wallet belongs to. */\n chain: EthereumChain;\n};\n\n/**\n * Parameters for requesting a wallet-ownership challenge. Modeled as a\n * discriminated union on `challengeType` so a `siwe` challenge must carry\n * `domain`/`uri`/`statement`, matching the backend contract at compile time.\n */\nexport type CreateWalletOwnershipChallengeParams =\n | (WalletOwnershipChallengeParamsBase & {\n /** A bare message the wallet signs. */\n challengeType: 'plain';\n })\n | (WalletOwnershipChallengeParamsBase & {\n /** Marks this as a Sign-In With Ethereum challenge. */\n challengeType: 'siwe';\n /** The requesting site's hostname (e.g. `example.com`). */\n domain: string;\n /** The requesting site's URI. */\n uri: string;\n /** Human-readable statement shown in the signing prompt. */\n statement: string;\n });\n\n/**\n * How the ownership challenge is framed: a plain message or a Sign-In With\n * Ethereum challenge. Extracted as its own type so SDK consumers can pass it as\n * a standalone param without reaching into the {@link CreateWalletOwnershipChallengeParams}\n * union.\n */\nexport type WalletChallengeType =\n CreateWalletOwnershipChallengeParams['challengeType'];\n\nexport const WalletOwnershipChallenge = {\n /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */\n fromDto: (dto: WalletOwnershipChallengeDto): WalletOwnershipChallenge => ({\n message: dto.message,\n expiresAt: new Date(dto.expires_at),\n }),\n};\n\nexport const CreateWalletOwnershipChallengeParams = {\n /**\n * Maps challenge-request params into the API DTO payload. The discriminated\n * union guarantees SIWE fields are present exactly when `challengeType` is\n * `siwe`, so the mapping narrows on the discriminant.\n */\n toDto: (\n params: CreateWalletOwnershipChallengeParams\n ): CreateWalletOwnershipChallengeDto => {\n switch (params.challengeType) {\n case 'plain':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'plain',\n };\n case 'siwe':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'siwe',\n domain: params.domain,\n uri: params.uri,\n statement: params.statement,\n };\n default: {\n const _exhaustive: never = params;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/shared/api/http-attributes';\nimport type { Sender } from '@/shared/api/http-client';\nimport type { OfferOptionAddressDto } from '@/shared/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/shared/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/shared/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\n/**\n * Creates a single-use wallet-ownership challenge. The consumer signs the\n * returned message with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 when params are invalid — an unparseable\n * address, or SIWE fields (`domain`/`uri`/`statement`) that are missing on a\n * `siwe` challenge or present on a `plain` one. The `ApiErrorDto` body\n * carries the validation detail.\n */\nexport async function createWalletOwnershipChallenge(\n api: Sender,\n params: CreateWalletOwnershipChallengeParams\n): Promise<WalletOwnershipChallenge> {\n const dto = await api.send<WalletOwnershipChallengeDto>({\n method: 'POST',\n url: '/v1/wallet-ownership',\n body: CreateWalletOwnershipChallengeParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return WalletOwnershipChallenge.fromDto(dto);\n}\n\n/**\n * Connects a proven external wallet to an offer option. Requires a signature\n * of a previously created, unconsumed wallet-ownership challenge for the same\n * wallet and chain.\n *\n * Single-slot (`external_wallet`) options replace the existing binding in place\n * on re-submit — the binding `id` is stable across a \"change wallet\" — so\n * `max_wallets_reached` only fires for `whitelisted_wallet` options at their cap.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 for every binding failure; discriminate via the\n * `ApiErrorDto` body. Failures with a machine-readable `code`:\n * `wallet_not_whitelisted`, `max_wallets_reached`. Every other binding failure\n * (protocol mismatch, concurrent-connect lock, etc.) is rendered as an opaque\n * generic 422 with no `code`, by backend design. Challenge-state failures\n * surface by message only: no unconsumed challenge, wallet/chain not matching\n * the challenge, expired, or already used. Expired and already-used are not\n * retry-safe — request a fresh challenge first.\n */\nexport async function connectExternalWallet(\n api: Sender,\n params: ConnectExternalWalletParams\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'POST',\n url: `/v1/offers/${params.offerId}/addresses`,\n body: ConnectExternalWalletParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n\n/**\n * Lists the user's proven wallet bindings for a single offer option. Single-slot\n * (`external_wallet`) options return at most one binding; `whitelisted_wallet`\n * options return up to the requirement's `max_wallets`. Works after the offer\n * ends, so partners can read the final bindings.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n */\nexport async function listOptionAddresses(\n api: Sender,\n offerId: OfferId,\n offerOptionId: OfferOptionId\n): Promise<OfferOptionAddress[]> {\n const { data } = await api.send<ListResponseDto<OfferOptionAddressDto>>({\n method: 'GET',\n url: `/v1/offers/${offerId}/addresses`,\n queryParams: { offer_option_id: offerOptionId },\n attributes: Attributes.protected(),\n });\n return data.map(OfferOptionAddress.fromDto);\n}\n\n/**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 with `code` `offer_ended` once the offer has\n * ended (bindings on an offer that has not yet started stay removable), or a\n * 404 when the binding does not exist or is not the caller's.\n */\nexport async function removeOptionAddress(\n api: Sender,\n offerId: OfferId,\n addressId: OfferOptionAddressId\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'DELETE',\n url: `/v1/offers/${offerId}/addresses/${addressId}`,\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n","import * as walletConnectApi from '@/shared/api/frontline/wallet-connect';\nimport type { SharedNamespaceContext } from '@/shared/core/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/shared/core/observability/internal-logger';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\nexport type ListOptionAddressesParams = {\n offerId: OfferId;\n /** Offer option whose bindings to list. */\n offerOptionId: OfferOptionId;\n};\n\nexport type RemoveOptionAddressParams = {\n offerId: OfferId;\n /** Binding to remove, as returned by {@link WalletsNamespace.list}. */\n addressId: OfferOptionAddressId;\n};\n\n/**\n * The user's external wallets: proving ownership of one, binding it to an\n * offer option, and managing those bindings.\n *\n * Ownership proof is a provider-agnostic primitive — the swap flow uses the\n * same challenge to allow-list a wallet — so it lives here rather than being\n * duplicated per product namespace.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface WalletsNamespace {\n /**\n * Creates a single-use challenge the user signs to prove they control a\n * wallet. Supports both `plain` and `siwe` challenges. Pass the signature of\n * the returned {@link WalletOwnershipChallenge.message} to\n * {@link connectExternal}.\n */\n createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n\n /**\n * Binds a proven external wallet to an offer option, using a signature of a\n * challenge from {@link createOwnershipChallenge}.\n */\n connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n\n /**\n * Lists the user's proven wallet bindings for one offer option — the single\n * bound address for an `external_wallet` option, or every allow-listed\n * wallet for a `whitelisted_wallet` option.\n */\n list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;\n\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n */\n remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;\n}\n\nexport class WalletsNamespaceImpl implements WalletsNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: SharedNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'WALLETS');\n }\n\n async createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n return this.log.wrap('createOwnershipChallenge', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(\n this.ctx.api,\n params\n );\n });\n }\n\n async connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n return this.log.wrap('connectExternal', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.connectExternalWallet(this.ctx.api, params);\n });\n }\n\n async list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]> {\n return this.log.wrap('list', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.ctx.api,\n params.offerId,\n params.offerOptionId\n );\n });\n }\n\n async remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress> {\n return this.log.wrap('remove', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.removeOptionAddress(\n this.ctx.api,\n params.offerId,\n params.addressId\n );\n });\n }\n}\n","import type { Hash } from 'viem';\n\n/**\n * A classified wallet or transaction failure. The SDK derives this from\n * whatever the {@link EvmWallet} throws, so hosts get a stable, typed error\n * shape regardless of the wallet library underneath.\n *\n * Lives here rather than beside its classifier because it is the failure half\n * of the {@link EvmWallet} contract, and because both `@/shared` and\n * `@/client` name it: {@link LogCause} carries one, and classifying a thrown\n * error into one needs viem's error classes, which are browser-side.\n */\nexport type WalletError =\n | { type: 'user_rejected' }\n | { type: 'insufficient_funds' }\n | {\n type: 'contract_reverted';\n /**\n * What the contract said, when it said anything: a `require` string, a\n * panic description, a custom error's name, or the four-byte selector of\n * an error the ABI could not decode.\n *\n * `null` when a revert carried no data, since the string the RPC node\n * offers in its place is not the contract's - see `classifyWalletError`.\n * Nullable rather than optional so that every arm has to answer the\n * question: \"it reverted and said nothing\" is a fact about the revert,\n * and a caller should have to read it rather than miss it.\n *\n * Never the custom error's arguments. A name is a compile-time\n * identifier; its operands are runtime values - an address, a balance -\n * and those are `'debug'` material.\n */\n reason: string | null;\n }\n | { type: 'timeout'; hash: Hash }\n | { type: 'unknown'; cause: unknown };\n\n/**\n * A {@link WalletError} as it may be reported above `'debug'`: the\n * classification, never the throw.\n *\n * Only the `unknown` arm differs, and it differs because it is the one arm\n * carrying a value the SDK did not author - the raw error the wallet library\n * threw, whose message and metadata hold the transaction's `from`, `to`,\n * `value` and calldata. The other four carry compile-time constants or a\n * server-minted identifier already, so they pass through as they stand.\n *\n * This exists as a type rather than as a scrub some function remembers to\n * apply: `LogCause` names it, so an arm that grew a raw field would fail the\n * build instead of quietly reaching {@link Logger.error}.\n */\nexport type RedactedWalletError =\n | Exclude<WalletError, { type: 'unknown' }>\n | { type: 'unknown' };\n\nexport const RedactedWalletError = {\n fromWalletError: (error: WalletError): RedactedWalletError =>\n error.type === 'unknown' ? { type: 'unknown' } : error,\n};\n","import type { OAuthSessionDto } from '@/shared/types/dto/oauth-session';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type ClientCredentialsOAuth = Newtype<\n OAuthAccessToken,\n 'ClientCredentialsOAuth'\n>;\nexport const ClientCredentialsOAuth = (value: OAuthAccessToken) =>\n value as ClientCredentialsOAuth;\n\nexport type OAuthAccessToken = {\n value: string;\n expiresAt: Date;\n};\n\nexport type OAuthRefreshToken = Newtype<string, 'OAuthRefreshToken'>;\nexport const OAuthRefreshToken = (value: string) => value as OAuthRefreshToken;\n\nexport type OAuthSession = {\n accessToken: OAuthAccessToken;\n refreshToken?: OAuthRefreshToken;\n};\n\nexport const OAuthSession = {\n fromDto: (dto: OAuthSessionDto): OAuthSession => {\n const expiresAt = new Date(Date.now() + dto.expires_in * 1000);\n return {\n accessToken: {\n value: dto.access_token,\n expiresAt,\n },\n ...(dto.refresh_token != null && dto.refresh_token !== ''\n ? { refreshToken: OAuthRefreshToken(dto.refresh_token) }\n : undefined),\n };\n },\n};\n","import type { UserDto } from '@/shared/types/dto/user';\nimport type { Newtype } from '@/shared/types/newtype';\n\nexport type UserId = Newtype<string, 'UserId'>;\nexport const UserId = (value: string) => value as UserId;\nexport type UserEmail = Newtype<string, 'UserEmail'>;\nexport const UserEmail = (value: string) => value as UserEmail;\n\nexport type User = {\n id: UserId;\n email: UserEmail;\n};\n\nexport const User = {\n fromDto: (dto: UserDto): User => ({\n id: UserId(dto.id),\n email: UserEmail(dto.email),\n }),\n};\n"],"mappings":"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","names":["import_viem","import_viem","import_viem","requestId"]}