@coinlist-co/react 0.12.0 → 0.12.1-rc.0fa5c3b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ZFBEI3BW.js → chunk-3EOK47CQ.js} +20 -330
- package/dist/chunk-3EOK47CQ.js.map +1 -0
- package/dist/{chunk-F6WGUKZC.js → chunk-I5EHOV7V.js} +129 -3
- package/dist/chunk-I5EHOV7V.js.map +1 -0
- package/dist/{chunk-6CQHDASY.js → chunk-VSYGGTI6.js} +1173 -156
- package/dist/chunk-VSYGGTI6.js.map +1 -0
- package/dist/client/index.cjs +8559 -7690
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +116 -48
- package/dist/client/index.d.ts +116 -48
- package/dist/client/index.js +4059 -4007
- package/dist/client/index.js.map +1 -1
- package/dist/{collections-DOm9VKVm.d.cts → collections-C6b-rJpx.d.ts} +1 -1
- package/dist/{collections-aCv-Wr2a.d.ts → collections-UYVlXbEh.d.cts} +1 -1
- package/dist/server/index.cjs +1291 -166
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +5 -3
- package/dist/server/index.js.map +1 -1
- package/dist/{config-DIaFzrMW.d.cts → tokens-namespace-C-BxcYMj.d.cts} +362 -188
- package/dist/{config-DIaFzrMW.d.ts → tokens-namespace-C-BxcYMj.d.ts} +362 -188
- package/dist/universal/index.cjs +1103 -405
- package/dist/universal/index.cjs.map +1 -1
- package/dist/universal/index.d.cts +427 -45
- package/dist/universal/index.d.ts +427 -45
- package/dist/universal/index.js +16 -14
- package/package.json +1 -1
- package/dist/chunk-6CQHDASY.js.map +0 -1
- package/dist/chunk-F6WGUKZC.js.map +0 -1
- package/dist/chunk-ZFBEI3BW.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts","../../src/universal/api/http-attributes.ts","../../src/universal/api/http.ts","../../src/universal/api/frontline/config.ts","../../src/universal/types/errors.ts","../../src/universal/core/shared/observability/log-cause.ts","../../src/universal/core/shared/observability/internal-logger.ts","../../src/universal/api/http-client.ts","../../src/universal/api/middleware/attach-session-middleware.ts","../../src/universal/core/shared/utils/crypto.ts","../../src/universal/api/middleware/idempotency-key.ts","../../src/universal/api/middleware/request-retry.ts","../../src/universal/api/middleware/session-renewal.ts","../../src/universal/api/authenticated-api-client.ts","../../src/server/core/api/api-client.ts","../../src/server/shared/errors.ts","../../src/universal/types/oauth-session.ts","../../src/server/core/server-auth-namespace.ts","../../src/universal/api/pagination.ts","../../src/universal/types/blockchain/core.ts","../../src/universal/types/offer.ts","../../src/universal/types/asset.ts","../../src/universal/types/offer-detail.ts","../../src/universal/types/pagination.ts","../../src/universal/api/frontline/offers.ts","../../src/server/core/server-offers-namespace.ts","../../src/universal/types/requirement.ts","../../src/universal/api/frontline/requirements.ts","../../src/universal/types/document-submission.ts","../../src/universal/api/frontline/documents.ts","../../src/universal/types/kyc.ts","../../src/universal/api/frontline/kyc.ts","../../src/universal/types/pii.ts","../../src/universal/api/frontline/pii.ts","../../src/universal/core/requirements/requirements-namespace.ts","../../src/server/core/server-requirements-namespace.ts","../../src/universal/api/nabu/config.ts","../../src/universal/types/providers/coin-list/token-sale.ts","../../src/universal/api/frontline/providers/coin-list/token-sale.ts","../../src/universal/core/checkout/coin-list/token-sale-namespace.ts","../../src/universal/core/shared/blockchain/formatters.ts","../../src/universal/types/blockchain/ui.ts","../../src/universal/core/shared/blockchain/chain.ts","../../src/universal/core/shared/blockchain/math.ts","../../src/universal/types/trading.ts","../../src/universal/types/providers/ondo/ondo.ts","../../src/universal/api/frontline/providers/ondo/ondo.ts","../../src/universal/core/checkout/ondo/ondo-namespace.ts","../../src/universal/types/providers/superstate/swap.ts","../../src/universal/api/frontline/providers/superstate/swap.ts","../../src/universal/core/checkout/superstate/swap-namespace.ts","../../src/universal/core/shared/blockchain/erc20/erc20-namespace.ts","../../src/universal/api/nabu/tokens.ts","../../src/universal/types/token-metadata.ts","../../src/universal/core/tokens/tokens-namespace.ts","../../src/universal/types/offer-option-address.ts","../../src/universal/types/wallet-ownership-challenge.ts","../../src/universal/api/frontline/wallet-connect.ts","../../src/universal/core/wallets/wallets-namespace.ts","../../src/server/core/coinlist-server.ts","../../src/server/core/observability/pino-server-logger.ts","../../src/universal/core/shared/observability/pino-logger.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. */\nexport * from '@/server/core/coinlist-server';\nexport * from '@/server/core/observability/pino-server-logger';\nexport * from '@/server/core/server-auth-namespace';\nexport * from '@/server/core/server-namespace-context';\nexport * from '@/server/core/server-offers-namespace';\nexport * from '@/server/core/server-requirements-namespace';\nexport * from '@/server/shared/errors';\n","import type { RequestId } from '@/universal/types/logger';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\n\nexport type HttpRequestAttributes = {\n /**\n * Correlates the log lines of one logical request. Minted by\n * {@link HttpClient} on the first attempt and carried onto every retry and\n * post-renewal re-send by {@link concat}, which is what lets a reader tell\n * three attempts of one request from three separate requests.\n */\n requestId?: RequestId;\n protected?: boolean;\n userAgent?: boolean;\n idempotencyKey?: boolean;\n /** Zero-based attempt index: 0 = first request, 1 = first retry, etc. */\n retryAttempt?: number;\n renewAttempted?: boolean;\n 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 '@/universal/api/http-attributes';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport type { RequestId } from '@/universal/types/logger';\n\nexport type HttpClientConfig = {\n baseUrl: string;\n /**\n * The frontline `X-API-Version` header. Omit for clients against other\n * backends (e.g. the token registry): a version header they don't know\n * would also force a CORS preflight the CDN cannot answer.\n */\n xApiVersion?: string;\n};\n\nexport type HttpRequest<TBody = unknown> =\n | {\n method: 'GET';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'POST';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n body: TBody;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'DELETE';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n };\nexport type HttpResponse<TBody = unknown> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody | null;\n /**\n * The id of the request that produced this response, stamped by\n * {@link HttpClient} so that whoever turns a non-2xx into an\n * {@link HttpError} can carry it without threading the request alongside.\n * Absent when the response did not come from an `HttpClient`.\n */\n requestId?: RequestId;\n};\n\nexport class HttpError<TBody = unknown> extends Error {\n readonly response: HttpResponse<TBody>;\n\n constructor(response: HttpResponse<TBody>) {\n super(`Request failed with ${response.status} status`);\n this.name = 'HttpError';\n this.response = response;\n }\n\n /**\n * Correlates this failure with the `[HTTP]` log lines for the same request,\n * which carry the method, the URL, the duration and every retry. `null` when\n * the response did not come from an {@link HttpClient}.\n *\n * Worth quoting in a bug report: it is what makes a log excerpt readable.\n */\n get requestId(): RequestId | null {\n return this.response.requestId ?? null;\n }\n}\n\n/**\n * The machine-readable `code` frontline attaches to an error, or `null` for\n * anything else - a non-HTTP failure, or an error body that carries only a\n * message.\n *\n * Frontline answers a failure with `{ type, message, code?, errors?,\n * event_id? }`, and `code` is the only part of it meant to be branched on:\n * `message` is prose that may be reworded, and `type` distinguishes\n * `invalid_request_error` from `api_error` without saying which one.\n *\n * Reach for this only where a code has a distinct remedy the user can act on.\n * Mapping the whole vocabulary would couple the SDK to strings frontline does\n * not version; falling back to a generic failure is the right default.\n */\nexport function apiErrorCode(error: unknown): string | null {\n if (!(error instanceof HttpError)) return null;\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const code: unknown = (body as { code?: unknown }).code;\n return typeof code === 'string' ? code : null;\n}\n\nexport async function makeRequest<TResponse = unknown>(\n request: HttpRequest\n): Promise<HttpResponse<TResponse>> {\n const headers: Record<string, string> = {\n Accept: 'application/json',\n ...(request.method === 'POST' && request.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(request.headers ?? {}),\n };\n\n const init: RequestInit = {\n method: request.method,\n headers,\n ...(request.redirect !== undefined ? { redirect: request.redirect } : {}),\n };\n\n if (request.method === 'POST' && request.body !== undefined) {\n init.body = JSON.stringify(request.body);\n }\n\n const response = await fetch(\n buildUrlWithQueryParams(request.url, request.queryParams),\n init\n );\n const responseHeaders = headersToRecord(response.headers);\n\n if (response.status === 204 || response.status === 205) {\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n await response.text();\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n const text = await response.text();\n let body: TResponse | null;\n try {\n body = text ? (JSON.parse(text) as TResponse) : null;\n } catch (_) {\n // A non-JSON body (an HTML error page from a CDN, proxy, or load\n // balancer) would otherwise surface as a bare SyntaxError with the status\n // lost. Throw the full response instead, so callers can classify the\n // failure by status and still see what the server actually sent.\n throw new HttpError({\n status: response.status,\n headers: responseHeaders,\n body: text,\n });\n }\n\n return {\n status: response.status,\n body,\n headers: responseHeaders,\n };\n}\n\n/**\n * The URL as `fetch` will see it, query string included.\n *\n * Exported for {@link HttpClient}'s `debug` request line, which renders the\n * request exactly as sent. Every other log line carries {@link HttpRequest.url}\n * alone - the query holds wallet addresses, chains and amounts, and `debug` is\n * the only level allowed to see them.\n */\nexport function buildUrlWithQueryParams(\n url: string,\n queryParams?: Record<string, QueryParamValues>\n): string {\n if (!queryParams) {\n return url;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) {\n continue;\n }\n searchParams.append(key, String(item));\n }\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const queryString = searchParams.toString();\n if (!queryString) {\n return url;\n }\n\n return url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`;\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key.toLowerCase()] = value;\n });\n return record;\n}\n\nfunction concatAttributes(\n request: HttpRequest,\n attrs: Attributes\n): HttpRequest {\n const nextAttributes = Attributes.concat(\n request.attributes ?? Attributes.empty,\n attrs\n );\n const nextRequest: typeof request = {\n ...request,\n attributes: nextAttributes,\n };\n return nextRequest;\n}\n\nexport const Request = {\n concatAttributes,\n};\n","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","/**\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 { apiErrorCode, HttpError } from '@/universal/api/http';\nimport {\n InvariantError,\n MathError,\n NotAuthenticatedError,\n NotImplementedError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type { FrontlineEventId, LogCause } from '@/universal/types/logger';\n\n/**\n * Classifies anything thrown inside the SDK into a {@link LogCause}.\n *\n * The SDK's **only** structured classification of a thrown error. It reaches\n * `warn` as well as `error`, since a recoverable failure is no less worth\n * naming than a fatal one.\n *\n * An `instanceof` chain rather than a pattern match, for the same reason\n * `classifyWalletError` is one: these are classes, not an ADT, so there is no\n * tag to match on. The chain is ordered most specific first and ends in\n * `generic-error`, which is total - a host-supplied lambda may throw anything\n * at all, a string included.\n *\n * Everything it returns is safe above `'debug'`, and the chain itself is the\n * opt-in list: only the five SDK-authored error classes named below reach an\n * arm carrying a `message`, because only those messages were written by the\n * SDK. Everything else contributes its class name and nothing more, since its\n * message and its fields are host-authored. {@link describeErrorUnredacted} is\n * where those go. A new error type has to be added here deliberately, which is\n * the moment to ask whether its message is SDK-authored all the way down;\n * defaulting to \"safe\" is how the leak ADR-8 replaced happened.\n *\n * Lives at Level 1 rather than beside {@link LogCause} because classifying an\n * {@link HttpError} means importing `@/universal/api`, which `@/universal/types` may\n * not do (`data.yaml#domain-models-dont-reach-the-api-layer`).\n */\nexport function classifyLogCause(error: unknown): LogCause {\n if (error instanceof HttpError) {\n return httpCause(error);\n }\n if (error instanceof ValidationError) {\n return { type: 'validation', message: error.message };\n }\n if (error instanceof InvariantError) {\n return { type: 'invariant', message: error.message };\n }\n if (error instanceof MathError) {\n return { type: 'math', message: error.message };\n }\n if (error instanceof NotAuthenticatedError) {\n return { type: 'not-authenticated' };\n }\n if (error instanceof NotImplementedError) {\n return { type: 'not-implemented' };\n }\n 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 '@/universal/core/shared/observability/log-cause';\nimport type {\n DebugEvent,\n LogBinding,\n LogBindings,\n LogCause,\n Logger,\n LogLevel,\n LogScope,\n SafeEvent,\n SafeFields,\n UnredactedFields,\n} from '@/universal/types/logger';\n\n/**\n * Wraps the host's {@link Logger}, or its absence, into the thing SDK code\n * actually calls.\n *\n * Three jobs, the first two of which exist so that no call site anywhere in\n * the SDK ever branches on whether logging is on:\n *\n * 1. **Absence is normalised away.** No logger yields {@link noopInternalLogger},\n * whose methods do nothing and whose `wrap` still runs the wrapped work.\n * 2. **The level is checked here, once per call.** Below the level, the\n * event lambda is never invoked and no {@link LogCause} is built. That is\n * the whole reason events are lambdas: expensive debug detail costs nothing\n * in production.\n * 3. **The safety boundary is enforced here.** `'debug'` is the unredacted\n * level; `info`, `warn` and `error` carry only what the SDK authored and\n * what the server minted. {@link InternalLogger.failure} and\n * {@link InternalLogger.warning} render an error twice - verbatim onto a\n * `debug` line, classified onto theirs - rather than once, so that a host\n * running at `'debug'` may still forward `error` to a tracker unchanged.\n *\n * The scope and the accumulated {@link LogBindings} are stamped here, so a\n * call site names only what happened. That is also why call sites hand over an\n * {@link InternalSafeEvent} rather than a finished {@link SafeEvent}: nothing\n * should have to know its own scope twice.\n *\n * ```ts\n * const log = internalLogger(ctx.logger, 'ONDO');\n * log.child({ flow: 'review' }).failure(\n * () => ({ msg: 'quote refresh failed' }),\n * error\n * );\n * // { scope: 'ONDO', flow: 'review', cause: { type: 'http', status: 410, ... },\n * // msg: 'quote refresh failed' }\n * ```\n */\nexport function internalLogger(\n logger: Logger | null | undefined,\n scope: LogScope\n): InternalLogger {\n return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;\n}\n\n/**\n * The logging surface SDK code uses. Never exported to hosts: they implement\n * {@link Logger}, which is deliberately smaller.\n */\nexport type InternalLogger = {\n /**\n * A logger narrowed by one more {@link LogBinding}, which every line it\n * emits carries as its own field.\n */\n child(binding: LogBinding): InternalLogger;\n\n /**\n * The unredacted level. Request and response bodies, full URLs, headers,\n * operation params and raw thrown errors belong here and **only** here.\n */\n debug(event: () => InternalDebugEvent): void;\n\n info(event: () => InternalSafeEvent): void;\n warn(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a failure whose cause is already known, or has none. Prefer\n * {@link failure}, which classifies a thrown error for you.\n */\n error(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a thrown error, classifying it into a {@link LogCause}. Prefer\n * this over `error` at a `catch`: classification only happens when the level\n * admits it.\n *\n * The `error` line names the error's class but never its message, since an\n * error the SDK did not author may say anything at all. The verbatim\n * rendering goes onto a paired `debug` line instead.\n *\n * For a failure the SDK recovers from, use {@link warning} instead. An\n * `error` line a host cannot act on is worse than no line at all: it trains\n * them to ignore the ones that matter.\n */\n failure(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * {@link failure} for trouble that did not break anything: a poll tick that\n * failed while the last value still stands, a retried request.\n *\n * Carries the classified {@link LogCause} exactly as `failure` does. The two\n * differ in level and in nothing else, because what separates them is\n * whether anything actually broke - not how much is known about it.\n */\n warning(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * Runs one namespace operation with logging around it: the call and its\n * params at `debug`, and any throw at `error` with the cause classified.\n * Every line carries `op` as a binding.\n *\n * **The params never reach the `error` line.** They routinely hold the\n * things this SDK must not put in front of a production error tracker - an\n * app bearer token, a document's signing fields, a wallet signature - and\n * the `debug` line plus the request id is how you get them back. The type\n * says so: `params` is `unknown`, which is not a {@link SafeFields} value.\n *\n * Always rethrows. Logging observes behaviour, it never changes it.\n */\n wrap<T>(op: string, params: unknown, run: () => Promise<T>): Promise<T>;\n};\n\n/**\n * What a call site hands to `info`, `warn`, `error`, `failure` or `warning` -\n * a {@link SafeEvent} minus the scope and bindings the logger stamps itself.\n */\nexport type InternalSafeEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: SafeFields;\n readonly cause?: LogCause;\n};\n\n/** What a call site hands to `debug`. Its fields accept anything. */\nexport type InternalDebugEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: UnredactedFields;\n};\n\n/** Each level admits itself and everything above it in this table. */\nconst LEVEL_RANK: Record<LogLevel, number> = {\n none: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction scopedLogger(\n logger: Logger,\n scope: LogScope,\n bindings: LogBindings\n): InternalLogger {\n const admits = (level: LogLevel): boolean =>\n LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];\n\n const safe = (event: InternalSafeEvent): SafeEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n ...(event.cause === undefined ? {} : { cause: event.cause }),\n });\n\n const unredacted = (event: InternalDebugEvent): DebugEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n });\n\n const self: InternalLogger = {\n child: (binding) =>\n scopedLogger(logger, scope, { ...bindings, ...binding }),\n\n debug: (event) => {\n if (admits('debug')) logger.debug(() => unredacted(event()));\n },\n\n info: (event) => {\n if (admits('info')) logger.info(() => safe(event()));\n },\n\n warn: (event) => {\n if (admits('warn')) logger.warn(() => safe(event()));\n },\n\n error: (event) => {\n if (admits('error')) logger.error(() => safe(event()));\n },\n\n failure: (event, error) => {\n // Two lines rather than one, and deliberately in this order: the `error`\n // line stays safe at every level, so a host running `'debug'` in beta\n // can still pipe `error` to Sentry without leaking what `debug` shows.\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('error')) logger.error(() => safe(classified(event(), error)));\n },\n\n warning: (event, error) => {\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('warn')) logger.warn(() => safe(classified(event(), error)));\n },\n\n wrap: async (op, params, run) => {\n const opLog = self.child({ op });\n opLog.debug(() => ({ msg: 'call', fields: { params } }));\n try {\n return await run();\n } catch (error) {\n opLog.failure(() => ({ msg: 'call failed' }), error);\n throw error;\n }\n },\n };\n\n return self;\n}\n\n/**\n * The same event with the thrown error rendered **verbatim** - for the\n * `'debug'` line, and nowhere else.\n */\nfunction verbatim(\n event: InternalSafeEvent,\n error: unknown\n): InternalDebugEvent {\n return {\n msg: event.msg,\n fields: { ...event.fields, error: describeErrorUnredacted(error) },\n };\n}\n\n/**\n * The same event with the thrown error classified into a {@link LogCause}\n * - safe at `'warn'` and `'error'`.\n *\n * An explicit `cause` on the event wins: a call site that already knows what\n * went wrong knows better than the classifier.\n */\nfunction classified(\n event: InternalSafeEvent,\n error: unknown\n): InternalSafeEvent {\n return { ...event, cause: event.cause ?? classifyLogCause(error) };\n}\n\n/**\n * What every SDK codepath gets when the host supplied no logger. `wrap` still\n * runs the work it is given; everything else is inert.\n *\n * There is no `console` fallback here or anywhere else in the SDK: a host who\n * supplied no logger gets silence, not a default destination they did not\n * choose.\n */\nexport const noopInternalLogger: InternalLogger = {\n child: () => noopInternalLogger,\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n failure: () => undefined,\n warning: () => undefined,\n wrap: (_op, _params, run) => run(),\n};\n","import { HEADER_API_VERSION } from '@/universal/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/universal/api/http';\nimport { buildUrlWithQueryParams, makeRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n Logger,\n RequestId,\n UnredactedFields,\n} from '@/universal/types/logger';\n\nexport type BeforeRequestMiddleware = (\n request: HttpRequest\n) => Promise<HttpRequest>;\n\nexport type AfterRequestMiddleware = (args: {\n request: HttpRequest;\n response: HttpResponse<unknown>;\n retry: (request?: HttpRequest) => Promise<HttpResponse<unknown>>;\n}) => Promise<HttpResponse<unknown>>;\n\nexport type HttpClientMiddleware = {\n beforeRequest?: BeforeRequestMiddleware[];\n afterRequest?: AfterRequestMiddleware[];\n};\n\nexport type HttpClientOptions = {\n /**\n * Mints the id that correlates one request's log lines. Injected so specs\n * can assert on log output, the same reason\n * {@link createRequestRetryMiddleware} takes a `delayFn`; defaults to a\n * short random string.\n */\n makeRequestId?: () => RequestId;\n};\n\n/**\n * Logging lives here rather than in a middleware pair so that every client\n * built on `HttpClient` reports by construction - the frontline client, the\n * token registry client, and whatever comes next. A middleware would have to\n * be remembered per client, and could not time a request or see one that threw\n * before producing a response.\n */\nexport class HttpClient {\n private readonly log: InternalLogger;\n private readonly makeRequestId: () => RequestId;\n\n constructor(\n readonly config: HttpClientConfig,\n readonly middleware: HttpClientMiddleware = {},\n logger: Logger | null = null,\n options: HttpClientOptions = {}\n ) {\n this.log = internalLogger(logger, 'HTTP');\n this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;\n }\n\n async send<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n return this.runRequestWithAfterMiddleware<TResponse>(request);\n }\n\n /**\n * Runs beforeRequest, executeRequest, then the full afterRequest middleware\n * chain. Used by send() and by the retry() callback so that when a\n * middleware calls retry(), the retried response also goes through all\n * afterRequest middleware (e.g. session renewal, retry). Middleware\n * must use request.attributes.retryAttempt (or similar) to avoid infinite\n * recursion when they trigger retries.\n */\n private async runRequestWithAfterMiddleware<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const preparedRequest = await this.runBeforeRequestMiddleware(\n this.withClientDefaults(request)\n );\n let response = await this.executeRequest<TResponse>(preparedRequest);\n\n for (const middleware of this.middleware.afterRequest ?? []) {\n response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) =>\n this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >,\n })) as HttpResponse<TResponse>;\n }\n\n return response;\n }\n\n private withClientDefaults(request: HttpRequest): HttpRequest {\n const url = this.resolveUrl(request.url);\n const headers = {\n ...(request.headers ?? {}),\n ...(this.config.xApiVersion !== undefined\n ? { [HEADER_API_VERSION]: this.config.xApiVersion }\n : {}),\n };\n\n return {\n ...request,\n url,\n headers,\n // Only when absent: a retry or a post-renewal re-send arrives with the\n // first attempt's id already on it, and keeping it is the whole point.\n attributes:\n Attributes.getRequestId(request.attributes) === null\n ? Attributes.concat(\n request.attributes ?? Attributes.empty,\n Attributes.requestId(this.makeRequestId())\n )\n : request.attributes,\n };\n }\n\n /**\n * Resolves a request URL against the client's baseUrl.\n *\n * @internal Public only for testing. Do not use in application code; use\n * {@link HttpClient.send} with a path and the client will resolve the URL.\n */\n resolveUrl(url: string): string {\n // If already absolute, use as-is.\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n // Otherwise append path to baseUrl so base path (e.g. /api) is preserved.\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const path = url.startsWith('/') ? url : `/${url}`;\n return base + path;\n }\n\n private async runBeforeRequestMiddleware(\n initialRequest: HttpRequest\n ): Promise<HttpRequest> {\n let request = initialRequest;\n for (const middleware of this.middleware.beforeRequest ?? []) {\n request = await middleware(request);\n }\n\n return request;\n }\n\n /**\n * One physical attempt, logged as one line.\n *\n * A non-2xx is a `warn` rather than an `error` because the wire does not\n * know whether it is a failure: the retry middleware may turn a 503 into a\n * success, and the token registry reads a 404 as \"not listed\". The namespace\n * above decides, and logs the `error` when it does.\n */\n private async executeRequest<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const requestId = Attributes.getRequestId(request.attributes);\n const log = requestId === null ? this.log : this.log.child({ requestId });\n const attempt = Attributes.getRetryAttempt(request.attributes) + 1;\n const startedAt = Date.now();\n\n log.debug(() => ({\n msg: 'request sent',\n fields: describeRequestUnredacted(request),\n }));\n\n try {\n const response = await makeRequest<TResponse>(request);\n const elapsed = Date.now() - startedAt;\n const outcome = () => ({\n msg: 'request completed',\n fields: {\n ...identifyRequest(request),\n 'http.response.status_code': response.status,\n duration_ms: elapsed,\n attempt,\n },\n });\n\n if (response.status >= 200 && response.status < 300) {\n log.info(outcome);\n } else {\n log.warn(outcome);\n }\n log.debug(() => ({\n msg: 'response received',\n fields: { body: response.body },\n }));\n\n return requestId === null ? response : { ...response, requestId };\n } catch (error) {\n const elapsed = Date.now() - startedAt;\n // `warning`, not two hand-written lines: it renders the error verbatim\n // at `'debug'` and classified at `'warn'`, which is the pairing this\n // used to spell out by hand.\n log.warning(\n () => ({\n msg: 'request threw',\n fields: {\n ...identifyRequest(request),\n duration_ms: elapsed,\n attempt,\n },\n }),\n error\n );\n throw error;\n }\n }\n}\n\n/**\n * How a request is named on every line above `'debug'`.\n *\n * `server.address` and `url.path` rather than OpenTelemetry's `url.full`, and\n * that is a deliberate deviation from the convention the rest of these keys\n * follow. `url.full` is defined to carry the query string, and frontline reads\n * take `chain`, `wallet_address` and `amount` as query parameters - so the\n * standard key would put host data on the levels this SDK keeps redacted.\n * The full URL appears at `'debug'` and nowhere else.\n *\n * `HttpRequest.url` carries no query to begin with - {@link makeRequest}\n * appends it on the way to `fetch` - so the split is about naming rather than\n * about stripping anything.\n */\nfunction identifyRequest(request: HttpRequest): {\n 'http.request.method': string;\n 'server.address': string | null;\n 'url.path': string;\n} {\n const { host, path } = splitUrl(request.url);\n return {\n 'http.request.method': request.method,\n 'server.address': host,\n 'url.path': path,\n };\n}\n\n/**\n * The host and the path of an absolute URL, separately, because OpenTelemetry\n * names them separately and because only the path is worth grouping on.\n *\n * Never throws: it runs inside an event lambda, and the {@link Logger}\n * contract says nothing the SDK hands over may turn a log line into a second\n * failure. A URL `URL` refuses is reported as it stands, which is safe either\n * way - `HttpRequest.url` never carries a query string.\n */\nfunction splitUrl(url: string): { host: string | null; path: string } {\n try {\n const parsed = new URL(url);\n return { host: parsed.host, path: parsed.pathname };\n } catch (_) {\n return { host: null, path: url };\n }\n}\n\n/**\n * Eight base36 characters. Short enough to read at the head of every line and\n * wide enough that two concurrent requests in one session will not collide.\n * Deliberately not a counter: a module-level counter would be global mutable\n * state shared by every client in the process.\n */\nfunction defaultMakeRequestId(): RequestId {\n return Math.random().toString(36).slice(2, 10).padEnd(8, '0') as RequestId;\n}\n\n/**\n * The request as sent - full URL, headers and body verbatim. `debug` is\n * documented as unredacted: it exists to reproduce a bug, and a redacted\n * `Authorization` is exactly what you need when the bug is that the wrong\n * token went out.\n *\n * The query string appears here and nowhere else, under `url.full`. Every\n * other line names the request through {@link identifyRequest}, whose\n * `url.path` has none - which is why those lines are safe above `debug`.\n * Rendering the sent URL here is what makes a `wallet_address`, a `chain` or\n * an `amount` reproducible at all.\n *\n * The values are handed over as they stand rather than stringified: a\n * {@link DebugEvent} accepts anything, and the logger implementation is what\n * guarantees a `bigint` or a cycle cannot fail to render.\n */\nfunction describeRequestUnredacted(request: HttpRequest): UnredactedFields {\n return {\n 'http.request.method': request.method,\n 'url.full': buildUrlWithQueryParams(request.url, request.queryParams),\n headers: request.headers,\n ...(request.method === 'POST' ? { body: request.body } : {}),\n };\n}\n\n/**\n * Structural interface satisfied by both {@link AuthenticatedApiClient} and\n * {@link ApiClient}. Used by the shared frontline API functions so they can\n * be called from either the client or server without any browser dependencies.\n */\nexport interface Sender {\n send<T>(request: HttpRequest): Promise<T>;\n}\n","import type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport function attachSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): BeforeRequestMiddleware {\n return async (request: HttpRequest): Promise<HttpRequest> => {\n if (!Attributes.isProtected(request.attributes)) {\n return request;\n }\n\n let accessToken = await fetchAccessToken(false);\n if (!accessToken) {\n const clientCreds = Attributes.getClientCredentials(request.attributes);\n if (clientCreds) {\n accessToken = clientCreds;\n }\n }\n\n if (accessToken === null) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n Authorization: `Bearer ${accessToken.value}`,\n },\n };\n };\n}\n","/**\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 { HEADER_IDEMPOTENCY_KEY } from '@/universal/api/frontline/config';\nimport type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { getUUIDv4 } from '@/universal/core/shared/utils/crypto';\n\nexport const idempotencyKeyMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.isIdempotent(request.attributes)) {\n return request;\n }\n\n const existingHeaders = request.headers ?? {};\n if (existingHeaders[HEADER_IDEMPOTENCY_KEY]) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...existingHeaders,\n [HEADER_IDEMPOTENCY_KEY]: getUUIDv4(),\n },\n };\n};\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\n\nconst MAX_ATTEMPTS = 3;\nconst INITIAL_DELAY_MS = 300;\nconst MAX_DELAY_MS = 2000;\n\nconst RETRYABLE_4XX = new Set([408, 409, 429]);\n\nexport function isRetryableStatus(status: number): boolean {\n return (status >= 500 && status < 600) || RETRYABLE_4XX.has(status);\n}\n\nfunction getRetryDelayMs(attempt: number): number {\n return Math.min(INITIAL_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n}\n\nexport type RequestRetryMiddlewareOptions = {\n /**\n * Optional delay function. Defaults to real setTimeout-based delay.\n * Use a no-op (e.g. () => Promise.resolve()) in tests to avoid slow tests.\n */\n delayFn?: (ms: number) => Promise<void>;\n};\n\n/**\n * Creates the request retry after-request middleware. Inject a no-op delayFn\n * in tests to avoid real delays (unit testing best practice).\n */\nexport function createRequestRetryMiddleware(\n options: RequestRetryMiddlewareOptions = {}\n): AfterRequestMiddleware {\n const delayFn = options.delayFn ?? defaultDelay;\n\n return async ({ request, response, retry }) => {\n if (!isRetryableStatus(response.status)) {\n return response;\n }\n\n const currentAttempt = Attributes.getRetryAttempt(request.attributes);\n if (currentAttempt >= MAX_ATTEMPTS - 1) {\n return response;\n }\n\n const nextAttempt = currentAttempt + 1;\n await delayFn(getRetryDelayMs(nextAttempt));\n\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.retryAttempt(nextAttempt)\n );\n return retry(nextRequest);\n };\n}\n\nfunction defaultDelay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retries the request up to 3 times with exponential backoff when the response\n * has a retryable status (5xx server errors). Uses request.attributes.retryAttempt\n * to decide delay and whether to retry, so the middleware does not loop when\n * retry() runs the full HTTP middleware chain again.\n */\nexport const requestRetryMiddleware: AfterRequestMiddleware =\n createRequestRetryMiddleware();\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport function renewSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): AfterRequestMiddleware {\n return async ({ request, response, retry }) => {\n if (response.status !== 401) {\n return response;\n }\n if (!Attributes.isProtected(request.attributes)) {\n return response;\n }\n if (Attributes.wasRenewAttempted(request.attributes)) {\n return response;\n }\n\n const newToken = await fetchAccessToken(true);\n if (newToken) {\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.renewAttempted(true)\n );\n return retry(nextRequest);\n } else {\n return response;\n }\n };\n}\n","import type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport { HttpError } from '@/universal/api/http';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { HttpClient } from '@/universal/api/http-client';\nimport { attachSessionMiddleware } from '@/universal/api/middleware/attach-session-middleware';\nimport { idempotencyKeyMiddleware } from '@/universal/api/middleware/idempotency-key';\nimport { requestRetryMiddleware } from '@/universal/api/middleware/request-retry';\nimport { renewSessionMiddleware } from '@/universal/api/middleware/session-renewal';\nimport type { Logger } from '@/universal/types/logger';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\n/**\n * Isomorphic HTTP client with session attachment, session renewal on 401,\n * idempotency key injection, and request retry. Works in both browser and\n * Node/server environments. Pass `additionalBeforeRequest` to inject\n * environment-specific middleware (e.g. `userAgentMiddleware` on the client).\n *\n * Pass `logger` through to have every request reported; the client logs\n * nothing without one.\n */\nexport class AuthenticatedApiClient {\n private readonly httpClient: HttpClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\n additionalBeforeRequest: BeforeRequestMiddleware[] = [],\n logger: Logger | null = null\n ) {\n this.httpClient = new HttpClient(\n config,\n {\n beforeRequest: [\n attachSessionMiddleware(fetchAccessToken),\n ...additionalBeforeRequest,\n idempotencyKeyMiddleware,\n ],\n afterRequest: [\n renewSessionMiddleware(fetchAccessToken),\n requestRetryMiddleware,\n ],\n },\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n const response = await this.httpClient.send<TResponse>(request);\n if (response.status >= 200 && response.status < 300) {\n return response.body as TResponse;\n } else {\n throw new HttpError(response);\n }\n }\n}\n","import { AuthenticatedApiClient } from '@/universal/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport type { Logger } from '@/universal/types/logger';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\n logger: Logger | null = null\n ) {\n this.client = new AuthenticatedApiClient(\n config,\n fetchAccessToken,\n [],\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","export class WritableSessionStoreRequiredError extends Error {\n constructor(\n message = 'This operation requires a writable SessionStore. Provide a `setSession` implementation in your SessionStore to persist or clear OAuth sessions.'\n ) {\n super(message);\n this.name = 'WritableSessionStoreRequiredError';\n }\n}\n","import type { OAuthSessionDto } from '@/universal/types/dto/oauth-session';\nimport type { Newtype } from '@/universal/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 { WritableSessionStoreRequiredError } from '@/server/shared/errors';\nimport { HttpError } from '@/universal/api/http';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Config } from '@/universal/types/config';\nimport type { OAuthSessionDto } from '@/universal/types/dto/oauth-session';\nimport type {\n AuthorizationCode,\n ClientSecret,\n CodeVerifier,\n} from '@/universal/types/oauth';\nimport {\n ClientCredentialsOAuth,\n type OAuthAccessToken,\n type OAuthRefreshToken,\n OAuthSession,\n} from '@/universal/types/oauth-session';\n\nexport interface SessionStore {\n getSession(): Promise<OAuthSession | null>;\n /**\n * Persists or clears the OAuth session.\n *\n * **Omit this method to create a read-only store.** When absent, the SDK\n * skips token refresh entirely — no network call is made and no refresh\n * token is consumed. This is the correct approach for contexts that can read\n * the session but cannot write it back, such as Next.js Server Components.\n *\n * ⚠️ Do **not** implement this as a no-op (`async () => {}`). If the method\n * is present, the SDK assumes writes succeed: it will fire a token refresh\n * network call, consume the refresh token, then invoke `setSession` — which\n * would silently discard the new session and leave the browser holding an\n * invalidated refresh token. Simply **omit** `setSession` to prevent any\n * refresh from being attempted.\n *\n * {@link ServerAuthNamespace.completeOAuth} and\n * {@link ServerAuthNamespace.logout} always require a writable store and\n * throw {@link WritableSessionStoreRequiredError} if `setSession` is absent.\n */\n setSession?(session: OAuthSession | null): Promise<void>;\n}\n\n/**\n * The empty session store: holds no session, reads nothing, never writes.\n *\n * For server contexts that act without a user — the client-credentials grant\n * (`auth.clientCredentials`) and the public token registry (`tokens`) read\n * nothing from the store, so hosts building those paths need no store of\n * their own.\n *\n * `setSession` is deliberately absent, not a no-op — see\n * {@link SessionStore.setSession} for why a no-op is a bug.\n */\nexport function emptySessionStore(): SessionStore {\n return { getSession: async () => null };\n}\n\n/** The PKCE pair `CoinListClient#auth.completeOAuth` hands to the backend. */\nexport interface CompleteOAuthParams {\n /** The short-lived authorization code parsed out of the redirect URL. */\n code: AuthorizationCode;\n /** The `code_verifier` the browser generated when starting the flow. */\n codeVerifier: CodeVerifier;\n}\n\n/**\n * OAuth session lifecycle on your backend: exchanging authorization codes,\n * keeping the access token fresh, minting app-level tokens, and logging out.\n *\n * This namespace is server-only: every method needs the `clientSecret` and the\n * {@link SessionStore}, neither of which may exist in a browser.\n */\nexport interface ServerAuthNamespace {\n /**\n * Exchanges an authorization code from `CoinListClient#auth.completeOAuth`\n * for an OAuth session and persists it via {@link SessionStore.setSession}.\n *\n * Throws {@link WritableSessionStoreRequiredError} if the session store does\n * not provide `setSession`.\n */\n completeOAuth(params: CompleteOAuthParams): Promise<OAuthSession>;\n\n /**\n * Returns a valid access token for the current session, refreshing it if it\n * is expired or near expiry. This is what you serve to\n * {@link ClientConfig.getAccessToken}.\n *\n * **Writable store**: if the token is expired, the SDK exchanges the refresh\n * token for a new session, persists it, and returns the fresh access token.\n * Returns `null` if there is no session or the refresh fails.\n *\n * **Read-only store** (no `setSession`): refresh is skipped entirely. The\n * stored token is returned as-is, even if it is expired — a non-null return\n * value does **not** guarantee the token is accepted by the API. Before\n * making API calls, check `token.expiresAt > new Date()`. Use a writable\n * store (e.g. in a Route Handler) when you need the SDK to renew the session\n * automatically.\n *\n * @returns the access token, or `null` if there is no session or the session\n * could not be refreshed.\n */\n getAccessToken(): Promise<OAuthAccessToken | null>;\n\n /**\n * Obtains an app-level access token via the OAuth 2.0 `client_credentials`\n * grant (RFC 6749 §4.4). No user is involved: the token authenticates the\n * partner application itself and only grants access to app-level resources\n * such as offers and offer requirements.\n *\n * The token is **not** persisted to the {@link SessionStore} and has no\n * refresh token. It expires at `expiresAt`; once expired, call this method\n * again to obtain a fresh token — the SDK does not renew it automatically.\n *\n * Pass the result to `ServerOffersNamespace` or\n * `ServerRequirementsNamespace.forOffer` to read without a user session.\n */\n clientCredentials(): Promise<ClientCredentialsOAuth>;\n\n /**\n * Revokes the current token via `POST /oauth/revoke` and clears the session.\n *\n * Throws {@link WritableSessionStoreRequiredError} if the session store does\n * not provide `setSession`.\n */\n logout(): Promise<void>;\n}\n\n/** What {@link ServerAuthNamespaceImpl} needs out of `ServerConfig`. */\nexport type ServerAuthConfig = Config & {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Seconds before expiry at which a token counts as expired for refresh. */\n readonly accessTokenExpiryBufferSeconds: number;\n /** Whether to rethrow errors the SDK could otherwise swallow (e.g. revoke). */\n readonly strict: boolean;\n};\n\nexport class ServerAuthNamespaceImpl implements ServerAuthNamespace {\n private readonly log: InternalLogger;\n\n constructor(\n private readonly api: Sender,\n private readonly config: ServerAuthConfig\n ) {\n this.log = internalLogger(config.logger ?? null, 'AUTH');\n }\n\n async completeOAuth(params: CompleteOAuthParams): Promise<OAuthSession> {\n return this.log.wrap('completeOAuth', undefined, async () => {\n const setSession = this.writableSessionStore();\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'authorization_code',\n code: params.code,\n redirect_uri: this.config.redirectUri,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n code_verifier: params.codeVerifier,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n await setSession(session);\n return session;\n });\n }\n\n async getAccessToken(): Promise<OAuthAccessToken | null> {\n // Wrapped despite running on every request: `sessionStore.getSession` is\n // host code, and when it throws there is nothing else between the failure\n // and the host's own catch to say which SDK call it came out of.\n return this.log.wrap('getAccessToken', undefined, () =>\n this.readAccessToken()\n );\n }\n\n private async readAccessToken(): Promise<OAuthAccessToken | null> {\n const sessionStore = this.config.sessionStore;\n const session = await sessionStore.getSession();\n if (session == null) return null;\n\n const now = Date.now();\n const expiresAt = session.accessToken.expiresAt.getTime();\n const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1000;\n if (expiresAt > now + bufferMs) {\n // Valid access token, return it regardless\n return session.accessToken;\n }\n\n const setSession = sessionStore.setSession?.bind(sessionStore);\n if (!setSession) {\n // No write session capabilities => can't refresh!\n // Return the access token as-is\n this.log.child({ op: 'getAccessToken' }).warn(() => ({\n msg: 'serving an expired token: the session store is read-only, so it cannot be refreshed',\n }));\n return session.accessToken;\n }\n return this.refreshSession(session.refreshToken, setSession);\n }\n\n private async refreshSession(\n refreshToken: OAuthRefreshToken | undefined,\n setSession: (session: OAuthSession | null) => Promise<void>\n ): Promise<OAuthAccessToken | null> {\n const log = this.log.child({ op: 'refresh' });\n if (!refreshToken) {\n log.warn(() => ({\n msg: 'clearing the session: it carries no refresh token',\n }));\n await setSession(null);\n return null;\n }\n\n try {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n const newSession = OAuthSession.fromDto(sessionDto);\n await setSession(newSession);\n log.info(() => ({ msg: 'session renewed' }));\n return newSession.accessToken;\n } catch (error) {\n // The user is logged out by this line, and nothing above sees why:\n // `getAccessToken` answers `null` either way.\n log.failure(\n () => ({ msg: 'refresh failed; clearing the session' }),\n error\n );\n await setSession(null);\n return null;\n }\n }\n\n async clientCredentials(): Promise<ClientCredentialsOAuth> {\n return this.log.wrap('clientCredentials', undefined, async () => {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'client_credentials',\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n return ClientCredentialsOAuth(session.accessToken);\n });\n }\n\n async logout(): Promise<void> {\n return this.log.wrap('logout', undefined, () => this.revokeAndClear());\n }\n\n private async revokeAndClear(): Promise<void> {\n const setSession = this.writableSessionStore();\n const session = await this.config.sessionStore.getSession();\n if (session == null) return;\n\n try {\n await this.api.send({\n method: 'POST',\n url: `/oauth/revoke`,\n body: {\n token: session.accessToken.value,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n } catch (err) {\n // A failed revoke still leaves the local session invalid, so only strict\n // callers care; anything that is not an HTTP failure is a real bug.\n if (!(err instanceof HttpError) || this.config.strict) {\n throw err;\n }\n this.log.child({ op: 'logout' }).warn(() => ({\n msg: 'the token was not revoked upstream; the local session is cleared regardless',\n }));\n }\n await setSession(null);\n }\n\n /**\n * Returns the store's `setSession`, or throws — the guard every\n * session-writing operation shares.\n */\n private writableSessionStore(): (\n session: OAuthSession | null\n ) => Promise<void> {\n const sessionStore = this.config.sessionStore;\n const setSession = sessionStore.setSession?.bind(sessionStore);\n if (!setSession) {\n throw new WritableSessionStoreRequiredError();\n }\n return setSession;\n }\n}\n","import type {\n Cursor,\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * Walks every page of a cursor-paginated endpoint and returns the flattened\n * result.\n *\n * Lives in the API layer rather than beside `PaginationParams` because it\n * drives requests: it is the auto-paginating half that `list()` is built on,\n * while the params and the response envelope are domain models the client and\n * the server both name.\n */\nexport async function fetchAllPages<\n A,\n P extends PaginationParams = PaginationParams,\n>(\n fetchPage: (params: P) => Promise<PaginatedResponse<A>>,\n baseParams?: Omit<P, keyof PaginationParams>\n): Promise<A[]> {\n const items: A[] = [];\n let cursor: Cursor | null = null;\n\n do {\n const params = {\n ...(baseParams ?? {}),\n after: cursor ?? undefined,\n } as P;\n const page = await fetchPage(params);\n items.push(...page.data);\n cursor = page.startingAfter;\n } while (cursor);\n\n return items;\n}\n","import {\n InvariantError,\n MathError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type EthereumChain =\n | 'ethereum_mainnet'\n | 'ethereum_sepolia'\n | 'base_mainnet'\n | 'base_sepolia';\n\n/**\n * The exhaustive chain set: a new {@link EthereumChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const ETHEREUM_CHAINS: Record<EthereumChain, true> = {\n ethereum_mainnet: true,\n ethereum_sepolia: true,\n base_mainnet: true,\n base_sepolia: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const EthereumChain = (value: string): EthereumChain => {\n if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Ethereum chain: \"${value}\"`);\n }\n return value as EthereumChain;\n};\n\nexport type SolanaChain = 'solana_mainnet' | 'solana_devnet';\n\n/**\n * The exhaustive chain set: a new {@link SolanaChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const SOLANA_CHAINS: Record<SolanaChain, true> = {\n solana_mainnet: true,\n solana_devnet: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const SolanaChain = (value: string): SolanaChain => {\n if (!Object.keys(SOLANA_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Solana chain: \"${value}\"`);\n }\n return value as SolanaChain;\n};\n\nexport type Chain = EthereumChain | SolanaChain;\n\n/**\n * {@link Chain}'s check without the throw, for a mapper over a list that drops\n * the entries it cannot name rather than rejecting the whole list. Frontline's\n * chain registry may carry chains this SDK does not model yet.\n */\nexport const isChain = (value: string): value is Chain =>\n Object.keys(ETHEREUM_CHAINS).includes(value) ||\n Object.keys(SOLANA_CHAINS).includes(value);\n\nexport const Chain = (value: string): Chain => {\n if (!isChain(value)) {\n throw new ValidationError(`Unsupported chain: \"${value}\"`);\n }\n return value;\n};\n\n/**\n * Protocol a wallet binding is scoped to. EVM-only for now: an EVM address\n * binds once per option regardless of which EVM chain proved ownership.\n * Frontline's enum also has `:solana`, but we don't handle Solana bindings yet,\n * so this stays `'ethereum'` until Solana support lands.\n */\nexport type WalletProtocol = 'ethereum';\n\n/**\n * EVM addresses keep a `0x${string}` base so they stay assignable to the\n * `0x${string}` shapes that on-chain libraries (viem/wagmi) expect. We only\n * drop the runtime `0x` narrowing: values are trusted at the boundary and\n * branded via the constructor.\n */\nexport type EvmWalletAddress = Newtype<`0x${string}`, 'EvmWalletAddress'>;\nexport const EvmWalletAddress = (value: string): EvmWalletAddress =>\n value as EvmWalletAddress;\n\nexport type EvmContractAddress = Newtype<`0x${string}`, 'EvmContractAddress'>;\nexport const EvmContractAddress = (value: string): EvmContractAddress =>\n value as EvmContractAddress;\n\n/**\n * What uniquely identifies a token: the chain it is deployed on plus its\n * contract address. Never a symbol, which can collide across issuers.\n */\nexport type TokenIdentifier = {\n /** The chain the token contract is deployed on. */\n chain: EthereumChain;\n /**\n * The token's contract address, in any casing — consumers that need the\n * EIP-55 form (e.g. the token registry routes) checksum it themselves.\n */\n address: EvmContractAddress;\n};\n\nexport type HexEncodedTransactionData = Newtype<\n `0x${string}`,\n 'HexEncodedTransactionData'\n>;\nexport const HexEncodedTransactionData = (\n value: string\n): HexEncodedTransactionData => value as HexEncodedTransactionData;\n\n/**\n * A transaction the backend has already encoded for us — the caller only\n * broadcasts it. Used by the flows that hand a wallet a ready-made `to`/`data`\n * pair (allow-listing a wallet, an Ondo swap) rather than encoding a contract\n * call themselves.\n */\nexport type Tx = {\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n};\n\n/**\n * The largest exponent whose power of ten still fits a uint256: 10^77 fits,\n * 10^78 does not.\n *\n * The bound is arithmetic rather than a token standard's. ERC-20 reports\n * `decimals()` as a `uint8`, so 255 is what a contract *can* say, but every\n * {@link AssetDecimals} in this codebase is paired with a {@link Uint256} raw\n * by construction, and scaling by anything past this leaves that pairing\n * unrepresentable. A value between 78 and 255 would therefore pass a\n * standard-faithful check and then break the first multiplication it reached.\n */\nexport const MAX_ASSET_DECIMALS = 77;\n\n/**\n * How many decimal places one whole token divides into.\n *\n * Validated, unlike its neighbours here — {@link Uint256} is a bare `bigint`\n * with a separate {@link assertUint256} guard, and {@link DecimalString} casts\n * unchecked. The asymmetry is deliberate and follows the value's provenance:\n * an `AssetDecimals` used to come only from literals and the token registry,\n * but backends now publish exponents of their own (`asset_decimals` on an Ondo\n * quote, both scales on a built swap), and those feed `10n ** BigInt(d)`\n * during render. Guarding at construction is what keeps a fractional or\n * unbounded exponent from surfacing as a `RangeError` mid-render — or, at\n * 10^200, as a hung tab — instead of as the failed state the screen has.\n *\n * See docs/ADR-7-VALIDATED-NEWTYPES.md.\n *\n * @throws ValidationError on a non-integer, a negative, or anything above\n * {@link MAX_ASSET_DECIMALS}.\n */\nexport type AssetDecimals = Newtype<number, 'AssetDecimals'>;\nexport const AssetDecimals = (value: number): AssetDecimals => {\n if (!Number.isInteger(value)) {\n throw new ValidationError(`Asset decimals must be an integer: ${value}`);\n }\n if (value < 0 || value > MAX_ASSET_DECIMALS) {\n throw new ValidationError(\n `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`\n );\n }\n return value as AssetDecimals;\n};\n\nexport const STABLE_DECIMALS = AssetDecimals(6);\n\n/**\n * A non-negative decimal number the backend sent as a string, kept unscaled.\n *\n * Reach for it when a response gives you a number but not the decimals to\n * scale it by, or gives you one it has already applied. Inventing an exponent\n * for either is how a display ends up orders of magnitude out.\n *\n * Contrast {@link BlockchainAmount}, which pairs a raw uint256 with the\n * decimals it is denominated in and so is only constructible when you know\n * both. Arithmetic on a `DecimalString` needs a decimal library we\n * deliberately do not ship.\n */\nexport type DecimalString = Newtype<string, 'DecimalString'>;\nexport const DecimalString = (value: string): DecimalString =>\n value as DecimalString;\n\nexport const MAX_UINT_256 = 2n ** 256n - 1n;\n\n/**\n * A non-negative integer within uint256 bounds. Kept unbranded (a plain\n * `bigint`) so raw on-chain amounts flow in without ceremony; bounds are\n * enforced where it matters (see {@link combineAmounts}).\n */\nexport type Uint256 = bigint;\n\n/**\n * Asserts a computed bigint falls within uint256 bounds. Use at on-chain\n * arithmetic boundaries (bps math, price computation) where the SDK's own\n * arithmetic could underflow below zero or overflow above 2^256-1.\n *\n * Throws {@link InvariantError}, because reaching it means the SDK computed\n * something no chain could represent. **For a value that came off the wire,\n * use {@link parseUint256} instead**: the backend sending an unrepresentable\n * number is a {@link ValidationError}, and the two have different remedies.\n */\nexport const assertUint256 = (value: bigint): Uint256 => {\n if (isUint256(value)) return value;\n throw new InvariantError(`Value out of uint256 bounds: ${value}`);\n};\n\n/**\n * {@link assertUint256} at a wire boundary: the same bounds check, reported as\n * a {@link ValidationError} against the named field, because a value out of\n * range here is the backend's, not the SDK's.\n *\n * `label` names the field the way a DTO mapper's other failures do, so a log\n * line says which one - `SwapPreview.pay_input_amount`, not `a number`.\n */\nexport const parseUint256 = (value: bigint, label: string): Uint256 => {\n if (isUint256(value)) return value;\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n};\n\nconst isUint256 = (value: bigint): boolean =>\n value >= 0n && value <= MAX_UINT_256;\n\nexport type BlockchainAmount = Newtype<\n { raw: Uint256; decimals: AssetDecimals },\n 'BlockchainAmount'\n>;\n\n/**\n * Constructs a {@link BlockchainAmount} and exposes arithmetic helpers.\n * TypeScript has no operator overloading, so use `BlockchainAmount.add(a, b)`\n * instead of `+`/`-`/`*`/`/` on the objects directly.\n */\nexport const BlockchainAmount = Object.assign(\n (value: { raw: Uint256; decimals: AssetDecimals }): BlockchainAmount =>\n value as BlockchainAmount,\n {\n add: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x + y),\n sub: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x - y),\n mul: multiplyAmounts,\n div: divideAmounts,\n }\n);\n\n/**\n * `a * b`, denominated in `a`'s decimals - a price times a quantity, an amount\n * times a rate.\n *\n * The exact inverse of {@link divideAmounts}, and it reads the same way round:\n * the answer stays in `a`'s scale and `b`'s divides back out, so the two\n * compose - `mul(div(a, b), b)` is `a` again, short only what truncation took.\n * That is what makes `price x quantity` land in the currency the price was\n * quoted in rather than at some product of two exponents no token uses.\n *\n * The multiplication happens *before* the division by `10^b.decimals`, so the\n * full precision of both operands survives into the one rounding at the end.\n * Like `div` it truncates towards zero on both signs, which is the safe\n * direction for money: a total is never inflated past what the parts hold.\n *\n * Total - unlike `div`, there is nothing here to reject. The scale it divides\n * by is a power of ten, never zero, and a product is not bounds-checked for\n * the same reason a quotient is not: whether one past uint256 is a corrupt\n * response or an expected magnitude belongs to the caller.\n */\nfunction multiplyAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n const product = a.raw * b.raw;\n return BlockchainAmount({\n raw: product / 10n ** BigInt(b.decimals),\n decimals: a.decimals,\n });\n}\n\n/**\n * `a / b`, denominated in `a`'s decimals - a price, a ratio, a rate.\n *\n * Unlike {@link combineAmounts}, the two operands may be at different scales,\n * and usually are: dividing dollars by shares is the point of the operation,\n * and the two tokens rarely share an exponent. `b`'s scale divides back out -\n * the numerator is scaled by `10^b.decimals` *before* the division, so nothing\n * is lost to integer truncation early and the quotient lands in `a`'s scale,\n * which is the one the amounts it is rendered beside are in.\n *\n * Truncates towards zero on both signs, which is what BigInt division already\n * does and the safe direction for money: the total a price implies never\n * exceeds, in magnitude, the amount that actually moved.\n *\n * A zero divisor is the only rejection. The quotient is deliberately *not*\n * bounds-checked the way {@link combineAmounts} checks a sum: scaling the\n * numerator carries even legal pairs past uint256 (a maximal amount over a\n * single base unit), and whether that reads as a corrupt response or an\n * expected magnitude is the caller's to judge - see `computeOndoBuyPrice` and\n * `computeOndoSellPrice`, which bounds-check the price they build out of this.\n *\n * @throws MathError when `b` is zero. `add` and `sub` throw a bare `Error`\n * because a scale mismatch is a programming error caught in review; a zero\n * divisor arrives from a server response and is divided by during render, so\n * it is a named failure a screen can catch and map to a failed state.\n */\nfunction divideAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n if (b.raw === 0n) {\n throw new MathError('Cannot divide a BlockchainAmount by zero');\n }\n\n const scaled = a.raw * 10n ** BigInt(b.decimals);\n return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });\n}\n\n/**\n * Combine two amounts with a raw-bigint `op`. Both operands must share the\n * same `decimals` — adding/subtracting differently-scaled amounts is a\n * programming error, so we throw rather than silently producing garbage.\n * The result is bounds-checked, so an underflow (negative `raw`) or uint256\n * overflow is rejected.\n */\nfunction combineAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount,\n op: (x: bigint, y: bigint) => bigint\n): BlockchainAmount {\n if (a.decimals !== b.decimals) {\n throw new InvariantError(\n 'Cannot combine BlockchainAmounts with different decimals: ' +\n `${a.decimals} vs ${b.decimals}`\n );\n }\n const raw = op(a.raw, b.raw);\n if (raw < 0n || raw > MAX_UINT_256) {\n throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);\n }\n return BlockchainAmount({ raw, decimals: a.decimals });\n}\n\nexport type AssetSymbol = Newtype<string, 'AssetSymbol'>;\nexport const AssetSymbol = (value: string): AssetSymbol => value as AssetSymbol;\n\n/**\n * A stablecoin symbol is an {@link AssetSymbol} narrowed to the coins we\n * support. It shares the `AssetSymbol` brand so it stays assignable to it.\n */\nexport type StablecoinSymbol = Newtype<'USDC' | 'USDT', 'AssetSymbol'>;\nexport const StablecoinSymbol = (value: 'USDC' | 'USDT'): StablecoinSymbol =>\n value as StablecoinSymbol;\n\nexport type KnownAssetSymbol = StablecoinSymbol;\nexport const KnownAssetSymbol = StablecoinSymbol;\n\nexport type Erc20Asset = {\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n};\n\nexport type Bps = Newtype<bigint, 'Bps'>;\nexport const Bps = (value: bigint): Bps => value as Bps;\n","import {\n Chain,\n EvmContractAddress,\n isChain,\n} from '@/universal/types/blockchain/core';\nimport type {\n OfferDto,\n OfferTokenDto,\n OfferTypeDto,\n} from '@/universal/types/dto/offer';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type OfferId = Newtype<string, 'OfferId'>;\nexport const OfferId = (value: string) => value as OfferId;\n\nexport type OfferSlug = Newtype<string, 'OfferSlug'>;\nexport const OfferSlug = (value: string) => value as OfferSlug;\n\nexport type OfferType = OfferTypeDto;\n\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: OfferToken.listFromDto(dto.tokens),\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 /**\n * Maps an offer's token list, dropping every token on a chain this SDK does\n * not name. Frontline's chain registry runs ahead of {@link Chain}, and a\n * plain `.map` would throw out of `Offer.fromDto` and, through\n * `PaginatedResponse.fromDto`, reject the whole offers page - which is how\n * one Base token blanked production's offers list. Dropping costs that\n * token's metadata alone: `coinlist.tokens.get` takes an `EthereumChain`,\n * so nobody could have looked it up anyway.\n *\n * Same shape as `TokenMetadata.fromRegistryDto`.\n */\n listFromDto: (dtos: OfferTokenDto[]): OfferToken[] =>\n dtos.filter((dto) => isChain(dto.chain)).map(OfferToken.fromDto),\n};\n","import type { AssetDto } from '@/universal/types/dto/asset';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type AssetId = Newtype<string, 'AssetId'>;\nexport const AssetId = (value: string) => value as AssetId;\n\nexport type AssetCode = Newtype<string, 'AssetCode'>;\nexport const AssetCode = (value: string) => value as AssetCode;\n\nexport type Asset = {\n id: AssetId;\n code: AssetCode;\n name: string;\n fractionalDigits: number;\n};\n\nexport const Asset = {\n fromDto: (dto: AssetDto): Asset => ({\n id: AssetId(dto.id),\n code: AssetCode(dto.code),\n name: dto.name,\n fractionalDigits: dto.fractional_digits,\n }),\n};\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { Asset } from '@/universal/types/asset';\nimport { Chain, EvmContractAddress } from '@/universal/types/blockchain/core';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailSwapContractDto,\n OfferDetailTermDto,\n} from '@/universal/types/dto/offer-detail';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\nimport {\n OfferId,\n OfferSlug,\n OfferToken,\n type OfferType,\n} from '@/universal/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 * Every chain this offer can be swapped on, with the CoinList contract each\n * settles through. Empty means it cannot be swapped anywhere.\n */\n swapContracts: OfferSwapContract[];\n\n 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\n/**\n * A chain an offer can be swapped on, with the CoinList contract the swap\n * settles through - the spender to approve before any quote exists.\n *\n * Carries no role, unlike {@link OfferToken}: there is one swap contract per\n * chain and it serves every Ondo asset on it, so which token is being traded\n * does not change the answer.\n */\nexport type OfferSwapContract = {\n chain: Chain;\n address: EvmContractAddress;\n};\n\nexport const OfferSwapContract = {\n fromDto: (dto: OfferDetailSwapContractDto): OfferSwapContract => ({\n chain: Chain(dto.chain),\n address: EvmContractAddress(dto.address),\n }),\n};\n\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n 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 // Absent is not an error. frontline#1365 puts `swap_contracts` on the Ondo\n // variant alone, so a token sale or Superstate offer carries no key at\n // all, and `[]` already means \"cannot swap here\".\n const swapContracts =\n dto.swap_contracts === undefined ? [] : dto.swap_contracts;\n if (!Array.isArray(swapContracts)) {\n throw new ValidationError(\n `OfferDetail.swap_contracts: expected an array, got ${typeof swapContracts}`\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: OfferToken.listFromDto(dto.tokens),\n swapContracts: swapContracts.map(OfferSwapContract.fromDto),\n\n about: notBlankStringOrNull(dto.about),\n tagline: dto.tagline,\n bannerUrl: dto.banner_url,\n logoUrl: dto.logo_url,\n category: dto.category,\n\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: dto.faqs.map(FaqItem.fromDto),\n links: dto.links.map(Link.fromDto),\n milestones: dto.milestones.map(Milestone.fromDto),\n options: dto.options.map(OfferOption.fromDto),\n terms: dto.terms.map(TermItem.fromDto),\n };\n },\n};\n\nexport const OfferOption = {\n fromDto: (dto: OfferDetailOptionDto): OfferOption => ({\n id: OfferOptionId(dto.id),\n slug: OfferOptionSlug(dto.slug),\n bidIncrement: dto.bid_increment,\n floorPriceUsd: dto.floor_price_usd,\n minimumPurchaseUsd: dto.minimum_purchase_usd,\n priceUsd: dto.price_usd,\n saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),\n totalTokenSupply: dto.total_token_supply,\n }),\n};\n\nexport const FaqItem = {\n fromDto: (dto: OfferDetailFaqDto): FaqItem => ({\n question: notBlankStringOrNull(dto.question),\n answer: notBlankStringOrNull(dto.answer),\n }),\n};\n\nexport const Link = {\n fromDto: (dto: OfferDetailLinkDto): Link => ({\n label: notBlankStringOrNull(dto.label),\n url: notBlankStringOrNull(dto.url),\n }),\n};\n\nexport const TermItem = {\n fromDto: (dto: OfferDetailTermDto): TermItem => ({\n key: notBlankStringOrNull(dto.key),\n value: notBlankStringOrNull(dto.value),\n }),\n};\n\nexport const Milestone = {\n fromDto: (dto: OfferDetailMilestoneDto): Milestone => ({\n name: notBlankStringOrNull(dto.name),\n schedule: notBlankStringOrNull(dto.schedule),\n status: dto.status,\n }),\n};\n","import type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type Cursor = Newtype<string, 'Cursor'>;\nexport const Cursor = (value: string) => value as Cursor;\n\n/**\n * Cursor-based pagination input used when requesting paginated API resources.\n * Set `after` or `before` to navigate relative to a known cursor, and `limit`\n * to control the maximum number of returned items.\n */\nexport interface PaginationParams {\n before?: Cursor;\n after?: Cursor;\n limit?: number;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n startingAfter: Cursor | null;\n startingBefore: Cursor | null;\n}\n\nexport const PaginatedResponse = {\n fromDto: <A, B>(\n dto: PaginatedResponseDto<A>,\n itemMapper: (item: A) => B\n ): PaginatedResponse<B> => ({\n 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 { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { OfferDto } from '@/universal/types/dto/offer';\nimport type { OfferDetailDto } from '@/universal/types/dto/offer-detail';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport { Offer, type OfferId } from '@/universal/types/offer';\nimport { OfferDetail } from '@/universal/types/offer-detail';\nimport {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\nexport async function fetchOffers(\n api: Sender,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Offer[]> {\n return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));\n}\n\nexport async function fetchOffersPage(\n api: Sender,\n params: PaginationParams,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<PaginatedResponse<Offer>> {\n const queryParams = PaginationParams.toQueryParams(params);\n const pageDto = await api.send<PaginatedResponseDto<OfferDto>>({\n method: 'GET',\n url: '/v1/offers',\n queryParams,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return PaginatedResponse.fromDto(pageDto, Offer.fromDto);\n}\n\nexport async function fetchOfferDetails(\n api: Sender,\n id: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<OfferDetail> {\n const dto = await api.send<OfferDetailDto>({\n method: 'GET',\n url: `/v1/offers/${id}`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return OfferDetail.fromDto(dto);\n}\n","import type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport * as offersApi from '@/universal/api/frontline/offers';\nimport type { OffersNamespace } from '@/universal/core/offers/offers-namespace';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { Offer, OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * The server-side offers namespace: the same reads as the shared\n * {@link OffersNamespace}, each additionally callable with an app-level token\n * from `ServerAuthNamespace.clientCredentials` instead of a user session.\n *\n * When a user session exists it takes precedence and `clientCreds` acts as a\n * fallback. Without either, the reads throw {@link NotAuthenticatedError}.\n */\nexport interface ServerOffersNamespace extends OffersNamespace {\n /** @param clientCreds app-level token to read without a user session. */\n list(clientCreds?: ClientCredentialsOAuth): Promise<Offer[]>;\n\n /** @param clientCreds app-level token to read without a user session. */\n listPage(\n params: PaginationParams,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<PaginatedResponse<Offer>>;\n\n /** @param clientCreds app-level token to read without a user session. */\n get(id: OfferId, clientCreds?: ClientCredentialsOAuth): Promise<OfferDetail>;\n}\n\nexport class ServerOffersNamespaceImpl implements ServerOffersNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: ServerNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'OFFERS');\n }\n\n async list(clientCreds?: ClientCredentialsOAuth): Promise<Offer[]> {\n return this.log.wrap('list', clientCreds, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOffers(this.ctx.api, clientCreds);\n });\n }\n\n async listPage(\n params: PaginationParams,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<PaginatedResponse<Offer>> {\n return this.log.wrap('listPage', { params, clientCreds }, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOffersPage(this.ctx.api, params, clientCreds);\n });\n }\n\n async get(\n id: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<OfferDetail> {\n return this.log.wrap('get', { id, clientCreds }, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOfferDetails(this.ctx.api, id, clientCreds);\n });\n }\n}\n","import type {\n RequirementActionNeededReasonDto,\n RequirementDto,\n RequirementStatusesDto,\n RequirementStatusValueDto,\n RequirementTypeDto,\n} from '@/universal/types/dto/requirement';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type RequirementId = Newtype<string, 'RequirementId'>;\nexport const RequirementId = (value: string) => value as RequirementId;\n\nexport type RequirementType = RequirementTypeDto;\nexport type RequirementStatusValue = RequirementStatusValueDto;\nexport type RequirementActionNeededReason = RequirementActionNeededReasonDto;\n\nexport type Requirement = {\n id: RequirementId;\n type: RequirementType;\n details: Record<string, unknown> | null;\n};\n\nexport const Requirement = {\n fromDto: (dto: RequirementDto): Requirement => ({\n id: RequirementId(dto.id),\n type: dto.type,\n details: dto.details,\n }),\n};\n\nexport type RequirementStatusInfo = {\n id: RequirementId;\n status: RequirementStatusValue;\n /** Why the requirement needs action (KYC-backed requirements only). */\n action: RequirementActionNeededReason | null;\n /**\n * The Sumsub verification level that resolves this requirement, prescribed\n * by the backend. Present exactly when an inline Sumsub flow can be started.\n */\n kycLevel?: KycLevelName;\n /**\n * Whether the Sumsub applicant must be reset before starting the flow\n * (redoing an already-approved level, e.g. to update stale PII). Forward to\n * the kyc-token request as-is.\n */\n kycReset?: boolean;\n};\n\nexport const RequirementStatusInfo = {\n fromStatusesDto: (dto: RequirementStatusesDto): RequirementStatusInfo[] =>\n Object.entries(dto.statuses).map(([id, value]) =>\n typeof value === 'string'\n ? { id: RequirementId(id), status: value, action: null }\n : {\n id: RequirementId(id),\n status: value.status,\n action: value.action ?? null,\n kycLevel: value.kyc_level,\n kycReset: value.kyc_reset,\n }\n ),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/universal/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport async function fetchOfferRequirements(\n api: Sender,\n offerId: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Record<OfferOptionId, Requirement[]>> {\n const response = await api.send<OfferRequirementsDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return Object.fromEntries(\n Object.entries(response.options).map(([optionId, list]) => [\n optionId,\n list.data.map(Requirement.fromDto),\n ])\n );\n}\n\nexport async function fetchRequirementStatuses(\n api: Sender,\n offerId: OfferId\n): Promise<RequirementStatusInfo[]> {\n const response = await api.send<RequirementStatusesDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements/statuses`,\n attributes: Attributes.protected(),\n });\n return RequirementStatusInfo.fromStatusesDto(response);\n}\n","import type {\n DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/universal/types/dto/document-submission';\n\n/** Document types that can be signed via {@link CoinListClient.submitDocument}. */\nexport type DocumentType = 'tax_certification';\n\n/** Signing-state machine status for a document submission. */\nexport type DocumentSubmissionStatus = DocumentSubmissionStatusDto;\n\n/** The tax form derived from the entity's kind (individual vs company/trust). */\nexport type DocumentFormType = DocumentFormTypeDto;\n\n/** Result of starting (or resuming) a document signing submission. */\nexport type DocumentSubmission = {\n status: DocumentSubmissionStatus;\n formType: DocumentFormType;\n};\n\nexport const DocumentSubmission = {\n fromDto: (dto: DocumentSubmissionDto): DocumentSubmission => ({\n status: dto.status,\n formType: dto.form_type,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/universal/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/universal/types/dto/document-submission';\n\n/**\n * Starts (or resumes) a document signing submission for the given type.\n *\n * `fields` are signing-form values keyed by the document's DocuSeal field\n * names (e.g. `\"Full Name\"`, `\"Permanent Address\"`) and are forwarded\n * verbatim to Passport to pre-fill the document. They are not validated or\n * persisted by Frontline.\n */\nexport async function submitDocument(\n api: Sender,\n documentType: DocumentType,\n fields: Record<string, string>\n): Promise<DocumentSubmission> {\n const dto = await api.send<DocumentSubmissionDto>({\n method: 'POST',\n url: `/v1/documents/${documentType}/submission`,\n body: fields,\n attributes: Attributes.protected(),\n });\n return DocumentSubmission.fromDto(dto);\n}\n","import type { KycTokenDto } from '@/universal/types/dto/kyc';\n\n/**\n * Sumsub verification level name. Determines which screens the Sumsub WebSDK\n * shows (levels are configured in the Sumsub dashboard). The backend\n * prescribes the level (and whether the applicant must be reset first) in the\n * requirement statuses response — clients never compute levels themselves.\n */\nexport type KycLevelName = string;\n\n/** Short-lived Sumsub WebSDK access token scoped to the current user. */\nexport type KycToken = {\n token: string;\n};\n\nexport const KycToken = {\n fromDto: (dto: KycTokenDto): KycToken => ({\n token: dto.token,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { KycTokenDto } from '@/universal/types/dto/kyc';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport { KycToken } from '@/universal/types/kyc';\n\nexport async function createKycToken(\n api: Sender,\n levelName?: KycLevelName,\n reset?: boolean\n): Promise<KycToken> {\n const dto = await api.send<KycTokenDto>({\n method: 'POST',\n url: '/v1/kyc-token',\n body: {\n ...(levelName === undefined ? {} : { level_name: levelName }),\n ...(reset === undefined ? {} : { reset }),\n },\n attributes: Attributes.protected(),\n });\n return KycToken.fromDto(dto);\n}\n","import type {\n PiiAddressDto,\n PiiDto,\n PiiJurisdictionDto,\n PiiKindDto,\n} from '@/universal/types/dto/pii';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/** Whether the PII belongs to an individual or a company/trust entity. */\nexport type PiiKind = PiiKindDto;\n\n/** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */\nexport type Iso2CountryCode = Newtype<string, 'Iso2CountryCode'>;\nexport const Iso2CountryCode = (value: string) => value as Iso2CountryCode;\n\n/** Jurisdiction derived from the entity's address country. */\nexport type PiiJurisdiction = {\n iso2: Iso2CountryCode;\n name: string | null;\n};\n\nexport const PiiJurisdiction = {\n fromDto: (dto: PiiJurisdictionDto): PiiJurisdiction => ({\n iso2: Iso2CountryCode(dto.iso_2),\n name: dto.name,\n }),\n};\n\n/** Permanent address on file for the entity. */\nexport type PiiAddress = {\n street: string | null;\n city: string | null;\n state: string | null;\n postalCode: string | null;\n country: string | null;\n};\n\nexport const PiiAddress = {\n fromDto: (dto: PiiAddressDto): PiiAddress => ({\n street: dto.street,\n city: dto.city,\n state: dto.state,\n postalCode: dto.postal_code,\n country: dto.country,\n }),\n};\n\n/**\n * The current user's PII, used to pre-fill tax forms such as the W-8BEN.\n * Fields the entity hasn't provided are `null`.\n */\nexport type Pii = {\n kind: PiiKind;\n fullLegalName: string | null;\n dateOfBirth: string | null;\n jurisdiction: PiiJurisdiction | null;\n taxId: string | null;\n permanentAddress: PiiAddress;\n};\n\nexport const Pii = {\n fromDto: (dto: PiiDto): Pii => ({\n kind: dto.kind,\n fullLegalName: dto.full_legal_name,\n dateOfBirth: dto.date_of_birth,\n jurisdiction: dto.jurisdiction\n ? PiiJurisdiction.fromDto(dto.jurisdiction)\n : null,\n taxId: dto.tax_id,\n permanentAddress: PiiAddress.fromDto(dto.permanent_address),\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { PiiDto } from '@/universal/types/dto/pii';\nimport { Pii } from '@/universal/types/pii';\n\nexport async function fetchPii(api: Sender): Promise<Pii> {\n const dto = await api.send<PiiDto>({\n method: 'GET',\n url: '/v1/pii',\n attributes: Attributes.protected(),\n });\n return Pii.fromDto(dto);\n}\n","import * as documentsApi from '@/universal/api/frontline/documents';\nimport * as kycApi from '@/universal/api/frontline/kyc';\nimport * as piiApi from '@/universal/api/frontline/pii';\nimport * as requirementsApi from '@/universal/api/frontline/requirements';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/universal/types/document-submission';\nimport type { KycLevelName, KycToken } from '@/universal/types/kyc';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Pii } from '@/universal/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport type CreateKycTokenParams = {\n /**\n * Sumsub verification level to run. Defaults to the backend's standard\n * level.\n */\n levelName?: KycLevelName;\n /**\n * Resets the Sumsub applicant first, so an already-approved level can be\n * executed again (e.g. to update stale PII). Pass the `kycReset` value from\n * the requirement status, and never on mid-flow token refreshes.\n */\n reset?: boolean;\n};\n\nexport type SubmitDocumentParams = {\n /** Currently only `tax_certification` (W-8BEN / W-8BEN-E). */\n documentType: DocumentType;\n /**\n * Signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to pre-fill the document.\n */\n fields: Record<string, string>;\n};\n\n/**\n * Everything a user must satisfy before they can participate in an offer:\n * reading the checklist and its live statuses, and the operations that satisfy\n * individual requirements — identity verification (KYC) and tax-document\n * signing.\n *\n * Wallet requirements (`external_wallet`, `whitelisted_wallet`) are satisfied\n * through `WalletsNamespace` instead, since wallet proofs are also used\n * outside the requirements flow.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface RequirementsNamespace {\n /**\n * Fetches the requirements for every option of an offer, grouped by option\n * id. This is the definition of the checklist; {@link statuses} tells you\n * where the user stands against it.\n */\n forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;\n\n /**\n * Fetches the current user's status for each requirement of an offer.\n */\n statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n\n /**\n * Creates a short-lived Sumsub WebSDK access token so an identity\n * verification (KYC) flow can be started, e.g. by the `IdentityVerification`\n * component.\n */\n createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;\n\n /**\n * Fetches the current user's PII, used to pre-fill tax forms such as the\n * W-8BEN. Fields the entity hasn't provided are `null`.\n */\n getPii(): Promise<Pii>;\n\n /**\n * Starts (or resumes) a document signing submission.\n */\n submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;\n}\n\nexport class RequirementsNamespaceImpl implements RequirementsNamespace {\n protected readonly log: InternalLogger;\n\n constructor(protected readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'REQUIREMENTS');\n }\n\n async forOffer(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchOfferRequirements(\n this.ctx.api,\n offerId,\n undefined\n );\n });\n }\n\n async statuses(offerId: OfferId): Promise<RequirementStatusInfo[]> {\n return this.log.wrap('statuses', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.ctx.api, offerId);\n });\n }\n\n async createKycToken(params?: CreateKycTokenParams): Promise<KycToken> {\n return this.log.wrap('createKycToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return kycApi.createKycToken(\n this.ctx.api,\n params?.levelName,\n params?.reset\n );\n });\n }\n\n async getPii(): Promise<Pii> {\n return this.log.wrap('getPii', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return piiApi.fetchPii(this.ctx.api);\n });\n }\n\n async submitDocument(\n params: SubmitDocumentParams\n ): Promise<DocumentSubmission> {\n return this.log.wrap('submitDocument', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return documentsApi.submitDocument(\n this.ctx.api,\n params.documentType,\n params.fields\n );\n });\n }\n}\n","import type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport * as requirementsApi from '@/universal/api/frontline/requirements';\nimport {\n type RequirementsNamespace,\n RequirementsNamespaceImpl,\n} from '@/universal/core/requirements/requirements-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Requirement } from '@/universal/types/requirement';\n\n/**\n * The server-side requirements namespace: the same surface as the shared\n * {@link RequirementsNamespace}, except {@link forOffer} — the offer's\n * requirement definitions are app-level data, so it is additionally callable\n * with a token from `ServerAuthNamespace.clientCredentials`.\n *\n * Everything else is per-user data and needs a user session. `handle` is\n * client-only: there is no browser tab to open on a server.\n */\nexport interface ServerRequirementsNamespace extends RequirementsNamespace {\n /** @param clientCreds app-level token to read without a user session. */\n forOffer(\n offerId: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n}\n\nexport class ServerRequirementsNamespaceImpl\n extends RequirementsNamespaceImpl\n implements ServerRequirementsNamespace\n{\n constructor(\n private readonly serverCtx: UniversalNamespaceContext &\n ServerNamespaceContext\n ) {\n super(serverCtx);\n }\n\n async forOffer(\n offerId: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', { offerId, clientCreds }, async () => {\n await this.serverCtx.ensureAuthenticated(clientCreds);\n return requirementsApi.fetchOfferRequirements(\n this.serverCtx.api,\n offerId,\n clientCreds\n );\n });\n }\n}\n","/**\n * Base URL of CoinList's public token registry (Nabu), a static CDN serving\n * token display metadata keyed by chain + contract address. Override per\n * environment via `Config.tokensBaseUrl`.\n */\nexport const NABU_BASE_URL = 'https://asset.coinlist.co';\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { Asset, type AssetId } from '@/universal/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/universal/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/universal/types/offer-detail';\nimport { PaginationParams } from '@/universal/types/pagination';\n\n/** Unique identifier for a participation. */\nexport type ParticipationId = Newtype<string, 'ParticipationId'>;\n/** Casts a string into a typed {@link ParticipationId}. */\nexport const ParticipationId = (value: string) => value as ParticipationId;\n\n/** Blockchain identifier for where a participation is funded. */\nexport type Blockchain = Newtype<string, 'Blockchain'>;\n/** Casts a string into a typed {@link Blockchain}. */\nexport const Blockchain = (value: string) => value as Blockchain;\n\n/** Wallet address used for a participation. */\nexport type WalletAddress = Newtype<`0x${string}`, 'WalletAddress'>;\n/** Casts a `0x`-prefixed string into a typed {@link WalletAddress}. */\nexport const WalletAddress = (value: `0x${string}`) => value as WalletAddress;\n\n/** Possible participation lifecycle states returned by the API. */\nexport type ParticipationStatus = ParticipationStatusDto;\n\n/** Domain model for a participation returned by CoinList APIs. */\nexport type Participation = {\n /** Unique participation id. */\n id: ParticipationId;\n /** Parent offer id. */\n offerId: OfferIdType;\n /** Selected offer option id. */\n offerOptionId: OfferOptionIdType;\n /** Current processing status. */\n status: ParticipationStatus;\n /** Raw participation amount from API. */\n amount: string;\n /** Human-readable formatted amount from API. */\n displayAmount: string;\n /** Asset metadata for the participation amount. */\n asset: Asset;\n /** Funding chain identifier. */\n chain: Blockchain;\n /** Creation timestamp, if returned by API. */\n insertedAt: Date | null;\n /** Last update timestamp, if returned by API. */\n updatedAt: Date | null;\n /** Wallet used for participation, blank values normalized to null. */\n walletAddress: WalletAddress | null;\n};\n\n/** Parameters required to create a new participation. */\nexport type CreateParticipationParams = {\n /** Offer to participate in. */\n offerId: OfferIdType;\n /** Offer option selected for participation. */\n offerOptionId: OfferOptionIdType;\n /** Blockchain for funding. */\n chain: Blockchain;\n /** Wallet address that funds the participation. */\n walletAddress: WalletAddress;\n /**\n * Decimal token amount to participate with (e.g. `\"100\"` for 100 USDC), NOT\n * raw base units. The backend rescales this by the asset's decimals to verify\n * it against the on-chain approval allowance.\n */\n amount: string;\n /** Funding asset id. */\n assetId: AssetId;\n /**\n * Hash of the ERC-20 `approve()` transaction covering this participation.\n * Required: the backend verifies it on-chain (sender, token, spender, and\n * approved amount) before confirming the participation.\n */\n approvalTransactionHash: string;\n};\n\n/** Pagination params for listing participations, with an optional offer filter. */\nexport interface ParticipationsPaginationParams extends PaginationParams {\n offerId?: OfferIdType;\n}\n\nexport const ParticipationsPaginationParams = {\n toQueryParams: (\n params: ParticipationsPaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams = PaginationParams.toQueryParams(params);\n if (params.offerId) {\n queryParams['filters[0][field]'] = 'offer_id';\n queryParams['filters[0][op]'] = '==';\n queryParams['filters[0][value]'] = params.offerId;\n }\n return queryParams;\n },\n};\n\nexport const Participation = {\n /** Maps API DTO shape into the SDK participation domain model. */\n fromDto: (dto: ParticipationDto): Participation => {\n const walletAddress = notBlankStringOrNull(dto.wallet_address);\n return {\n id: ParticipationId(dto.id),\n offerId: OfferId(dto.offer_id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n status: dto.status,\n amount: dto.amount,\n displayAmount: dto.amount_string,\n asset: Asset.fromDto(dto.asset),\n chain: Blockchain(dto.chain),\n insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,\n updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,\n walletAddress: walletAddress\n ? WalletAddress(walletAddress as `0x${string}`)\n : null,\n };\n },\n};\n\nexport const CreateParticipationParams = {\n /** Maps participation creation params into API DTO payload. */\n toDto: (params: CreateParticipationParams): CreateParticipationDto => ({\n offer_id: params.offerId,\n offer_option_id: params.offerOptionId,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount,\n asset_id: params.assetId,\n approval_transaction_hash: params.approvalTransactionHash,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ParticipationDto } from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { OfferId } from '@/universal/types/offer';\nimport { PaginatedResponse } from '@/universal/types/pagination';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\nexport async function fetchParticipations(\n api: Sender,\n offerId?: OfferId\n): Promise<Participation[]> {\n return fetchAllPages<Participation, ParticipationsPaginationParams>(\n (params) => fetchParticipationsPage(api, params),\n { offerId }\n );\n}\n\nexport async function fetchParticipationsPage(\n api: Sender,\n params: ParticipationsPaginationParams\n): Promise<PaginatedResponse<Participation>> {\n const pageDto = await api.send<PaginatedResponseDto<ParticipationDto>>({\n method: 'GET',\n url: '/v1/participations',\n queryParams: ParticipationsPaginationParams.toQueryParams(params),\n attributes: Attributes.protected(),\n });\n return PaginatedResponse.fromDto(pageDto, Participation.fromDto);\n}\n\nexport async function fetchParticipation(\n api: Sender,\n id: ParticipationId\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'GET',\n url: `/v1/participations/${id}`,\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n\nexport async function createParticipation(\n api: Sender,\n params: CreateParticipationParams\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'POST',\n url: '/v1/participations',\n body: CreateParticipationParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n","import * as participationsApi from '@/universal/api/frontline/providers/coin-list/token-sale';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { PaginatedResponse } from '@/universal/types/pagination';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\n/**\n * Read/write operations for token sales: listing and reading the current user's\n * participations, and recording a new one. The on-chain execution flow\n * (`executeTokenSale`) is layered on top of this in the client-side namespace.\n */\nexport interface CoinListTokenSaleNamespace {\n /**\n * Fetches all participations by iterating through every paginated response,\n * optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n list(offerId?: OfferId): Promise<Participation[]>;\n\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n\n /**\n * Fetches a participation by id.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n get(id: ParticipationId): Promise<Participation>;\n\n /**\n * Records a participation with CoinList.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n}\n\nexport class CoinListTokenSaleNamespaceImpl\n implements CoinListTokenSaleNamespace\n{\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'TOKEN_SALE');\n }\n\n async list(offerId?: OfferId): Promise<Participation[]> {\n return this.log.wrap('list', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipations(this.ctx.api, offerId);\n });\n }\n\n async listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipationsPage(this.ctx.api, params);\n });\n }\n\n async get(id: ParticipationId): Promise<Participation> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipation(this.ctx.api, id);\n });\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n return this.log.wrap('createParticipation', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.createParticipation(this.ctx.api, params);\n });\n }\n}\n","import { formatUnits } from 'viem';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport { AssetDecimals } from '@/universal/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/universal/types/blockchain/ui';\n\nexport function shortenAddress(\n address: EvmWalletAddress\n): ShortenedWalletAddress {\n const short =\n address.length > 10\n ? `${address.slice(0, 6)}…${address.slice(-4)}`\n : address;\n return ShortenedWalletAddress(short);\n}\n\nexport type FormatAmountOptions = {\n maxFractionDigits?: AssetDecimals;\n};\n\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 type { Newtype } from '@/universal/types/newtype';\n\nexport type FormattedAmountUi = Newtype<string, 'FormattedAmountUi'>;\nexport const FormattedAmountUi = (value: string): FormattedAmountUi =>\n value as FormattedAmountUi;\n\nexport type FormattedPercentUi = Newtype<string, 'FormattedPercentUi'>;\nexport const FormattedPercentUi = (value: string): FormattedPercentUi =>\n value as FormattedPercentUi;\n\nexport type TxExplorerUrl = Newtype<string, 'TxExplorerUrl'>;\nexport const TxExplorerUrl = (value: string): TxExplorerUrl =>\n value as TxExplorerUrl;\n\n/**\n * A wallet address shortened for display (e.g. `0x1234…5678`). Keeps a\n * `0x${string}` base but drops the runtime `0x` narrowing.\n */\nexport type ShortenedWalletAddress = Newtype<\n `0x${string}`,\n 'ShortenedWalletAddress'\n>;\nexport const ShortenedWalletAddress = (value: string): ShortenedWalletAddress =>\n value as ShortenedWalletAddress;\n\nexport type FormattedAmountAssetUi = Newtype<string, 'FormattedAmountAssetUi'>;\nexport const FormattedAmountAssetUi = (value: string): FormattedAmountAssetUi =>\n value as FormattedAmountAssetUi;\n\nexport type AssetIconUrl = Newtype<string, 'AssetIconUrl'>;\nexport const AssetIconUrl = (value: string): AssetIconUrl =>\n value as AssetIconUrl;\n","import type { Hash } from 'viem';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport { TxExplorerUrl } from '@/universal/types/blockchain/ui';\nimport { ValidationError } from '@/universal/types/errors';\n\n/**\n * The one 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","import { parseUnits } from 'viem';\nimport {\n type AssetDecimals,\n assertUint256,\n BlockchainAmount,\n MAX_UINT_256,\n} from '@/universal/types/blockchain/core';\nimport { ValidationError } from '@/universal/types/errors';\n\n/** A typed, i18n-agnostic reason a raw amount string failed to parse. */\nexport type AmountParseErrorReason =\n | { type: 'empty' }\n | { type: 'negative' }\n | { type: 'invalid-format' }\n | { type: 'too-many-decimals'; maxDecimals: AssetDecimals }\n /** Scaled up by `decimals`, the amount no longer fits a uint256. */\n | { type: 'overflow' };\n\nexport type AmountParseResult =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; reason: AmountParseErrorReason };\n\n/**\n * Wraps a raw uint256 base-unit string — what Ondo and the on-chain reads\n * return (\"100000000\" is 100 USDC, not 100 wei-of-nothing) — in a\n * {@link BlockchainAmount} at the given decimals. The value is already scaled,\n * so `decimals` is only the unit tag that travels with it.\n *\n * Distinct from {@link parseBlockchainAmount}, which takes a *human decimal*\n * string and scales it up. Feeding a raw amount to that one silently\n * multiplies it by 10^decimals — pick by what the backend sends, not by which\n * one is closer at hand.\n *\n * @throws ValidationError when the string is not a non-negative uint256\n * integer. A backend that regresses to decimal strings fails loudly here\n * rather than truncating.\n */\nexport function blockchainAmountFromRawOrThrow({\n label,\n raw,\n decimals,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n}): BlockchainAmount {\n const trimmed = raw.trim();\n // BigInt('') is 0n, not an error — an absent amount must not read as zero.\n if (trimmed === '') {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n let value: bigint;\n try {\n // BigInt() rejects \"0.5\", \"abc\" and \"1e18\" by throwing SyntaxError.\n value = BigInt(trimmed);\n } catch {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n try {\n return BlockchainAmount({ raw: assertUint256(value), decimals });\n } catch {\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n }\n}\n\n/**\n * Parses a user-entered decimal string into a {@link BlockchainAmount} at the\n * given token decimals. Rejects scientific notation, negatives, malformed\n * input, more fractional digits than the token supports, and amounts that\n * scale past uint256 — surfacing a typed {@link AmountParseErrorReason} so\n * callers own the display copy.\n */\nexport function parseBlockchainAmount(\n amount: string,\n decimals: AssetDecimals\n): AmountParseResult {\n const trimmed = amount.trim();\n if (trimmed === '') return { valid: false, reason: { type: 'empty' } };\n if (trimmed.startsWith('-')) {\n return { valid: false, reason: { type: 'negative' } };\n }\n // viem accepts \"1e18\" as scientific notation — reject it explicitly\n if (/[eE]/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // reject bare decimal point 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 type { Newtype } from '@/universal/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 '@/universal/core/shared/blockchain/chain';\nimport { blockchainAmountFromRawOrThrow } from '@/universal/core/shared/blockchain/math';\nimport {\n AssetDecimals,\n AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n HexEncodedTransactionData,\n type Tx,\n} from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoSwapDtoCore,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport { type OrderBookSide, Ticker } from '@/universal/types/trading';\n\n/**\n * Whether an Ondo asset can be traded right now.\n *\n * The caps only mean anything while trading is open, so they live on the\n * `tradable` branch. They stay {@link DecimalString} rather than\n * {@link BlockchainAmount} because the response carries no `asset_decimals`:\n * there is no honest exponent to attach, and the USD caps arrive with more\n * fractional digits than a stablecoin has decimals.\n *\n * Each cap is independently nullable even when tradable — Ondo may open an\n * asset for trading without publishing every limit.\n *\n * `side` is carried through from the response rather than dropped: the whole\n * status describes one side, so a buy and a sell status are otherwise\n * indistinguishable once a caller holds both.\n */\nexport type OndoTradingStatus =\n | {\n type: 'tradable';\n side: OrderBookSide;\n /** Largest order in whole tokens. */\n grossMaxTokens: DecimalString | null;\n /** Largest order in USD. */\n grossMaxNotionalValue: DecimalString | null;\n /** USD cap for the session the market is currently in. */\n grossMaxActiveNotionalValue: DecimalString | null;\n }\n | {\n type: 'not-tradable';\n side: OrderBookSide;\n };\n\nexport const OndoTradingStatus = {\n fromDto: (dto: OndoTradingStatusDto): OndoTradingStatus => {\n if (!dto.tradable) return { type: 'not-tradable', side: dto.side };\n return {\n type: 'tradable',\n side: dto.side,\n grossMaxTokens: decimalOrNull(dto.gross_max_tokens),\n grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),\n grossMaxActiveNotionalValue: decimalOrNull(\n dto.gross_max_active_notional_value\n ),\n };\n },\n};\n\nconst decimalOrNull = (value: string | null): DecimalString | null =>\n value === null ? null : DecimalString(value);\n\n/**\n * An indicative price for an Ondo asset, free to poll while the user edits an\n * order.\n *\n * **No CoinList fee is applied to the quantity or the price.** Ondo prices\n * exactly the amount asked for. A CoinList approval is fee-inclusive, so\n * sizing a quote against one without netting the fee first overstates what the\n * user receives. Showing a gross/net breakdown needs a CoinList swap\n * contract's `preview`, and no such contract exists for Ondo yet.\n *\n * The quote carries no transaction to broadcast and no expiry. Building one is\n * a separate endpoint per side that spends an attestation - see\n * {@link OndoBuyTransaction} and {@link OndoSellTransaction}.\n */\nexport type OndoQuote = {\n /** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */\n chain: EthereumChain;\n ticker: Ticker;\n /**\n * Needed to approve or transfer the asset; the quote is the only source.\n *\n * **Resolved on Ethereum mainnet**, like everything else on this quote, and\n * therefore not necessarily the contract the swap pulls from on the chain\n * the order executes on. Frontline resolves that one per chain and publishes\n * it nowhere, so on a testnet these are two different tokens. Tracked\n * against the frontline stack that follows ENG-1756.\n */\n assetAddress: EvmContractAddress;\n /**\n * The asset as the quote resolves it, from frontline's own catalogue.\n *\n * Its `decimals` scale {@link tokenBaseUnits} and nothing else. They are\n * **not** the scale of a built transaction's spend or output: those are\n * reported by whatever priced them, the sources are allowed to disagree, and\n * only the one that produced a number answers for it.\n */\n asset: Erc20Asset;\n side: OrderBookSide;\n tokenBaseUnits: BlockchainAmount;\n /**\n * USD price of one whole token. Unscaled because Ondo has already scaled it,\n * and by USDon's 18 decimals rather than the stablecoin's 6 — re-scaling it\n * by either would be wrong.\n */\n price: DecimalString;\n};\n\nexport const OndoQuote = {\n fromDto: (dto: OndoQuoteDto): OndoQuote => {\n const assetDecimals = AssetDecimals(dto.asset_decimals);\n return {\n chain: chainFromId(dto.chain_id),\n ticker: Ticker(dto.ticker),\n assetAddress: EvmContractAddress(dto.asset_address),\n asset: {\n name: dto.ticker,\n symbol: AssetSymbol(dto.symbol),\n decimals: assetDecimals,\n },\n side: dto.side,\n tokenBaseUnits: blockchainAmountFromRawOrThrow({\n label: 'tokenBaseUnits',\n raw: dto.token_base_units,\n decimals: assetDecimals,\n }),\n price: DecimalString(dto.price),\n };\n },\n};\n\n/**\n * The half of a built swap that both sides share: the calldata, its deadline,\n * and what the wallet parts with.\n *\n * There is deliberately **no union over the two sides**. Each is built by its\n * own endpoint and its own namespace method, so a caller never holds one\n * without knowing which it is, and a union would only re-pose a question the\n * call site had already answered. What is genuinely common lives here, and\n * {@link executeOndoSwap} takes this rather than either arm - broadcasting\n * knows nothing about the direction of the trade.\n *\n * `side` is not on this type but on each arm, as a literal the SDK authors\n * from the method that was called. The wire stopped echoing one when the\n * endpoint split, and it is still worth carrying: `OndoOrderPlaced` is a union\n * the SDK builds from both, and that union needs a tag.\n */\nexport type OndoSwapTransactionCore = {\n /**\n * Broadcast as-is. The `to` is the swap contract, which is also the ERC-20\n * spender the user must have approved.\n */\n tx: Tx;\n /**\n * When the calldata stops being accepted. A transaction broadcast after this\n * reverts, so callers must compare against it before signing.\n */\n expiresAt: Date;\n /**\n * Gross amount the wallet spends, in the decimals of the token this side\n * spends: the funding token on a buy, the asset on a sell.\n *\n * The same field at two scales, which is the whole reason the two sides are\n * two types. It is also what the approval has to cover.\n */\n spendInputAmount: BlockchainAmount;\n};\n\n/**\n * A signed, expiring purchase: a funding token in, an exact quantity of the\n * asset out.\n *\n * Distinct from {@link OndoQuote} in three ways that matter: it costs an\n * attestation to obtain, it expires, and it carries a {@link Tx} the wallet\n * broadcasts verbatim. Treat it as single-use - once broadcast (or once\n * `expiresAt` passes) it is spent, and a new one must be built.\n *\n * **The quantity is attested and exact, with no floor beneath it.** That is\n * what separates it from an {@link OndoSellTransaction}, which commits to a\n * range: nothing here is an estimate.\n *\n * **It carries no other identity.** No chain, ticker or asset: the endpoint\n * publishes none of them, and inventing them from the request would assert\n * what the server resolved rather than report it. What it does publish is the\n * scale of every amount on it, so a caller needs nothing alongside it to read\n * the numbers - only to name the assets, which the offer already does.\n *\n * It carries no price either. See `computeOndoBuyPrice`, which derives it from\n * the amounts the response does carry - the price this transaction fills at,\n * rather than an indicative one that has since moved.\n */\nexport type OndoBuyTransaction = OndoSwapTransactionCore & {\n side: 'buy';\n /**\n * CoinList's cut, in `spendInputAmount`'s decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Taken at execution rather than added on top, so the approval never has to\n * cover more than `spendInputAmount`.\n */\n fee: BlockchainAmount;\n /**\n * `spendInputAmount` less `fee`, in the same decimals: what Ondo priced, and\n * the numerator of the fill price.\n *\n * Read from the response rather than subtracted here. Whether the fee comes\n * off the deposit or goes on top of it is the server's definition to change,\n * and a client that derives this cannot notice when it does.\n */\n notionalValue: BlockchainAmount;\n /**\n * Quantity of the asset the wallet receives, at the scale whatever priced it\n * reported - not at the {@link OndoQuote}'s `asset.decimals`.\n */\n receiveOutputAmount: BlockchainAmount;\n};\n\nexport const OndoBuyTransaction = {\n fromDto: (dto: OndoBuyDto): OndoBuyTransaction => {\n // Read once each, so a mapper that reached for the wrong exponent on one\n // of the amounts is a visible mistake rather than a plausible one.\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'buy',\n fee: blockchainAmountFromRawOrThrow({\n label: 'fee',\n raw: dto.fee,\n decimals: spendDecimals,\n }),\n notionalValue: blockchainAmountFromRawOrThrow({\n label: 'notional_value',\n raw: dto.notional_value,\n decimals: spendDecimals,\n }),\n receiveOutputAmount: parsePositiveAmount({\n label: 'receive_output_amount',\n raw: dto.receive_output_amount,\n decimals: outputDecimals,\n // A transaction that yields nothing is not one to sign - the user\n // would pay the deposit and receive no asset - and frontline refuses\n // to emit one. A zero here is a changed encoding, not a small order.\n // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`\n // divide by it without a fallible result: the failure surfaces as the\n // data hook's ERROR state rather than as a division during render.\n reason: 'a buy that yields nothing is not fillable',\n }),\n };\n },\n};\n\n/**\n * One end of the range a sale commits to: what arrives, and what CoinList took\n * to get it there.\n *\n * The two travel together because they are charged against each other -\n * `quantity` is already **net** of `fee` - and because the pair a caller wants\n * is always both halves of the same outcome. Grouping them is what makes\n * \"the expected quantity, less the fee at the floor\" unrepresentable rather\n * than merely wrong.\n */\nexport type OndoSellOutcome = {\n /** What the wallet receives at this outcome, net of {@link fee}. */\n quantity: BlockchainAmount;\n /**\n * CoinList's cut at this outcome, in the same decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Already deducted from {@link quantity} rather than charged on top of it.\n */\n fee: BlockchainAmount;\n};\n\n/**\n * A signed, expiring sale: the asset in, a settlement coin out, somewhere\n * between two published outcomes.\n *\n * Single-use and expiring for the same reasons as an {@link OndoBuyTransaction},\n * and obtained the same way - one endpoint, one attestation.\n *\n * **A sale commits to a range, not a quantity.** Ondo settles through USDon\n * before converting to the settlement token, so {@link expected} is what to\n * expect and {@link minimum} is what the calldata enforces. A screen that\n * shows only the first presents a firm-looking number the contract may\n * legitimately fill below.\n *\n * There is deliberately no counterpart to a buy's `notionalValue`. A sale\n * commits on the output side, so frontline reports no fee-exclusive input and\n * refuses to relate numbers Ninshubur did not relate. What it does relate is\n * each quantity to the fee beside it, which is why {@link OndoSellOutcome}\n * pairs them.\n *\n * One thing this type cannot see: the floor signed into `tx.data` is gross of\n * the fee, so a caller decoding the calldata finds a larger number than\n * `minimum.quantity`. Both are correct; `minimum.quantity` is what the wallet\n * actually receives.\n */\nexport type OndoSellTransaction = OndoSwapTransactionCore & {\n side: 'sell';\n /** What the sale is expected to return. An expectation, not a guarantee. */\n expected: OndoSellOutcome;\n /**\n * The floor the calldata enforces. A fill below it reverts on chain, so this\n * - not {@link expected} - is what a seller is actually guaranteed.\n */\n minimum: OndoSellOutcome;\n};\n\nexport const OndoSellTransaction = {\n fromDto: (dto: OndoSellDto): OndoSellTransaction => {\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n // One exponent for all four amounts below, unlike a buy where the fee\n // follows the spend. A sale takes its cut from the coin it settles in.\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n const expectedQuantity = parsePositiveAmount({\n label: 'expected_quantity',\n raw: dto.expected_quantity,\n decimals: outputDecimals,\n reason: 'a sale that yields nothing is not fillable',\n });\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'sell',\n expected: {\n quantity: expectedQuantity,\n fee: blockchainAmountFromRawOrThrow({\n label: 'expected_fee',\n raw: dto.expected_fee,\n decimals: outputDecimals,\n }),\n },\n minimum: {\n quantity: parseMinimumQuantity(\n dto.minimum_quantity,\n outputDecimals,\n expectedQuantity\n ),\n fee: blockchainAmountFromRawOrThrow({\n label: 'minimum_fee',\n raw: dto.minimum_fee,\n decimals: outputDecimals,\n }),\n },\n };\n },\n};\n\n/**\n * The three fields both responses carry, mapped once.\n *\n * `spendDecimals` is passed in rather than read here because a buy also\n * denominates its `fee` and `notionalValue` in it, so reading it twice would\n * leave two places to get wrong.\n */\nfunction parseSwapCore(\n dto: OndoSwapDtoCore,\n spendDecimals: AssetDecimals\n): OndoSwapTransactionCore {\n return {\n tx: {\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n },\n expiresAt: parseExpiresAt(dto.expires_at),\n spendInputAmount: parsePositiveAmount({\n label: 'spend_input_amount',\n raw: dto.spend_input_amount,\n decimals: spendDecimals,\n // A transaction that takes nothing from the wallet is not one to sign:\n // it would settle one leg of a trade and skip the other. Frontline\n // refuses an `amount` of zero whichever way the trade runs, so this is a\n // changed encoding rather than a small order.\n //\n // Guarded on both sides rather than on the sale alone, because which\n // amount becomes the divisor in the price flips with the direction: a\n // guard placed by that would be a rule about the arithmetic rather than\n // about the trade.\n reason: 'a swap that spends nothing is not fillable',\n }),\n };\n}\n\n/**\n * The floor under a sale's proceeds, refused when it cannot be one.\n *\n * A floor above the amount it is a floor on cannot be filled: the calldata\n * would revert on every outcome. Frontline validates both bounds\n * (`minimum <= expected`, and `> 0`), so either is a changed encoding rather\n * than a tight quote.\n *\n * Rejecting them at the boundary is what lets the review screen render the\n * pair without deciding what to do when they contradict each other - the\n * failure surfaces as the data hook's ERROR state instead.\n */\nfunction parseMinimumQuantity(\n raw: string,\n decimals: AssetDecimals,\n expectedQuantity: BlockchainAmount\n): BlockchainAmount {\n const amount = parsePositiveAmount({\n label: 'minimum_quantity',\n raw,\n decimals,\n reason: 'a floor of zero guarantees nothing',\n });\n if (amount.raw > expectedQuantity.raw) {\n throw new ValidationError(\n `minimum_quantity: must not exceed expected_quantity (\"${raw}\" > \"${expectedQuantity.raw}\")`\n );\n }\n return amount;\n}\n\n/**\n * An amount the trade cannot proceed without, refused at zero.\n *\n * `reason` says what the zero would have meant, so the message names the trade\n * rather than the field alone - the same field is a deposit on one side and a\n * quantity of shares on the other.\n */\nfunction parsePositiveAmount({\n label,\n raw,\n decimals,\n reason,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n reason: string;\n}): BlockchainAmount {\n const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });\n if (amount.raw <= 0n) {\n throw new ValidationError(\n `${label}: must be greater than zero (\"${raw}\") - ${reason}`\n );\n }\n return amount;\n}\n\n/**\n * A transaction whose expiry cannot be read is not safely fillable - the\n * deadline is encoded in the calldata either way, so broadcasting against an\n * unknown one only spends gas on a revert. Fail here instead.\n */\nfunction parseExpiresAt(value: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n throw new ValidationError(`expires_at: not a date (\"${value}\")`);\n }\n return date;\n}\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport { formatRawAmount } from '@/universal/core/shared/blockchain/formatters';\nimport type { BlockchainAmount } from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\nexport async function getOndoTradingStatus(\n api: Sender,\n params: GetOndoTradingStatusParams\n): Promise<OndoTradingStatus> {\n const dto = await api.send<OndoTradingStatusDto>({\n method: 'GET',\n url: '/v1/ondo/swap/trading-status',\n queryParams: { symbol: params.symbol, side: params.side },\n attributes: Attributes.protected(),\n });\n return OndoTradingStatus.fromDto(dto);\n}\n\nexport async function getOndoQuote(\n api: Sender,\n params: GetOndoQuoteParams\n): Promise<OndoQuote> {\n const dto = await api.send<OndoQuoteDto>({\n method: 'GET',\n url: '/v1/ondo/swap/quote',\n queryParams: {\n symbol: params.symbol,\n side: params.side,\n duration: params.duration,\n ...sizeParam(params),\n },\n attributes: Attributes.protected(),\n });\n return OndoQuote.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a purchase: spends an attestation and\n * returns signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the funding token**, unlike\n * `getOndoQuote`'s `token_amount` which is in whole tokens: this number\n * becomes the ERC-20 pull encoded into the calldata, so it is the on-chain\n * integer, not a human figure. Frontline refuses zero, and refuses a wallet\n * whose allowance on that token does not cover it with a 422 carrying\n * `code: \"insufficient_allowance\"`.\n *\n * The body carries no `side`. It used to, optional on the wire and defaulting\n * to `buy`, which is exactly the silent default the endpoint split removed:\n * the path is now what says which trade to sign and which token's allowance to\n * read, and a request cannot lose it.\n */\nexport async function buildOndoBuy(\n api: Sender,\n params: BuildOndoBuyParams\n): Promise<OndoBuyTransaction> {\n const dto = await api.send<OndoBuyDto>({\n method: 'POST',\n url: '/v1/ondo/swap/buy',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'purchase',\n });\n return OndoBuyTransaction.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a sale: spends an attestation and returns\n * signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the asset**, which is the one thing\n * that makes this materially different from {@link buildOndoBuy} rather than a\n * mirror of it. The same integer means something 1e12 different on the two\n * sides, so an order sized in the funding token's units and posted here is not\n * a rejected request but a wrong one.\n *\n * Frontline reads the allowance on the **asset** before asking Ninshubur for\n * anything - a sale delivers it, so the swap contract pulls it with\n * `transferFrom` - and refuses a short one with a 422 carrying\n * `code: \"insufficient_allowance\"` and a message naming that address.\n */\nexport async function buildOndoSell(\n api: Sender,\n params: BuildOndoSellParams\n): Promise<OndoSellTransaction> {\n const dto = await api.send<OndoSellDto>({\n method: 'POST',\n url: '/v1/ondo/swap/sell',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'sale',\n // The two answers come from two chains, so on a testnet they can disagree\n // for a reason that is neither the caller's nor a corrupt response. Say so,\n // or a QA run reads as a puzzle rather than a diagnosis.\n note:\n 'the quote resolves the asset on Ethereum mainnet while the swap ' +\n 'executes on the chain requested, so these disagree until frontline ' +\n 'serves a chain-scoped quote',\n });\n return OndoSellTransaction.fromDto(dto);\n}\n\n/**\n * The four fields both endpoints take, spelled the same way for both.\n *\n * `amount` is the only one whose meaning forks, and it forks in the *token*\n * rather than in the encoding - a uint256 decimal string either way.\n */\nfunction swapBody(\n params: BuildOndoBuyParams | BuildOndoSellParams\n): Record<string, string> {\n return {\n symbol: params.symbol,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount.raw.toString(),\n };\n}\n\n/**\n * Refuses a response denominated in a different scale than the request was.\n *\n * The two are independent resolutions of the same token: the caller sized\n * `amount` in the coin it chose and approved, while frontline reads\n * `decimals()` on-chain from the token the side spends, which it resolves from\n * the offer. On a purchase they should never differ - an approval on some\n * other token reads as a zero allowance, which frontline refuses before it\n * signs anything - so a disagreement is a changed encoding rather than a user\n * error, the same reasoning the mapper rejects a zero amount under.\n *\n * Worth the check because of where the value lands: `spend_input_amount` at\n * the wrong exponent renders the review screen's committed amount orders of\n * magnitude out, on the screen where the user commits money.\n */\nfunction assertSpendScaleAgrees({\n published,\n sized,\n trade,\n note,\n}: {\n published: number;\n sized: BlockchainAmount;\n trade: 'purchase' | 'sale';\n note?: string;\n}): void {\n if (published === sized.decimals) return;\n const because = note === undefined ? '' : ` - ${note}`;\n throw new ValidationError(\n `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`\n );\n}\n\n/**\n * `token_amount` is in **whole tokens**, unlike the response's\n * `token_base_units` — Ondo names both `tokenAmount`, 1e18 apart. Hence the\n * unscale on the way out.\n *\n * The size is checked at runtime because the types do not cover it: TypeScript\n * rejects an object carrying *neither*, but against a union of object types it\n * accepts one carrying *both*, and a JavaScript caller gets no check at all.\n */\nfunction sizeParam(\n params: GetOndoQuoteParams\n): Record<string, QueryParamValues> {\n const tokenAmount = 'tokenAmount' in params ? params.tokenAmount : undefined;\n const notionalValue =\n 'notionalValue' in params ? params.notionalValue : undefined;\n\n if (tokenAmount !== undefined) {\n if (notionalValue !== undefined) {\n throw new ValidationError(\n 'An Ondo quote takes tokenAmount or notionalValue, not both'\n );\n }\n return { token_amount: formatRawAmount(tokenAmount) };\n }\n if (notionalValue === undefined) {\n throw new ValidationError(\n 'An Ondo quote must be sized by tokenAmount or notionalValue'\n );\n }\n return { notional_value: notionalValue };\n}\n","import {\n buildOndoBuy,\n buildOndoSell,\n getOndoQuote,\n getOndoTradingStatus,\n} from '@/universal/api/frontline/providers/ondo/ondo';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\n/**\n * Ondo swap reads, plus the write that turns one into a fillable transaction.\n *\n * The two reads are free to poll - neither spends an attestation, so a client\n * may call them while the user edits an order. The two builders are not:\n * budget one call per order placed, plus one per refresh the user asks for.\n *\n * **One builder per side, mirroring the endpoints.** A purchase and a sale\n * agree on how to broadcast and on nothing else: a purchase commits to an\n * exact quantity, a sale to a range with a floor beneath it, and `amount` is\n * the funding token on one and the asset on the other. A single method taking\n * a `side` would have to return a union the caller then re-narrows, having\n * already decided which trade it was placing.\n *\n * **No CoinList fee is applied to a read quote, and no read discloses one.**\n * Ondo prices exactly the amount passed. A CoinList approval is fee-inclusive,\n * so sizing a quote against a user's approval without subtracting the fee\n * first overstates what they receive. A built transaction carries the fee\n * explicitly, and it is zero until one lands (ENG-1718).\n *\n * Every method requires `AuthState === 'logged-in'` and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface OndoNamespace {\n getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus>;\n getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;\n /**\n * Builds a purchase for a specific wallet and deposit: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoBuyTransaction.expiresAt}.\n *\n * The wallet must have approved the swap contract to spend `amount` of the\n * offer's **funding token** first. Frontline reads that allowance before\n * asking Ninshubur for anything, and rejects a short one with a 422 carrying\n * `code: \"insufficient_allowance\"`. See `prepareBuy` on the client\n * namespace, which approves and then builds, in that order.\n *\n * The tokens themselves are the offer's rather than the caller's to name.\n */\n buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;\n /**\n * Builds a sale for a specific wallet and quantity: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoSellTransaction.expiresAt}.\n *\n * The approval this one needs is on the **asset**, not on a stablecoin - a\n * sale delivers the asset, so the swap contract pulls it with `transferFrom`\n * exactly as it pulls the deposit on a purchase. Same 422 when it is short,\n * with a message naming that address. See `prepareSell` on the client\n * namespace.\n *\n * Returns a range rather than a quantity: Ondo settles through USDon before\n * converting to the settlement token, so disclose\n * {@link OndoSellTransaction.minimum} and not only `expected`.\n */\n buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction>;\n}\n\nexport class OndoNamespaceImpl implements OndoNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ONDO');\n }\n\n async getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus> {\n return this.log.wrap('getTradingStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoTradingStatus(this.ctx.api, params);\n });\n }\n\n async getQuote(params: GetOndoQuoteParams): Promise<OndoQuote> {\n return this.log.wrap('getQuote', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoQuote(this.ctx.api, params);\n });\n }\n\n async buildBuyTransaction(\n params: BuildOndoBuyParams\n ): Promise<OndoBuyTransaction> {\n return this.log.wrap('buildBuyTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoBuy(this.ctx.api, params);\n });\n }\n\n async buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction> {\n return this.log.wrap('buildSellTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoSell(this.ctx.api, params);\n });\n }\n}\n","import {\n EvmContractAddress,\n HexEncodedTransactionData,\n parseUint256,\n type Uint256,\n} from '@/universal/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/universal/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 '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n} from '@/universal/types/blockchain/core';\nimport type {\n AllowWalletResponseDto,\n SwapOutputTokenDto,\n SwapPreviewDto,\n SwapStatusDto,\n TokenAllowanceDto,\n TokenBalanceDto,\n WalletAuthorizationDto,\n} from '@/universal/types/dto/providers/superstate/swap';\nimport {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n TokenAllowance,\n TokenBalance,\n} from '@/universal/types/providers/superstate/swap';\n\nexport async function getSwapAuthorization(\n api: Sender,\n params: GetSwapAuthorizationParams\n): Promise<SwapAuthorization> {\n const dto = await api.send<WalletAuthorizationDto>({\n method: 'GET',\n url: '/v1/wallet/authorized',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n wallet_address: params.walletAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapAuthorization.fromDto(dto);\n}\n\nexport async function getSwapOutputToken(\n api: Sender,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const dto = await api.send<SwapOutputTokenDto>({\n method: 'GET',\n url: '/v1/swap/output-token',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return toErc20Asset(dto);\n}\n\nexport async function getSwapPreview(\n api: Sender,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const dto = await api.send<SwapPreviewDto>({\n method: 'GET',\n url: '/v1/swap/preview',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n input_token: params.inputToken,\n amount: params.amount.toString(),\n },\n attributes: Attributes.protected(),\n });\n return SwapPreview.fromDto(dto);\n}\n\nexport async function getSwapStatus(\n api: Sender,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const dto = await api.send<SwapStatusDto>({\n method: 'GET',\n url: '/v1/swap/status',\n queryParams: {\n chain: params.chain,\n contract_address: params.contractAddress,\n },\n attributes: Attributes.protected(),\n });\n return SwapStatus.fromDto(dto);\n}\n\nexport async function getTokenAllowance(\n api: Sender,\n params: GetTokenAllowanceParams\n): Promise<TokenAllowance> {\n const dto = await api.send<TokenAllowanceDto>({\n method: 'GET',\n url: '/v1/token/allowance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n spender: params.spender,\n },\n attributes: Attributes.protected(),\n });\n return TokenAllowance.fromDto(dto);\n}\n\nexport async function getTokenBalance(\n api: Sender,\n params: GetTokenBalanceParams\n): Promise<TokenBalance> {\n const dto = await api.send<TokenBalanceDto>({\n method: 'GET',\n url: '/v1/token/balance',\n queryParams: {\n chain: params.chain,\n token_address: params.tokenAddress,\n owner: params.owner,\n },\n attributes: Attributes.protected(),\n });\n return TokenBalance.fromDto(dto);\n}\n\nexport async function allowWallet(\n api: Sender,\n params: AllowWalletParams\n): Promise<AllowWalletResponse> {\n const dto = await api.send<AllowWalletResponseDto>({\n method: 'POST',\n url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,\n body: {\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n },\n attributes: Attributes.protected(),\n });\n return AllowWalletResponse.fromDto(dto);\n}\n\nfunction toErc20Asset(dto: SwapOutputTokenDto): Erc20Asset {\n return {\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n };\n}\n","import {\n allowWallet,\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/universal/api/frontline/providers/superstate/swap';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Erc20Asset } from '@/universal/types/blockchain/core';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapPreview,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, 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: UniversalNamespaceContext) {\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 {\n getTokenAllowance,\n getTokenBalance,\n} from '@/universal/api/frontline/providers/superstate/swap';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n TokenAllowance,\n TokenBalance,\n} from '@/universal/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: UniversalNamespaceContext) {\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 { getAddress } from 'viem';\nimport { HttpError, type HttpResponse } from '@/universal/api/http';\nimport { HttpClient } from '@/universal/api/http-client';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Logger } from '@/universal/types/logger';\nimport { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * An {@link HttpClient} against the token registry rather than frontline: no\n * `X-API-Version` (the registry doesn't know it, and the extra header would\n * force a CORS preflight the static CDN cannot answer) and no session\n * middleware (the registry is public).\n */\nexport function createNabuApiClient(\n baseUrl: string,\n logger: Logger | null = null\n): HttpClient {\n return new HttpClient({ baseUrl }, {}, logger);\n}\n\n/**\n * Fetches one token's display metadata from the registry.\n *\n * Returns `null` when the registry does not list the token: the registry is\n * curated, so \"not listed\" is a domain answer, not a failure. The deployment\n * signals it as either a 404 or — Cloudflare Pages' fallback for unknown\n * routes — a 2xx serving its HTML inspection page, so both map to `null`.\n * Everything else throws: a non-2xx status is an {@link HttpError} carrying\n * the registry's response, including a 5xx whose body is an HTML error page.\n */\nexport async function fetchTokenMetadata(\n client: HttpClient,\n token: TokenIdentifier\n): Promise<TokenMetadata | null> {\n // The registry's canonical route uses the EIP-55 checksummed address:\n // lowercase costs a redirect round-trip and wrong mixed casing 404s.\n const address = checksummed(token.address);\n let response: HttpResponse<NabuTokenDto>;\n try {\n response = await client.send<NabuTokenDto>({\n method: 'GET',\n url: `/${token.chain}/token/${address}`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n return null;\n }\n throw error;\n }\n\n if (response.status === 404) {\n return null;\n }\n assertOk(response);\n if (response.body === null) {\n // Not a \"not listed\" signal — those are the 404 and the HTML fallback. A\n // 2xx with a zero-length body is a broken deploy or a mangling\n // intermediary, and mapping it to null would hide a listed token.\n throw new ValidationError(\n `Token registry returned an empty body for token \"${address}\" on \"${token.chain}\"`\n );\n }\n return TokenMetadata.fromDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches all available tokens the registry lists for `chain`, in a single\n * request against the chain snapshot — fetching N tokens one by one would\n * cost N round-trips for a catalogue that arrives whole anyway.\n *\n * Unlike {@link fetchTokenMetadata}, a missing snapshot throws rather than\n * mapping to an empty answer: the registry publishes a snapshot for every\n * chain it knows, so its absence is a deployment problem — and an invented\n * `[]` would render as \"no metadata\" without anyone noticing.\n */\nexport async function fetchTokensMetadata(\n client: HttpClient,\n chain: EthereumChain\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuChainAssetsDto>;\n try {\n response = await client.send<NabuChainAssetsDto>({\n method: 'GET',\n url: `/${chain}/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n `Token registry returned non-JSON for the \"${chain}\" snapshot`\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n `Token registry returned an empty \"${chain}\" snapshot`\n );\n }\n return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches every token the registry lists, across all chains, in a single\n * request against the complete snapshot — the cheapest way to resolve a\n * multi-chain catalogue: one download regardless of how many assets or\n * chains it spans.\n *\n * Chains outside the SDK's type surface (e.g. Solana) are skipped rather\n * than failing the whole snapshot. As with the per-chain snapshot, a missing\n * or empty response throws: the registry always publishes `/assets.json`, so\n * its absence is a deployment problem, not an empty catalogue.\n */\nexport async function fetchAllTokensMetadata(\n client: HttpClient\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuRegistryDto>;\n try {\n response = await client.send<NabuRegistryDto>({\n method: 'GET',\n url: `/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n 'Token registry returned non-JSON for the complete snapshot'\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n 'Token registry returned an empty complete snapshot'\n );\n }\n return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);\n}\n\n/**\n * The registry's deployment answers routes that have no static file with its\n * HTML inspection page and a 2xx status. `makeRequest` surfaces any non-JSON\n * body as an {@link HttpError} carrying the status, so \"2xx but not JSON\" is\n * precisely the registry's \"no such file\" signal — while a non-2xx with an\n * HTML body (a CDN 502/503 page, a proxy block page) keeps its status and\n * stays an outage for the caller to see, never a domain answer.\n */\nfunction isRegistryHtmlFallback(error: unknown): boolean {\n return (\n error instanceof HttpError &&\n error.response.status >= 200 &&\n error.response.status < 300\n );\n}\n\nfunction assertOk(response: HttpResponse<unknown>): void {\n if (response.status < 200 || response.status >= 300) {\n // The full response, never a stripped one: HttpError is public API and\n // callers classify failures off `response.body` (e.g. a 429 vs a 502).\n throw new HttpError(response);\n }\n}\n\nfunction checksummed(address: string): string {\n try {\n return getAddress(address);\n } catch (_) {\n throw new ValidationError(`Invalid EVM contract address: \"${address}\"`);\n }\n}\n","import {\n AssetDecimals,\n AssetSymbol,\n EthereumChain,\n EvmContractAddress,\n type TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuLogoDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * An absolute URL to a logo image in the token registry. Registry image URLs\n * are content-fingerprinted and served immutable, so a value is safe to cache\n * for as long as you hold it.\n */\nexport type TokenLogoUrl = Newtype<string, 'TokenLogoUrl'>;\nexport const TokenLogoUrl = (value: string): TokenLogoUrl =>\n value as TokenLogoUrl;\n\nexport type TokenLogoImage = {\n url: TokenLogoUrl;\n width: number;\n height: number;\n};\n\n/**\n * `VECTOR` is a single SVG. `RASTER` has webp variants at 32/64/128/256/512px\n * widths (never wider than the original): use the smallest one that covers\n * your render size, or `original` if none does.\n */\nexport type TokenLogo =\n | { kind: 'VECTOR'; url: TokenLogoUrl }\n | { kind: 'RASTER'; original: TokenLogoImage; variants: TokenLogoImage[] };\n\nexport const TokenLogo = {\n /** `baseUrl` is the registry origin; registry URLs are root-relative. */\n fromDto: (dto: NabuLogoDto, baseUrl: string): TokenLogo =>\n dto.kind === 'VECTOR'\n ? { kind: 'VECTOR', url: resolveLogoUrl(dto.url, baseUrl) }\n : {\n kind: 'RASTER',\n original: logoImageFromDto(dto.original, baseUrl),\n variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl)),\n },\n};\n\n/**\n * Display metadata for one token, from CoinList's public token registry.\n *\n * Keyed by `(chain, address)` — never by symbol, which can collide. The\n * registry is curated: a token missing from it is an expected answer, not an\n * error, so lookups return `null` rather than throwing.\n */\nexport type TokenMetadata = {\n identifier: TokenIdentifier;\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n logo: TokenLogo;\n /** Dark-theme logo; `null` when the registry configures none. */\n logoDark: TokenLogo | null;\n};\n\nexport const TokenMetadata = {\n /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */\n fromDto: (dto: NabuTokenDto, baseUrl: string): TokenMetadata => {\n assertSupportedSchemaVersion(dto.schema_version);\n return {\n identifier: {\n chain: EthereumChain(dto.chain),\n address: EvmContractAddress(dto.address),\n },\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n logo: TokenLogo.fromDto(dto.logo, baseUrl),\n logoDark:\n dto.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(dto.logo_dark, baseUrl),\n };\n },\n\n /**\n * Maps the complete registry snapshot to every token it lists across the\n * chains this SDK models, skipping native coins and chains outside\n * {@link EthereumChain} (e.g. Solana) rather than failing on them — the\n * registry may serve chains ahead of the SDK's type surface.\n */\n fromRegistryDto: (dto: NabuRegistryDto, baseUrl: string): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return dto.chains.flatMap((chainDto) => {\n let chain: EthereumChain;\n try {\n chain = EthereumChain(chainDto.chain);\n } catch {\n return [];\n }\n return tokensOfChain(chain, chainDto.assets, baseUrl);\n });\n },\n\n /**\n * Maps a chain snapshot to the tokens it lists, skipping the chain's native\n * coin (`kind: 'COIN'`, no contract address).\n */\n fromChainAssetsDto: (\n dto: NabuChainAssetsDto,\n baseUrl: string\n ): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);\n },\n};\n\n/** The token rows of one chain's asset list, skipping the native coin. */\nfunction tokensOfChain(\n chain: EthereumChain,\n assets: NabuChainAssetsDto['assets'],\n baseUrl: string\n): TokenMetadata[] {\n return assets\n .filter((asset) => asset.kind === 'TOKEN' && asset.address !== undefined)\n .map((asset) => ({\n identifier: {\n chain,\n // The filter above cannot narrow `address` for the type checker.\n address: EvmContractAddress(asset.address as string),\n },\n name: asset.name,\n symbol: AssetSymbol(asset.symbol),\n decimals: AssetDecimals(asset.decimals),\n logo: TokenLogo.fromDto(asset.logo, baseUrl),\n logoDark:\n asset.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(asset.logo_dark, baseUrl),\n }));\n}\n\n/**\n * The registry bumps schema_version only on breaking changes, so mapping a\n * newer schema with this code would produce silent garbage — fail instead.\n */\nfunction assertSupportedSchemaVersion(version: number): void {\n if (version !== 1) {\n throw new ValidationError(\n `Unsupported token registry schema_version: ${version}`\n );\n }\n}\n\nconst logoImageFromDto = (\n dto: { url: string; width: number; height: number },\n baseUrl: string\n): TokenLogoImage => ({\n url: resolveLogoUrl(dto.url, baseUrl),\n width: dto.width,\n height: dto.height,\n});\n\nconst resolveLogoUrl = (url: string, baseUrl: string): TokenLogoUrl =>\n TokenLogoUrl(\n url.startsWith('http') ? url : `${baseUrl.replace(/\\/$/, '')}${url}`\n );\n","import type { HttpClient } from '@/universal/api/http-client';\nimport {\n createNabuApiClient,\n fetchAllTokensMetadata,\n fetchTokenMetadata,\n fetchTokensMetadata,\n} from '@/universal/api/nabu/tokens';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type { Logger } from '@/universal/types/logger';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Token display metadata — name, symbol, decimals, and logos — from\n * CoinList's public token registry, keyed by {@link TokenIdentifier} (the\n * same chain + address pairs `Offer.tokens` carries).\n *\n * Unlike the other namespaces, this one is public: no method requires an\n * authenticated user, and nothing here touches the CoinList API — reads go to\n * the registry's CDN.\n */\nexport interface TokensNamespace {\n /**\n * Fetches metadata for one token. Returns `null` when the registry does not\n * list the token — the registry is curated, so callers must fall back to\n * their own display defaults rather than treat this as an error.\n */\n get(token: TokenIdentifier): Promise<TokenMetadata | null>;\n\n /**\n * Fetches every token the registry lists, in one request: the complete\n * snapshot with no `chain`, or one chain's snapshot with it. Prefer this\n * over calling {@link get} in a loop when displaying a catalogue — two\n * hundred tokens across three chains is still a single download.\n *\n * The complete snapshot spans every chain the registry knows; tokens on\n * chains this SDK does not model (e.g. Solana) are left out of the result.\n *\n * Unlike {@link get}, a missing snapshot throws rather than returning `[]`:\n * the registry always publishes the complete snapshot and one per chain it\n * knows, so an absence is a deployment problem, not an empty catalogue.\n */\n list(chain?: EthereumChain): Promise<TokenMetadata[]>;\n}\n\nexport class TokensNamespaceImpl implements TokensNamespace {\n private readonly api: HttpClient;\n private readonly log: InternalLogger;\n\n /**\n * Takes the registry origin rather than a `UniversalNamespaceContext`: the\n * registry is unauthenticated and on its own host, so the frontline sender\n * and the auth check would both be dead weight here.\n */\n constructor(baseUrl: string, logger: Logger | null = null) {\n this.api = createNabuApiClient(baseUrl, logger);\n this.log = internalLogger(logger, 'TOKENS');\n }\n\n get(token: TokenIdentifier): Promise<TokenMetadata | null> {\n return this.log.wrap('get', token, () =>\n fetchTokenMetadata(this.api, token)\n );\n }\n\n list(chain?: EthereumChain): Promise<TokenMetadata[]> {\n return this.log.wrap('list', chain, () =>\n chain === undefined\n ? fetchAllTokensMetadata(this.api)\n : fetchTokensMetadata(this.api, chain)\n );\n }\n}\n","import type { Hex } from 'viem';\nimport {\n type EthereumChain,\n EvmWalletAddress,\n type WalletProtocol,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/universal/types/dto/offer-option-address';\nimport type { Newtype } from '@/universal/types/newtype';\nimport type { OfferId } from '@/universal/types/offer';\nimport { OfferOptionId } from '@/universal/types/offer-detail';\n\n/** Unique identifier for a proven wallet binding on an offer option. */\nexport type OfferOptionAddressId = Newtype<string, 'OfferOptionAddressId'>;\n/** Casts a string into a typed {@link OfferOptionAddressId}. */\nexport const OfferOptionAddressId = (value: string) =>\n value as OfferOptionAddressId;\n\n/**\n * A user's external wallet, proven via a wallet-ownership challenge and bound\n * to an offer option. Returned by the `/v1/offers/:offer_id/addresses` resource.\n */\nexport type OfferOptionAddress = {\n /** Unique binding id. */\n id: OfferOptionAddressId;\n /** Offer option the wallet is bound to. */\n offerOptionId: OfferOptionId;\n /** The connected external wallet address. */\n address: EvmWalletAddress;\n /**\n * Protocol the binding is scoped to. An EVM address binds once per option\n * regardless of which EVM chain proved ownership.\n */\n protocol: WalletProtocol;\n /** When the binding was created. */\n createdAt: Date;\n};\n\n/** Parameters required to connect a proven external wallet to an offer option. */\nexport type ConnectExternalWalletParams = {\n /** Offer the option belongs to. */\n offerId: OfferId;\n /** Offer option to bind the wallet to. */\n offerOptionId: OfferOptionId;\n /** External wallet address that was proven. */\n walletAddress: EvmWalletAddress;\n /** Chain the ownership was proven on. */\n chain: EthereumChain;\n /** Signature of the wallet-ownership challenge message. */\n signature: Hex;\n};\n\nexport const OfferOptionAddress = {\n /** Maps the API DTO into the SDK offer-option-address domain model. */\n fromDto: (dto: OfferOptionAddressDto): OfferOptionAddress => ({\n id: OfferOptionAddressId(dto.id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n address: EvmWalletAddress(dto.address),\n protocol: dto.protocol,\n createdAt: new Date(dto.created_at),\n }),\n};\n\nexport const ConnectExternalWalletParams = {\n /** Maps connect-wallet params into the API DTO payload. */\n toDto: (\n params: ConnectExternalWalletParams\n ): CreateOfferOptionAddressDto => ({\n offer_option_id: params.offerOptionId,\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n }),\n};\n","import type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/universal/types/dto/wallet-ownership-challenge';\n\n/**\n * A single-use ownership challenge returned by `POST /v1/wallet-ownership`.\n * The consumer signs {@link message} with their wallet, then submits the\n * signature to connect the wallet to an offer option.\n */\nexport type WalletOwnershipChallenge = {\n /** The message the wallet must sign. */\n message: string;\n /** When the challenge expires and can no longer be consumed. */\n expiresAt: Date;\n};\n\n/** Fields common to every wallet-ownership challenge request. */\ntype WalletOwnershipChallengeParamsBase = {\n /** Wallet address to prove ownership of. */\n walletAddress: EvmWalletAddress;\n /** Chain the wallet belongs to. */\n chain: EthereumChain;\n};\n\n/**\n * Parameters for requesting a wallet-ownership challenge. Modeled as a\n * discriminated union on `challengeType` so a `siwe` challenge must carry\n * `domain`/`uri`/`statement`, matching the backend contract at compile time.\n */\nexport type CreateWalletOwnershipChallengeParams =\n | (WalletOwnershipChallengeParamsBase & {\n /** A bare message the wallet signs. */\n challengeType: 'plain';\n })\n | (WalletOwnershipChallengeParamsBase & {\n /** Marks this as a Sign-In With Ethereum challenge. */\n challengeType: 'siwe';\n /** The requesting site's hostname (e.g. `example.com`). */\n domain: string;\n /** The requesting site's URI. */\n uri: string;\n /** Human-readable statement shown in the signing prompt. */\n statement: string;\n });\n\n/**\n * How the ownership challenge is framed: a plain message or a Sign-In With\n * Ethereum challenge. Extracted as its own type so SDK consumers can pass it as\n * a standalone param without reaching into the {@link CreateWalletOwnershipChallengeParams}\n * union.\n */\nexport type WalletChallengeType =\n CreateWalletOwnershipChallengeParams['challengeType'];\n\nexport const WalletOwnershipChallenge = {\n /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */\n fromDto: (dto: WalletOwnershipChallengeDto): WalletOwnershipChallenge => ({\n message: dto.message,\n expiresAt: new Date(dto.expires_at),\n }),\n};\n\nexport const CreateWalletOwnershipChallengeParams = {\n /**\n * Maps challenge-request params into the API DTO payload. The discriminated\n * union guarantees SIWE fields are present exactly when `challengeType` is\n * `siwe`, so the mapping narrows on the discriminant.\n */\n toDto: (\n params: CreateWalletOwnershipChallengeParams\n ): CreateWalletOwnershipChallengeDto => {\n switch (params.challengeType) {\n case 'plain':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'plain',\n };\n case 'siwe':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'siwe',\n domain: params.domain,\n uri: params.uri,\n statement: params.statement,\n };\n default: {\n const _exhaustive: never = params;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { OfferOptionAddressDto } from '@/universal/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/universal/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/universal/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\n/**\n * Creates a single-use wallet-ownership challenge. The consumer signs the\n * returned message with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 when params are invalid — an unparseable\n * address, or SIWE fields (`domain`/`uri`/`statement`) that are missing on a\n * `siwe` challenge or present on a `plain` one. The `ApiErrorDto` body\n * carries the validation detail.\n */\nexport async function createWalletOwnershipChallenge(\n api: Sender,\n params: CreateWalletOwnershipChallengeParams\n): Promise<WalletOwnershipChallenge> {\n const dto = await api.send<WalletOwnershipChallengeDto>({\n method: 'POST',\n url: '/v1/wallet-ownership',\n body: CreateWalletOwnershipChallengeParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return WalletOwnershipChallenge.fromDto(dto);\n}\n\n/**\n * Connects a proven external wallet to an offer option. Requires a signature\n * of a previously created, unconsumed wallet-ownership challenge for the same\n * wallet and chain.\n *\n * Single-slot (`external_wallet`) options replace the existing binding in place\n * on re-submit — the binding `id` is stable across a \"change wallet\" — so\n * `max_wallets_reached` only fires for `whitelisted_wallet` options at their cap.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 for every binding failure; discriminate via the\n * `ApiErrorDto` body. Failures with a machine-readable `code`:\n * `wallet_not_whitelisted`, `max_wallets_reached`. Every other binding failure\n * (protocol mismatch, concurrent-connect lock, etc.) is rendered as an opaque\n * generic 422 with no `code`, by backend design. Challenge-state failures\n * surface by message only: no unconsumed challenge, wallet/chain not matching\n * the challenge, expired, or already used. Expired and already-used are not\n * retry-safe — request a fresh challenge first.\n */\nexport async function connectExternalWallet(\n api: Sender,\n params: ConnectExternalWalletParams\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'POST',\n url: `/v1/offers/${params.offerId}/addresses`,\n body: ConnectExternalWalletParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n\n/**\n * Lists the user's proven wallet bindings for a single offer option. Single-slot\n * (`external_wallet`) options return at most one binding; `whitelisted_wallet`\n * options return up to the requirement's `max_wallets`. Works after the offer\n * ends, so partners can read the final bindings.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n */\nexport async function listOptionAddresses(\n api: Sender,\n offerId: OfferId,\n offerOptionId: OfferOptionId\n): Promise<OfferOptionAddress[]> {\n const { data } = await api.send<ListResponseDto<OfferOptionAddressDto>>({\n method: 'GET',\n url: `/v1/offers/${offerId}/addresses`,\n queryParams: { offer_option_id: offerOptionId },\n attributes: Attributes.protected(),\n });\n return data.map(OfferOptionAddress.fromDto);\n}\n\n/**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 with `code` `offer_ended` once the offer has\n * ended (bindings on an offer that has not yet started stay removable), or a\n * 404 when the binding does not exist or is not the caller's.\n */\nexport async function removeOptionAddress(\n api: Sender,\n offerId: OfferId,\n addressId: OfferOptionAddressId\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'DELETE',\n url: `/v1/offers/${offerId}/addresses/${addressId}`,\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n","import * as walletConnectApi from '@/universal/api/frontline/wallet-connect';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\nexport type ListOptionAddressesParams = {\n offerId: OfferId;\n /** Offer option whose bindings to list. */\n offerOptionId: OfferOptionId;\n};\n\nexport type RemoveOptionAddressParams = {\n offerId: OfferId;\n /** Binding to remove, as returned by {@link WalletsNamespace.list}. */\n addressId: OfferOptionAddressId;\n};\n\n/**\n * The user's external wallets: proving ownership of one, binding it to an\n * offer option, and managing those bindings.\n *\n * Ownership proof is a provider-agnostic primitive — the swap flow uses the\n * same challenge to allow-list a wallet — so it lives here rather than being\n * duplicated per product namespace.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface WalletsNamespace {\n /**\n * Creates a single-use challenge the user signs to prove they control a\n * wallet. Supports both `plain` and `siwe` challenges. Pass the signature of\n * the returned {@link WalletOwnershipChallenge.message} to\n * {@link connectExternal}.\n */\n createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n\n /**\n * Binds a proven external wallet to an offer option, using a signature of a\n * challenge from {@link createOwnershipChallenge}.\n */\n connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n\n /**\n * Lists the user's proven wallet bindings for one offer option — the single\n * bound address for an `external_wallet` option, or every allow-listed\n * wallet for a `whitelisted_wallet` option.\n */\n list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;\n\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n */\n remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;\n}\n\nexport class WalletsNamespaceImpl implements WalletsNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'WALLETS');\n }\n\n async createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n return this.log.wrap('createOwnershipChallenge', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(\n this.ctx.api,\n params\n );\n });\n }\n\n async connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n return this.log.wrap('connectExternal', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.connectExternalWallet(this.ctx.api, params);\n });\n }\n\n async list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]> {\n return this.log.wrap('list', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.ctx.api,\n params.offerId,\n params.offerOptionId\n );\n });\n }\n\n async remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress> {\n return this.log.wrap('remove', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.removeOptionAddress(\n this.ctx.api,\n params.offerId,\n params.addressId\n );\n });\n }\n}\n","import { ApiClient } from '@/server/core/api/api-client';\nimport {\n type ServerAuthNamespace,\n ServerAuthNamespaceImpl,\n type SessionStore,\n} from '@/server/core/server-auth-namespace';\nimport type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport {\n type ServerOffersNamespace,\n ServerOffersNamespaceImpl,\n} from '@/server/core/server-offers-namespace';\nimport {\n type ServerRequirementsNamespace,\n ServerRequirementsNamespaceImpl,\n} from '@/server/core/server-requirements-namespace';\nimport {\n API_VERSION,\n PUBLIC_API_BASE_URL,\n} from '@/universal/api/frontline/config';\nimport { NABU_BASE_URL } from '@/universal/api/nabu/config';\nimport {\n type CoinListTokenSaleNamespace,\n CoinListTokenSaleNamespaceImpl,\n} from '@/universal/core/checkout/coin-list/token-sale-namespace';\nimport {\n type OndoNamespace,\n OndoNamespaceImpl,\n} from '@/universal/core/checkout/ondo/ondo-namespace';\nimport {\n type SuperstateSwapNamespace,\n SuperstateSwapNamespaceImpl,\n} from '@/universal/core/checkout/superstate/swap-namespace';\nimport {\n type Erc20Namespace,\n Erc20NamespaceImpl,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type TokensNamespace,\n TokensNamespaceImpl,\n} from '@/universal/core/tokens/tokens-namespace';\nimport {\n type WalletsNamespace,\n WalletsNamespaceImpl,\n} from '@/universal/core/wallets/wallets-namespace';\nimport type { Config } from '@/universal/types/config';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { ClientSecret } from '@/universal/types/oauth';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\n\n/** Buffer in seconds before expiry to consider token expired for refresh. */\nconst ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;\n\nexport interface ServerConfig extends Config {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Buffer in seconds before expiry to consider token expired for refresh. */\n readonly accessTokenExpiryBufferSeconds?: number;\n /**\n * Whether SDK will throw an exception in cases it can be silent.\n * For example, if token revokation on logout fails.\n */\n readonly strict?: boolean;\n}\n\n/**\n * Server-side CoinList SDK client.\n *\n * Functionality is grouped into namespaces — `coinlist.auth.getAccessToken()`,\n * `coinlist.offers.list()`, `coinlist.requirements.statuses(offerId)`.\n *\n * Operates in one of two modes depending on whether {@link SessionStore}\n * includes a `setSession` implementation:\n *\n * - **Writable store** (`setSession` provided) — full functionality: token\n * refresh, `auth.completeOAuth`, and `auth.logout` all work normally.\n *\n * - **Read-only store** (no `setSession`) — token refresh is skipped entirely,\n * meaning no network call is made and no refresh token is consumed.\n * `auth.completeOAuth` and `auth.logout` throw\n * {@link WritableSessionStoreRequiredError}. `auth.getAccessToken` may\n * return an expired token (see its docs). Use this mode in execution\n * contexts that can read the session but cannot write it back, such as\n * Next.js Server Components.\n *\n * Unless a namespace says otherwise, its methods require a user session and\n * throw {@link NotAuthenticatedError} when there is none.\n */\nexport interface CoinListServer {\n /**\n * OAuth session lifecycle: exchanging an authorization code, serving a valid\n * access token to the browser, minting app-level tokens, and logging out —\n * e.g. `coinlist.auth.getAccessToken()`.\n */\n readonly auth: ServerAuthNamespace;\n\n /**\n * The offer catalogue — e.g. `coinlist.offers.list()`. Every read also\n * accepts an app-level token from {@link ServerAuthNamespace.clientCredentials}\n * so it can run without a user session.\n */\n readonly offers: ServerOffersNamespace;\n\n /**\n * Offer requirements and the operations that satisfy them — e.g.\n * `coinlist.requirements.statuses(offerId)`. `forOffer` also accepts an\n * app-level token; the rest is per-user data and needs a user session.\n */\n readonly requirements: ServerRequirementsNamespace;\n\n /**\n * The user's external wallets: ownership proofs and offer-option bindings —\n * e.g. `coinlist.wallets.list({ offerId, offerOptionId })`.\n */\n readonly wallets: WalletsNamespace;\n\n /**\n * Generic ERC-20 reads (token allowance and balance) — e.g.\n * `coinlist.erc20.getBalance({ ... })`.\n */\n readonly erc20: Erc20Namespace;\n\n /**\n * Token-sale operations: listing, reading, and recording participations —\n * e.g. `coinlist.tokenSale.list()`. The on-chain `execute`\n * flow is client-only and is not exposed here.\n */\n readonly tokenSale: CoinListTokenSaleNamespace;\n\n /**\n * On-chain swap operations: quoting a swap, reading swap-contract state, and\n * allow-listing a proven wallet — e.g.\n * `coinlist.superstate.getOutputToken({ contractAddress, chain })`.\n */\n readonly superstate: SuperstateSwapNamespace;\n\n /**\n * Ondo swap reads: trading status and quoting. Both are free to poll.\n *\n * No CoinList fee is applied to a quote; see {@link OndoNamespace}.\n *\n * This is Ondo's whole surface for now — the wallet-driven half arrives with\n * ENG-1680 and will be client-only, since it needs a wallet to sign with.\n */\n readonly ondo: OndoNamespace;\n\n /**\n * Token display metadata (name, symbol, decimals, logos) from CoinList's\n * public token registry, keyed by chain + contract address — e.g.\n * `coinlist.tokens.get({ chain, address })` for an entry of\n * `Offer.tokens`, or `coinlist.tokens.list()` for the whole\n * catalogue in one request.\n *\n * Public and unauthenticated: unlike the other namespaces, its methods never\n * require a session, so it also works with a read-only store.\n */\n readonly tokens: TokensNamespace;\n}\n\nclass CoinListServerImpl implements CoinListServer {\n private readonly api: ApiClient;\n readonly auth: ServerAuthNamespace;\n readonly offers: ServerOffersNamespace;\n readonly requirements: ServerRequirementsNamespace;\n readonly wallets: WalletsNamespace;\n readonly erc20: Erc20Namespace;\n readonly tokenSale: CoinListTokenSaleNamespace;\n readonly superstate: SuperstateSwapNamespace;\n readonly ondo: OndoNamespace;\n readonly tokens: TokensNamespace;\n\n constructor(private readonly _config: ServerConfig) {\n const logger = _config.logger ?? null;\n this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n // When refresh=true the renewal middleware has received a 401 and wants a\n // fresh token. A read-only store cannot persist a new session, so return\n // null immediately — this tells the middleware to skip the retry rather\n // than re-sending with the same expired token and wasting a round-trip.\n (refresh) =>\n refresh && !this._config.sessionStore.setSession\n ? Promise.resolve(null)\n : this.auth.getAccessToken(),\n logger\n );\n this.auth = new ServerAuthNamespaceImpl(this.api, {\n ..._config,\n accessTokenExpiryBufferSeconds:\n _config.accessTokenExpiryBufferSeconds ??\n ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,\n strict: _config.strict ?? false,\n });\n\n const ctx: UniversalNamespaceContext & ServerNamespaceContext = {\n api: this.api,\n logger,\n ensureUserAuthenticated: () => this.ensureAuthenticated(undefined),\n ensureAuthenticated: (clientCreds) =>\n this.ensureAuthenticated(clientCreds),\n };\n this.offers = new ServerOffersNamespaceImpl(ctx);\n this.requirements = new ServerRequirementsNamespaceImpl(ctx);\n this.wallets = new WalletsNamespaceImpl(ctx);\n this.erc20 = new Erc20NamespaceImpl(ctx);\n this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);\n this.superstate = new SuperstateSwapNamespaceImpl(ctx);\n this.ondo = new OndoNamespaceImpl(ctx);\n this.tokens = new TokensNamespaceImpl(\n _config.tokensBaseUrl ?? NABU_BASE_URL,\n logger\n );\n }\n\n /**\n * An app-level token authenticates a request on its own; without one the\n * caller needs a user session.\n */\n private async ensureAuthenticated(\n clientCreds: ClientCredentialsOAuth | undefined\n ): Promise<void> {\n if (clientCreds) return;\n const token = await this.auth.getAccessToken();\n if (token === null) {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nexport function createCoinListServer(config: ServerConfig): CoinListServer {\n return new CoinListServerImpl(config);\n}\n","import { pino } from 'pino';\nimport {\n loggerOverPino,\n PINO_LEVEL,\n SDK_LOGGER_NAME,\n} from '@/universal/core/shared/observability/pino-logger';\nimport type { Logger, PinoLoggerOptions } from '@/universal/types/logger';\n\n/**\n * A {@link Logger} that writes newline-delimited JSON to stdout through pino.\n *\n * ```ts\n * createCoinListServer({\n * ...config,\n * logger: pinoServerLogger({ isDev: false, level: 'info' }),\n * });\n * ```\n *\n * The Node counterpart of {@link pinoClientLogger}, for a route handler, a BFF\n * or SSR. One line per record, which is what every log aggregator ingests\n * without configuration.\n *\n * ## What it deliberately does not do\n *\n * **No transport, and no `pino-pretty`.** A pino transport runs on a worker\n * thread through `thread-stream`, which every bundler has to be told about\n * (`serverExternalPackages` in Next) and which edge runtimes cannot run at\n * all. Pretty-printing is a pipe the host owns rather than a dependency the\n * SDK takes on their behalf:\n *\n * ```sh\n * node server.js | npx pino-pretty\n * ```\n *\n * **No environment-dependent formatting.** `isDev` decides which levels are\n * legal and nothing else, so a development record and a production record are\n * the same shape - what you debug is what you ship.\n *\n * If you already run pino, or want transports, redaction or `destination`,\n * implement {@link Logger} yourself: it is four methods over an event, and\n * `@opentelemetry/instrumentation-pino` patches the pino module rather than an\n * instance, so trace correlation reaches this logger either way.\n *\n * ## Production\n *\n * **Not advised in production**, the same as everywhere else this seam is\n * documented: the SDK's default answer is to leave {@link Config.logger}\n * undefined outside development, staging and incident reproduction. A backend\n * is the least bad place to disregard that - the records go to your process\n * and your sink rather than to a page the end user can read - but it is still\n * a disregard, and the retention and access questions become yours.\n *\n * If you run one, `isDev: false` restricts you to `'error'`, `'warn'` and\n * `'info'` - `{ isDev: false, level: 'debug' }` does not compile, see\n * {@link PinoLoggerOptions}. Those levels are redacted by construction, which\n * is a mechanism the SDK holds itself to; whether that clears your bar is a\n * judgement the SDK is not in a position to make for you.\n *\n * Holds no module-level state: every call builds its own pino instance, and\n * the level is fixed at construction, so two loggers never interfere. Fixed is\n * this implementation's choice, not the seam's - the SDK re-reads\n * {@link Logger.level} before every log call - so if you want a level you can\n * change at runtime, implement {@link Logger} over your own pino instance\n * rather than calling this.\n */\nexport function pinoServerLogger(options: PinoLoggerOptions): Logger {\n return loggerOverPino(\n // `name` as a child binding rather than pino's `name` option: the option\n // is honoured by pino's node build and silently dropped by its browser\n // build, so a binding is the only spelling that identifies the SDK in\n // both environments.\n pino({\n level: PINO_LEVEL[options.level],\n }).child({ name: SDK_LOGGER_NAME }),\n options.level\n );\n}\n","import type {\n DebugEvent,\n Logger,\n LogLevel,\n SafeEvent,\n} from '@/universal/types/logger';\n\n/**\n * The SDK's logging seam expressed over pino, minus the environment.\n *\n * Imports no pino - {@link PinoSink} is a structural type - so `@/universal`\n * stays pino-free and the `./universal` entry point costs a consumer nothing.\n * Both shipped implementations\n * ({@link pinoClientLogger}, {@link pinoServerLogger}) differ only in the pino\n * instance they construct; everything worth testing lives here.\n *\n * ## Nothing here may throw\n *\n * A {@link Logger} implementation is called inline, on the codepath of the\n * work it reports, and the SDK does not catch it - so a log line that fails to\n * render would turn a successful request into an exception. That risk is real\n * rather than theoretical: `'debug'` fields carry whatever the SDK was\n * handling, and this codebase routinely handles `bigint` (every uint256 on\n * every DTO), which `JSON.stringify` throws on. Response bodies may be\n * circular, params may hold functions, and a host's object may have a getter\n * that throws.\n *\n * So {@link toPinoRecord} is total by construction: every value is rendered\n * into something a JSON serialiser cannot refuse, every property read is\n * guarded, and the whole translation has a fallback. Pino is never handed a\n * value it could fail on.\n */\n\n/**\n * Flattens an event into the object pino merges into its output line.\n *\n * Flat rather than nested, because nesting is what a host has to un-nest\n * before they can facet on it: `scope`, the {@link LogBindings} and every\n * field sit at the top level, and only `cause` stays an object because its\n * arms are a closed union a host switches on.\n *\n * `msg` is **not** included: it is pino's own second argument.\n *\n * Never throws. A value it cannot render becomes a `<tag>` string rather than\n * an exception, and a translation that fails entirely degrades to a record\n * naming the failure.\n */\nexport function toPinoRecord(event: SafeEvent | DebugEvent): PinoRecord {\n try {\n const record: Record<string, unknown> = {};\n\n for (const key of ownKeys(event.fields)) {\n record[key] = readProperty(event.fields, key, 0, new WeakSet());\n }\n\n const cause = 'cause' in event ? event.cause : undefined;\n if (cause !== undefined) {\n record.cause = sanitize(cause, 0, new WeakSet());\n }\n\n // Last, so the stamped keys win. `scope` and the bindings are what a host\n // routes and filters on, and they are stamped by `internalLogger` rather\n // than written at a call site - so a field that happened to be named\n // `scope` or `op` must not be able to take their place.\n return { ...record, scope: event.scope, ...event.bindings };\n } catch (_) {\n // The event itself is malformed - a Proxy for `fields`, a frozen exotic\n // object. Report that rather than losing the line, and never rethrow.\n return { 'log.render': '<unrenderable event>' };\n }\n}\n\n/** What pino merges into one output line. */\nexport type PinoRecord = Readonly<Record<string, unknown>>;\n\n/**\n * The SDK's five levels in pino's vocabulary.\n *\n * `'none'` is pino's `'silent'`; the other four are the same word in both, and\n * deliberately so. The SDK does not adopt pino's seven because `'trace'` would\n * sit below `'debug'`, and the guarantee \"`debug` is unredacted and every\n * other level is not\" only closes while `'debug'` is the bottom.\n */\nexport const PINO_LEVEL = {\n none: 'silent',\n error: 'error',\n warn: 'warn',\n info: 'info',\n debug: 'debug',\n} as const satisfies Record<LogLevel, string>;\n\n/**\n * How deep a `'debug'` field is followed before it is summarised.\n *\n * A bound rather than a guess at what is deep enough: a self-referential\n * structure is already caught by the cycle check, but a legitimately deep DTO\n * would otherwise cost real time inside a log line.\n */\nconst MAX_DEPTH = 8;\n\n/**\n * Renders any value into something a JSON serialiser cannot refuse.\n *\n * `bigint` is the one that matters in practice - every uint256 the SDK handles\n * is one - but the rest are all reachable from a `'debug'` field: `undefined`\n * and functions from an operation's params, `NaN` from arithmetic, symbols\n * from a host's object.\n */\nfunction sanitize(\n value: unknown,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return value;\n case 'number':\n // `NaN` and the infinities serialise to `null`, which reads as \"absent\"\n // rather than \"not a number\". Name them instead.\n return Number.isFinite(value) ? value : String(value);\n case 'bigint':\n return value.toString();\n case 'undefined':\n return '<undefined>';\n case 'function':\n return '<function>';\n case 'symbol':\n return value.toString();\n case 'object':\n return value === null ? null : sanitizeObject(value, depth, seen);\n default:\n return '<unrenderable>';\n }\n}\n\nfunction sanitizeObject(\n value: object,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n if (seen.has(value)) return '<circular>';\n if (depth >= MAX_DEPTH) return '<max depth>';\n\n // `name`, `message` and `stack` are all non-enumerable, so an `Error` handed\n // to a structured sink as an object serialises to `{}`.\n if (value instanceof Error) return describeError(value);\n if (value instanceof Date) return describeDate(value);\n\n seen.add(value);\n try {\n if (Array.isArray(value)) {\n return value.map((_item, index) =>\n readProperty(value, String(index), depth, seen)\n );\n }\n\n const out: Record<string, unknown> = {};\n for (const key of ownKeys(value)) {\n out[key] = readProperty(value, key, depth, seen);\n }\n return out;\n } finally {\n // Removed on the way out, so a value referenced twice in a tree renders\n // twice. Only a genuine cycle is `<circular>`.\n seen.delete(value);\n }\n}\n\n/**\n * One property read, guarded. A getter may throw, and a log line is not\n * allowed to be the reason a request fails.\n */\nfunction readProperty(\n owner: object,\n key: string,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n try {\n return sanitize((owner as Record<string, unknown>)[key], depth + 1, seen);\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/** Own enumerable keys, guarded: an exotic object may refuse to be enumerated. */\nfunction ownKeys(value: object): readonly string[] {\n try {\n return Object.keys(value);\n } catch (_) {\n return [];\n }\n}\n\nfunction describeError(error: Error): Record<string, unknown> {\n return {\n name: safeRead(() => error.name),\n message: safeRead(() => error.message),\n stack: safeRead(() => error.stack),\n };\n}\n\nfunction describeDate(date: Date): unknown {\n // An invalid `Date` throws from `toISOString`.\n return safeRead(() => date.toISOString());\n}\n\nfunction safeRead(read: () => unknown): unknown {\n try {\n const value = read();\n return typeof value === 'string' ? value : '<unreadable>';\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/**\n * The part of a pino logger this adapter uses.\n *\n * Structural rather than `import type { Logger } from 'pino'`, so that\n * `@/universal` takes no dependency on pino at all. A real pino instance - node\n * or browser build - satisfies it.\n */\nexport type PinoSink = {\n debug(record: PinoRecord, msg: string): void;\n info(record: PinoRecord, msg: string): void;\n warn(record: PinoRecord, msg: string): void;\n error(record: PinoRecord, msg: string): void;\n};\n\n/**\n * The `name` binding every SDK line carries, so a partner can separate the\n * SDK's output from their own in a shared aggregator without matching on\n * `scope`.\n *\n * Applied through `pino.child({ name })` rather than pino's `name` *option*,\n * which its browser build ignores. The browser lane's spec is what caught\n * that, and is what keeps it caught.\n */\nexport const SDK_LOGGER_NAME = '@coinlist-co/react';\n\n/**\n * Adapts a pino instance into the {@link Logger} the SDK consumes.\n *\n * **Total, and that is the point.** The SDK calls a `Logger` inline and does\n * not catch it, so an exception raised while reporting a successful request\n * would fail that request. Three things could raise one - the event lambda\n * itself, rendering the event, and the sink - and all three are caught here.\n * A render failure is reported through the sink rather than swallowed, since a\n * log line that silently vanishes is a bug nobody finds; if the sink is what\n * broke, there is nowhere left to report it and the error stops here.\n *\n * **The level is fixed here, and that is this adapter's choice rather than the\n * seam's.** {@link InternalLogger} calls {@link Logger.level} before *every*\n * log call and caches nothing, so a host-implemented `Logger` reading a mutable\n * field has a level they can change at runtime. This adapter captures `level`\n * instead, and the pino instance it wraps is built with a fixed one - so\n * `Logger.level` is a constant lookup and two loggers never interfere. A host\n * who wants to turn `'debug'` on without rebuilding implements {@link Logger}\n * directly over their own pino instance; the port is four methods and this\n * function is the worked example.\n */\nexport function loggerOverPino(sink: PinoSink, level: LogLevel): Logger {\n return {\n level: () => level,\n debug: (event) => emit(sink, 'debug', event),\n info: (event) => emit(sink, 'info', event),\n warn: (event) => emit(sink, 'warn', event),\n error: (event) => emit(sink, 'error', event),\n };\n}\n\nfunction emit(\n sink: PinoSink,\n method: keyof PinoSink,\n event: () => SafeEvent | DebugEvent\n): void {\n try {\n const value = event();\n sink[method](toPinoRecord(value), value.msg);\n } catch (error) {\n reportRenderFailure(sink, error);\n }\n}\n\nfunction reportRenderFailure(sink: PinoSink, error: unknown): void {\n try {\n sink.error(\n { 'error.type': error instanceof Error ? error.name : typeof error },\n 'log event failed to render'\n );\n } catch (_) {\n // The sink itself threw. There is nowhere left to report this, and the SDK\n // is on the other side of the call that got us here.\n }\n}\n"],"mappings":"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","names":["requestId","import_viem","import_viem"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts","../../src/universal/api/http-attributes.ts","../../src/universal/api/http.ts","../../src/universal/api/frontline/config.ts","../../src/universal/core/shared/observability/log-cause.ts","../../src/universal/types/errors.ts","../../src/universal/core/shared/observability/internal-logger.ts","../../src/universal/api/http-client.ts","../../src/universal/api/middleware/attach-session-middleware.ts","../../src/universal/core/shared/utils/crypto.ts","../../src/universal/api/middleware/idempotency-key.ts","../../src/universal/api/middleware/request-retry.ts","../../src/universal/api/middleware/session-renewal.ts","../../src/universal/api/authenticated-api-client.ts","../../src/server/core/api/api-client.ts","../../src/server/shared/errors.ts","../../src/universal/types/oauth-session.ts","../../src/server/core/server-auth-namespace.ts","../../src/universal/api/pagination.ts","../../src/universal/types/blockchain/core.ts","../../src/universal/types/offer.ts","../../src/universal/types/asset.ts","../../src/universal/types/trading.ts","../../src/universal/types/offer-detail.ts","../../src/universal/types/pagination.ts","../../src/universal/api/frontline/offers.ts","../../src/server/core/server-offers-namespace.ts","../../src/universal/types/requirement.ts","../../src/universal/api/frontline/requirements.ts","../../src/universal/types/document-submission.ts","../../src/universal/api/frontline/documents.ts","../../src/universal/types/kyc.ts","../../src/universal/api/frontline/kyc.ts","../../src/universal/types/pii.ts","../../src/universal/api/frontline/pii.ts","../../src/universal/core/requirements/requirements-namespace.ts","../../src/server/core/server-requirements-namespace.ts","../../src/universal/api/nabu/config.ts","../../src/universal/api/rpc/public-clients.ts","../../src/universal/api/rpc/frontline-transport.ts","../../src/universal/core/shared/blockchain/chain.ts","../../src/universal/types/blockchain/ui.ts","../../src/universal/types/providers/coin-list/token-sale.ts","../../src/universal/api/frontline/providers/coin-list/token-sale.ts","../../src/universal/core/checkout/coin-list/token-sale-namespace.ts","../../src/universal/core/shared/blockchain/formatters.ts","../../src/universal/core/shared/blockchain/math.ts","../../src/universal/types/providers/ondo/ondo.ts","../../src/universal/api/frontline/providers/ondo/ondo.ts","../../src/universal/core/checkout/ondo/ondo-namespace.ts","../../src/universal/types/providers/superstate/swap.ts","../../src/universal/api/frontline/providers/superstate/swap.ts","../../src/universal/core/checkout/superstate/blockchain/abi.ts","../../src/universal/core/shared/blockchain/erc20/abi.ts","../../src/universal/api/rpc/providers/superstate/swap.ts","../../src/universal/core/checkout/superstate/swap-namespace.ts","../../src/universal/api/rpc/erc20.ts","../../src/universal/core/shared/blockchain/erc20/erc20-namespace.ts","../../src/universal/api/nabu/tokens.ts","../../src/universal/types/token-metadata.ts","../../src/universal/core/tokens/tokens-namespace.ts","../../src/universal/types/offer-option-address.ts","../../src/universal/types/wallet-ownership-challenge.ts","../../src/universal/api/frontline/wallet-connect.ts","../../src/universal/core/wallets/wallets-namespace.ts","../../src/server/core/coinlist-server.ts","../../src/server/core/observability/pino-server-logger.ts","../../src/universal/core/shared/observability/pino-logger.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. */\nexport * from '@/server/core/coinlist-server';\nexport * from '@/server/core/observability/pino-server-logger';\nexport * from '@/server/core/server-auth-namespace';\nexport * from '@/server/core/server-namespace-context';\nexport * from '@/server/core/server-offers-namespace';\nexport * from '@/server/core/server-requirements-namespace';\nexport * from '@/server/shared/errors';\n","import type { RequestId } from '@/universal/types/logger';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\n\nexport type HttpRequestAttributes = {\n /**\n * Correlates the log lines of one logical request. Minted by\n * {@link HttpClient} on the first attempt and carried onto every retry and\n * post-renewal re-send by {@link concat}, which is what lets a reader tell\n * three attempts of one request from three separate requests.\n */\n requestId?: RequestId;\n protected?: boolean;\n userAgent?: boolean;\n idempotencyKey?: boolean;\n /** Zero-based attempt index: 0 = first request, 1 = first retry, etc. */\n retryAttempt?: number;\n renewAttempted?: boolean;\n 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 '@/universal/api/http-attributes';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport type { RequestId } from '@/universal/types/logger';\n\nexport type HttpClientConfig = {\n baseUrl: string;\n /**\n * The frontline `X-API-Version` header. Omit for clients against other\n * backends (e.g. the token registry): a version header they don't know\n * would also force a CORS preflight the CDN cannot answer.\n */\n xApiVersion?: string;\n};\n\nexport type HttpRequest<TBody = unknown> =\n | {\n method: 'GET';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'POST';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n body: TBody;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n }\n | {\n method: 'DELETE';\n url: string;\n queryParams?: Record<string, QueryParamValues>;\n headers?: Record<string, string>;\n attributes?: HttpRequestAttributes;\n redirect?: RequestRedirect;\n };\nexport type HttpResponse<TBody = unknown> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody | null;\n /**\n * The id of the request that produced this response, stamped by\n * {@link HttpClient} so that whoever turns a non-2xx into an\n * {@link HttpError} can carry it without threading the request alongside.\n * Absent when the response did not come from an `HttpClient`.\n */\n requestId?: RequestId;\n};\n\nexport class HttpError<TBody = unknown> extends Error {\n readonly response: HttpResponse<TBody>;\n\n constructor(response: HttpResponse<TBody>) {\n super(`Request failed with ${response.status} status`);\n this.name = 'HttpError';\n this.response = response;\n }\n\n /**\n * Correlates this failure with the `[HTTP]` log lines for the same request,\n * which carry the method, the URL, the duration and every retry. `null` when\n * the response did not come from an {@link HttpClient}.\n *\n * Worth quoting in a bug report: it is what makes a log excerpt readable.\n */\n get requestId(): RequestId | null {\n return this.response.requestId ?? null;\n }\n}\n\n/**\n * The machine-readable `code` frontline attaches to an error, or `null` for\n * anything else - a non-HTTP failure, or an error body that carries only a\n * message.\n *\n * Frontline answers a failure with `{ type, message, code?, errors?,\n * event_id? }`, and `code` is the only part of it meant to be branched on:\n * `message` is prose that may be reworded, and `type` distinguishes\n * `invalid_request_error` from `api_error` without saying which one.\n *\n * Reach for this only where a code has a distinct remedy the user can act on.\n * Mapping the whole vocabulary would couple the SDK to strings frontline does\n * not version; falling back to a generic failure is the right default.\n */\nexport function apiErrorCode(error: unknown): string | null {\n if (!(error instanceof HttpError)) return null;\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const code: unknown = (body as { code?: unknown }).code;\n return typeof code === 'string' ? code : null;\n}\n\nexport async function makeRequest<TResponse = unknown>(\n request: HttpRequest\n): Promise<HttpResponse<TResponse>> {\n const headers: Record<string, string> = {\n Accept: 'application/json',\n ...(request.method === 'POST' && request.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(request.headers ?? {}),\n };\n\n const init: RequestInit = {\n method: request.method,\n headers,\n ...(request.redirect !== undefined ? { redirect: request.redirect } : {}),\n };\n\n if (request.method === 'POST' && request.body !== undefined) {\n init.body = JSON.stringify(request.body);\n }\n\n const response = await fetch(\n buildUrlWithQueryParams(request.url, request.queryParams),\n init\n );\n const responseHeaders = headersToRecord(response.headers);\n\n if (response.status === 204 || response.status === 205) {\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n if (response.status >= 300 && response.status < 400) {\n await response.text();\n return {\n status: response.status,\n body: null,\n headers: responseHeaders,\n };\n }\n\n const text = await response.text();\n let body: TResponse | null;\n try {\n body = text ? (JSON.parse(text) as TResponse) : null;\n } catch (_) {\n // A non-JSON body (an HTML error page from a CDN, proxy, or load\n // balancer) would otherwise surface as a bare SyntaxError with the status\n // lost. Throw the full response instead, so callers can classify the\n // failure by status and still see what the server actually sent.\n throw new HttpError({\n status: response.status,\n headers: responseHeaders,\n body: text,\n });\n }\n\n return {\n status: response.status,\n body,\n headers: responseHeaders,\n };\n}\n\n/**\n * The URL as `fetch` will see it, query string included.\n *\n * Exported for {@link HttpClient}'s `debug` request line, which renders the\n * request exactly as sent. Every other log line carries {@link HttpRequest.url}\n * alone - the query holds wallet addresses, chains and amounts, and `debug` is\n * the only level allowed to see them.\n */\nexport function buildUrlWithQueryParams(\n url: string,\n queryParams?: Record<string, QueryParamValues>\n): string {\n if (!queryParams) {\n return url;\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item === undefined || item === null) {\n continue;\n }\n searchParams.append(key, String(item));\n }\n continue;\n }\n\n searchParams.append(key, String(value));\n }\n\n const queryString = searchParams.toString();\n if (!queryString) {\n return url;\n }\n\n return url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`;\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key.toLowerCase()] = value;\n });\n return record;\n}\n\nfunction concatAttributes(\n request: HttpRequest,\n attrs: Attributes\n): HttpRequest {\n const nextAttributes = Attributes.concat(\n request.attributes ?? Attributes.empty,\n attrs\n );\n const nextRequest: typeof request = {\n ...request,\n attributes: nextAttributes,\n };\n return nextRequest;\n}\n\nexport const Request = {\n concatAttributes,\n};\n","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 {\n BaseError,\n ContractFunctionExecutionError,\n ContractFunctionRevertedError,\n HttpRequestError,\n RpcError,\n SocketClosedError,\n TimeoutError,\n WebSocketRequestError,\n} from 'viem';\nimport { apiErrorCode, HttpError } from '@/universal/api/http';\nimport {\n InvariantError,\n MathError,\n NotAuthenticatedError,\n NotImplementedError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type {\n FrontlineEventId,\n LogCause,\n RpcFailureReason,\n} from '@/universal/types/logger';\n\n/**\n * Classifies anything thrown inside the SDK into a {@link LogCause}.\n *\n * The SDK's **only** structured classification of a thrown error. It reaches\n * `warn` as well as `error`, since a recoverable failure is no less worth\n * naming than a fatal one.\n *\n * An `instanceof` chain rather than a pattern match, for the same reason\n * `classifyWalletError` is one: these are classes, not an ADT, so there is no\n * tag to match on. The chain is ordered most specific first and ends in\n * `generic-error`, which is total - a host-supplied lambda may throw anything\n * at all, a string included.\n *\n * Everything it returns is safe above `'debug'`, and the chain itself is the\n * opt-in list: only the five SDK-authored error classes named below reach an\n * arm carrying a `message`, because only those messages were written by the\n * SDK. Everything else contributes its class name and nothing more, since its\n * message and its fields are host-authored. {@link describeErrorUnredacted} is\n * where those go. A new error type has to be added here deliberately, which is\n * the moment to ask whether its message is SDK-authored all the way down;\n * defaulting to \"safe\" is how the leak ADR-8 replaced happened.\n *\n * Lives at Level 1 rather than beside {@link LogCause} because classifying an\n * {@link HttpError} means importing `@/universal/api`, which `@/universal/types` may\n * not do (`data.yaml#domain-models-dont-reach-the-api-layer`).\n */\nexport function classifyLogCause(error: unknown): LogCause {\n if (error instanceof HttpError) {\n return httpCause(error);\n }\n if (error instanceof ValidationError) {\n return { type: 'validation', message: error.message };\n }\n if (error instanceof InvariantError) {\n return { type: 'invariant', message: error.message };\n }\n if (error instanceof MathError) {\n return { type: 'math', message: error.message };\n }\n if (error instanceof NotAuthenticatedError) {\n return { type: 'not-authenticated' };\n }\n if (error instanceof NotImplementedError) {\n return { type: 'not-implemented' };\n }\n if (error instanceof BaseError) {\n // viem wraps whatever a `Transport` threw, so an `HttpError` the SDK's own\n // proxy transport raised arrives inside a chain failure. It is an HTTP\n // failure, not a bad decode, and its `requestId` is what leads to the rest.\n const http = error.walk((e) => e instanceof HttpError);\n if (http instanceof HttpError) {\n return httpCause(http);\n }\n return { type: 'rpc', reason: rpcFailureReason(error) };\n }\n return { type: 'generic-error', name: errorName(error) };\n}\n\n/**\n * Classifies a viem error by what a caller would do about it.\n *\n * `instanceof` against viem's exported classes and nothing else. Reading\n * `error.name` would be simpler and is unsafe twice over: it is a writable\n * property, so a host-supplied `Transport` throwing a doctored error would put\n * its own string on an `'error'` line, and a class name is a fact about viem's\n * hierarchy rather than a remedy. `walk` is viem's own accessor for the cause\n * chain - a revert arrives wrapped in a `ContractFunctionExecutionError`, so\n * the specific arm is never the outermost one.\n *\n * `malformed-response` is decided **structurally, by elimination**, rather than\n * from a list of viem's decoding classes. The wrapper says only that the\n * failure came out of a contract call: `getContractError` builds a\n * `ContractFunctionExecutionError` on every throw out of `call`, a transport\n * that never reached the node included. So the elimination is sound only\n * because **every transport class viem can raise is named in the arm above** -\n * that list is load-bearing, and a transport error class viem grows later\n * belongs in it rather than here. Given it, an error carrying the wrapper that\n * is not a revert, not an `RpcError` and not a transport failure can only be\n * the returned bytes failing to fit the ABI - a wrong address or a stale\n * constant. An allowlist cannot express that:\n * a return type the ABI no longer matches surfaces as `IntegerOutOfRangeError`,\n * which is not an `Abi*` class at all, and is the same class viem raises when\n * *encoding* an out-of-range argument. Only the wrapper separates the two.\n *\n * Which is also why the encode side falls through to `'unknown'`. An argument\n * the SDK got wrong, or a `functionName` absent from its own ABI constant, is\n * raised before the call and arrives unwrapped: an SDK bug rather than anything\n * the chain answered, and not something `malformed-response` should claim.\n *\n * `'unknown'` discloses nothing. The full message, the revert reason and the\n * calldata are on the paired `'debug'` line, via\n * {@link describeErrorUnredacted}.\n */\nfunction rpcFailureReason(error: BaseError): RpcFailureReason {\n if (error.walk((e) => e instanceof ContractFunctionRevertedError)) {\n return 'reverted';\n }\n if (error.walk((e) => e instanceof RpcError)) {\n return 'node-rejected';\n }\n if (\n error.walk(\n (e) =>\n e instanceof HttpRequestError ||\n e instanceof WebSocketRequestError ||\n e instanceof SocketClosedError ||\n e instanceof TimeoutError\n )\n ) {\n return 'transport';\n }\n if (error instanceof ContractFunctionExecutionError) {\n return 'malformed-response';\n }\n return 'unknown';\n}\n\n/**\n * A one-line rendering of a thrown error **verbatim**, message included.\n *\n * Unredacted, and therefore `'debug'` only: every caller puts the result in a\n * {@link DebugEvent} field, which the level check has already admitted. Always\n * called inside an event lambda, so it never runs below the level.\n *\n * The difference from {@link classifyLogCause} is one word - `message` - and\n * it is the whole safety boundary. A viem `BaseError.message` embeds the\n * transaction's `from`, `to`, `value` and calldata; a host's `getAccessToken`\n * may throw `new Error('token abc123 rejected')`. Neither is something the SDK\n * can vouch for.\n *\n * A rendered string rather than the error object, because an `Error`'s `name`,\n * `message` and `stack` are all non-enumerable: handed to a structured sink as\n * an object it serialises to `{}`.\n */\nexport function describeErrorUnredacted(error: unknown): string {\n if (error instanceof HttpError) {\n return describeHttpErrorRedacted(error);\n }\n if (error instanceof Error) {\n return `${error.name}: ${error.message}`;\n }\n return `thrown non-error: ${stringifyUnredacted(error)}`;\n}\n\n/**\n * Renders a value for a log field without ever throwing. A DTO holding a\n * `bigint`, or a params object the host made circular, must not turn a log\n * line into a second failure.\n *\n * Unredacted by construction - it stringifies whatever it is handed - so every\n * call site must be a `'debug'` one.\n */\nexport function stringifyUnredacted(value: unknown): string {\n if (value === undefined) return '';\n try {\n // `JSON.stringify` answers `undefined` for a function or a symbol, which\n // a params object can legitimately hold - an `onProgress` callback, say.\n return (\n JSON.stringify(value, (_key, item: unknown) =>\n typeof item === 'bigint' ? `${item}` : item\n ) ?? String(value)\n );\n } catch (_) {\n return '<unserializable>';\n }\n}\n\n/**\n * The status and frontline's code. Server-authored, so it is the same string\n * at every level rather than two renderings of one failure.\n */\nfunction describeHttpErrorRedacted(error: HttpError): string {\n const code = apiErrorCode(error);\n const status = error.response.status;\n return code === null\n ? `HttpError ${status}`\n : `HttpError ${status} (${code})`;\n}\n\n/**\n * The class name of an unrecognised throw, which is all of it that the SDK may\n * repeat above `'debug'`. A thrown non-error has no class worth naming, so its\n * `typeof` stands in.\n */\nfunction errorName(error: unknown): string {\n return error instanceof Error ? error.name : `non-error ${typeof error}`;\n}\n\n/**\n * The status and the two identifiers, and nothing else. The body stays out:\n * this value reaches `Logger.error`, which runs at every level a host would\n * enable in production, and a response body is a `'debug'`-only disclosure.\n * `requestId` is what leads back to it.\n */\nfunction httpCause(error: HttpError): LogCause {\n return {\n type: 'http',\n requestId: error.requestId,\n status: error.response.status,\n code: apiErrorCode(error),\n eventId: apiErrorEventId(error),\n };\n}\n\n/**\n * Frontline stamps a failure with `event_id`, the id its own logs are keyed\n * by. It is the single most useful thing to quote when raising a ticket, which\n * is why it is pulled out of the body rather than left for a reader to find.\n *\n * Private, unlike `apiErrorCode`: nothing branches on it, so it is a logging\n * detail rather than public API.\n */\nfunction apiErrorEventId(error: HttpError): FrontlineEventId | null {\n const body: unknown = error.response.body;\n if (typeof body !== 'object' || body === null) return null;\n const eventId: unknown = (body as { event_id?: unknown }).event_id;\n return typeof eventId === 'string' ? (eventId as FrontlineEventId) : null;\n}\n","/**\n * Error thrown when a feature or code path is not yet implemented.\n */\nexport class NotImplementedError extends Error {\n constructor(message = 'Not implemented yet') {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\n/**\n * Error thrown when accessing a feature that requires authentication\n * without being authenticated.\n */\nexport class NotAuthenticatedError extends Error {\n constructor(\n message = 'The user is not authenticated. Go through the OAuth flow first!'\n ) {\n super(message);\n this.name = 'NotAuthenticatedError';\n }\n}\n\nexport class ValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Error thrown when the SDK computes something impossible: a value outside\n * uint256 after its own arithmetic, a symbol missing from a registry the SDK\n * itself ships. Distinct from {@link ValidationError}, which means the backend\n * sent a shape the SDK does not understand.\n *\n * The two have different remedies, which is the whole reason they are separate\n * types: a {@link ValidationError} is worth reporting to CoinList, an\n * `InvariantError` is an SDK bug worth reporting against the SDK.\n */\nexport class InvariantError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvariantError';\n }\n}\n\n/**\n * Error thrown when an arithmetic operation has no answer to give: a division\n * by zero, or a result that falls outside the range its type can represent.\n *\n * Distinct from {@link ValidationError}, which says a value arrived malformed.\n * A `MathError` says every operand was well-formed and the operation on them\n * still has no result, so the two are worth catching apart: one points at the\n * response, the other at the arithmetic we asked for.\n */\nexport class MathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MathError';\n }\n}\n","import {\n classifyLogCause,\n describeErrorUnredacted,\n} from '@/universal/core/shared/observability/log-cause';\nimport type {\n DebugEvent,\n LogBinding,\n LogBindings,\n LogCause,\n Logger,\n LogLevel,\n LogScope,\n SafeEvent,\n SafeFields,\n UnredactedFields,\n} from '@/universal/types/logger';\n\n/**\n * Wraps the host's {@link Logger}, or its absence, into the thing SDK code\n * actually calls.\n *\n * Three jobs, the first two of which exist so that no call site anywhere in\n * the SDK ever branches on whether logging is on:\n *\n * 1. **Absence is normalised away.** No logger yields {@link noopInternalLogger},\n * whose methods do nothing and whose `wrap` still runs the wrapped work.\n * 2. **The level is checked here, once per call.** Below the level, the\n * event lambda is never invoked and no {@link LogCause} is built. That is\n * the whole reason events are lambdas: expensive debug detail costs nothing\n * in production.\n * 3. **The safety boundary is enforced here.** `'debug'` is the unredacted\n * level; `info`, `warn` and `error` carry only what the SDK authored and\n * what the server minted. {@link InternalLogger.failure} and\n * {@link InternalLogger.warning} render an error twice - verbatim onto a\n * `debug` line, classified onto theirs - rather than once, so that a host\n * running at `'debug'` may still forward `error` to a tracker unchanged.\n *\n * The scope and the accumulated {@link LogBindings} are stamped here, so a\n * call site names only what happened. That is also why call sites hand over an\n * {@link InternalSafeEvent} rather than a finished {@link SafeEvent}: nothing\n * should have to know its own scope twice.\n *\n * ```ts\n * const log = internalLogger(ctx.logger, 'ONDO');\n * log.child({ flow: 'review' }).failure(\n * () => ({ msg: 'quote refresh failed' }),\n * error\n * );\n * // { scope: 'ONDO', flow: 'review', cause: { type: 'http', status: 410, ... },\n * // msg: 'quote refresh failed' }\n * ```\n */\nexport function internalLogger(\n logger: Logger | null | undefined,\n scope: LogScope\n): InternalLogger {\n return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;\n}\n\n/**\n * The logging surface SDK code uses. Never exported to hosts: they implement\n * {@link Logger}, which is deliberately smaller.\n */\nexport type InternalLogger = {\n /**\n * A logger narrowed by one more {@link LogBinding}, which every line it\n * emits carries as its own field.\n */\n child(binding: LogBinding): InternalLogger;\n\n /**\n * The unredacted level. Request and response bodies, full URLs, headers,\n * operation params and raw thrown errors belong here and **only** here.\n */\n debug(event: () => InternalDebugEvent): void;\n\n info(event: () => InternalSafeEvent): void;\n warn(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a failure whose cause is already known, or has none. Prefer\n * {@link failure}, which classifies a thrown error for you.\n */\n error(event: () => InternalSafeEvent): void;\n\n /**\n * Reports a thrown error, classifying it into a {@link LogCause}. Prefer\n * this over `error` at a `catch`: classification only happens when the level\n * admits it.\n *\n * The `error` line names the error's class but never its message, since an\n * error the SDK did not author may say anything at all. The verbatim\n * rendering goes onto a paired `debug` line instead.\n *\n * For a failure the SDK recovers from, use {@link warning} instead. An\n * `error` line a host cannot act on is worse than no line at all: it trains\n * them to ignore the ones that matter.\n */\n failure(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * {@link failure} for trouble that did not break anything: a poll tick that\n * failed while the last value still stands, a retried request.\n *\n * Carries the classified {@link LogCause} exactly as `failure` does. The two\n * differ in level and in nothing else, because what separates them is\n * whether anything actually broke - not how much is known about it.\n */\n warning(event: () => InternalSafeEvent, error: unknown): void;\n\n /**\n * Runs one namespace operation with logging around it: the call and its\n * params at `debug`, and any throw at `error` with the cause classified.\n * Every line carries `op` as a binding.\n *\n * **The params never reach the `error` line.** They routinely hold the\n * things this SDK must not put in front of a production error tracker - an\n * app bearer token, a document's signing fields, a wallet signature - and\n * the `debug` line plus the request id is how you get them back. The type\n * says so: `params` is `unknown`, which is not a {@link SafeFields} value.\n *\n * Always rethrows. Logging observes behaviour, it never changes it.\n */\n wrap<T>(op: string, params: unknown, run: () => Promise<T>): Promise<T>;\n};\n\n/**\n * What a call site hands to `info`, `warn`, `error`, `failure` or `warning` -\n * a {@link SafeEvent} minus the scope and bindings the logger stamps itself.\n */\nexport type InternalSafeEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: SafeFields;\n readonly cause?: LogCause;\n};\n\n/** What a call site hands to `debug`. Its fields accept anything. */\nexport type InternalDebugEvent = {\n /** A **constant** string literal. Every varying value belongs in `fields`. */\n readonly msg: string;\n readonly fields?: UnredactedFields;\n};\n\n/** Each level admits itself and everything above it in this table. */\nconst LEVEL_RANK: Record<LogLevel, number> = {\n none: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction scopedLogger(\n logger: Logger,\n scope: LogScope,\n bindings: LogBindings\n): InternalLogger {\n const admits = (level: LogLevel): boolean =>\n LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];\n\n const safe = (event: InternalSafeEvent): SafeEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n ...(event.cause === undefined ? {} : { cause: event.cause }),\n });\n\n const unredacted = (event: InternalDebugEvent): DebugEvent => ({\n msg: event.msg,\n scope,\n bindings,\n fields: event.fields ?? {},\n });\n\n const self: InternalLogger = {\n child: (binding) =>\n scopedLogger(logger, scope, { ...bindings, ...binding }),\n\n debug: (event) => {\n if (admits('debug')) logger.debug(() => unredacted(event()));\n },\n\n info: (event) => {\n if (admits('info')) logger.info(() => safe(event()));\n },\n\n warn: (event) => {\n if (admits('warn')) logger.warn(() => safe(event()));\n },\n\n error: (event) => {\n if (admits('error')) logger.error(() => safe(event()));\n },\n\n failure: (event, error) => {\n // Two lines rather than one, and deliberately in this order: the `error`\n // line stays safe at every level, so a host running `'debug'` in beta\n // can still pipe `error` to Sentry without leaking what `debug` shows.\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('error')) logger.error(() => safe(classified(event(), error)));\n },\n\n warning: (event, error) => {\n if (admits('debug'))\n logger.debug(() => unredacted(verbatim(event(), error)));\n if (admits('warn')) logger.warn(() => safe(classified(event(), error)));\n },\n\n wrap: async (op, params, run) => {\n const opLog = self.child({ op });\n opLog.debug(() => ({ msg: 'call', fields: { params } }));\n try {\n return await run();\n } catch (error) {\n opLog.failure(() => ({ msg: 'call failed' }), error);\n throw error;\n }\n },\n };\n\n return self;\n}\n\n/**\n * The same event with the thrown error rendered **verbatim** - for the\n * `'debug'` line, and nowhere else.\n */\nfunction verbatim(\n event: InternalSafeEvent,\n error: unknown\n): InternalDebugEvent {\n return {\n msg: event.msg,\n fields: { ...event.fields, error: describeErrorUnredacted(error) },\n };\n}\n\n/**\n * The same event with the thrown error classified into a {@link LogCause}\n * - safe at `'warn'` and `'error'`.\n *\n * An explicit `cause` on the event wins: a call site that already knows what\n * went wrong knows better than the classifier.\n */\nfunction classified(\n event: InternalSafeEvent,\n error: unknown\n): InternalSafeEvent {\n return { ...event, cause: event.cause ?? classifyLogCause(error) };\n}\n\n/**\n * What every SDK codepath gets when the host supplied no logger. `wrap` still\n * runs the work it is given; everything else is inert.\n *\n * There is no `console` fallback here or anywhere else in the SDK: a host who\n * supplied no logger gets silence, not a default destination they did not\n * choose.\n */\nexport const noopInternalLogger: InternalLogger = {\n child: () => noopInternalLogger,\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n failure: () => undefined,\n warning: () => undefined,\n wrap: (_op, _params, run) => run(),\n};\n","import { HEADER_API_VERSION } from '@/universal/api/frontline/config';\nimport type {\n HttpClientConfig,\n HttpRequest,\n HttpResponse,\n} from '@/universal/api/http';\nimport { buildUrlWithQueryParams, makeRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n Logger,\n RequestId,\n UnredactedFields,\n} from '@/universal/types/logger';\n\nexport type BeforeRequestMiddleware = (\n request: HttpRequest\n) => Promise<HttpRequest>;\n\nexport type AfterRequestMiddleware = (args: {\n request: HttpRequest;\n response: HttpResponse<unknown>;\n retry: (request?: HttpRequest) => Promise<HttpResponse<unknown>>;\n}) => Promise<HttpResponse<unknown>>;\n\nexport type HttpClientMiddleware = {\n beforeRequest?: BeforeRequestMiddleware[];\n afterRequest?: AfterRequestMiddleware[];\n};\n\nexport type HttpClientOptions = {\n /**\n * Mints the id that correlates one request's log lines. Injected so specs\n * can assert on log output, the same reason\n * {@link createRequestRetryMiddleware} takes a `delayFn`; defaults to a\n * short random string.\n */\n makeRequestId?: () => RequestId;\n};\n\n/**\n * Logging lives here rather than in a middleware pair so that every client\n * built on `HttpClient` reports by construction - the frontline client, the\n * token registry client, and whatever comes next. A middleware would have to\n * be remembered per client, and could not time a request or see one that threw\n * before producing a response.\n */\nexport class HttpClient {\n private readonly log: InternalLogger;\n private readonly makeRequestId: () => RequestId;\n\n constructor(\n readonly config: HttpClientConfig,\n readonly middleware: HttpClientMiddleware = {},\n logger: Logger | null = null,\n options: HttpClientOptions = {}\n ) {\n this.log = internalLogger(logger, 'HTTP');\n this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;\n }\n\n async send<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n return this.runRequestWithAfterMiddleware<TResponse>(request);\n }\n\n /**\n * Runs beforeRequest, executeRequest, then the full afterRequest middleware\n * chain. Used by send() and by the retry() callback so that when a\n * middleware calls retry(), the retried response also goes through all\n * afterRequest middleware (e.g. session renewal, retry). Middleware\n * must use request.attributes.retryAttempt (or similar) to avoid infinite\n * recursion when they trigger retries.\n */\n private async runRequestWithAfterMiddleware<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const preparedRequest = await this.runBeforeRequestMiddleware(\n this.withClientDefaults(request)\n );\n let response = await this.executeRequest<TResponse>(preparedRequest);\n\n for (const middleware of this.middleware.afterRequest ?? []) {\n response = (await middleware({\n request: preparedRequest,\n response,\n retry: (nextRequest = preparedRequest) =>\n this.runRequestWithAfterMiddleware(nextRequest) as Promise<\n HttpResponse<TResponse>\n >,\n })) as HttpResponse<TResponse>;\n }\n\n return response;\n }\n\n private withClientDefaults(request: HttpRequest): HttpRequest {\n const url = this.resolveUrl(request.url);\n const headers = {\n ...(request.headers ?? {}),\n ...(this.config.xApiVersion !== undefined\n ? { [HEADER_API_VERSION]: this.config.xApiVersion }\n : {}),\n };\n\n return {\n ...request,\n url,\n headers,\n // Only when absent: a retry or a post-renewal re-send arrives with the\n // first attempt's id already on it, and keeping it is the whole point.\n attributes:\n Attributes.getRequestId(request.attributes) === null\n ? Attributes.concat(\n request.attributes ?? Attributes.empty,\n Attributes.requestId(this.makeRequestId())\n )\n : request.attributes,\n };\n }\n\n /**\n * Resolves a request URL against the client's baseUrl.\n *\n * @internal Public only for testing. Do not use in application code; use\n * {@link HttpClient.send} with a path and the client will resolve the URL.\n */\n resolveUrl(url: string): string {\n // If already absolute, use as-is.\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n // Otherwise append path to baseUrl so base path (e.g. /api) is preserved.\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const path = url.startsWith('/') ? url : `/${url}`;\n return base + path;\n }\n\n private async runBeforeRequestMiddleware(\n initialRequest: HttpRequest\n ): Promise<HttpRequest> {\n let request = initialRequest;\n for (const middleware of this.middleware.beforeRequest ?? []) {\n request = await middleware(request);\n }\n\n return request;\n }\n\n /**\n * One physical attempt, logged as one line.\n *\n * A non-2xx is a `warn` rather than an `error` because the wire does not\n * know whether it is a failure: the retry middleware may turn a 503 into a\n * success, and the token registry reads a 404 as \"not listed\". The namespace\n * above decides, and logs the `error` when it does.\n */\n private async executeRequest<TResponse = unknown>(\n request: HttpRequest\n ): Promise<HttpResponse<TResponse>> {\n const requestId = Attributes.getRequestId(request.attributes);\n const log = requestId === null ? this.log : this.log.child({ requestId });\n const attempt = Attributes.getRetryAttempt(request.attributes) + 1;\n const startedAt = Date.now();\n\n log.debug(() => ({\n msg: 'request sent',\n fields: describeRequestUnredacted(request),\n }));\n\n try {\n const response = await makeRequest<TResponse>(request);\n const elapsed = Date.now() - startedAt;\n const outcome = () => ({\n msg: 'request completed',\n fields: {\n ...identifyRequest(request),\n 'http.response.status_code': response.status,\n duration_ms: elapsed,\n attempt,\n },\n });\n\n if (response.status >= 200 && response.status < 300) {\n log.info(outcome);\n } else {\n log.warn(outcome);\n }\n log.debug(() => ({\n msg: 'response received',\n fields: { body: response.body },\n }));\n\n return requestId === null ? response : { ...response, requestId };\n } catch (error) {\n const elapsed = Date.now() - startedAt;\n // `warning`, not two hand-written lines: it renders the error verbatim\n // at `'debug'` and classified at `'warn'`, which is the pairing this\n // used to spell out by hand.\n log.warning(\n () => ({\n msg: 'request threw',\n fields: {\n ...identifyRequest(request),\n duration_ms: elapsed,\n attempt,\n },\n }),\n error\n );\n throw error;\n }\n }\n}\n\n/**\n * How a request is named on every line above `'debug'`.\n *\n * `server.address` and `url.path` rather than OpenTelemetry's `url.full`, and\n * that is a deliberate deviation from the convention the rest of these keys\n * follow. `url.full` is defined to carry the query string, and frontline reads\n * take `chain`, `wallet_address` and `amount` as query parameters - so the\n * standard key would put host data on the levels this SDK keeps redacted.\n * The full URL appears at `'debug'` and nowhere else.\n *\n * `HttpRequest.url` carries no query to begin with - {@link makeRequest}\n * appends it on the way to `fetch` - so the split is about naming rather than\n * about stripping anything.\n */\nfunction identifyRequest(request: HttpRequest): {\n 'http.request.method': string;\n 'server.address': string | null;\n 'url.path': string;\n} {\n const { host, path } = splitUrl(request.url);\n return {\n 'http.request.method': request.method,\n 'server.address': host,\n 'url.path': path,\n };\n}\n\n/**\n * The host and the path of an absolute URL, separately, because OpenTelemetry\n * names them separately and because only the path is worth grouping on.\n *\n * Never throws: it runs inside an event lambda, and the {@link Logger}\n * contract says nothing the SDK hands over may turn a log line into a second\n * failure. A URL `URL` refuses is reported as it stands, which is safe either\n * way - `HttpRequest.url` never carries a query string.\n */\nfunction splitUrl(url: string): { host: string | null; path: string } {\n try {\n const parsed = new URL(url);\n return { host: parsed.host, path: parsed.pathname };\n } catch (_) {\n return { host: null, path: url };\n }\n}\n\n/**\n * Eight base36 characters. Short enough to read at the head of every line and\n * wide enough that two concurrent requests in one session will not collide.\n * Deliberately not a counter: a module-level counter would be global mutable\n * state shared by every client in the process.\n */\nfunction defaultMakeRequestId(): RequestId {\n return Math.random().toString(36).slice(2, 10).padEnd(8, '0') as RequestId;\n}\n\n/**\n * The request as sent - full URL, headers and body verbatim. `debug` is\n * documented as unredacted: it exists to reproduce a bug, and a redacted\n * `Authorization` is exactly what you need when the bug is that the wrong\n * token went out.\n *\n * The query string appears here and nowhere else, under `url.full`. Every\n * other line names the request through {@link identifyRequest}, whose\n * `url.path` has none - which is why those lines are safe above `debug`.\n * Rendering the sent URL here is what makes a `wallet_address`, a `chain` or\n * an `amount` reproducible at all.\n *\n * The values are handed over as they stand rather than stringified: a\n * {@link DebugEvent} accepts anything, and the logger implementation is what\n * guarantees a `bigint` or a cycle cannot fail to render.\n */\nfunction describeRequestUnredacted(request: HttpRequest): UnredactedFields {\n return {\n 'http.request.method': request.method,\n 'url.full': buildUrlWithQueryParams(request.url, request.queryParams),\n headers: request.headers,\n ...(request.method === 'POST' ? { body: request.body } : {}),\n };\n}\n\n/**\n * Structural interface satisfied by both {@link AuthenticatedApiClient} and\n * {@link ApiClient}. Used by the shared frontline API functions so they can\n * be called from either the client or server without any browser dependencies.\n */\nexport interface Sender {\n send<T>(request: HttpRequest): Promise<T>;\n}\n","import type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport function attachSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): BeforeRequestMiddleware {\n return async (request: HttpRequest): Promise<HttpRequest> => {\n if (!Attributes.isProtected(request.attributes)) {\n return request;\n }\n\n let accessToken = await fetchAccessToken(false);\n if (!accessToken) {\n const clientCreds = Attributes.getClientCredentials(request.attributes);\n if (clientCreds) {\n accessToken = clientCreds;\n }\n }\n\n if (accessToken === null) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n Authorization: `Bearer ${accessToken.value}`,\n },\n };\n };\n}\n","/**\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 { HEADER_IDEMPOTENCY_KEY } from '@/universal/api/frontline/config';\nimport type { HttpRequest } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { getUUIDv4 } from '@/universal/core/shared/utils/crypto';\n\nexport const idempotencyKeyMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.isIdempotent(request.attributes)) {\n return request;\n }\n\n const existingHeaders = request.headers ?? {};\n if (existingHeaders[HEADER_IDEMPOTENCY_KEY]) {\n return request;\n }\n\n return {\n ...request,\n headers: {\n ...existingHeaders,\n [HEADER_IDEMPOTENCY_KEY]: getUUIDv4(),\n },\n };\n};\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\n\nconst MAX_ATTEMPTS = 3;\nconst INITIAL_DELAY_MS = 300;\nconst MAX_DELAY_MS = 2000;\n\nconst RETRYABLE_4XX = new Set([408, 409, 429]);\n\nexport function isRetryableStatus(status: number): boolean {\n return (status >= 500 && status < 600) || RETRYABLE_4XX.has(status);\n}\n\nfunction getRetryDelayMs(attempt: number): number {\n return Math.min(INITIAL_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n}\n\nexport type RequestRetryMiddlewareOptions = {\n /**\n * Optional delay function. Defaults to real setTimeout-based delay.\n * Use a no-op (e.g. () => Promise.resolve()) in tests to avoid slow tests.\n */\n delayFn?: (ms: number) => Promise<void>;\n};\n\n/**\n * Creates the request retry after-request middleware. Inject a no-op delayFn\n * in tests to avoid real delays (unit testing best practice).\n */\nexport function createRequestRetryMiddleware(\n options: RequestRetryMiddlewareOptions = {}\n): AfterRequestMiddleware {\n const delayFn = options.delayFn ?? defaultDelay;\n\n return async ({ request, response, retry }) => {\n if (!isRetryableStatus(response.status)) {\n return response;\n }\n\n const currentAttempt = Attributes.getRetryAttempt(request.attributes);\n if (currentAttempt >= MAX_ATTEMPTS - 1) {\n return response;\n }\n\n const nextAttempt = currentAttempt + 1;\n await delayFn(getRetryDelayMs(nextAttempt));\n\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.retryAttempt(nextAttempt)\n );\n return retry(nextRequest);\n };\n}\n\nfunction defaultDelay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retries the request up to 3 times with exponential backoff when the response\n * has a retryable status (5xx server errors). Uses request.attributes.retryAttempt\n * to decide delay and whether to retry, so the middleware does not loop when\n * retry() runs the full HTTP middleware chain again.\n */\nexport const requestRetryMiddleware: AfterRequestMiddleware =\n createRequestRetryMiddleware();\n","import { Request } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { AfterRequestMiddleware } from '@/universal/api/http-client';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport function renewSessionMiddleware(\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n): AfterRequestMiddleware {\n return async ({ request, response, retry }) => {\n if (response.status !== 401) {\n return response;\n }\n if (!Attributes.isProtected(request.attributes)) {\n return response;\n }\n if (Attributes.wasRenewAttempted(request.attributes)) {\n return response;\n }\n\n const newToken = await fetchAccessToken(true);\n if (newToken) {\n const nextRequest = Request.concatAttributes(\n request,\n Attributes.renewAttempted(true)\n );\n return retry(nextRequest);\n } else {\n return response;\n }\n };\n}\n","import type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport { HttpError } from '@/universal/api/http';\nimport type { BeforeRequestMiddleware } from '@/universal/api/http-client';\nimport { HttpClient } from '@/universal/api/http-client';\nimport { attachSessionMiddleware } from '@/universal/api/middleware/attach-session-middleware';\nimport { idempotencyKeyMiddleware } from '@/universal/api/middleware/idempotency-key';\nimport { requestRetryMiddleware } from '@/universal/api/middleware/request-retry';\nimport { renewSessionMiddleware } from '@/universal/api/middleware/session-renewal';\nimport type { Logger } from '@/universal/types/logger';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\n/**\n * Isomorphic HTTP client with session attachment, session renewal on 401,\n * idempotency key injection, and request retry. Works in both browser and\n * Node/server environments. Pass `additionalBeforeRequest` to inject\n * environment-specific middleware (e.g. `userAgentMiddleware` on the client).\n *\n * Pass `logger` through to have every request reported; the client logs\n * nothing without one.\n */\nexport class AuthenticatedApiClient {\n private readonly httpClient: HttpClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\n additionalBeforeRequest: BeforeRequestMiddleware[] = [],\n logger: Logger | null = null\n ) {\n this.httpClient = new HttpClient(\n config,\n {\n beforeRequest: [\n attachSessionMiddleware(fetchAccessToken),\n ...additionalBeforeRequest,\n idempotencyKeyMiddleware,\n ],\n afterRequest: [\n renewSessionMiddleware(fetchAccessToken),\n requestRetryMiddleware,\n ],\n },\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n const response = await this.httpClient.send<TResponse>(request);\n if (response.status >= 200 && response.status < 300) {\n return response.body as TResponse;\n } else {\n throw new HttpError(response);\n }\n }\n}\n","import { AuthenticatedApiClient } from '@/universal/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/universal/api/http';\nimport type { Logger } from '@/universal/types/logger';\nimport type { OAuthAccessToken } from '@/universal/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>,\n logger: Logger | null = null\n ) {\n this.client = new AuthenticatedApiClient(\n config,\n fetchAccessToken,\n [],\n logger\n );\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","export class WritableSessionStoreRequiredError extends Error {\n constructor(\n message = 'This operation requires a writable SessionStore. Provide a `setSession` implementation in your SessionStore to persist or clear OAuth sessions.'\n ) {\n super(message);\n this.name = 'WritableSessionStoreRequiredError';\n }\n}\n","import type { OAuthSessionDto } from '@/universal/types/dto/oauth-session';\nimport type { Newtype } from '@/universal/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 { WritableSessionStoreRequiredError } from '@/server/shared/errors';\nimport { HttpError } from '@/universal/api/http';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Config } from '@/universal/types/config';\nimport type { OAuthSessionDto } from '@/universal/types/dto/oauth-session';\nimport type {\n AuthorizationCode,\n ClientSecret,\n CodeVerifier,\n} from '@/universal/types/oauth';\nimport {\n ClientCredentialsOAuth,\n type OAuthAccessToken,\n type OAuthRefreshToken,\n OAuthSession,\n} from '@/universal/types/oauth-session';\n\nexport interface SessionStore {\n getSession(): Promise<OAuthSession | null>;\n /**\n * Persists or clears the OAuth session.\n *\n * **Omit this method to create a read-only store.** When absent, the SDK\n * skips token refresh entirely — no network call is made and no refresh\n * token is consumed. This is the correct approach for contexts that can read\n * the session but cannot write it back, such as Next.js Server Components.\n *\n * ⚠️ Do **not** implement this as a no-op (`async () => {}`). If the method\n * is present, the SDK assumes writes succeed: it will fire a token refresh\n * network call, consume the refresh token, then invoke `setSession` — which\n * would silently discard the new session and leave the browser holding an\n * invalidated refresh token. Simply **omit** `setSession` to prevent any\n * refresh from being attempted.\n *\n * {@link ServerAuthNamespace.completeOAuth} and\n * {@link ServerAuthNamespace.logout} always require a writable store and\n * throw {@link WritableSessionStoreRequiredError} if `setSession` is absent.\n */\n setSession?(session: OAuthSession | null): Promise<void>;\n}\n\n/**\n * The empty session store: holds no session, reads nothing, never writes.\n *\n * For server contexts that act without a user — the client-credentials grant\n * (`auth.clientCredentials`) and the public token registry (`tokens`) read\n * nothing from the store, so hosts building those paths need no store of\n * their own.\n *\n * `setSession` is deliberately absent, not a no-op — see\n * {@link SessionStore.setSession} for why a no-op is a bug.\n */\nexport function emptySessionStore(): SessionStore {\n return { getSession: async () => null };\n}\n\n/** The PKCE pair `CoinListClient#auth.completeOAuth` hands to the backend. */\nexport interface CompleteOAuthParams {\n /** The short-lived authorization code parsed out of the redirect URL. */\n code: AuthorizationCode;\n /** The `code_verifier` the browser generated when starting the flow. */\n codeVerifier: CodeVerifier;\n}\n\n/**\n * OAuth session lifecycle on your backend: exchanging authorization codes,\n * keeping the access token fresh, minting app-level tokens, and logging out.\n *\n * This namespace is server-only: every method needs the `clientSecret` and the\n * {@link SessionStore}, neither of which may exist in a browser.\n */\nexport interface ServerAuthNamespace {\n /**\n * Exchanges an authorization code from `CoinListClient#auth.completeOAuth`\n * for an OAuth session and persists it via {@link SessionStore.setSession}.\n *\n * Throws {@link WritableSessionStoreRequiredError} if the session store does\n * not provide `setSession`.\n */\n completeOAuth(params: CompleteOAuthParams): Promise<OAuthSession>;\n\n /**\n * Returns a valid access token for the current session, refreshing it if it\n * is expired or near expiry. This is what you serve to\n * {@link ClientConfig.getAccessToken}.\n *\n * **Writable store**: if the token is expired, the SDK exchanges the refresh\n * token for a new session, persists it, and returns the fresh access token.\n * Returns `null` if there is no session or the refresh fails.\n *\n * **Read-only store** (no `setSession`): refresh is skipped entirely. The\n * stored token is returned as-is, even if it is expired — a non-null return\n * value does **not** guarantee the token is accepted by the API. Before\n * making API calls, check `token.expiresAt > new Date()`. Use a writable\n * store (e.g. in a Route Handler) when you need the SDK to renew the session\n * automatically.\n *\n * @returns the access token, or `null` if there is no session or the session\n * could not be refreshed.\n */\n getAccessToken(): Promise<OAuthAccessToken | null>;\n\n /**\n * Obtains an app-level access token via the OAuth 2.0 `client_credentials`\n * grant (RFC 6749 §4.4). No user is involved: the token authenticates the\n * partner application itself and only grants access to app-level resources\n * such as offers and offer requirements.\n *\n * The token is **not** persisted to the {@link SessionStore} and has no\n * refresh token. It expires at `expiresAt`; once expired, call this method\n * again to obtain a fresh token — the SDK does not renew it automatically.\n *\n * Pass the result to `ServerOffersNamespace` or\n * `ServerRequirementsNamespace.forOffer` to read without a user session.\n */\n clientCredentials(): Promise<ClientCredentialsOAuth>;\n\n /**\n * Revokes the current token via `POST /oauth/revoke` and clears the session.\n *\n * Throws {@link WritableSessionStoreRequiredError} if the session store does\n * not provide `setSession`.\n */\n logout(): Promise<void>;\n}\n\n/** What {@link ServerAuthNamespaceImpl} needs out of `ServerConfig`. */\nexport type ServerAuthConfig = Config & {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Seconds before expiry at which a token counts as expired for refresh. */\n readonly accessTokenExpiryBufferSeconds: number;\n /** Whether to rethrow errors the SDK could otherwise swallow (e.g. revoke). */\n readonly strict: boolean;\n};\n\nexport class ServerAuthNamespaceImpl implements ServerAuthNamespace {\n private readonly log: InternalLogger;\n\n constructor(\n private readonly api: Sender,\n private readonly config: ServerAuthConfig\n ) {\n this.log = internalLogger(config.logger ?? null, 'AUTH');\n }\n\n async completeOAuth(params: CompleteOAuthParams): Promise<OAuthSession> {\n return this.log.wrap('completeOAuth', undefined, async () => {\n const setSession = this.writableSessionStore();\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'authorization_code',\n code: params.code,\n redirect_uri: this.config.redirectUri,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n code_verifier: params.codeVerifier,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n await setSession(session);\n return session;\n });\n }\n\n async getAccessToken(): Promise<OAuthAccessToken | null> {\n // Wrapped despite running on every request: `sessionStore.getSession` is\n // host code, and when it throws there is nothing else between the failure\n // and the host's own catch to say which SDK call it came out of.\n return this.log.wrap('getAccessToken', undefined, () =>\n this.readAccessToken()\n );\n }\n\n private async readAccessToken(): Promise<OAuthAccessToken | null> {\n const sessionStore = this.config.sessionStore;\n const session = await sessionStore.getSession();\n if (session == null) return null;\n\n const now = Date.now();\n const expiresAt = session.accessToken.expiresAt.getTime();\n const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1000;\n if (expiresAt > now + bufferMs) {\n // Valid access token, return it regardless\n return session.accessToken;\n }\n\n const setSession = sessionStore.setSession?.bind(sessionStore);\n if (!setSession) {\n // No write session capabilities => can't refresh!\n // Return the access token as-is\n this.log.child({ op: 'getAccessToken' }).warn(() => ({\n msg: 'serving an expired token: the session store is read-only, so it cannot be refreshed',\n }));\n return session.accessToken;\n }\n return this.refreshSession(session.refreshToken, setSession);\n }\n\n private async refreshSession(\n refreshToken: OAuthRefreshToken | undefined,\n setSession: (session: OAuthSession | null) => Promise<void>\n ): Promise<OAuthAccessToken | null> {\n const log = this.log.child({ op: 'refresh' });\n if (!refreshToken) {\n log.warn(() => ({\n msg: 'clearing the session: it carries no refresh token',\n }));\n await setSession(null);\n return null;\n }\n\n try {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n const newSession = OAuthSession.fromDto(sessionDto);\n await setSession(newSession);\n log.info(() => ({ msg: 'session renewed' }));\n return newSession.accessToken;\n } catch (error) {\n // The user is logged out by this line, and nothing above sees why:\n // `getAccessToken` answers `null` either way.\n log.failure(\n () => ({ msg: 'refresh failed; clearing the session' }),\n error\n );\n await setSession(null);\n return null;\n }\n }\n\n async clientCredentials(): Promise<ClientCredentialsOAuth> {\n return this.log.wrap('clientCredentials', undefined, async () => {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'client_credentials',\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n return ClientCredentialsOAuth(session.accessToken);\n });\n }\n\n async logout(): Promise<void> {\n return this.log.wrap('logout', undefined, () => this.revokeAndClear());\n }\n\n private async revokeAndClear(): Promise<void> {\n const setSession = this.writableSessionStore();\n const session = await this.config.sessionStore.getSession();\n if (session == null) return;\n\n try {\n await this.api.send({\n method: 'POST',\n url: `/oauth/revoke`,\n body: {\n token: session.accessToken.value,\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n },\n });\n } catch (err) {\n // A failed revoke still leaves the local session invalid, so only strict\n // callers care; anything that is not an HTTP failure is a real bug.\n if (!(err instanceof HttpError) || this.config.strict) {\n throw err;\n }\n this.log.child({ op: 'logout' }).warn(() => ({\n msg: 'the token was not revoked upstream; the local session is cleared regardless',\n }));\n }\n await setSession(null);\n }\n\n /**\n * Returns the store's `setSession`, or throws — the guard every\n * session-writing operation shares.\n */\n private writableSessionStore(): (\n session: OAuthSession | null\n ) => Promise<void> {\n const sessionStore = this.config.sessionStore;\n const setSession = sessionStore.setSession?.bind(sessionStore);\n if (!setSession) {\n throw new WritableSessionStoreRequiredError();\n }\n return setSession;\n }\n}\n","import type {\n Cursor,\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * Walks every page of a cursor-paginated endpoint and returns the flattened\n * result.\n *\n * Lives in the API layer rather than beside `PaginationParams` because it\n * drives requests: it is the auto-paginating half that `list()` is built on,\n * while the params and the response envelope are domain models the client and\n * the server both name.\n */\nexport async function fetchAllPages<\n A,\n P extends PaginationParams = PaginationParams,\n>(\n fetchPage: (params: P) => Promise<PaginatedResponse<A>>,\n baseParams?: Omit<P, keyof PaginationParams>\n): Promise<A[]> {\n const items: A[] = [];\n let cursor: Cursor | null = null;\n\n do {\n const params = {\n ...(baseParams ?? {}),\n after: cursor ?? undefined,\n } as P;\n const page = await fetchPage(params);\n items.push(...page.data);\n cursor = page.startingAfter;\n } while (cursor);\n\n return items;\n}\n","import {\n InvariantError,\n MathError,\n ValidationError,\n} from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type EthereumChain =\n | 'ethereum_mainnet'\n | 'ethereum_sepolia'\n | 'base_mainnet'\n | 'base_sepolia';\n\n/**\n * The exhaustive chain set: a new {@link EthereumChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const ETHEREUM_CHAINS: Record<EthereumChain, true> = {\n ethereum_mainnet: true,\n ethereum_sepolia: true,\n base_mainnet: true,\n base_sepolia: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const EthereumChain = (value: string): EthereumChain => {\n if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Ethereum chain: \"${value}\"`);\n }\n return value as EthereumChain;\n};\n\nexport type SolanaChain = 'solana_mainnet' | 'solana_devnet';\n\n/**\n * The exhaustive chain set: a new {@link SolanaChain} is a compile error\n * here until it is listed, which is what keeps the constructor total.\n */\nexport const SOLANA_CHAINS: Record<SolanaChain, true> = {\n solana_mainnet: true,\n solana_devnet: true,\n};\n\n/**\n * Validates that a raw backend string names a chain the SDK supports.\n *\n * @throws ValidationError on anything else. Passing an unknown chain through\n * would let downstream EIP-155 lookups blow up far from the response that\n * caused it.\n */\nexport const SolanaChain = (value: string): SolanaChain => {\n if (!Object.keys(SOLANA_CHAINS).includes(value)) {\n throw new ValidationError(`Unsupported Solana chain: \"${value}\"`);\n }\n return value as SolanaChain;\n};\n\nexport type Chain = EthereumChain | SolanaChain;\n\n/**\n * {@link Chain}'s check without the throw, for a mapper over a list that drops\n * the entries it cannot name rather than rejecting the whole list. Frontline's\n * chain registry may carry chains this SDK does not model yet.\n */\nexport const isChain = (value: string): value is Chain =>\n Object.keys(ETHEREUM_CHAINS).includes(value) ||\n Object.keys(SOLANA_CHAINS).includes(value);\n\nexport const Chain = (value: string): Chain => {\n if (!isChain(value)) {\n throw new ValidationError(`Unsupported chain: \"${value}\"`);\n }\n return value;\n};\n\n/**\n * Protocol a wallet binding is scoped to. EVM-only for now: an EVM address\n * binds once per option regardless of which EVM chain proved ownership.\n * Frontline's enum also has `:solana`, but we don't handle Solana bindings yet,\n * so this stays `'ethereum'` until Solana support lands.\n */\nexport type WalletProtocol = 'ethereum';\n\n/**\n * EVM addresses keep a `0x${string}` base so they stay assignable to the\n * `0x${string}` shapes that on-chain libraries (viem/wagmi) expect. We only\n * drop the runtime `0x` narrowing: values are trusted at the boundary and\n * branded via the constructor.\n */\nexport type EvmWalletAddress = Newtype<`0x${string}`, 'EvmWalletAddress'>;\nexport const EvmWalletAddress = (value: string): EvmWalletAddress =>\n value as EvmWalletAddress;\n\nexport type EvmContractAddress = Newtype<`0x${string}`, 'EvmContractAddress'>;\nexport const EvmContractAddress = (value: string): EvmContractAddress =>\n value as EvmContractAddress;\n\n/**\n * What uniquely identifies a token: the chain it is deployed on plus its\n * contract address. Never a symbol, which can collide across issuers.\n */\nexport type TokenIdentifier = {\n /** The chain the token contract is deployed on. */\n chain: EthereumChain;\n /**\n * The token's contract address, in any casing — consumers that need the\n * EIP-55 form (e.g. the token registry routes) checksum it themselves.\n */\n address: EvmContractAddress;\n};\n\nexport type HexEncodedTransactionData = Newtype<\n `0x${string}`,\n 'HexEncodedTransactionData'\n>;\nexport const HexEncodedTransactionData = (\n value: string\n): HexEncodedTransactionData => value as HexEncodedTransactionData;\n\n/**\n * A transaction the backend has already encoded for us — the caller only\n * broadcasts it. Used by the flows that hand a wallet a ready-made `to`/`data`\n * pair (allow-listing a wallet, an Ondo swap) rather than encoding a contract\n * call themselves.\n */\nexport type Tx = {\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n};\n\n/**\n * The largest exponent whose power of ten still fits a uint256: 10^77 fits,\n * 10^78 does not.\n *\n * The bound is arithmetic rather than a token standard's. ERC-20 reports\n * `decimals()` as a `uint8`, so 255 is what a contract *can* say, but every\n * {@link AssetDecimals} in this codebase is paired with a {@link Uint256} raw\n * by construction, and scaling by anything past this leaves that pairing\n * unrepresentable. A value between 78 and 255 would therefore pass a\n * standard-faithful check and then break the first multiplication it reached.\n */\nexport const MAX_ASSET_DECIMALS = 77;\n\n/**\n * How many decimal places one whole token divides into.\n *\n * Validated, unlike its neighbours here — {@link Uint256} is a bare `bigint`\n * with a separate {@link assertUint256} guard, and {@link DecimalString} casts\n * unchecked. The asymmetry is deliberate and follows the value's provenance:\n * an `AssetDecimals` used to come only from literals and the token registry,\n * but backends now publish exponents of their own (`asset_decimals` on an Ondo\n * quote, both scales on a built swap), and those feed `10n ** BigInt(d)`\n * during render. Guarding at construction is what keeps a fractional or\n * unbounded exponent from surfacing as a `RangeError` mid-render — or, at\n * 10^200, as a hung tab — instead of as the failed state the screen has.\n *\n * See docs/ADR-7-VALIDATED-NEWTYPES.md.\n *\n * @throws ValidationError on a non-integer, a negative, or anything above\n * {@link MAX_ASSET_DECIMALS}.\n */\nexport type AssetDecimals = Newtype<number, 'AssetDecimals'>;\nexport const AssetDecimals = (value: number): AssetDecimals => {\n if (!Number.isInteger(value)) {\n throw new ValidationError(`Asset decimals must be an integer: ${value}`);\n }\n if (value < 0 || value > MAX_ASSET_DECIMALS) {\n throw new ValidationError(\n `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`\n );\n }\n return value as AssetDecimals;\n};\n\nexport const STABLE_DECIMALS = AssetDecimals(6);\n\n/**\n * A non-negative decimal number the backend sent as a string, kept unscaled.\n *\n * Reach for it when a response gives you a number but not the decimals to\n * scale it by, or gives you one it has already applied. Inventing an exponent\n * for either is how a display ends up orders of magnitude out.\n *\n * Contrast {@link BlockchainAmount}, which pairs a raw uint256 with the\n * decimals it is denominated in and so is only constructible when you know\n * both. Arithmetic on a `DecimalString` needs a decimal library we\n * deliberately do not ship.\n */\nexport type DecimalString = Newtype<string, 'DecimalString'>;\nexport const DecimalString = (value: string): DecimalString =>\n value as DecimalString;\n\nexport const MAX_UINT_256 = 2n ** 256n - 1n;\n\n/**\n * A non-negative integer within uint256 bounds. Kept unbranded (a plain\n * `bigint`) so raw on-chain amounts flow in without ceremony; bounds are\n * enforced where it matters (see {@link combineAmounts}).\n */\nexport type Uint256 = bigint;\n\n/**\n * Asserts a computed bigint falls within uint256 bounds. Use at on-chain\n * arithmetic boundaries (bps math, price computation) where the SDK's own\n * arithmetic could underflow below zero or overflow above 2^256-1.\n *\n * Throws {@link InvariantError}, because reaching it means the SDK computed\n * something no chain could represent. **For a value that came off the wire,\n * use {@link parseUint256} instead**: the backend sending an unrepresentable\n * number is a {@link ValidationError}, and the two have different remedies.\n */\nexport const assertUint256 = (value: bigint): Uint256 => {\n if (isUint256(value)) return value;\n throw new InvariantError(`Value out of uint256 bounds: ${value}`);\n};\n\n/**\n * {@link assertUint256} at a wire boundary: the same bounds check, reported as\n * a {@link ValidationError} against the named field, because a value out of\n * range here is the backend's, not the SDK's.\n *\n * `label` names the field the way a DTO mapper's other failures do, so a log\n * line says which one - `SwapPreview.pay_input_amount`, not `a number`.\n */\nexport const parseUint256 = (value: bigint, label: string): Uint256 => {\n if (isUint256(value)) return value;\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n};\n\nconst isUint256 = (value: bigint): boolean =>\n value >= 0n && value <= MAX_UINT_256;\n\nexport type BlockchainAmount = Newtype<\n { raw: Uint256; decimals: AssetDecimals },\n 'BlockchainAmount'\n>;\n\n/**\n * Constructs a {@link BlockchainAmount} and exposes arithmetic helpers.\n * TypeScript has no operator overloading, so use `BlockchainAmount.add(a, b)`\n * instead of `+`/`-`/`*`/`/` on the objects directly.\n */\nexport const BlockchainAmount = Object.assign(\n (value: { raw: Uint256; decimals: AssetDecimals }): BlockchainAmount =>\n value as BlockchainAmount,\n {\n add: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x + y),\n sub: (a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount =>\n combineAmounts(a, b, (x, y) => x - y),\n mul: multiplyAmounts,\n div: divideAmounts,\n }\n);\n\n/**\n * `a * b`, denominated in `a`'s decimals - a price times a quantity, an amount\n * times a rate.\n *\n * The exact inverse of {@link divideAmounts}, and it reads the same way round:\n * the answer stays in `a`'s scale and `b`'s divides back out, so the two\n * compose - `mul(div(a, b), b)` is `a` again, short only what truncation took.\n * That is what makes `price x quantity` land in the currency the price was\n * quoted in rather than at some product of two exponents no token uses.\n *\n * The multiplication happens *before* the division by `10^b.decimals`, so the\n * full precision of both operands survives into the one rounding at the end.\n * Like `div` it truncates towards zero on both signs, which is the safe\n * direction for money: a total is never inflated past what the parts hold.\n *\n * Total - unlike `div`, there is nothing here to reject. The scale it divides\n * by is a power of ten, never zero, and a product is not bounds-checked for\n * the same reason a quotient is not: whether one past uint256 is a corrupt\n * response or an expected magnitude belongs to the caller.\n */\nfunction multiplyAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n const product = a.raw * b.raw;\n return BlockchainAmount({\n raw: product / 10n ** BigInt(b.decimals),\n decimals: a.decimals,\n });\n}\n\n/**\n * `a / b`, denominated in `a`'s decimals - a price, a ratio, a rate.\n *\n * Unlike {@link combineAmounts}, the two operands may be at different scales,\n * and usually are: dividing dollars by shares is the point of the operation,\n * and the two tokens rarely share an exponent. `b`'s scale divides back out -\n * the numerator is scaled by `10^b.decimals` *before* the division, so nothing\n * is lost to integer truncation early and the quotient lands in `a`'s scale,\n * which is the one the amounts it is rendered beside are in.\n *\n * Truncates towards zero on both signs, which is what BigInt division already\n * does and the safe direction for money: the total a price implies never\n * exceeds, in magnitude, the amount that actually moved.\n *\n * A zero divisor is the only rejection. The quotient is deliberately *not*\n * bounds-checked the way {@link combineAmounts} checks a sum: scaling the\n * numerator carries even legal pairs past uint256 (a maximal amount over a\n * single base unit), and whether that reads as a corrupt response or an\n * expected magnitude is the caller's to judge - see `computeOndoBuyPrice` and\n * `computeOndoSellPrice`, which bounds-check the price they build out of this.\n *\n * @throws MathError when `b` is zero. `add` and `sub` throw a bare `Error`\n * because a scale mismatch is a programming error caught in review; a zero\n * divisor arrives from a server response and is divided by during render, so\n * it is a named failure a screen can catch and map to a failed state.\n */\nfunction divideAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount\n): BlockchainAmount {\n if (b.raw === 0n) {\n throw new MathError('Cannot divide a BlockchainAmount by zero');\n }\n\n const scaled = a.raw * 10n ** BigInt(b.decimals);\n return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });\n}\n\n/**\n * Combine two amounts with a raw-bigint `op`. Both operands must share the\n * same `decimals` — adding/subtracting differently-scaled amounts is a\n * programming error, so we throw rather than silently producing garbage.\n * The result is bounds-checked, so an underflow (negative `raw`) or uint256\n * overflow is rejected.\n */\nfunction combineAmounts(\n a: BlockchainAmount,\n b: BlockchainAmount,\n op: (x: bigint, y: bigint) => bigint\n): BlockchainAmount {\n if (a.decimals !== b.decimals) {\n throw new InvariantError(\n 'Cannot combine BlockchainAmounts with different decimals: ' +\n `${a.decimals} vs ${b.decimals}`\n );\n }\n const raw = op(a.raw, b.raw);\n if (raw < 0n || raw > MAX_UINT_256) {\n throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);\n }\n return BlockchainAmount({ raw, decimals: a.decimals });\n}\n\nexport type AssetSymbol = Newtype<string, 'AssetSymbol'>;\nexport const AssetSymbol = (value: string): AssetSymbol => value as AssetSymbol;\n\n/**\n * A stablecoin symbol is an {@link AssetSymbol} narrowed to the coins we\n * support. It shares the `AssetSymbol` brand so it stays assignable to it.\n */\nexport type StablecoinSymbol = Newtype<'USDC' | 'USDT', 'AssetSymbol'>;\nexport const StablecoinSymbol = (value: 'USDC' | 'USDT'): StablecoinSymbol =>\n value as StablecoinSymbol;\n\nexport type KnownAssetSymbol = StablecoinSymbol;\nexport const KnownAssetSymbol = StablecoinSymbol;\n\nexport type Erc20Asset = {\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n};\n\nexport type Bps = Newtype<bigint, 'Bps'>;\nexport const Bps = (value: bigint): Bps => value as Bps;\n","import {\n Chain,\n EvmContractAddress,\n isChain,\n} from '@/universal/types/blockchain/core';\nimport type {\n OfferDto,\n OfferTokenDto,\n OfferTypeDto,\n} from '@/universal/types/dto/offer';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type OfferId = Newtype<string, 'OfferId'>;\nexport const OfferId = (value: string) => value as OfferId;\n\nexport type OfferSlug = Newtype<string, 'OfferSlug'>;\nexport const OfferSlug = (value: string) => value as OfferSlug;\n\nexport type OfferType = OfferTypeDto;\n\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: OfferToken.listFromDto(dto.tokens),\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 /**\n * Maps an offer's token list, dropping every token on a chain this SDK does\n * not name. Frontline's chain registry runs ahead of {@link Chain}, and a\n * plain `.map` would throw out of `Offer.fromDto` and, through\n * `PaginatedResponse.fromDto`, reject the whole offers page - which is how\n * one Base token blanked production's offers list. Dropping costs that\n * token's metadata alone: `coinlist.tokens.get` takes an `EthereumChain`,\n * so nobody could have looked it up anyway.\n *\n * Same shape as `TokenMetadata.fromRegistryDto`.\n */\n listFromDto: (dtos: OfferTokenDto[]): OfferToken[] =>\n dtos.filter((dto) => isChain(dto.chain)).map(OfferToken.fromDto),\n};\n","import type { AssetDto } from '@/universal/types/dto/asset';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type AssetId = Newtype<string, 'AssetId'>;\nexport const AssetId = (value: string) => value as AssetId;\n\nexport type AssetCode = Newtype<string, 'AssetCode'>;\nexport const AssetCode = (value: string) => value as AssetCode;\n\nexport type Asset = {\n id: AssetId;\n code: AssetCode;\n name: string;\n fractionalDigits: number;\n};\n\nexport const Asset = {\n fromDto: (dto: AssetDto): Asset => ({\n id: AssetId(dto.id),\n code: AssetCode(dto.code),\n name: dto.name,\n fractionalDigits: dto.fractional_digits,\n }),\n};\n","import type { Newtype } from '@/universal/types/newtype';\n\nexport type Ticker = Newtype<string, 'Ticker'>;\nexport const Ticker = (value: string): Ticker => value as Ticker;\n\n/**\n * An ISO 6166 International Securities Identification Number, e.g.\n * `US0378331005`. Identifies the security itself, which is what makes it the\n * stable key across venues where a {@link Ticker} is not: the same security\n * trades under different tickers in different places, and the same ticker\n * means different securities in different places.\n *\n * Not validated on construction — the value comes from a supplier that has\n * already checked it, and a client-side check-digit test could only reject\n * data the SDK still has to display.\n */\nexport type Isin = Newtype<string, 'Isin'>;\nexport const Isin = (value: string): Isin => value as Isin;\n\nexport type OrderBookSide = 'buy' | 'sell';\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { Asset } from '@/universal/types/asset';\nimport { Chain, EvmContractAddress } from '@/universal/types/blockchain/core';\nimport type {\n OfferDetailDto,\n OfferDetailFaqDto,\n OfferDetailLinkDto,\n OfferDetailMilestoneDto,\n OfferDetailOptionDto,\n OfferDetailSwapContractDto,\n OfferDetailTermDto,\n} from '@/universal/types/dto/offer-detail';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\nimport {\n OfferId,\n OfferSlug,\n OfferToken,\n type OfferType,\n} from '@/universal/types/offer';\nimport { Isin, Ticker } from '@/universal/types/trading';\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 * Every chain this offer can be swapped on, with the CoinList contract each\n * settles through. Empty means it cannot be swapped anywhere.\n */\n swapContracts: OfferSwapContract[];\n\n about: string | null;\n tagline: string;\n bannerUrl: string;\n logoUrl: string;\n category: string;\n\n /**\n * The legal issuer of the *token*, e.g. `'Ondo Global Markets'`. The issuer\n * of the security it tracks is {@link OfferDetail.name} (`'Apple Inc.'`).\n * Null on offers with no single named issuer.\n */\n issuer: string | null;\n\n /**\n * ISO 6166 identifier of the underlying security, e.g. `'US0378331005'`.\n * Null both on offers that tokenize no security and on the few that do but\n * whose supplier publishes no ISIN, so absence does not imply \"not a\n * security\".\n */\n isin: Isin | null;\n\n /**\n * The underlying security's symbol on its listing venue, e.g. `'QQQ'`. This\n * is *not* the token's symbol — that is `asset.code` (`'QQQon'`). Null on\n * offers that tokenize no listed security.\n */\n ticker: Ticker | null;\n\n /**\n * What kind of instrument the underlying is, as the supplier classifies it:\n * `'Stock'`, `'ETF'`. Distinct from {@link OfferDetail.category}, which is\n * the broader class the offer is grouped under (`'Equities'`) — this field\n * describes the single instrument, `category` describes the shelf it sits\n * on.\n *\n * An open set: the vocabulary belongs to the supplier and may grow without\n * notice, so render an unrecognized value rather than branching on it. Note\n * the supplier's spelling is its own — a common stock arrives as `'Stock'`.\n */\n instrumentType: string | null;\n\n /**\n * The exchange the underlying security lists on, e.g. `'NASDAQ'`. Not\n * derivable from {@link OfferDetail.isin}, whose country prefix is the\n * country of issuance rather than the venue.\n *\n * Unlike the fields above, this one is recorded by hand rather than served\n * by the supplier, so it is null until someone records it — on a newly\n * listed offer that is the normal state, and it says nothing about whether\n * the offer tokenizes a security.\n */\n listingVenue: string | null;\n\n 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\n/**\n * A chain an offer can be swapped on, with the CoinList contract the swap\n * settles through - the spender to approve before any quote exists.\n *\n * Carries no role, unlike {@link OfferToken}: there is one swap contract per\n * chain and it serves every Ondo asset on it, so which token is being traded\n * does not change the answer.\n */\nexport type OfferSwapContract = {\n chain: Chain;\n address: EvmContractAddress;\n};\n\nexport const OfferSwapContract = {\n fromDto: (dto: OfferDetailSwapContractDto): OfferSwapContract => ({\n chain: Chain(dto.chain),\n address: EvmContractAddress(dto.address),\n }),\n};\n\nexport const OfferDetail = {\n fromDto: (dto: OfferDetailDto): OfferDetail => {\n 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 // Absent is not an error. frontline#1365 puts `swap_contracts` on the Ondo\n // variant alone, so a token sale or Superstate offer carries no key at\n // all, and `[]` already means \"cannot swap here\".\n const swapContracts =\n dto.swap_contracts === undefined ? [] : dto.swap_contracts;\n if (!Array.isArray(swapContracts)) {\n throw new ValidationError(\n `OfferDetail.swap_contracts: expected an array, got ${typeof swapContracts}`\n );\n }\n\n const isin = notBlankStringOrNull(dto.isin);\n const ticker = notBlankStringOrNull(dto.ticker);\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: OfferToken.listFromDto(dto.tokens),\n swapContracts: swapContracts.map(OfferSwapContract.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 issuer: notBlankStringOrNull(dto.issuer),\n isin: isin === null ? null : Isin(isin),\n ticker: ticker === null ? null : Ticker(ticker),\n instrumentType: notBlankStringOrNull(dto.instrument_type),\n listingVenue: notBlankStringOrNull(dto.listing_venue),\n\n startsAt: new Date(dto.starts_at),\n endsAt: dto.ends_at ? new Date(dto.ends_at) : null,\n\n faqs: dto.faqs.map(FaqItem.fromDto),\n links: dto.links.map(Link.fromDto),\n milestones: dto.milestones.map(Milestone.fromDto),\n options: dto.options.map(OfferOption.fromDto),\n terms: dto.terms.map(TermItem.fromDto),\n };\n },\n};\n\nexport const OfferOption = {\n fromDto: (dto: OfferDetailOptionDto): OfferOption => ({\n id: OfferOptionId(dto.id),\n slug: OfferOptionSlug(dto.slug),\n bidIncrement: dto.bid_increment,\n floorPriceUsd: dto.floor_price_usd,\n minimumPurchaseUsd: dto.minimum_purchase_usd,\n priceUsd: dto.price_usd,\n saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),\n totalTokenSupply: dto.total_token_supply,\n }),\n};\n\nexport const FaqItem = {\n fromDto: (dto: OfferDetailFaqDto): FaqItem => ({\n question: notBlankStringOrNull(dto.question),\n answer: notBlankStringOrNull(dto.answer),\n }),\n};\n\nexport const Link = {\n fromDto: (dto: OfferDetailLinkDto): Link => ({\n label: notBlankStringOrNull(dto.label),\n url: notBlankStringOrNull(dto.url),\n }),\n};\n\nexport const TermItem = {\n fromDto: (dto: OfferDetailTermDto): TermItem => ({\n key: notBlankStringOrNull(dto.key),\n value: notBlankStringOrNull(dto.value),\n }),\n};\n\nexport const Milestone = {\n fromDto: (dto: OfferDetailMilestoneDto): Milestone => ({\n name: notBlankStringOrNull(dto.name),\n schedule: notBlankStringOrNull(dto.schedule),\n status: dto.status,\n }),\n};\n","import type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type Cursor = Newtype<string, 'Cursor'>;\nexport const Cursor = (value: string) => value as Cursor;\n\n/**\n * Cursor-based pagination input used when requesting paginated API resources.\n * Set `after` or `before` to navigate relative to a known cursor, and `limit`\n * to control the maximum number of returned items.\n */\nexport interface PaginationParams {\n before?: Cursor;\n after?: Cursor;\n limit?: number;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n startingAfter: Cursor | null;\n startingBefore: Cursor | null;\n}\n\nexport const PaginatedResponse = {\n fromDto: <A, B>(\n dto: PaginatedResponseDto<A>,\n itemMapper: (item: A) => B\n ): PaginatedResponse<B> => ({\n 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 { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { OfferDto } from '@/universal/types/dto/offer';\nimport type { OfferDetailDto } from '@/universal/types/dto/offer-detail';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport { Offer, type OfferId } from '@/universal/types/offer';\nimport { OfferDetail } from '@/universal/types/offer-detail';\nimport {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\nexport async function fetchOffers(\n api: Sender,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Offer[]> {\n return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));\n}\n\nexport async function fetchOffersPage(\n api: Sender,\n params: PaginationParams,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<PaginatedResponse<Offer>> {\n const queryParams = PaginationParams.toQueryParams(params);\n const pageDto = await api.send<PaginatedResponseDto<OfferDto>>({\n method: 'GET',\n url: '/v1/offers',\n queryParams,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return PaginatedResponse.fromDto(pageDto, Offer.fromDto);\n}\n\nexport async function fetchOfferDetails(\n api: Sender,\n id: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<OfferDetail> {\n const dto = await api.send<OfferDetailDto>({\n method: 'GET',\n url: `/v1/offers/${id}`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return OfferDetail.fromDto(dto);\n}\n","import type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport * as offersApi from '@/universal/api/frontline/offers';\nimport type { OffersNamespace } from '@/universal/core/offers/offers-namespace';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { Offer, OfferId } from '@/universal/types/offer';\nimport type { OfferDetail } from '@/universal/types/offer-detail';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/universal/types/pagination';\n\n/**\n * The server-side offers namespace: the same reads as the shared\n * {@link OffersNamespace}, each additionally callable with an app-level token\n * from `ServerAuthNamespace.clientCredentials` instead of a user session.\n *\n * When a user session exists it takes precedence and `clientCreds` acts as a\n * fallback. Without either, the reads throw {@link NotAuthenticatedError}.\n */\nexport interface ServerOffersNamespace extends OffersNamespace {\n /** @param clientCreds app-level token to read without a user session. */\n list(clientCreds?: ClientCredentialsOAuth): Promise<Offer[]>;\n\n /** @param clientCreds app-level token to read without a user session. */\n listPage(\n params: PaginationParams,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<PaginatedResponse<Offer>>;\n\n /** @param clientCreds app-level token to read without a user session. */\n get(id: OfferId, clientCreds?: ClientCredentialsOAuth): Promise<OfferDetail>;\n}\n\nexport class ServerOffersNamespaceImpl implements ServerOffersNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: ServerNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'OFFERS');\n }\n\n async list(clientCreds?: ClientCredentialsOAuth): Promise<Offer[]> {\n return this.log.wrap('list', clientCreds, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOffers(this.ctx.api, clientCreds);\n });\n }\n\n async listPage(\n params: PaginationParams,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<PaginatedResponse<Offer>> {\n return this.log.wrap('listPage', { params, clientCreds }, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOffersPage(this.ctx.api, params, clientCreds);\n });\n }\n\n async get(\n id: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<OfferDetail> {\n return this.log.wrap('get', { id, clientCreds }, async () => {\n await this.ctx.ensureAuthenticated(clientCreds);\n return offersApi.fetchOfferDetails(this.ctx.api, id, clientCreds);\n });\n }\n}\n","import type {\n RequirementActionNeededReasonDto,\n RequirementDto,\n RequirementStatusesDto,\n RequirementStatusValueDto,\n RequirementTypeDto,\n} from '@/universal/types/dto/requirement';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport type { Newtype } from '@/universal/types/newtype';\n\nexport type RequirementId = Newtype<string, 'RequirementId'>;\nexport const RequirementId = (value: string) => value as RequirementId;\n\nexport type RequirementType = RequirementTypeDto;\nexport type RequirementStatusValue = RequirementStatusValueDto;\nexport type RequirementActionNeededReason = RequirementActionNeededReasonDto;\n\nexport type Requirement = {\n id: RequirementId;\n type: RequirementType;\n details: Record<string, unknown> | null;\n};\n\nexport const Requirement = {\n fromDto: (dto: RequirementDto): Requirement => ({\n id: RequirementId(dto.id),\n type: dto.type,\n details: dto.details,\n }),\n};\n\nexport type RequirementStatusInfo = {\n id: RequirementId;\n status: RequirementStatusValue;\n /** Why the requirement needs action (KYC-backed requirements only). */\n action: RequirementActionNeededReason | null;\n /**\n * The Sumsub verification level that resolves this requirement, prescribed\n * by the backend. Present exactly when an inline Sumsub flow can be started.\n */\n kycLevel?: KycLevelName;\n /**\n * Whether the Sumsub applicant must be reset before starting the flow\n * (redoing an already-approved level, e.g. to update stale PII). Forward to\n * the kyc-token request as-is.\n */\n kycReset?: boolean;\n};\n\nexport const RequirementStatusInfo = {\n fromStatusesDto: (dto: RequirementStatusesDto): RequirementStatusInfo[] =>\n Object.entries(dto.statuses).map(([id, value]) =>\n typeof value === 'string'\n ? { id: RequirementId(id), status: value, action: null }\n : {\n id: RequirementId(id),\n status: value.status,\n action: value.action ?? null,\n kycLevel: value.kyc_level,\n kycReset: value.kyc_reset,\n }\n ),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n OfferRequirementsDto,\n RequirementStatusesDto,\n} from '@/universal/types/dto/requirement';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport async function fetchOfferRequirements(\n api: Sender,\n offerId: OfferId,\n clientCreds: ClientCredentialsOAuth | undefined\n): Promise<Record<OfferOptionId, Requirement[]>> {\n const response = await api.send<OfferRequirementsDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements`,\n attributes: Attributes.concat(\n Attributes.protected(),\n Attributes.clientCredentials(clientCreds)\n ),\n });\n return Object.fromEntries(\n Object.entries(response.options).map(([optionId, list]) => [\n optionId,\n list.data.map(Requirement.fromDto),\n ])\n );\n}\n\nexport async function fetchRequirementStatuses(\n api: Sender,\n offerId: OfferId\n): Promise<RequirementStatusInfo[]> {\n const response = await api.send<RequirementStatusesDto>({\n method: 'GET',\n url: `/v1/offers/${offerId}/requirements/statuses`,\n attributes: Attributes.protected(),\n });\n return RequirementStatusInfo.fromStatusesDto(response);\n}\n","import type {\n DocumentFormTypeDto,\n DocumentSubmissionDto,\n DocumentSubmissionStatusDto,\n} from '@/universal/types/dto/document-submission';\n\n/** Document types that can be signed via {@link CoinListClient.submitDocument}. */\nexport type DocumentType = 'tax_certification';\n\n/** Signing-state machine status for a document submission. */\nexport type DocumentSubmissionStatus = DocumentSubmissionStatusDto;\n\n/** The tax form derived from the entity's kind (individual vs company/trust). */\nexport type DocumentFormType = DocumentFormTypeDto;\n\n/** Result of starting (or resuming) a document signing submission. */\nexport type DocumentSubmission = {\n status: DocumentSubmissionStatus;\n formType: DocumentFormType;\n};\n\nexport const DocumentSubmission = {\n fromDto: (dto: DocumentSubmissionDto): DocumentSubmission => ({\n status: dto.status,\n formType: dto.form_type,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n DocumentSubmission,\n type DocumentType,\n} from '@/universal/types/document-submission';\nimport type { DocumentSubmissionDto } from '@/universal/types/dto/document-submission';\n\n/**\n * Starts (or resumes) a document signing submission for the given type.\n *\n * `fields` are signing-form values keyed by the document's DocuSeal field\n * names (e.g. `\"Full Name\"`, `\"Permanent Address\"`) and are forwarded\n * verbatim to Passport to pre-fill the document. They are not validated or\n * persisted by Frontline.\n */\nexport async function submitDocument(\n api: Sender,\n documentType: DocumentType,\n fields: Record<string, string>\n): Promise<DocumentSubmission> {\n const dto = await api.send<DocumentSubmissionDto>({\n method: 'POST',\n url: `/v1/documents/${documentType}/submission`,\n body: fields,\n attributes: Attributes.protected(),\n });\n return DocumentSubmission.fromDto(dto);\n}\n","import type { KycTokenDto } from '@/universal/types/dto/kyc';\n\n/**\n * Sumsub verification level name. Determines which screens the Sumsub WebSDK\n * shows (levels are configured in the Sumsub dashboard). The backend\n * prescribes the level (and whether the applicant must be reset first) in the\n * requirement statuses response — clients never compute levels themselves.\n */\nexport type KycLevelName = string;\n\n/** Short-lived Sumsub WebSDK access token scoped to the current user. */\nexport type KycToken = {\n token: string;\n};\n\nexport const KycToken = {\n fromDto: (dto: KycTokenDto): KycToken => ({\n token: dto.token,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { KycTokenDto } from '@/universal/types/dto/kyc';\nimport type { KycLevelName } from '@/universal/types/kyc';\nimport { KycToken } from '@/universal/types/kyc';\n\nexport async function createKycToken(\n api: Sender,\n levelName?: KycLevelName,\n reset?: boolean\n): Promise<KycToken> {\n const dto = await api.send<KycTokenDto>({\n method: 'POST',\n url: '/v1/kyc-token',\n body: {\n ...(levelName === undefined ? {} : { level_name: levelName }),\n ...(reset === undefined ? {} : { reset }),\n },\n attributes: Attributes.protected(),\n });\n return KycToken.fromDto(dto);\n}\n","import type {\n PiiAddressDto,\n PiiDto,\n PiiJurisdictionDto,\n PiiKindDto,\n} from '@/universal/types/dto/pii';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/** Whether the PII belongs to an individual or a company/trust entity. */\nexport type PiiKind = PiiKindDto;\n\n/** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */\nexport type Iso2CountryCode = Newtype<string, 'Iso2CountryCode'>;\nexport const Iso2CountryCode = (value: string) => value as Iso2CountryCode;\n\n/** Jurisdiction derived from the entity's address country. */\nexport type PiiJurisdiction = {\n iso2: Iso2CountryCode;\n name: string | null;\n};\n\nexport const PiiJurisdiction = {\n fromDto: (dto: PiiJurisdictionDto): PiiJurisdiction => ({\n iso2: Iso2CountryCode(dto.iso_2),\n name: dto.name,\n }),\n};\n\n/** Permanent address on file for the entity. */\nexport type PiiAddress = {\n street: string | null;\n city: string | null;\n state: string | null;\n postalCode: string | null;\n country: string | null;\n};\n\nexport const PiiAddress = {\n fromDto: (dto: PiiAddressDto): PiiAddress => ({\n street: dto.street,\n city: dto.city,\n state: dto.state,\n postalCode: dto.postal_code,\n country: dto.country,\n }),\n};\n\n/**\n * The current user's PII, used to pre-fill tax forms such as the W-8BEN.\n * Fields the entity hasn't provided are `null`.\n */\nexport type Pii = {\n kind: PiiKind;\n fullLegalName: string | null;\n dateOfBirth: string | null;\n jurisdiction: PiiJurisdiction | null;\n taxId: string | null;\n permanentAddress: PiiAddress;\n};\n\nexport const Pii = {\n fromDto: (dto: PiiDto): Pii => ({\n kind: dto.kind,\n fullLegalName: dto.full_legal_name,\n dateOfBirth: dto.date_of_birth,\n jurisdiction: dto.jurisdiction\n ? PiiJurisdiction.fromDto(dto.jurisdiction)\n : null,\n taxId: dto.tax_id,\n permanentAddress: PiiAddress.fromDto(dto.permanent_address),\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { PiiDto } from '@/universal/types/dto/pii';\nimport { Pii } from '@/universal/types/pii';\n\nexport async function fetchPii(api: Sender): Promise<Pii> {\n const dto = await api.send<PiiDto>({\n method: 'GET',\n url: '/v1/pii',\n attributes: Attributes.protected(),\n });\n return Pii.fromDto(dto);\n}\n","import * as documentsApi from '@/universal/api/frontline/documents';\nimport * as kycApi from '@/universal/api/frontline/kyc';\nimport * as piiApi from '@/universal/api/frontline/pii';\nimport * as requirementsApi from '@/universal/api/frontline/requirements';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/universal/types/document-submission';\nimport type { KycLevelName, KycToken } from '@/universal/types/kyc';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Pii } from '@/universal/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/universal/types/requirement';\n\nexport type CreateKycTokenParams = {\n /**\n * Sumsub verification level to run. Defaults to the backend's standard\n * level.\n */\n levelName?: KycLevelName;\n /**\n * Resets the Sumsub applicant first, so an already-approved level can be\n * executed again (e.g. to update stale PII). Pass the `kycReset` value from\n * the requirement status, and never on mid-flow token refreshes.\n */\n reset?: boolean;\n};\n\nexport type SubmitDocumentParams = {\n /** Currently only `tax_certification` (W-8BEN / W-8BEN-E). */\n documentType: DocumentType;\n /**\n * Signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to pre-fill the document.\n */\n fields: Record<string, string>;\n};\n\n/**\n * Everything a user must satisfy before they can participate in an offer:\n * reading the checklist and its live statuses, and the operations that satisfy\n * individual requirements — identity verification (KYC) and tax-document\n * signing.\n *\n * Wallet requirements (`external_wallet`, `whitelisted_wallet`) are satisfied\n * through `WalletsNamespace` instead, since wallet proofs are also used\n * outside the requirements flow.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface RequirementsNamespace {\n /**\n * Fetches the requirements for every option of an offer, grouped by option\n * id. This is the definition of the checklist; {@link statuses} tells you\n * where the user stands against it.\n */\n forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;\n\n /**\n * Fetches the current user's status for each requirement of an offer.\n */\n statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n\n /**\n * Creates a short-lived Sumsub WebSDK access token so an identity\n * verification (KYC) flow can be started, e.g. by the `IdentityVerification`\n * component.\n */\n createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;\n\n /**\n * Fetches the current user's PII, used to pre-fill tax forms such as the\n * W-8BEN. Fields the entity hasn't provided are `null`.\n */\n getPii(): Promise<Pii>;\n\n /**\n * Starts (or resumes) a document signing submission.\n */\n submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;\n}\n\nexport class RequirementsNamespaceImpl implements RequirementsNamespace {\n protected readonly log: InternalLogger;\n\n constructor(protected readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'REQUIREMENTS');\n }\n\n async forOffer(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchOfferRequirements(\n this.ctx.api,\n offerId,\n undefined\n );\n });\n }\n\n async statuses(offerId: OfferId): Promise<RequirementStatusInfo[]> {\n return this.log.wrap('statuses', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.ctx.api, offerId);\n });\n }\n\n async createKycToken(params?: CreateKycTokenParams): Promise<KycToken> {\n return this.log.wrap('createKycToken', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return kycApi.createKycToken(\n this.ctx.api,\n params?.levelName,\n params?.reset\n );\n });\n }\n\n async getPii(): Promise<Pii> {\n return this.log.wrap('getPii', undefined, async () => {\n await this.ctx.ensureUserAuthenticated();\n return piiApi.fetchPii(this.ctx.api);\n });\n }\n\n async submitDocument(\n params: SubmitDocumentParams\n ): Promise<DocumentSubmission> {\n return this.log.wrap('submitDocument', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return documentsApi.submitDocument(\n this.ctx.api,\n params.documentType,\n params.fields\n );\n });\n }\n}\n","import type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport * as requirementsApi from '@/universal/api/frontline/requirements';\nimport {\n type RequirementsNamespace,\n RequirementsNamespaceImpl,\n} from '@/universal/core/requirements/requirements-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type { Requirement } from '@/universal/types/requirement';\n\n/**\n * The server-side requirements namespace: the same surface as the shared\n * {@link RequirementsNamespace}, except {@link forOffer} — the offer's\n * requirement definitions are app-level data, so it is additionally callable\n * with a token from `ServerAuthNamespace.clientCredentials`.\n *\n * Everything else is per-user data and needs a user session. `handle` is\n * client-only: there is no browser tab to open on a server.\n */\nexport interface ServerRequirementsNamespace extends RequirementsNamespace {\n /** @param clientCreds app-level token to read without a user session. */\n forOffer(\n offerId: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n}\n\nexport class ServerRequirementsNamespaceImpl\n extends RequirementsNamespaceImpl\n implements ServerRequirementsNamespace\n{\n constructor(\n private readonly serverCtx: UniversalNamespaceContext &\n ServerNamespaceContext\n ) {\n super(serverCtx);\n }\n\n async forOffer(\n offerId: OfferId,\n clientCreds?: ClientCredentialsOAuth\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n return this.log.wrap('forOffer', { offerId, clientCreds }, async () => {\n await this.serverCtx.ensureAuthenticated(clientCreds);\n return requirementsApi.fetchOfferRequirements(\n this.serverCtx.api,\n offerId,\n clientCreds\n );\n });\n }\n}\n","/**\n * Base URL of CoinList's public token registry (Nabu), a static CDN serving\n * token display metadata keyed by chain + contract address. Override per\n * environment via `Config.tokensBaseUrl`.\n */\nexport const NABU_BASE_URL = 'https://asset.coinlist.co';\n","import {\n createPublicClient,\n http,\n type PublicClient,\n type Transport,\n} from 'viem';\nimport type { Sender } from '@/universal/api/http-client';\nimport { frontlineTransport } from '@/universal/api/rpc/frontline-transport';\nimport { viemChain } from '@/universal/core/shared/blockchain/chain';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport type { RpcConfig } from '@/universal/types/config';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * Resolves a chain to the viem `PublicClient` the SDK reads it through.\n *\n * One function rather than a client per read, because the client is where the\n * batching lives: viem's multicall scheduler is keyed on the client's `uid`,\n * so two reads only ever share an `eth_call` if they share a client. Hence the\n * memoisation - it is correctness for batching, not a performance tweak.\n */\nexport type PublicClients = (chain: EthereumChain) => PublicClient;\n\n/**\n * Builds the per-chain `PublicClient` factory, lazily and once per chain.\n *\n * `batch: { multicall: true }` routes concurrent `eth_call`s through\n * Multicall3, whose address comes from viem's own chain definitions (see\n * `viemChain`). A checkout screen mounts several hooks that each read\n * independently - status, authorization, allowance, balance - and they collapse\n * into a single request. Per-call failures survive it: viem calls `aggregate3`\n * with `allowFailure: true` and re-throws each revert on its own call.\n *\n * **A read reached through these clients must take its subject as an\n * argument.** Batching makes `msg.sender` the Multicall3 address rather than\n * the caller, so a view that reads `msg.sender` would answer differently under\n * batching than without. Nothing the SDK reads does - `allowance(owner,\n * spender)`, `balanceOf(account)`, `authorized(user)` all name theirs - and a\n * new read must keep it that way.\n */\nexport function publicClients(\n api: Sender,\n config: RpcConfig | undefined,\n logger: Logger | null = null\n): PublicClients {\n const cache = new Map<EthereumChain, PublicClient>();\n\n return (chain) => {\n const cached = cache.get(chain);\n if (cached) return cached;\n\n const client = createPublicClient({\n chain: viemChain(chain),\n transport: transportFor(api, config?.[chain], chain, logger),\n batch: { multicall: true },\n });\n cache.set(chain, client);\n return client;\n };\n}\n\n/**\n * A host's override, or CoinList's proxy. A string is a URL the SDK wraps in\n * `http()`; a {@link Transport} is used as it stands, so `fallback([...])` and\n * a partner's own transport both pass through untouched.\n *\n * Only the proxy transport is given the logger. A host's own transport reports\n * however they built it, and viem's `http()` has no logging seam, so a host on\n * their own node gets whatever they wired up and nothing from the SDK.\n */\nfunction transportFor(\n api: Sender,\n override: string | Transport | undefined,\n chain: EthereumChain,\n logger: Logger | null\n): Transport {\n if (override === undefined) return frontlineTransport(api, chain, logger);\n return typeof override === 'string' ? http(override) : override;\n}\n","import { custom, RpcRequestError, type Transport } from 'viem';\nimport { HttpError } from '@/universal/api/http';\nimport { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport type { Logger } from '@/universal/types/logger';\n\n/**\n * A viem {@link Transport} that speaks JSON-RPC to CoinList's proxy,\n * `POST /v1/chains/{chain}/rpc`.\n *\n * Built over the SDK's own {@link Sender} rather than viem's `http()`, so an\n * on-chain read is an SDK request like any other: it carries the bearer token,\n * renews a stale session on a 401 and retries, is stamped with a request id,\n * and is reported by `HttpClient` by construction. Pointing `http()` at the\n * same URL would mean a second HTTP path through the SDK with none of that.\n * Retrying is the `Sender`'s job alone: viem's own `retryCount` is set to `0`\n * here, because it would otherwise rerun that whole pipeline on top of itself.\n *\n * **This is where the session requirement lives**, and it is the proxy that\n * enforces it: the endpoint is OAuth-gated, so a logged-out read comes back\n * `401` and reaches the caller as viem's `ContractFunctionExecutionError`\n * wrapping the SDK's own `HttpError`. Deliberately *not* translated to\n * `NotAuthenticatedError` - viem re-wraps whatever a `Transport` throws, so the\n * translation would not survive to the caller anyway and would only buy a\n * promise the SDK cannot keep. `classifyLogCause` walks the chain, so the\n * failure still logs as the HTTP failure it is.\n *\n * A partner who supplies their own node via {@link RpcConfig} never reaches\n * this transport and correctly needs no CoinList session.\n *\n * **What its `RPC` lines add over the `HTTP` ones for the same request.** The\n * JSON-RPC method, which the path `/v1/chains/{chain}/rpc` does not carry; and\n * a JSON-RPC error, which usually arrives with HTTP 200 and is therefore an\n * `info` success as far as `HttpClient` can tell.\n *\n * **They do not name the contract call**, and cannot: `publicClients` batches\n * through Multicall3, so one `eth_call` here may be several reads and its `to`\n * is Multicall3 rather than any contract. What is available is on the `debug`\n * line - the raw params, so the target address and the calldata. Which method\n * asked for the read, and whether it reverted, come from the namespace above.\n */\nexport function frontlineTransport(\n api: Sender,\n chain: EthereumChain,\n logger: Logger | null = null\n): Transport {\n const log = internalLogger(logger, 'RPC');\n let nextId = 0;\n\n return custom(\n {\n async request({ method, params }) {\n const id = ++nextId;\n return sendRpc({ api, log, chain, id, method, params });\n },\n },\n // The `Sender` below already retries: `requestRetryMiddleware` makes three\n // attempts at a 5xx and `renewSessionMiddleware` re-sends once after a 401.\n // viem's own default is `retryCount: 3`, and it applies on top: an\n // `HttpError` carries no numeric `code`, so `buildRequest` wraps it in\n // `UnknownRpcError` (`code === -1`) and `shouldRetry` says yes. That reruns\n // the whole pipeline four times - twelve requests for one `eth_call`, and\n // with multicall batching one `eth_call` is a screen's worth of reads. The\n // SDK's retry policy is the one that applies, so viem's is turned off.\n { retryCount: 0 }\n );\n}\n\nasync function sendRpc({\n api,\n log,\n chain,\n id,\n method,\n params,\n}: {\n api: Sender;\n log: InternalLogger;\n chain: EthereumChain;\n /** The JSON-RPC envelope's `id`, unique per request within one transport. */\n id: number;\n method: string;\n /** The JSON-RPC method's own params, passed through untouched. */\n params: unknown;\n}): Promise<unknown> {\n const url = rpcPath(chain);\n const startedAt = Date.now();\n\n // `params` carries calldata, so the envelope is a `'debug'` disclosure.\n log.debug(() => ({\n msg: 'rpc call sent',\n fields: { id, method, chain, params },\n }));\n\n const response = await sendEnvelope(api, url, {\n jsonrpc: '2.0',\n id,\n method,\n params,\n });\n const elapsed = Date.now() - startedAt;\n\n // A JSON-RPC error usually arrives with HTTP 200, so the `Sender` hands it\n // back as a success. viem's own `http()` transport raises `RpcRequestError`\n // here, and every viem action above - `readContract`'s revert decoding\n // included - is written against that.\n if (response.error) {\n const error = new RpcRequestError({\n body: { method, params },\n error: response.error,\n url,\n });\n // `warn`: the node declined, and only the namespace above knows whether\n // that broke anything. The code is the node's own, not a message anyone\n // wrote about this request.\n //\n // The cause is stated rather than classified. viem's `buildRequest` maps a\n // `RpcRequestError` onto one of its `RpcError` subclasses on the way out,\n // which is what `classifyLogCause` recognises - but that happens *above*\n // this throw, so classifying here would answer `'unknown'` for every\n // rejection. This call site knows: the node answered with an error object.\n log.warning(\n () => ({\n msg: 'rpc call rejected',\n cause: { type: 'rpc', reason: 'node-rejected' },\n fields: {\n method,\n chain,\n duration_ms: elapsed,\n 'rpc.error_code': response.error?.code ?? null,\n },\n }),\n error\n );\n throw error;\n }\n\n log.info(() => ({\n msg: 'rpc call',\n fields: { method, chain, duration_ms: elapsed },\n }));\n return response.result;\n}\n\nfunction rpcPath(chain: EthereumChain): string {\n return `/v1/chains/${encodeURIComponent(chain)}/rpc`;\n}\n\n/**\n * Posts the envelope, and reads a JSON-RPC error out of a non-2xx as well.\n *\n * The proxy forwards the node's status alongside its body, so a node that\n * answers a JSON-RPC error with, say, a `400` reaches the `Sender` as an\n * {@link HttpError}. Left as that, the node's error code and any revert data\n * would be lost behind an opaque HTTP failure. An `HttpError` whose body is not\n * a JSON-RPC error - frontline's own `422` for an unsupported chain or a\n * disallowed method, a `401`, a `5xx` - is the HTTP failure it looks like and\n * propagates untouched.\n */\nasync function sendEnvelope(\n api: Sender,\n url: string,\n body: { jsonrpc: '2.0'; id: number; method: string; params: unknown }\n): Promise<JsonRpcResponse> {\n try {\n return await api.send<JsonRpcResponse>({\n method: 'POST',\n url,\n body,\n attributes: Attributes.protected(),\n });\n } catch (error) {\n if (error instanceof HttpError && isJsonRpcError(error.response.body)) {\n return error.response.body;\n }\n throw error;\n }\n}\n\nfunction isJsonRpcError(\n body: unknown\n): body is Required<Pick<JsonRpcResponse, 'error'>> {\n if (typeof body !== 'object' || body === null || !('error' in body)) {\n return false;\n }\n const { error } = body;\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n typeof error.code === 'number'\n );\n}\n\n/**\n * Only what the transport branches on. The SDK does not model the envelope as\n * a DTO: it is JSON-RPC's shape, not frontline's, and every field but these\n * two is handed straight back to viem.\n */\ntype JsonRpcResponse = {\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n};\n","import type { Chain, Hash } from 'viem';\nimport { base, baseSepolia, mainnet, sepolia } from 'viem/chains';\nimport type { EthereumChain } from '@/universal/types/blockchain/core';\nimport { TxExplorerUrl } from '@/universal/types/blockchain/ui';\nimport { ValidationError } from '@/universal/types/errors';\n\n/**\n * The one chain table. `satisfies` makes a new {@link EthereumChain} a compile\n * error here until its definition is added, which is what keeps every lookup\n * below total.\n *\n * viem's own definitions rather than a hand-written `{ id }` map: they carry\n * the EIP-155 id *and* the deployed Multicall3 address, which is what lets\n * `publicClients` batch concurrent reads into one `eth_call`. A hand-rolled\n * definition would silently lose that.\n */\nconst VIEM_CHAINS = {\n ethereum_mainnet: mainnet,\n ethereum_sepolia: sepolia,\n base_mainnet: base,\n base_sepolia: baseSepolia,\n} as const satisfies Record<EthereumChain, Chain>;\n\n/** The viem chain definition the SDK reads and writes this chain through. */\nexport function viemChain(chain: EthereumChain): Chain {\n return VIEM_CHAINS[chain];\n}\n\nexport function getChainId(chain: EthereumChain): number {\n return VIEM_CHAINS[chain].id;\n}\n\n/**\n * Resolves an EIP-155 chain id to the chain the SDK names it by — the inverse\n * of {@link getChainId}, for backends that report a bare `chain_id`.\n *\n * @throws ValidationError on an unrecognised id. Defaulting to mainnet would\n * let a testnet response read as a live one.\n */\nexport function chainFromId(chainId: string): EthereumChain {\n const chains = Object.keys(VIEM_CHAINS) as EthereumChain[];\n const chain = chains.find((c) => String(VIEM_CHAINS[c].id) === chainId);\n if (!chain) {\n throw new ValidationError(`Unsupported EIP-155 chain id: \"${chainId}\"`);\n }\n return chain;\n}\n\nexport function getNetworkName(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'Ethereum';\n case 'ethereum_sepolia':\n return 'Ethereum Sepolia';\n case 'base_mainnet':\n return 'Base';\n case 'base_sepolia':\n return 'Base Sepolia';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n\nexport function txExplorerUrl(\n chain: EthereumChain,\n txHash: Hash\n): TxExplorerUrl {\n return TxExplorerUrl(`${explorerBaseUrl(chain)}/tx/${txHash}`);\n}\n\nfunction explorerBaseUrl(chain: EthereumChain): string {\n switch (chain) {\n case 'ethereum_mainnet':\n return 'https://etherscan.io';\n case 'ethereum_sepolia':\n return 'https://sepolia.etherscan.io';\n case 'base_mainnet':\n return 'https://basescan.org';\n case 'base_sepolia':\n return 'https://sepolia-explorer.base.org';\n default: {\n const _exhaustive: never = chain;\n return _exhaustive;\n }\n }\n}\n","import type { Newtype } from '@/universal/types/newtype';\n\nexport type FormattedAmountUi = Newtype<string, 'FormattedAmountUi'>;\nexport const FormattedAmountUi = (value: string): FormattedAmountUi =>\n value as FormattedAmountUi;\n\nexport type FormattedPercentUi = Newtype<string, 'FormattedPercentUi'>;\nexport const FormattedPercentUi = (value: string): FormattedPercentUi =>\n value as FormattedPercentUi;\n\nexport type TxExplorerUrl = Newtype<string, 'TxExplorerUrl'>;\nexport const TxExplorerUrl = (value: string): TxExplorerUrl =>\n value as TxExplorerUrl;\n\n/**\n * A wallet address shortened for display (e.g. `0x1234…5678`). Keeps a\n * `0x${string}` base but drops the runtime `0x` narrowing.\n */\nexport type ShortenedWalletAddress = Newtype<\n `0x${string}`,\n 'ShortenedWalletAddress'\n>;\nexport const ShortenedWalletAddress = (value: string): ShortenedWalletAddress =>\n value as ShortenedWalletAddress;\n\nexport type FormattedAmountAssetUi = Newtype<string, 'FormattedAmountAssetUi'>;\nexport const FormattedAmountAssetUi = (value: string): FormattedAmountAssetUi =>\n value as FormattedAmountAssetUi;\n\nexport type AssetIconUrl = Newtype<string, 'AssetIconUrl'>;\nexport const AssetIconUrl = (value: string): AssetIconUrl =>\n value as AssetIconUrl;\n","import { notBlankStringOrNull } from '@/universal/core/shared/utils/crypto';\nimport { Asset, type AssetId } from '@/universal/types/asset';\nimport type {\n CreateParticipationDto,\n ParticipationDto,\n ParticipationStatusDto,\n} from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { QueryParamValue } from '@/universal/types/http';\nimport type { Newtype } from '@/universal/types/newtype';\nimport { OfferId, type OfferId as OfferIdType } from '@/universal/types/offer';\nimport {\n OfferOptionId,\n type OfferOptionId as OfferOptionIdType,\n} from '@/universal/types/offer-detail';\nimport { PaginationParams } from '@/universal/types/pagination';\n\n/** Unique identifier for a participation. */\nexport type ParticipationId = Newtype<string, 'ParticipationId'>;\n/** Casts a string into a typed {@link ParticipationId}. */\nexport const ParticipationId = (value: string) => value as ParticipationId;\n\n/** Blockchain identifier for where a participation is funded. */\nexport type Blockchain = Newtype<string, 'Blockchain'>;\n/** Casts a string into a typed {@link Blockchain}. */\nexport const Blockchain = (value: string) => value as Blockchain;\n\n/** Wallet address used for a participation. */\nexport type WalletAddress = Newtype<`0x${string}`, 'WalletAddress'>;\n/** Casts a `0x`-prefixed string into a typed {@link WalletAddress}. */\nexport const WalletAddress = (value: `0x${string}`) => value as WalletAddress;\n\n/** Possible participation lifecycle states returned by the API. */\nexport type ParticipationStatus = ParticipationStatusDto;\n\n/** Domain model for a participation returned by CoinList APIs. */\nexport type Participation = {\n /** Unique participation id. */\n id: ParticipationId;\n /** Parent offer id. */\n offerId: OfferIdType;\n /** Selected offer option id. */\n offerOptionId: OfferOptionIdType;\n /** Current processing status. */\n status: ParticipationStatus;\n /** Raw participation amount from API. */\n amount: string;\n /** Human-readable formatted amount from API. */\n displayAmount: string;\n /** Asset metadata for the participation amount. */\n asset: Asset;\n /** Funding chain identifier. */\n chain: Blockchain;\n /** Creation timestamp, if returned by API. */\n insertedAt: Date | null;\n /** Last update timestamp, if returned by API. */\n updatedAt: Date | null;\n /** Wallet used for participation, blank values normalized to null. */\n walletAddress: WalletAddress | null;\n};\n\n/** Parameters required to create a new participation. */\nexport type CreateParticipationParams = {\n /** Offer to participate in. */\n offerId: OfferIdType;\n /** Offer option selected for participation. */\n offerOptionId: OfferOptionIdType;\n /** Blockchain for funding. */\n chain: Blockchain;\n /** Wallet address that funds the participation. */\n walletAddress: WalletAddress;\n /**\n * Decimal token amount to participate with (e.g. `\"100\"` for 100 USDC), NOT\n * raw base units. The backend rescales this by the asset's decimals to verify\n * it against the on-chain approval allowance.\n */\n amount: string;\n /** Funding asset id. */\n assetId: AssetId;\n /**\n * Hash of the ERC-20 `approve()` transaction covering this participation.\n * Required: the backend verifies it on-chain (sender, token, spender, and\n * approved amount) before confirming the participation.\n */\n approvalTransactionHash: string;\n};\n\n/** Pagination params for listing participations, with an optional offer filter. */\nexport interface ParticipationsPaginationParams extends PaginationParams {\n offerId?: OfferIdType;\n}\n\nexport const ParticipationsPaginationParams = {\n toQueryParams: (\n params: ParticipationsPaginationParams\n ): Record<string, QueryParamValue> => {\n const queryParams = PaginationParams.toQueryParams(params);\n if (params.offerId) {\n queryParams['filters[0][field]'] = 'offer_id';\n queryParams['filters[0][op]'] = '==';\n queryParams['filters[0][value]'] = params.offerId;\n }\n return queryParams;\n },\n};\n\nexport const Participation = {\n /** Maps API DTO shape into the SDK participation domain model. */\n fromDto: (dto: ParticipationDto): Participation => {\n const walletAddress = notBlankStringOrNull(dto.wallet_address);\n return {\n id: ParticipationId(dto.id),\n offerId: OfferId(dto.offer_id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n status: dto.status,\n amount: dto.amount,\n displayAmount: dto.amount_string,\n asset: Asset.fromDto(dto.asset),\n chain: Blockchain(dto.chain),\n insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,\n updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,\n walletAddress: walletAddress\n ? WalletAddress(walletAddress as `0x${string}`)\n : null,\n };\n },\n};\n\nexport const CreateParticipationParams = {\n /** Maps participation creation params into API DTO payload. */\n toDto: (params: CreateParticipationParams): CreateParticipationDto => ({\n offer_id: params.offerId,\n offer_option_id: params.offerOptionId,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount,\n asset_id: params.assetId,\n approval_transaction_hash: params.approvalTransactionHash,\n }),\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport { fetchAllPages } from '@/universal/api/pagination';\nimport type { PaginatedResponseDto } from '@/universal/types/dto/pagination';\nimport type { ParticipationDto } from '@/universal/types/dto/providers/coin-list/token-sale';\nimport type { OfferId } from '@/universal/types/offer';\nimport { PaginatedResponse } from '@/universal/types/pagination';\nimport {\n CreateParticipationParams,\n Participation,\n type ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\nexport async function fetchParticipations(\n api: Sender,\n offerId?: OfferId\n): Promise<Participation[]> {\n return fetchAllPages<Participation, ParticipationsPaginationParams>(\n (params) => fetchParticipationsPage(api, params),\n { offerId }\n );\n}\n\nexport async function fetchParticipationsPage(\n api: Sender,\n params: ParticipationsPaginationParams\n): Promise<PaginatedResponse<Participation>> {\n const pageDto = await api.send<PaginatedResponseDto<ParticipationDto>>({\n method: 'GET',\n url: '/v1/participations',\n queryParams: ParticipationsPaginationParams.toQueryParams(params),\n attributes: Attributes.protected(),\n });\n return PaginatedResponse.fromDto(pageDto, Participation.fromDto);\n}\n\nexport async function fetchParticipation(\n api: Sender,\n id: ParticipationId\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'GET',\n url: `/v1/participations/${id}`,\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n\nexport async function createParticipation(\n api: Sender,\n params: CreateParticipationParams\n): Promise<Participation> {\n const dto = await api.send<ParticipationDto>({\n method: 'POST',\n url: '/v1/participations',\n body: CreateParticipationParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return Participation.fromDto(dto);\n}\n","import * as participationsApi from '@/universal/api/frontline/providers/coin-list/token-sale';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { PaginatedResponse } from '@/universal/types/pagination';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/universal/types/providers/coin-list/token-sale';\n\n/**\n * Read/write operations for token sales: listing and reading the current user's\n * participations, and recording a new one. The on-chain execution flow\n * (`executeTokenSale`) is layered on top of this in the client-side namespace.\n */\nexport interface CoinListTokenSaleNamespace {\n /**\n * Fetches all participations by iterating through every paginated response,\n * optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n list(offerId?: OfferId): Promise<Participation[]>;\n\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n\n /**\n * Fetches a participation by id.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n get(id: ParticipationId): Promise<Participation>;\n\n /**\n * Records a participation with CoinList.\n *\n * Requires an authenticated user; throws {@link NotAuthenticatedError}\n * otherwise.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n}\n\nexport class CoinListTokenSaleNamespaceImpl\n implements CoinListTokenSaleNamespace\n{\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'TOKEN_SALE');\n }\n\n async list(offerId?: OfferId): Promise<Participation[]> {\n return this.log.wrap('list', offerId, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipations(this.ctx.api, offerId);\n });\n }\n\n async listPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n return this.log.wrap('listPage', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipationsPage(this.ctx.api, params);\n });\n }\n\n async get(id: ParticipationId): Promise<Participation> {\n return this.log.wrap('get', id, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.fetchParticipation(this.ctx.api, id);\n });\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n return this.log.wrap('createParticipation', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return participationsApi.createParticipation(this.ctx.api, params);\n });\n }\n}\n","import { formatUnits } from 'viem';\nimport type {\n AssetSymbol,\n BlockchainAmount,\n Bps,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport { AssetDecimals } from '@/universal/types/blockchain/core';\nimport {\n FormattedAmountAssetUi,\n FormattedAmountUi,\n FormattedPercentUi,\n ShortenedWalletAddress,\n} from '@/universal/types/blockchain/ui';\n\nexport function shortenAddress(\n address: EvmWalletAddress\n): ShortenedWalletAddress {\n const short =\n address.length > 10\n ? `${address.slice(0, 6)}…${address.slice(-4)}`\n : address;\n return ShortenedWalletAddress(short);\n}\n\nexport type FormatAmountOptions = {\n maxFractionDigits?: AssetDecimals;\n};\n\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 '@/universal/types/blockchain/core';\nimport { ValidationError } from '@/universal/types/errors';\n\n/** A typed, i18n-agnostic reason a raw amount string failed to parse. */\nexport type AmountParseErrorReason =\n | { type: 'empty' }\n | { type: 'negative' }\n | { type: 'invalid-format' }\n | { type: 'too-many-decimals'; maxDecimals: AssetDecimals }\n /** Scaled up by `decimals`, the amount no longer fits a uint256. */\n | { type: 'overflow' };\n\nexport type AmountParseResult =\n | { valid: true; amount: BlockchainAmount }\n | { valid: false; reason: AmountParseErrorReason };\n\n/**\n * Wraps a raw uint256 base-unit string — what Ondo and the on-chain reads\n * return (\"100000000\" is 100 USDC, not 100 wei-of-nothing) — in a\n * {@link BlockchainAmount} at the given decimals. The value is already scaled,\n * so `decimals` is only the unit tag that travels with it.\n *\n * Distinct from {@link parseBlockchainAmount}, which takes a *human decimal*\n * string and scales it up. Feeding a raw amount to that one silently\n * multiplies it by 10^decimals — pick by what the backend sends, not by which\n * one is closer at hand.\n *\n * @throws ValidationError when the string is not a non-negative uint256\n * integer. A backend that regresses to decimal strings fails loudly here\n * rather than truncating.\n */\nexport function blockchainAmountFromRawOrThrow({\n label,\n raw,\n decimals,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n}): BlockchainAmount {\n const trimmed = raw.trim();\n // BigInt('') is 0n, not an error — an absent amount must not read as zero.\n if (trimmed === '') {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n let value: bigint;\n try {\n // BigInt() rejects \"0.5\", \"abc\" and \"1e18\" by throwing SyntaxError.\n value = BigInt(trimmed);\n } catch {\n throw new ValidationError(`${label}: not a uint256 integer (\"${raw}\")`);\n }\n try {\n return BlockchainAmount({ raw: assertUint256(value), decimals });\n } catch {\n throw new ValidationError(`${label}: out of uint256 bounds (${value})`);\n }\n}\n\n/**\n * Parses a user-entered decimal string into a {@link BlockchainAmount} at the\n * given token decimals. Rejects scientific notation, negatives, malformed\n * input, more fractional digits than the token supports, and amounts that\n * scale past uint256 — surfacing a typed {@link AmountParseErrorReason} so\n * callers own the display copy.\n */\nexport function parseBlockchainAmount(\n amount: string,\n decimals: AssetDecimals\n): AmountParseResult {\n const trimmed = amount.trim();\n if (trimmed === '') return { valid: false, reason: { type: 'empty' } };\n if (trimmed.startsWith('-')) {\n return { valid: false, reason: { type: 'negative' } };\n }\n // viem accepts \"1e18\" as scientific notation — reject it explicitly\n if (/[eE]/.test(trimmed)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // reject bare decimal point\n if (trimmed === '.') {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n // normalize a leading or trailing decimal\n // replace(/^./, '0.') -> Turns \".25\" to \"0.25\"\n // replace(/.$/, '') -> Turns \"25.\" to \"25\"\n const normalised = trimmed.replace(/^\\./, '0.').replace(/\\.$/, '');\n if (!/^\\d+(\\.\\d+)?$/.test(normalised)) {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n const [, fraction = ''] = normalised.split('.');\n if (fraction.length > decimals) {\n return {\n valid: false,\n reason: { type: 'too-many-decimals', maxDecimals: decimals },\n };\n }\n try {\n // parseUnits is unbounded: a long enough input scales past uint256, which\n // no on-chain amount can hold. Reporting it as valid would send a\n // truncated or reverting value to a contract.\n const raw = parseUnits(normalised, decimals);\n if (raw > MAX_UINT_256) {\n return { valid: false, reason: { type: 'overflow' } };\n }\n return {\n valid: true,\n amount: BlockchainAmount({ raw, decimals }),\n };\n } catch {\n return { valid: false, reason: { type: 'invalid-format' } };\n }\n}\n","import { chainFromId } from '@/universal/core/shared/blockchain/chain';\nimport { blockchainAmountFromRawOrThrow } from '@/universal/core/shared/blockchain/math';\nimport {\n AssetDecimals,\n AssetSymbol,\n type BlockchainAmount,\n DecimalString,\n type Erc20Asset,\n type EthereumChain,\n EvmContractAddress,\n HexEncodedTransactionData,\n type Tx,\n} from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoSwapDtoCore,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport { type OrderBookSide, Ticker } from '@/universal/types/trading';\n\n/**\n * Whether an Ondo asset can be traded right now.\n *\n * The caps only mean anything while trading is open, so they live on the\n * `tradable` branch. They stay {@link DecimalString} rather than\n * {@link BlockchainAmount} because the response carries no `asset_decimals`:\n * there is no honest exponent to attach, and the USD caps arrive with more\n * fractional digits than a stablecoin has decimals.\n *\n * Each cap is independently nullable even when tradable — Ondo may open an\n * asset for trading without publishing every limit.\n *\n * `side` is carried through from the response rather than dropped: the whole\n * status describes one side, so a buy and a sell status are otherwise\n * indistinguishable once a caller holds both.\n */\nexport type OndoTradingStatus =\n | {\n type: 'tradable';\n side: OrderBookSide;\n /** Largest order in whole tokens. */\n grossMaxTokens: DecimalString | null;\n /** Largest order in USD. */\n grossMaxNotionalValue: DecimalString | null;\n /** USD cap for the session the market is currently in. */\n grossMaxActiveNotionalValue: DecimalString | null;\n }\n | {\n type: 'not-tradable';\n side: OrderBookSide;\n };\n\nexport const OndoTradingStatus = {\n fromDto: (dto: OndoTradingStatusDto): OndoTradingStatus => {\n if (!dto.tradable) return { type: 'not-tradable', side: dto.side };\n return {\n type: 'tradable',\n side: dto.side,\n grossMaxTokens: decimalOrNull(dto.gross_max_tokens),\n grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),\n grossMaxActiveNotionalValue: decimalOrNull(\n dto.gross_max_active_notional_value\n ),\n };\n },\n};\n\nconst decimalOrNull = (value: string | null): DecimalString | null =>\n value === null ? null : DecimalString(value);\n\n/**\n * An indicative price for an Ondo asset, free to poll while the user edits an\n * order.\n *\n * **No CoinList fee is applied to the quantity or the price.** Ondo prices\n * exactly the amount asked for. A CoinList approval is fee-inclusive, so\n * sizing a quote against one without netting the fee first overstates what the\n * user receives. Showing a gross/net breakdown needs a CoinList swap\n * contract's `preview`, and no such contract exists for Ondo yet.\n *\n * The quote carries no transaction to broadcast and no expiry. Building one is\n * a separate endpoint per side that spends an attestation - see\n * {@link OndoBuyTransaction} and {@link OndoSellTransaction}.\n */\nexport type OndoQuote = {\n /** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */\n chain: EthereumChain;\n ticker: Ticker;\n /**\n * Needed to approve or transfer the asset; the quote is the only source.\n *\n * **Resolved on Ethereum mainnet**, like everything else on this quote, and\n * therefore not necessarily the contract the swap pulls from on the chain\n * the order executes on. Frontline resolves that one per chain and publishes\n * it nowhere, so on a testnet these are two different tokens. Tracked\n * against the frontline stack that follows ENG-1756.\n */\n assetAddress: EvmContractAddress;\n /**\n * The asset as the quote resolves it, from frontline's own catalogue.\n *\n * Its `decimals` scale {@link tokenBaseUnits} and nothing else. They are\n * **not** the scale of a built transaction's spend or output: those are\n * reported by whatever priced them, the sources are allowed to disagree, and\n * only the one that produced a number answers for it.\n */\n asset: Erc20Asset;\n side: OrderBookSide;\n tokenBaseUnits: BlockchainAmount;\n /**\n * USD price of one whole token. Unscaled because Ondo has already scaled it,\n * and by USDon's 18 decimals rather than the stablecoin's 6 — re-scaling it\n * by either would be wrong.\n */\n price: DecimalString;\n};\n\nexport const OndoQuote = {\n fromDto: (dto: OndoQuoteDto): OndoQuote => {\n const assetDecimals = AssetDecimals(dto.asset_decimals);\n return {\n chain: chainFromId(dto.chain_id),\n ticker: Ticker(dto.ticker),\n assetAddress: EvmContractAddress(dto.asset_address),\n asset: {\n name: dto.ticker,\n symbol: AssetSymbol(dto.symbol),\n decimals: assetDecimals,\n },\n side: dto.side,\n tokenBaseUnits: blockchainAmountFromRawOrThrow({\n label: 'tokenBaseUnits',\n raw: dto.token_base_units,\n decimals: assetDecimals,\n }),\n price: DecimalString(dto.price),\n };\n },\n};\n\n/**\n * The half of a built swap that both sides share: the calldata, its deadline,\n * and what the wallet parts with.\n *\n * There is deliberately **no union over the two sides**. Each is built by its\n * own endpoint and its own namespace method, so a caller never holds one\n * without knowing which it is, and a union would only re-pose a question the\n * call site had already answered. What is genuinely common lives here, and\n * {@link executeOndoSwap} takes this rather than either arm - broadcasting\n * knows nothing about the direction of the trade.\n *\n * `side` is not on this type but on each arm, as a literal the SDK authors\n * from the method that was called. The wire stopped echoing one when the\n * endpoint split, and it is still worth carrying: `OndoOrderPlaced` is a union\n * the SDK builds from both, and that union needs a tag.\n */\nexport type OndoSwapTransactionCore = {\n /**\n * Broadcast as-is. The `to` is the swap contract, which is also the ERC-20\n * spender the user must have approved.\n */\n tx: Tx;\n /**\n * When the calldata stops being accepted. A transaction broadcast after this\n * reverts, so callers must compare against it before signing.\n */\n expiresAt: Date;\n /**\n * Gross amount the wallet spends, in the decimals of the token this side\n * spends: the funding token on a buy, the asset on a sell.\n *\n * The same field at two scales, which is the whole reason the two sides are\n * two types. It is also what the approval has to cover.\n */\n spendInputAmount: BlockchainAmount;\n};\n\n/**\n * A signed, expiring purchase: a funding token in, an exact quantity of the\n * asset out.\n *\n * Distinct from {@link OndoQuote} in three ways that matter: it costs an\n * attestation to obtain, it expires, and it carries a {@link Tx} the wallet\n * broadcasts verbatim. Treat it as single-use - once broadcast (or once\n * `expiresAt` passes) it is spent, and a new one must be built.\n *\n * **The quantity is attested and exact, with no floor beneath it.** That is\n * what separates it from an {@link OndoSellTransaction}, which commits to a\n * range: nothing here is an estimate.\n *\n * **It carries no other identity.** No chain, ticker or asset: the endpoint\n * publishes none of them, and inventing them from the request would assert\n * what the server resolved rather than report it. What it does publish is the\n * scale of every amount on it, so a caller needs nothing alongside it to read\n * the numbers - only to name the assets, which the offer already does.\n *\n * It carries no price either. See `computeOndoBuyPrice`, which derives it from\n * the amounts the response does carry - the price this transaction fills at,\n * rather than an indicative one that has since moved.\n */\nexport type OndoBuyTransaction = OndoSwapTransactionCore & {\n side: 'buy';\n /**\n * CoinList's cut, in `spendInputAmount`'s decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Taken at execution rather than added on top, so the approval never has to\n * cover more than `spendInputAmount`.\n */\n fee: BlockchainAmount;\n /**\n * `spendInputAmount` less `fee`, in the same decimals: what Ondo priced, and\n * the numerator of the fill price.\n *\n * Read from the response rather than subtracted here. Whether the fee comes\n * off the deposit or goes on top of it is the server's definition to change,\n * and a client that derives this cannot notice when it does.\n */\n notionalValue: BlockchainAmount;\n /**\n * Quantity of the asset the wallet receives, at the scale whatever priced it\n * reported - not at the {@link OndoQuote}'s `asset.decimals`.\n */\n receiveOutputAmount: BlockchainAmount;\n};\n\nexport const OndoBuyTransaction = {\n fromDto: (dto: OndoBuyDto): OndoBuyTransaction => {\n // Read once each, so a mapper that reached for the wrong exponent on one\n // of the amounts is a visible mistake rather than a plausible one.\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'buy',\n fee: blockchainAmountFromRawOrThrow({\n label: 'fee',\n raw: dto.fee,\n decimals: spendDecimals,\n }),\n notionalValue: blockchainAmountFromRawOrThrow({\n label: 'notional_value',\n raw: dto.notional_value,\n decimals: spendDecimals,\n }),\n receiveOutputAmount: parsePositiveAmount({\n label: 'receive_output_amount',\n raw: dto.receive_output_amount,\n decimals: outputDecimals,\n // A transaction that yields nothing is not one to sign - the user\n // would pay the deposit and receive no asset - and frontline refuses\n // to emit one. A zero here is a changed encoding, not a small order.\n // Rejecting it at the boundary is also what lets `computeOndoBuyPrice`\n // divide by it without a fallible result: the failure surfaces as the\n // data hook's ERROR state rather than as a division during render.\n reason: 'a buy that yields nothing is not fillable',\n }),\n };\n },\n};\n\n/**\n * One end of the range a sale commits to: what arrives, and what CoinList took\n * to get it there.\n *\n * The two travel together because they are charged against each other -\n * `quantity` is already **net** of `fee` - and because the pair a caller wants\n * is always both halves of the same outcome. Grouping them is what makes\n * \"the expected quantity, less the fee at the floor\" unrepresentable rather\n * than merely wrong.\n */\nexport type OndoSellOutcome = {\n /** What the wallet receives at this outcome, net of {@link fee}. */\n quantity: BlockchainAmount;\n /**\n * CoinList's cut at this outcome, in the same decimals. Zero until ENG-1718\n * lands - frontline rejects a non-zero one on either side today.\n *\n * Already deducted from {@link quantity} rather than charged on top of it.\n */\n fee: BlockchainAmount;\n};\n\n/**\n * A signed, expiring sale: the asset in, a settlement coin out, somewhere\n * between two published outcomes.\n *\n * Single-use and expiring for the same reasons as an {@link OndoBuyTransaction},\n * and obtained the same way - one endpoint, one attestation.\n *\n * **A sale commits to a range, not a quantity.** Ondo settles through USDon\n * before converting to the settlement token, so {@link expected} is what to\n * expect and {@link minimum} is what the calldata enforces. A screen that\n * shows only the first presents a firm-looking number the contract may\n * legitimately fill below.\n *\n * There is deliberately no counterpart to a buy's `notionalValue`. A sale\n * commits on the output side, so frontline reports no fee-exclusive input and\n * refuses to relate numbers Ninshubur did not relate. What it does relate is\n * each quantity to the fee beside it, which is why {@link OndoSellOutcome}\n * pairs them.\n *\n * One thing this type cannot see: the floor signed into `tx.data` is gross of\n * the fee, so a caller decoding the calldata finds a larger number than\n * `minimum.quantity`. Both are correct; `minimum.quantity` is what the wallet\n * actually receives.\n */\nexport type OndoSellTransaction = OndoSwapTransactionCore & {\n side: 'sell';\n /** What the sale is expected to return. An expectation, not a guarantee. */\n expected: OndoSellOutcome;\n /**\n * The floor the calldata enforces. A fill below it reverts on chain, so this\n * - not {@link expected} - is what a seller is actually guaranteed.\n */\n minimum: OndoSellOutcome;\n};\n\nexport const OndoSellTransaction = {\n fromDto: (dto: OndoSellDto): OndoSellTransaction => {\n const spendDecimals = AssetDecimals(dto.spend_input_decimals);\n // One exponent for all four amounts below, unlike a buy where the fee\n // follows the spend. A sale takes its cut from the coin it settles in.\n const outputDecimals = AssetDecimals(dto.receive_output_decimals);\n const expectedQuantity = parsePositiveAmount({\n label: 'expected_quantity',\n raw: dto.expected_quantity,\n decimals: outputDecimals,\n reason: 'a sale that yields nothing is not fillable',\n });\n return {\n ...parseSwapCore(dto, spendDecimals),\n side: 'sell',\n expected: {\n quantity: expectedQuantity,\n fee: blockchainAmountFromRawOrThrow({\n label: 'expected_fee',\n raw: dto.expected_fee,\n decimals: outputDecimals,\n }),\n },\n minimum: {\n quantity: parseMinimumQuantity(\n dto.minimum_quantity,\n outputDecimals,\n expectedQuantity\n ),\n fee: blockchainAmountFromRawOrThrow({\n label: 'minimum_fee',\n raw: dto.minimum_fee,\n decimals: outputDecimals,\n }),\n },\n };\n },\n};\n\n/**\n * The three fields both responses carry, mapped once.\n *\n * `spendDecimals` is passed in rather than read here because a buy also\n * denominates its `fee` and `notionalValue` in it, so reading it twice would\n * leave two places to get wrong.\n */\nfunction parseSwapCore(\n dto: OndoSwapDtoCore,\n spendDecimals: AssetDecimals\n): OndoSwapTransactionCore {\n return {\n tx: {\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n },\n expiresAt: parseExpiresAt(dto.expires_at),\n spendInputAmount: parsePositiveAmount({\n label: 'spend_input_amount',\n raw: dto.spend_input_amount,\n decimals: spendDecimals,\n // A transaction that takes nothing from the wallet is not one to sign:\n // it would settle one leg of a trade and skip the other. Frontline\n // refuses an `amount` of zero whichever way the trade runs, so this is a\n // changed encoding rather than a small order.\n //\n // Guarded on both sides rather than on the sale alone, because which\n // amount becomes the divisor in the price flips with the direction: a\n // guard placed by that would be a rule about the arithmetic rather than\n // about the trade.\n reason: 'a swap that spends nothing is not fillable',\n }),\n };\n}\n\n/**\n * The floor under a sale's proceeds, refused when it cannot be one.\n *\n * A floor above the amount it is a floor on cannot be filled: the calldata\n * would revert on every outcome. Frontline validates both bounds\n * (`minimum <= expected`, and `> 0`), so either is a changed encoding rather\n * than a tight quote.\n *\n * Rejecting them at the boundary is what lets the review screen render the\n * pair without deciding what to do when they contradict each other - the\n * failure surfaces as the data hook's ERROR state instead.\n */\nfunction parseMinimumQuantity(\n raw: string,\n decimals: AssetDecimals,\n expectedQuantity: BlockchainAmount\n): BlockchainAmount {\n const amount = parsePositiveAmount({\n label: 'minimum_quantity',\n raw,\n decimals,\n reason: 'a floor of zero guarantees nothing',\n });\n if (amount.raw > expectedQuantity.raw) {\n throw new ValidationError(\n `minimum_quantity: must not exceed expected_quantity (\"${raw}\" > \"${expectedQuantity.raw}\")`\n );\n }\n return amount;\n}\n\n/**\n * An amount the trade cannot proceed without, refused at zero.\n *\n * `reason` says what the zero would have meant, so the message names the trade\n * rather than the field alone - the same field is a deposit on one side and a\n * quantity of shares on the other.\n */\nfunction parsePositiveAmount({\n label,\n raw,\n decimals,\n reason,\n}: {\n label: string;\n raw: string;\n decimals: AssetDecimals;\n reason: string;\n}): BlockchainAmount {\n const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });\n if (amount.raw <= 0n) {\n throw new ValidationError(\n `${label}: must be greater than zero (\"${raw}\") - ${reason}`\n );\n }\n return amount;\n}\n\n/**\n * A transaction whose expiry cannot be read is not safely fillable - the\n * deadline is encoded in the calldata either way, so broadcasting against an\n * unknown one only spends gas on a revert. Fail here instead.\n */\nfunction parseExpiresAt(value: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n throw new ValidationError(`expires_at: not a date (\"${value}\")`);\n }\n return date;\n}\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport { formatRawAmount } from '@/universal/core/shared/blockchain/formatters';\nimport type { BlockchainAmount } from '@/universal/types/blockchain/core';\nimport type {\n OndoBuyDto,\n OndoQuoteDto,\n OndoSellDto,\n OndoTradingStatusDto,\n} from '@/universal/types/dto/providers/ondo/ondo';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { QueryParamValues } from '@/universal/types/http';\nimport {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\nexport async function getOndoTradingStatus(\n api: Sender,\n params: GetOndoTradingStatusParams\n): Promise<OndoTradingStatus> {\n const dto = await api.send<OndoTradingStatusDto>({\n method: 'GET',\n url: '/v1/ondo/swap/trading-status',\n queryParams: { symbol: params.symbol, side: params.side },\n attributes: Attributes.protected(),\n });\n return OndoTradingStatus.fromDto(dto);\n}\n\nexport async function getOndoQuote(\n api: Sender,\n params: GetOndoQuoteParams\n): Promise<OndoQuote> {\n const dto = await api.send<OndoQuoteDto>({\n method: 'GET',\n url: '/v1/ondo/swap/quote',\n queryParams: {\n symbol: params.symbol,\n side: params.side,\n duration: params.duration,\n ...sizeParam(params),\n },\n attributes: Attributes.protected(),\n });\n return OndoQuote.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a purchase: spends an attestation and\n * returns signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the funding token**, unlike\n * `getOndoQuote`'s `token_amount` which is in whole tokens: this number\n * becomes the ERC-20 pull encoded into the calldata, so it is the on-chain\n * integer, not a human figure. Frontline refuses zero, and refuses a wallet\n * whose allowance on that token does not cover it with a 422 carrying\n * `code: \"insufficient_allowance\"`.\n *\n * The body carries no `side`. It used to, optional on the wire and defaulting\n * to `buy`, which is exactly the silent default the endpoint split removed:\n * the path is now what says which trade to sign and which token's allowance to\n * read, and a request cannot lose it.\n */\nexport async function buildOndoBuy(\n api: Sender,\n params: BuildOndoBuyParams\n): Promise<OndoBuyTransaction> {\n const dto = await api.send<OndoBuyDto>({\n method: 'POST',\n url: '/v1/ondo/swap/buy',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'purchase',\n });\n return OndoBuyTransaction.fromDto(dto);\n}\n\n/**\n * Builds the transaction that fills a sale: spends an attestation and returns\n * signed calldata with a deadline.\n *\n * `amount` goes out in **base units of the asset**, which is the one thing\n * that makes this materially different from {@link buildOndoBuy} rather than a\n * mirror of it. The same integer means something 1e12 different on the two\n * sides, so an order sized in the funding token's units and posted here is not\n * a rejected request but a wrong one.\n *\n * Frontline reads the allowance on the **asset** before asking Ninshubur for\n * anything - a sale delivers it, so the swap contract pulls it with\n * `transferFrom` - and refuses a short one with a 422 carrying\n * `code: \"insufficient_allowance\"` and a message naming that address.\n */\nexport async function buildOndoSell(\n api: Sender,\n params: BuildOndoSellParams\n): Promise<OndoSellTransaction> {\n const dto = await api.send<OndoSellDto>({\n method: 'POST',\n url: '/v1/ondo/swap/sell',\n body: swapBody(params),\n attributes: Attributes.protected(),\n });\n assertSpendScaleAgrees({\n published: dto.spend_input_decimals,\n sized: params.amount,\n trade: 'sale',\n // The two answers come from two chains, so on a testnet they can disagree\n // for a reason that is neither the caller's nor a corrupt response. Say so,\n // or a QA run reads as a puzzle rather than a diagnosis.\n note:\n 'the quote resolves the asset on Ethereum mainnet while the swap ' +\n 'executes on the chain requested, so these disagree until frontline ' +\n 'serves a chain-scoped quote',\n });\n return OndoSellTransaction.fromDto(dto);\n}\n\n/**\n * The four fields both endpoints take, spelled the same way for both.\n *\n * `amount` is the only one whose meaning forks, and it forks in the *token*\n * rather than in the encoding - a uint256 decimal string either way.\n */\nfunction swapBody(\n params: BuildOndoBuyParams | BuildOndoSellParams\n): Record<string, string> {\n return {\n symbol: params.symbol,\n chain: params.chain,\n wallet_address: params.walletAddress,\n amount: params.amount.raw.toString(),\n };\n}\n\n/**\n * Refuses a response denominated in a different scale than the request was.\n *\n * The two are independent resolutions of the same token: the caller sized\n * `amount` in the coin it chose and approved, while frontline reads\n * `decimals()` on-chain from the token the side spends, which it resolves from\n * the offer. On a purchase they should never differ - an approval on some\n * other token reads as a zero allowance, which frontline refuses before it\n * signs anything - so a disagreement is a changed encoding rather than a user\n * error, the same reasoning the mapper rejects a zero amount under.\n *\n * Worth the check because of where the value lands: `spend_input_amount` at\n * the wrong exponent renders the review screen's committed amount orders of\n * magnitude out, on the screen where the user commits money.\n */\nfunction assertSpendScaleAgrees({\n published,\n sized,\n trade,\n note,\n}: {\n published: number;\n sized: BlockchainAmount;\n trade: 'purchase' | 'sale';\n note?: string;\n}): void {\n if (published === sized.decimals) return;\n const because = note === undefined ? '' : ` - ${note}`;\n throw new ValidationError(\n `spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`\n );\n}\n\n/**\n * `token_amount` is in **whole tokens**, unlike the response's\n * `token_base_units` — Ondo names both `tokenAmount`, 1e18 apart. Hence the\n * unscale on the way out.\n *\n * The size is checked at runtime because the types do not cover it: TypeScript\n * rejects an object carrying *neither*, but against a union of object types it\n * accepts one carrying *both*, and a JavaScript caller gets no check at all.\n */\nfunction sizeParam(\n params: GetOndoQuoteParams\n): Record<string, QueryParamValues> {\n const tokenAmount = 'tokenAmount' in params ? params.tokenAmount : undefined;\n const notionalValue =\n 'notionalValue' in params ? params.notionalValue : undefined;\n\n if (tokenAmount !== undefined) {\n if (notionalValue !== undefined) {\n throw new ValidationError(\n 'An Ondo quote takes tokenAmount or notionalValue, not both'\n );\n }\n return { token_amount: formatRawAmount(tokenAmount) };\n }\n if (notionalValue === undefined) {\n throw new ValidationError(\n 'An Ondo quote must be sized by tokenAmount or notionalValue'\n );\n }\n return { notional_value: notionalValue };\n}\n","import {\n buildOndoBuy,\n buildOndoSell,\n getOndoQuote,\n getOndoTradingStatus,\n} from '@/universal/api/frontline/providers/ondo/ondo';\nimport type {\n BuildOndoBuyParams,\n BuildOndoSellParams,\n GetOndoQuoteParams,\n GetOndoTradingStatusParams,\n} from '@/universal/core/checkout/ondo/ondo-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n OndoBuyTransaction,\n OndoQuote,\n OndoSellTransaction,\n OndoTradingStatus,\n} from '@/universal/types/providers/ondo/ondo';\n\n/**\n * Ondo swap reads, plus the write that turns one into a fillable transaction.\n *\n * The two reads are free to poll - neither spends an attestation, so a client\n * may call them while the user edits an order. The two builders are not:\n * budget one call per order placed, plus one per refresh the user asks for.\n *\n * **One builder per side, mirroring the endpoints.** A purchase and a sale\n * agree on how to broadcast and on nothing else: a purchase commits to an\n * exact quantity, a sale to a range with a floor beneath it, and `amount` is\n * the funding token on one and the asset on the other. A single method taking\n * a `side` would have to return a union the caller then re-narrows, having\n * already decided which trade it was placing.\n *\n * **No CoinList fee is applied to a read quote, and no read discloses one.**\n * Ondo prices exactly the amount passed. A CoinList approval is fee-inclusive,\n * so sizing a quote against a user's approval without subtracting the fee\n * first overstates what they receive. A built transaction carries the fee\n * explicitly, and it is zero until one lands (ENG-1718).\n *\n * Every method requires `AuthState === 'logged-in'` and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface OndoNamespace {\n getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus>;\n getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;\n /**\n * Builds a purchase for a specific wallet and deposit: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoBuyTransaction.expiresAt}.\n *\n * The wallet must have approved the swap contract to spend `amount` of the\n * offer's **funding token** first. Frontline reads that allowance before\n * asking Ninshubur for anything, and rejects a short one with a 422 carrying\n * `code: \"insufficient_allowance\"`. See `prepareBuy` on the client\n * namespace, which approves and then builds, in that order.\n *\n * The tokens themselves are the offer's rather than the caller's to name.\n */\n buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;\n /**\n * Builds a sale for a specific wallet and quantity: spends an attestation\n * and returns calldata to broadcast, valid until\n * {@link OndoSellTransaction.expiresAt}.\n *\n * The approval this one needs is on the **asset**, not on a stablecoin - a\n * sale delivers the asset, so the swap contract pulls it with `transferFrom`\n * exactly as it pulls the deposit on a purchase. Same 422 when it is short,\n * with a message naming that address. See `prepareSell` on the client\n * namespace.\n *\n * Returns a range rather than a quantity: Ondo settles through USDon before\n * converting to the settlement token, so disclose\n * {@link OndoSellTransaction.minimum} and not only `expected`.\n */\n buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction>;\n}\n\nexport class OndoNamespaceImpl implements OndoNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ONDO');\n }\n\n async getTradingStatus(\n params: GetOndoTradingStatusParams\n ): Promise<OndoTradingStatus> {\n return this.log.wrap('getTradingStatus', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoTradingStatus(this.ctx.api, params);\n });\n }\n\n async getQuote(params: GetOndoQuoteParams): Promise<OndoQuote> {\n return this.log.wrap('getQuote', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return getOndoQuote(this.ctx.api, params);\n });\n }\n\n async buildBuyTransaction(\n params: BuildOndoBuyParams\n ): Promise<OndoBuyTransaction> {\n return this.log.wrap('buildBuyTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoBuy(this.ctx.api, params);\n });\n }\n\n async buildSellTransaction(\n params: BuildOndoSellParams\n ): Promise<OndoSellTransaction> {\n return this.log.wrap('buildSellTransaction', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return buildOndoSell(this.ctx.api, params);\n });\n }\n}\n","import {\n EvmContractAddress,\n HexEncodedTransactionData,\n parseUint256,\n type Uint256,\n} from '@/universal/types/blockchain/core';\nimport type { AllowWalletResponseDto } from '@/universal/types/dto/providers/superstate/swap';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * A read-only quote for a swap: how much goes in, the protocol fee, and how\n * much would come out. All amounts are raw on-chain integers (uint256).\n */\nexport type SwapPreview = {\n inputAmount: Uint256;\n fee: Uint256;\n outputAmount: Uint256;\n};\n\nexport const SwapPreview = {\n /** Maps the contract's `Preview { input, fee, output }` struct. */\n fromContract: (preview: {\n input: bigint;\n fee: bigint;\n output: bigint;\n }): SwapPreview => ({\n inputAmount: parseUint256(preview.input, 'SwapPreview.input'),\n fee: parseUint256(preview.fee, 'SwapPreview.fee'),\n outputAmount: parseUint256(preview.output, 'SwapPreview.output'),\n }),\n};\n\n/**\n * The bitmask of operations a swap contract has paused, as `Operable.paused`\n * reports it. Each bit is one operation level; swapping is\n * {@link SWAP_LEVEL}.\n *\n * Meaningful only while the contract is paused, which is why it lives on that\n * arm of {@link SwapStatus} alone: an active contract has nothing paused, and\n * a stopped one is past caring which level was.\n */\nexport type PauseFlags = Newtype<number, 'PauseFlags'>;\nexport const PauseFlags = (value: number): PauseFlags => value as PauseFlags;\n\n/**\n * The on-chain state of a swap contract, as `status()` reports it.\n *\n * - `active` - operating normally.\n * - `paused` - one or more operations are suspended, and may be resumed.\n * `pausedLevels` says which. **This does not by itself mean swapping is\n * down**: a contract can pause an unrelated operation and keep swapping.\n * Ask `isSwapAvailable` rather than reading the state.\n * - `stopped` - permanently halted, and cannot be reactivated.\n */\nexport type SwapStatus =\n | { state: 'active' }\n | { state: 'paused'; pausedLevels: PauseFlags }\n | { state: 'stopped' };\n\nexport const SwapStatus = {\n /**\n * Maps the contract's `Status { uint32 flags; State state }` struct, where\n * `State` is `0 = Active | 1 = Paused | 2 = Stopped`.\n *\n * `flags` is carried onto the `paused` arm only. On the other two the\n * contract sets it to a self-identifying marker rather than to information -\n * so repeating it would invite a caller to read meaning into a constant.\n *\n * @throws ValidationError on a `state` outside the enum. A contract that has\n * grown a fourth state is one the SDK does not model, and guessing `active`\n * would let a halted swap read as a live one.\n */\n fromContract: (status: { flags: number; state: number }): SwapStatus => {\n switch (status.state) {\n case 0:\n return { state: 'active' };\n case 1:\n return { state: 'paused', pausedLevels: PauseFlags(status.flags) };\n case 2:\n return { state: 'stopped' };\n default:\n throw new ValidationError(\n `SwapStatus.state: unknown contract state (${status.state})`\n );\n }\n },\n};\n\n/**\n * The backend's response to an allow-wallet request. Either the caller must\n * broadcast an on-chain transaction to complete allow-listing, or nothing is\n * required because the wallet is already allowed.\n */\nexport type AllowWalletResponse =\n | {\n action: 'broadcast_transaction';\n to: EvmContractAddress;\n data: HexEncodedTransactionData;\n }\n | {\n action: 'none';\n alreadyAllowed: boolean;\n };\n\nexport const AllowWalletResponse = {\n fromDto: (dto: AllowWalletResponseDto): AllowWalletResponse => {\n switch (dto.action) {\n case 'broadcast_transaction':\n return {\n action: 'broadcast_transaction',\n to: EvmContractAddress(dto.to),\n data: HexEncodedTransactionData(dto.data),\n };\n case 'none':\n return {\n action: 'none',\n alreadyAllowed: dto.already_allowed,\n };\n default: {\n const _exhaustive: never = dto;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { AllowWalletParams } from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type { AllowWalletResponseDto } from '@/universal/types/dto/providers/superstate/swap';\nimport { AllowWalletResponse } from '@/universal/types/providers/superstate/swap';\n\n/**\n * What is left of the Superstate swap's backend surface once the contract\n * reads moved on-chain (ADR-11): allow-listing is a backend write, decided by\n * frontline against the offer, so it stays an endpoint.\n */\nexport async function allowWallet(\n api: Sender,\n params: AllowWalletParams\n): Promise<AllowWalletResponse> {\n const dto = await api.send<AllowWalletResponseDto>({\n method: 'POST',\n url: `/v1/offers/${encodeURIComponent(params.offerId)}/allow-wallet`,\n body: {\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n },\n attributes: Attributes.protected(),\n });\n return AllowWalletResponse.fromDto(dto);\n}\n","/**\n * The Superstate swap contract's ABI, generated verbatim from the shared\n * `TokenSwap` base contract:\n *\n * ```\n * cd ../solidity && forge inspect TokenSwap abi --json --use 0.8.34\n * ```\n *\n * Generated rather than hand-trimmed to the four methods the SDK calls, so\n * regenerating after a contract change is one command and a paste. The custom\n * errors carry their weight in particular: viem decodes a revert against them,\n * so a `preview()` on a stopped contract surfaces as `IsStopped` rather than\n * as an opaque `0x`-prefixed blob.\n *\n * `status()` returns `Status { uint32 flags; State state }` where `State` is\n * `0 = Active | 1 = Paused | 2 = Stopped`. It replaced the older\n * `stopped() -> uint256` bitmask, which this contract still exposes but as a\n * `bool`; {@link SwapStatus} reads `status()` and nothing else.\n */\nexport const SUPERSTATE_SWAP_ABI = [\n {\n type: 'function',\n name: 'KIND',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint16',\n internalType: 'uint16',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'ONE_HUNDRED_P',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'SWAP_LEVEL',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'VERSION',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint16',\n internalType: 'uint16',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'authorized',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'bpp',\n inputs: [\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'bps',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'cancelOwnershipHandover',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'completeOwnershipHandover',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'fee',\n inputs: [\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'id',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bytes32',\n internalType: 'bytes32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'inputTokens',\n inputs: [\n {\n name: '',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputToken',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'address',\n internalType: 'address',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'outputTokenBalance',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'owner',\n inputs: [],\n outputs: [\n {\n name: 'result',\n type: 'address',\n internalType: 'address',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'ownershipHandoverExpiresAt',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: 'result',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'pause',\n inputs: [\n {\n name: 'level',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'paused',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'preview',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Preview',\n components: [\n {\n name: 'input',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'fee',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'output',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'renounceOwnership',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'requestOwnershipHandover',\n inputs: [],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'setBps',\n inputs: [\n {\n name: 'points',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'setInputToken',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'val',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'status',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct Status',\n components: [\n {\n name: 'flags',\n type: 'uint32',\n internalType: 'uint32',\n },\n {\n name: 'state',\n type: 'uint8',\n internalType: 'enum State',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'stop',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'stopped',\n inputs: [],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'swap',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'slip',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'tokenBalance',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n {\n name: 'inputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'feeSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'outputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'count',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totals',\n inputs: [\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'tuple',\n internalType: 'struct SwapTotal',\n components: [\n {\n name: 'inputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'feeSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'outputSum',\n type: 'uint256',\n internalType: 'uint256',\n },\n {\n name: 'count',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n {\n name: 'to',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n {\n name: 'to',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n internalType: 'uint256',\n },\n ],\n outputs: [\n {\n name: '',\n type: 'bool',\n internalType: 'bool',\n },\n ],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transferOwnership',\n inputs: [\n {\n name: 'newOwner',\n type: 'address',\n internalType: 'address',\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n {\n type: 'event',\n name: 'BpsUpdated',\n inputs: [\n {\n name: 'prev',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'next',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'InputTokenUpdated',\n inputs: [\n {\n name: 'token',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'prev',\n type: 'bool',\n indexed: false,\n internalType: 'bool',\n },\n {\n name: 'next',\n type: 'bool',\n indexed: false,\n internalType: 'bool',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipHandoverCanceled',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipHandoverRequested',\n inputs: [\n {\n name: 'pendingOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'OwnershipTransferred',\n inputs: [\n {\n name: 'oldOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'newOwner',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Paused',\n inputs: [\n {\n name: 'previous',\n type: 'uint32',\n indexed: false,\n internalType: 'uint32',\n },\n {\n name: 'next',\n type: 'uint32',\n indexed: false,\n internalType: 'uint32',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Stopped',\n inputs: [],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Swapped',\n inputs: [\n {\n name: 'user',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'inputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'outputToken',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'inputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'fee',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n {\n name: 'outputAmount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Transferred',\n inputs: [\n {\n name: 'to',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n indexed: true,\n internalType: 'address',\n },\n {\n name: 'amount',\n type: 'uint256',\n indexed: false,\n internalType: 'uint256',\n },\n ],\n anonymous: false,\n },\n {\n type: 'error',\n name: 'AlreadyInitialized',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InsufficientAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'InvalidAmount',\n inputs: [],\n },\n {\n type: 'error',\n name: 'IsPaused',\n inputs: [\n {\n name: 'level',\n type: 'uint32',\n internalType: 'uint32',\n },\n ],\n },\n {\n type: 'error',\n name: 'IsStopped',\n inputs: [],\n },\n {\n type: 'error',\n name: 'NewOwnerIsZeroAddress',\n inputs: [],\n },\n {\n type: 'error',\n name: 'NoHandoverRequest',\n inputs: [],\n },\n {\n type: 'error',\n name: 'SwapFailed',\n inputs: [\n {\n name: 'user',\n type: 'address',\n internalType: 'address',\n },\n {\n name: 'token',\n type: 'address',\n internalType: 'address',\n },\n ],\n },\n {\n type: 'error',\n name: 'Unauthorized',\n inputs: [],\n },\n] as const;\n","/**\n * Minimal ERC-20 ABI the SDK writes against (mirrors viem's `erc20Abi`). The\n * swap flow uses `approve`; `allowance`/`balanceOf`/`decimals`/`symbol`/`name`\n * are included so reads share a single SDK-owned ABI.\n */\nexport const ERC20_ABI = [\n {\n type: 'function',\n name: 'allowance',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'approve',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'decimals',\n inputs: [],\n outputs: [{ name: '', type: 'uint8' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'name',\n inputs: [],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'symbol',\n inputs: [],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalSupply',\n inputs: [],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'recipient', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'transferFrom',\n inputs: [\n { name: 'sender', type: 'address' },\n { name: 'recipient', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'event',\n name: 'Approval',\n inputs: [\n { name: 'owner', type: 'address', indexed: true },\n { name: 'spender', type: 'address', indexed: true },\n { name: 'value', type: 'uint256', indexed: false },\n ],\n anonymous: false,\n },\n {\n type: 'event',\n name: 'Transfer',\n inputs: [\n { name: 'from', type: 'address', indexed: true },\n { name: 'to', type: 'address', indexed: true },\n { name: 'value', type: 'uint256', indexed: false },\n ],\n anonymous: false,\n },\n] as const;\n","import type { PublicClients } from '@/universal/api/rpc/public-clients';\nimport { SUPERSTATE_SWAP_ABI } from '@/universal/core/checkout/superstate/blockchain/abi';\nimport type {\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport { ERC20_ABI } from '@/universal/core/shared/blockchain/erc20/abi';\nimport {\n AssetDecimals,\n AssetSymbol,\n type Erc20Asset,\n EvmContractAddress,\n} from '@/universal/types/blockchain/core';\nimport {\n SwapPreview,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\n\n/**\n * The Superstate swap contract's views, read straight from the chain.\n *\n * Each of these was a bespoke frontline endpoint until the SDK gained a\n * generic JSON-RPC transport (ADR-11). They take their subject as an argument\n * rather than reading `msg.sender`, which is what makes them safe to batch -\n * see `publicClients`.\n */\nexport async function getSwapAuthorization(\n clients: PublicClients,\n params: GetSwapAuthorizationParams\n): Promise<boolean> {\n return clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'authorized',\n args: [params.walletAddress],\n });\n}\n\nexport async function getSwapPreview(\n clients: PublicClients,\n params: GetSwapPreviewParams\n): Promise<SwapPreview> {\n const preview = await clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'preview',\n args: [params.inputToken, params.amount],\n });\n return SwapPreview.fromContract(preview);\n}\n\nexport async function getSwapStatus(\n clients: PublicClients,\n params: SwapContractRef\n): Promise<SwapStatus> {\n const status = await clients(params.chain).readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'status',\n });\n return SwapStatus.fromContract(status);\n}\n\n/**\n * The ERC-20 the swap pays out, with the metadata a UI needs to render an\n * amount of it.\n *\n * Two round-trips, and it cannot be one: `outputToken()` has to answer before\n * there is an address to ask for `name`/`symbol`/`decimals`. The second is an\n * explicit `multicall` rather than three awaited reads - the client would\n * batch them anyway, but writing it out says the three belong together and\n * survives someone turning auto-batching off.\n */\nexport async function getSwapOutputToken(\n clients: PublicClients,\n params: SwapContractRef\n): Promise<Erc20Asset> {\n const client = clients(params.chain);\n\n const tokenAddress = await client.readContract({\n address: params.contractAddress,\n abi: SUPERSTATE_SWAP_ABI,\n functionName: 'outputToken',\n });\n\n const token = { address: EvmContractAddress(tokenAddress), abi: ERC20_ABI };\n const [name, symbol, decimals] = await client.multicall({\n contracts: [\n { ...token, functionName: 'name' },\n { ...token, functionName: 'symbol' },\n { ...token, functionName: 'decimals' },\n ],\n allowFailure: false,\n });\n\n return {\n name,\n symbol: AssetSymbol(symbol),\n decimals: AssetDecimals(decimals),\n };\n}\n","import { allowWallet } from '@/universal/api/frontline/providers/superstate/swap';\nimport {\n getSwapAuthorization,\n getSwapOutputToken,\n getSwapPreview,\n getSwapStatus,\n} from '@/universal/api/rpc/providers/superstate/swap';\nimport type {\n AllowWalletParams,\n GetSwapAuthorizationParams,\n GetSwapPreviewParams,\n SwapContractRef,\n} from '@/universal/core/checkout/superstate/swap-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Erc20Asset } from '@/universal/types/blockchain/core';\nimport type {\n AllowWalletResponse,\n SwapPreview,\n SwapStatus,\n} from '@/universal/types/providers/superstate/swap';\n\n/**\n * Read/write operations for the on-chain swap flow: quoting a swap, inspecting\n * contract state, and proving/allow-listing wallet ownership.\n *\n * Every read here is a contract call the SDK makes itself. By default those go\n * through CoinList's authenticated JSON-RPC proxy, so a logged-out caller gets\n * the proxy's `401` - surfaced as a viem error wrapping the SDK's `HttpError`,\n * not as `NotAuthenticatedError`, since viem re-wraps whatever a `Transport`\n * throws. Point `Config.rpc` at your own node for this chain and no CoinList\n * session is involved at all. `allowWallet` is the exception: it is a backend\n * write and always needs one, and throws `NotAuthenticatedError` without.\n */\nexport interface SuperstateSwapNamespace {\n /**\n * Checks whether a wallet is authorized to swap against the given contract.\n */\n getAuthorization(params: GetSwapAuthorizationParams): Promise<boolean>;\n\n /**\n * Fetches a read-only quote for swapping `amount` of `inputToken`.\n *\n * The contract reverts rather than quoting when it is stopped, or when\n * `inputToken` is not one it accepts, so this surfaces a viem\n * `ContractFunctionRevertedError` naming the contract's own error. Check\n * {@link getStatus} first if you would rather not provoke one.\n */\n getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;\n\n /**\n * Reads the current on-chain state of a swap contract. See\n * {@link isSwapAvailable} before concluding that a `paused` contract cannot\n * swap - the two are not the same question.\n */\n getStatus(params: SwapContractRef): Promise<SwapStatus>;\n\n /**\n * Reads the ERC-20 output token a swap contract pays out, with its metadata.\n */\n getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;\n\n /**\n * Submits a signed wallet-ownership challenge to allow-list the wallet for\n * an offer, identified by its offer id. Obtain the challenge from\n * `WalletsNamespace.createOwnershipChallenge`.\n *\n * @throws NotAuthenticatedError without a logged-in user.\n */\n allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;\n}\n\nexport class SuperstateSwapNamespaceImpl implements SuperstateSwapNamespace {\n protected readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'SUPERSTATE');\n }\n\n async getAuthorization(params: GetSwapAuthorizationParams): Promise<boolean> {\n return this.log.wrap('getAuthorization', params, async () =>\n getSwapAuthorization(this.ctx.rpc, params)\n );\n }\n\n async getPreview(params: GetSwapPreviewParams): Promise<SwapPreview> {\n return this.log.wrap('getPreview', params, async () =>\n getSwapPreview(this.ctx.rpc, params)\n );\n }\n\n async getStatus(params: SwapContractRef): Promise<SwapStatus> {\n return this.log.wrap('getStatus', params, async () =>\n getSwapStatus(this.ctx.rpc, params)\n );\n }\n\n async getOutputToken(params: SwapContractRef): Promise<Erc20Asset> {\n return this.log.wrap('getOutputToken', params, async () =>\n getSwapOutputToken(this.ctx.rpc, params)\n );\n }\n\n async allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse> {\n return this.log.wrap('allowWallet', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return allowWallet(this.ctx.api, params);\n });\n }\n}\n","import type { PublicClients } from '@/universal/api/rpc/public-clients';\nimport { ERC20_ABI } from '@/universal/core/shared/blockchain/erc20/abi';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport { parseUint256, type Uint256 } from '@/universal/types/blockchain/core';\n\n/**\n * Generic ERC-20 reads, straight from the chain.\n *\n * Both take their subject as an argument rather than reading `msg.sender`,\n * which is what makes them safe to batch - see `publicClients`.\n */\nexport async function getTokenAllowance(\n clients: PublicClients,\n params: GetTokenAllowanceParams\n): Promise<Uint256> {\n const allowance = await clients(params.chain).readContract({\n address: params.tokenAddress,\n abi: ERC20_ABI,\n functionName: 'allowance',\n args: [params.owner, params.spender],\n });\n return parseUint256(allowance, 'allowance');\n}\n\nexport async function getTokenBalance(\n clients: PublicClients,\n params: GetTokenBalanceParams\n): Promise<Uint256> {\n const balance = await clients(params.chain).readContract({\n address: params.tokenAddress,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [params.owner],\n });\n return parseUint256(balance, 'balanceOf');\n}\n","import { getTokenAllowance, getTokenBalance } from '@/universal/api/rpc/erc20';\nimport type {\n GetTokenAllowanceParams,\n GetTokenBalanceParams,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace.types';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { Uint256 } from '@/universal/types/blockchain/core';\n\n/**\n * Generic ERC-20 reads shared across on-chain flows (swap, token sale): the\n * allowance an owner has granted a spender, and the raw token balance an owner\n * holds. These are plain token reads, not tied to any single product flow.\n *\n * Read from the chain rather than from a CoinList endpoint. By default that\n * goes through CoinList's authenticated JSON-RPC proxy, so a logged-out caller\n * gets the proxy's `401` - surfaced as a viem error wrapping the SDK's\n * `HttpError`, not as `NotAuthenticatedError`, since viem re-wraps whatever a\n * `Transport` throws. Point `Config.rpc` at your own node for this chain and no\n * CoinList session is involved at all. See {@link RpcConfig}.\n */\nexport interface Erc20Namespace {\n /**\n * Reads the ERC-20 allowance an `owner` has granted a `spender`, as a raw\n * on-chain integer.\n */\n getAllowance(params: GetTokenAllowanceParams): Promise<Uint256>;\n\n /**\n * Reads the raw ERC-20 balance an `owner` holds of a token.\n */\n getBalance(params: GetTokenBalanceParams): Promise<Uint256>;\n}\n\nexport class Erc20NamespaceImpl implements Erc20Namespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'ERC20');\n }\n\n async getAllowance(params: GetTokenAllowanceParams): Promise<Uint256> {\n return this.log.wrap('getAllowance', params, async () =>\n getTokenAllowance(this.ctx.rpc, params)\n );\n }\n\n async getBalance(params: GetTokenBalanceParams): Promise<Uint256> {\n return this.log.wrap('getBalance', params, async () =>\n getTokenBalance(this.ctx.rpc, params)\n );\n }\n}\n","import { getAddress } from 'viem';\nimport { HttpError, type HttpResponse } from '@/universal/api/http';\nimport { HttpClient } from '@/universal/api/http-client';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Logger } from '@/universal/types/logger';\nimport { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * An {@link HttpClient} against the token registry rather than frontline: no\n * `X-API-Version` (the registry doesn't know it, and the extra header would\n * force a CORS preflight the static CDN cannot answer) and no session\n * middleware (the registry is public).\n */\nexport function createNabuApiClient(\n baseUrl: string,\n logger: Logger | null = null\n): HttpClient {\n return new HttpClient({ baseUrl }, {}, logger);\n}\n\n/**\n * Fetches one token's display metadata from the registry.\n *\n * Returns `null` when the registry does not list the token: the registry is\n * curated, so \"not listed\" is a domain answer, not a failure. The deployment\n * signals it as either a 404 or — Cloudflare Pages' fallback for unknown\n * routes — a 2xx serving its HTML inspection page, so both map to `null`.\n * Everything else throws: a non-2xx status is an {@link HttpError} carrying\n * the registry's response, including a 5xx whose body is an HTML error page.\n */\nexport async function fetchTokenMetadata(\n client: HttpClient,\n token: TokenIdentifier\n): Promise<TokenMetadata | null> {\n // The registry's canonical route uses the EIP-55 checksummed address:\n // lowercase costs a redirect round-trip and wrong mixed casing 404s.\n const address = checksummed(token.address);\n let response: HttpResponse<NabuTokenDto>;\n try {\n response = await client.send<NabuTokenDto>({\n method: 'GET',\n url: `/${token.chain}/token/${address}`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n return null;\n }\n throw error;\n }\n\n if (response.status === 404) {\n return null;\n }\n assertOk(response);\n if (response.body === null) {\n // Not a \"not listed\" signal — those are the 404 and the HTML fallback. A\n // 2xx with a zero-length body is a broken deploy or a mangling\n // intermediary, and mapping it to null would hide a listed token.\n throw new ValidationError(\n `Token registry returned an empty body for token \"${address}\" on \"${token.chain}\"`\n );\n }\n return TokenMetadata.fromDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches all available tokens the registry lists for `chain`, in a single\n * request against the chain snapshot — fetching N tokens one by one would\n * cost N round-trips for a catalogue that arrives whole anyway.\n *\n * Unlike {@link fetchTokenMetadata}, a missing snapshot throws rather than\n * mapping to an empty answer: the registry publishes a snapshot for every\n * chain it knows, so its absence is a deployment problem — and an invented\n * `[]` would render as \"no metadata\" without anyone noticing.\n */\nexport async function fetchTokensMetadata(\n client: HttpClient,\n chain: EthereumChain\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuChainAssetsDto>;\n try {\n response = await client.send<NabuChainAssetsDto>({\n method: 'GET',\n url: `/${chain}/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n `Token registry returned non-JSON for the \"${chain}\" snapshot`\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n `Token registry returned an empty \"${chain}\" snapshot`\n );\n }\n return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);\n}\n\n/**\n * Fetches every token the registry lists, across all chains, in a single\n * request against the complete snapshot — the cheapest way to resolve a\n * multi-chain catalogue: one download regardless of how many assets or\n * chains it spans.\n *\n * Chains outside the SDK's type surface (e.g. Solana) are skipped rather\n * than failing the whole snapshot. As with the per-chain snapshot, a missing\n * or empty response throws: the registry always publishes `/assets.json`, so\n * its absence is a deployment problem, not an empty catalogue.\n */\nexport async function fetchAllTokensMetadata(\n client: HttpClient\n): Promise<TokenMetadata[]> {\n let response: HttpResponse<NabuRegistryDto>;\n try {\n response = await client.send<NabuRegistryDto>({\n method: 'GET',\n url: `/assets.json`,\n });\n } catch (error) {\n if (isRegistryHtmlFallback(error)) {\n throw new ValidationError(\n 'Token registry returned non-JSON for the complete snapshot'\n );\n }\n throw error;\n }\n\n assertOk(response);\n if (response.body === null) {\n throw new ValidationError(\n 'Token registry returned an empty complete snapshot'\n );\n }\n return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);\n}\n\n/**\n * The registry's deployment answers routes that have no static file with its\n * HTML inspection page and a 2xx status. `makeRequest` surfaces any non-JSON\n * body as an {@link HttpError} carrying the status, so \"2xx but not JSON\" is\n * precisely the registry's \"no such file\" signal — while a non-2xx with an\n * HTML body (a CDN 502/503 page, a proxy block page) keeps its status and\n * stays an outage for the caller to see, never a domain answer.\n */\nfunction isRegistryHtmlFallback(error: unknown): boolean {\n return (\n error instanceof HttpError &&\n error.response.status >= 200 &&\n error.response.status < 300\n );\n}\n\nfunction assertOk(response: HttpResponse<unknown>): void {\n if (response.status < 200 || response.status >= 300) {\n // The full response, never a stripped one: HttpError is public API and\n // callers classify failures off `response.body` (e.g. a 429 vs a 502).\n throw new HttpError(response);\n }\n}\n\nfunction checksummed(address: string): string {\n try {\n return getAddress(address);\n } catch (_) {\n throw new ValidationError(`Invalid EVM contract address: \"${address}\"`);\n }\n}\n","import {\n AssetDecimals,\n AssetSymbol,\n EthereumChain,\n EvmContractAddress,\n type TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type {\n NabuChainAssetsDto,\n NabuLogoDto,\n NabuRegistryDto,\n NabuTokenDto,\n} from '@/universal/types/dto/nabu-token';\nimport { ValidationError } from '@/universal/types/errors';\nimport type { Newtype } from '@/universal/types/newtype';\n\n/**\n * An absolute URL to a logo image in the token registry. Registry image URLs\n * are content-fingerprinted and served immutable, so a value is safe to cache\n * for as long as you hold it.\n */\nexport type TokenLogoUrl = Newtype<string, 'TokenLogoUrl'>;\nexport const TokenLogoUrl = (value: string): TokenLogoUrl =>\n value as TokenLogoUrl;\n\nexport type TokenLogoImage = {\n url: TokenLogoUrl;\n width: number;\n height: number;\n};\n\n/**\n * `VECTOR` is a single SVG. `RASTER` has webp variants at 32/64/128/256/512px\n * widths (never wider than the original): use the smallest one that covers\n * your render size, or `original` if none does.\n */\nexport type TokenLogo =\n | { kind: 'VECTOR'; url: TokenLogoUrl }\n | { kind: 'RASTER'; original: TokenLogoImage; variants: TokenLogoImage[] };\n\nexport const TokenLogo = {\n /** `baseUrl` is the registry origin; registry URLs are root-relative. */\n fromDto: (dto: NabuLogoDto, baseUrl: string): TokenLogo =>\n dto.kind === 'VECTOR'\n ? { kind: 'VECTOR', url: resolveLogoUrl(dto.url, baseUrl) }\n : {\n kind: 'RASTER',\n original: logoImageFromDto(dto.original, baseUrl),\n variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl)),\n },\n};\n\n/**\n * Display metadata for one token, from CoinList's public token registry.\n *\n * Keyed by `(chain, address)` — never by symbol, which can collide. The\n * registry is curated: a token missing from it is an expected answer, not an\n * error, so lookups return `null` rather than throwing.\n */\nexport type TokenMetadata = {\n identifier: TokenIdentifier;\n name: string;\n symbol: AssetSymbol;\n decimals: AssetDecimals;\n logo: TokenLogo;\n /** Dark-theme logo; `null` when the registry configures none. */\n logoDark: TokenLogo | null;\n};\n\nexport const TokenMetadata = {\n /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */\n fromDto: (dto: NabuTokenDto, baseUrl: string): TokenMetadata => {\n assertSupportedSchemaVersion(dto.schema_version);\n return {\n identifier: {\n chain: EthereumChain(dto.chain),\n address: EvmContractAddress(dto.address),\n },\n name: dto.name,\n symbol: AssetSymbol(dto.symbol),\n decimals: AssetDecimals(dto.decimals),\n logo: TokenLogo.fromDto(dto.logo, baseUrl),\n logoDark:\n dto.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(dto.logo_dark, baseUrl),\n };\n },\n\n /**\n * Maps the complete registry snapshot to every token it lists across the\n * chains this SDK models, skipping native coins and chains outside\n * {@link EthereumChain} (e.g. Solana) rather than failing on them — the\n * registry may serve chains ahead of the SDK's type surface.\n */\n fromRegistryDto: (dto: NabuRegistryDto, baseUrl: string): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return dto.chains.flatMap((chainDto) => {\n let chain: EthereumChain;\n try {\n chain = EthereumChain(chainDto.chain);\n } catch {\n return [];\n }\n return tokensOfChain(chain, chainDto.assets, baseUrl);\n });\n },\n\n /**\n * Maps a chain snapshot to the tokens it lists, skipping the chain's native\n * coin (`kind: 'COIN'`, no contract address).\n */\n fromChainAssetsDto: (\n dto: NabuChainAssetsDto,\n baseUrl: string\n ): TokenMetadata[] => {\n assertSupportedSchemaVersion(dto.schema_version);\n return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);\n },\n};\n\n/** The token rows of one chain's asset list, skipping the native coin. */\nfunction tokensOfChain(\n chain: EthereumChain,\n assets: NabuChainAssetsDto['assets'],\n baseUrl: string\n): TokenMetadata[] {\n return assets\n .filter((asset) => asset.kind === 'TOKEN' && asset.address !== undefined)\n .map((asset) => ({\n identifier: {\n chain,\n // The filter above cannot narrow `address` for the type checker.\n address: EvmContractAddress(asset.address as string),\n },\n name: asset.name,\n symbol: AssetSymbol(asset.symbol),\n decimals: AssetDecimals(asset.decimals),\n logo: TokenLogo.fromDto(asset.logo, baseUrl),\n logoDark:\n asset.logo_dark === undefined\n ? null\n : TokenLogo.fromDto(asset.logo_dark, baseUrl),\n }));\n}\n\n/**\n * The registry bumps schema_version only on breaking changes, so mapping a\n * newer schema with this code would produce silent garbage — fail instead.\n */\nfunction assertSupportedSchemaVersion(version: number): void {\n if (version !== 1) {\n throw new ValidationError(\n `Unsupported token registry schema_version: ${version}`\n );\n }\n}\n\nconst logoImageFromDto = (\n dto: { url: string; width: number; height: number },\n baseUrl: string\n): TokenLogoImage => ({\n url: resolveLogoUrl(dto.url, baseUrl),\n width: dto.width,\n height: dto.height,\n});\n\nconst resolveLogoUrl = (url: string, baseUrl: string): TokenLogoUrl =>\n TokenLogoUrl(\n url.startsWith('http') ? url : `${baseUrl.replace(/\\/$/, '')}${url}`\n );\n","import type { HttpClient } from '@/universal/api/http-client';\nimport {\n createNabuApiClient,\n fetchAllTokensMetadata,\n fetchTokenMetadata,\n fetchTokensMetadata,\n} from '@/universal/api/nabu/tokens';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type {\n EthereumChain,\n TokenIdentifier,\n} from '@/universal/types/blockchain/core';\nimport type { Logger } from '@/universal/types/logger';\nimport type { TokenMetadata } from '@/universal/types/token-metadata';\n\n/**\n * Token display metadata — name, symbol, decimals, and logos — from\n * CoinList's public token registry, keyed by {@link TokenIdentifier} (the\n * same chain + address pairs `Offer.tokens` carries).\n *\n * Unlike the other namespaces, this one is public: no method requires an\n * authenticated user, and nothing here touches the CoinList API — reads go to\n * the registry's CDN.\n */\nexport interface TokensNamespace {\n /**\n * Fetches metadata for one token. Returns `null` when the registry does not\n * list the token — the registry is curated, so callers must fall back to\n * their own display defaults rather than treat this as an error.\n */\n get(token: TokenIdentifier): Promise<TokenMetadata | null>;\n\n /**\n * Fetches every token the registry lists, in one request: the complete\n * snapshot with no `chain`, or one chain's snapshot with it. Prefer this\n * over calling {@link get} in a loop when displaying a catalogue — two\n * hundred tokens across three chains is still a single download.\n *\n * The complete snapshot spans every chain the registry knows; tokens on\n * chains this SDK does not model (e.g. Solana) are left out of the result.\n *\n * Unlike {@link get}, a missing snapshot throws rather than returning `[]`:\n * the registry always publishes the complete snapshot and one per chain it\n * knows, so an absence is a deployment problem, not an empty catalogue.\n */\n list(chain?: EthereumChain): Promise<TokenMetadata[]>;\n}\n\nexport class TokensNamespaceImpl implements TokensNamespace {\n private readonly api: HttpClient;\n private readonly log: InternalLogger;\n\n /**\n * Takes the registry origin rather than a `UniversalNamespaceContext`: the\n * registry is unauthenticated and on its own host, so the frontline sender\n * and the auth check would both be dead weight here.\n */\n constructor(baseUrl: string, logger: Logger | null = null) {\n this.api = createNabuApiClient(baseUrl, logger);\n this.log = internalLogger(logger, 'TOKENS');\n }\n\n get(token: TokenIdentifier): Promise<TokenMetadata | null> {\n return this.log.wrap('get', token, () =>\n fetchTokenMetadata(this.api, token)\n );\n }\n\n list(chain?: EthereumChain): Promise<TokenMetadata[]> {\n return this.log.wrap('list', chain, () =>\n chain === undefined\n ? fetchAllTokensMetadata(this.api)\n : fetchTokensMetadata(this.api, chain)\n );\n }\n}\n","import type { Hex } from 'viem';\nimport {\n type EthereumChain,\n EvmWalletAddress,\n type WalletProtocol,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateOfferOptionAddressDto,\n OfferOptionAddressDto,\n} from '@/universal/types/dto/offer-option-address';\nimport type { Newtype } from '@/universal/types/newtype';\nimport type { OfferId } from '@/universal/types/offer';\nimport { OfferOptionId } from '@/universal/types/offer-detail';\n\n/** Unique identifier for a proven wallet binding on an offer option. */\nexport type OfferOptionAddressId = Newtype<string, 'OfferOptionAddressId'>;\n/** Casts a string into a typed {@link OfferOptionAddressId}. */\nexport const OfferOptionAddressId = (value: string) =>\n value as OfferOptionAddressId;\n\n/**\n * A user's external wallet, proven via a wallet-ownership challenge and bound\n * to an offer option. Returned by the `/v1/offers/:offer_id/addresses` resource.\n */\nexport type OfferOptionAddress = {\n /** Unique binding id. */\n id: OfferOptionAddressId;\n /** Offer option the wallet is bound to. */\n offerOptionId: OfferOptionId;\n /** The connected external wallet address. */\n address: EvmWalletAddress;\n /**\n * Protocol the binding is scoped to. An EVM address binds once per option\n * regardless of which EVM chain proved ownership.\n */\n protocol: WalletProtocol;\n /** When the binding was created. */\n createdAt: Date;\n};\n\n/** Parameters required to connect a proven external wallet to an offer option. */\nexport type ConnectExternalWalletParams = {\n /** Offer the option belongs to. */\n offerId: OfferId;\n /** Offer option to bind the wallet to. */\n offerOptionId: OfferOptionId;\n /** External wallet address that was proven. */\n walletAddress: EvmWalletAddress;\n /** Chain the ownership was proven on. */\n chain: EthereumChain;\n /** Signature of the wallet-ownership challenge message. */\n signature: Hex;\n};\n\nexport const OfferOptionAddress = {\n /** Maps the API DTO into the SDK offer-option-address domain model. */\n fromDto: (dto: OfferOptionAddressDto): OfferOptionAddress => ({\n id: OfferOptionAddressId(dto.id),\n offerOptionId: OfferOptionId(dto.offer_option_id),\n address: EvmWalletAddress(dto.address),\n protocol: dto.protocol,\n createdAt: new Date(dto.created_at),\n }),\n};\n\nexport const ConnectExternalWalletParams = {\n /** Maps connect-wallet params into the API DTO payload. */\n toDto: (\n params: ConnectExternalWalletParams\n ): CreateOfferOptionAddressDto => ({\n offer_option_id: params.offerOptionId,\n wallet_address: params.walletAddress,\n chain: params.chain,\n signature: params.signature,\n }),\n};\n","import type {\n EthereumChain,\n EvmWalletAddress,\n} from '@/universal/types/blockchain/core';\nimport type {\n CreateWalletOwnershipChallengeDto,\n WalletOwnershipChallengeDto,\n} from '@/universal/types/dto/wallet-ownership-challenge';\n\n/**\n * A single-use ownership challenge returned by `POST /v1/wallet-ownership`.\n * The consumer signs {@link message} with their wallet, then submits the\n * signature to connect the wallet to an offer option.\n */\nexport type WalletOwnershipChallenge = {\n /** The message the wallet must sign. */\n message: string;\n /** When the challenge expires and can no longer be consumed. */\n expiresAt: Date;\n};\n\n/** Fields common to every wallet-ownership challenge request. */\ntype WalletOwnershipChallengeParamsBase = {\n /** Wallet address to prove ownership of. */\n walletAddress: EvmWalletAddress;\n /** Chain the wallet belongs to. */\n chain: EthereumChain;\n};\n\n/**\n * Parameters for requesting a wallet-ownership challenge. Modeled as a\n * discriminated union on `challengeType` so a `siwe` challenge must carry\n * `domain`/`uri`/`statement`, matching the backend contract at compile time.\n */\nexport type CreateWalletOwnershipChallengeParams =\n | (WalletOwnershipChallengeParamsBase & {\n /** A bare message the wallet signs. */\n challengeType: 'plain';\n })\n | (WalletOwnershipChallengeParamsBase & {\n /** Marks this as a Sign-In With Ethereum challenge. */\n challengeType: 'siwe';\n /** The requesting site's hostname (e.g. `example.com`). */\n domain: string;\n /** The requesting site's URI. */\n uri: string;\n /** Human-readable statement shown in the signing prompt. */\n statement: string;\n });\n\n/**\n * How the ownership challenge is framed: a plain message or a Sign-In With\n * Ethereum challenge. Extracted as its own type so SDK consumers can pass it as\n * a standalone param without reaching into the {@link CreateWalletOwnershipChallengeParams}\n * union.\n */\nexport type WalletChallengeType =\n CreateWalletOwnershipChallengeParams['challengeType'];\n\nexport const WalletOwnershipChallenge = {\n /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */\n fromDto: (dto: WalletOwnershipChallengeDto): WalletOwnershipChallenge => ({\n message: dto.message,\n expiresAt: new Date(dto.expires_at),\n }),\n};\n\nexport const CreateWalletOwnershipChallengeParams = {\n /**\n * Maps challenge-request params into the API DTO payload. The discriminated\n * union guarantees SIWE fields are present exactly when `challengeType` is\n * `siwe`, so the mapping narrows on the discriminant.\n */\n toDto: (\n params: CreateWalletOwnershipChallengeParams\n ): CreateWalletOwnershipChallengeDto => {\n switch (params.challengeType) {\n case 'plain':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'plain',\n };\n case 'siwe':\n return {\n wallet_address: params.walletAddress,\n chain: params.chain,\n challenge_type: 'siwe',\n domain: params.domain,\n uri: params.uri,\n statement: params.statement,\n };\n default: {\n const _exhaustive: never = params;\n return _exhaustive;\n }\n }\n },\n};\n","import { Attributes } from '@/universal/api/http-attributes';\nimport type { Sender } from '@/universal/api/http-client';\nimport type { OfferOptionAddressDto } from '@/universal/types/dto/offer-option-address';\nimport type { ListResponseDto } from '@/universal/types/dto/shared';\nimport type { WalletOwnershipChallengeDto } from '@/universal/types/dto/wallet-ownership-challenge';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n type OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\n/**\n * Creates a single-use wallet-ownership challenge. The consumer signs the\n * returned message with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 when params are invalid — an unparseable\n * address, or SIWE fields (`domain`/`uri`/`statement`) that are missing on a\n * `siwe` challenge or present on a `plain` one. The `ApiErrorDto` body\n * carries the validation detail.\n */\nexport async function createWalletOwnershipChallenge(\n api: Sender,\n params: CreateWalletOwnershipChallengeParams\n): Promise<WalletOwnershipChallenge> {\n const dto = await api.send<WalletOwnershipChallengeDto>({\n method: 'POST',\n url: '/v1/wallet-ownership',\n body: CreateWalletOwnershipChallengeParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return WalletOwnershipChallenge.fromDto(dto);\n}\n\n/**\n * Connects a proven external wallet to an offer option. Requires a signature\n * of a previously created, unconsumed wallet-ownership challenge for the same\n * wallet and chain.\n *\n * Single-slot (`external_wallet`) options replace the existing binding in place\n * on re-submit — the binding `id` is stable across a \"change wallet\" — so\n * `max_wallets_reached` only fires for `whitelisted_wallet` options at their cap.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 for every binding failure; discriminate via the\n * `ApiErrorDto` body. Failures with a machine-readable `code`:\n * `wallet_not_whitelisted`, `max_wallets_reached`. Every other binding failure\n * (protocol mismatch, concurrent-connect lock, etc.) is rendered as an opaque\n * generic 422 with no `code`, by backend design. Challenge-state failures\n * surface by message only: no unconsumed challenge, wallet/chain not matching\n * the challenge, expired, or already used. Expired and already-used are not\n * retry-safe — request a fresh challenge first.\n */\nexport async function connectExternalWallet(\n api: Sender,\n params: ConnectExternalWalletParams\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'POST',\n url: `/v1/offers/${params.offerId}/addresses`,\n body: ConnectExternalWalletParams.toDto(params),\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n\n/**\n * Lists the user's proven wallet bindings for a single offer option. Single-slot\n * (`external_wallet`) options return at most one binding; `whitelisted_wallet`\n * options return up to the requirement's `max_wallets`. Works after the offer\n * ends, so partners can read the final bindings.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n */\nexport async function listOptionAddresses(\n api: Sender,\n offerId: OfferId,\n offerOptionId: OfferOptionId\n): Promise<OfferOptionAddress[]> {\n const { data } = await api.send<ListResponseDto<OfferOptionAddressDto>>({\n method: 'GET',\n url: `/v1/offers/${offerId}/addresses`,\n queryParams: { offer_option_id: offerOptionId },\n attributes: Attributes.protected(),\n });\n return data.map(OfferOptionAddress.fromDto);\n}\n\n/**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * @throws {NotAuthenticatedError} when the request is unauthenticated (401).\n * @throws {HttpError} on a 422 with `code` `offer_ended` once the offer has\n * ended (bindings on an offer that has not yet started stay removable), or a\n * 404 when the binding does not exist or is not the caller's.\n */\nexport async function removeOptionAddress(\n api: Sender,\n offerId: OfferId,\n addressId: OfferOptionAddressId\n): Promise<OfferOptionAddress> {\n const dto = await api.send<OfferOptionAddressDto>({\n method: 'DELETE',\n url: `/v1/offers/${offerId}/addresses/${addressId}`,\n attributes: Attributes.protected(),\n });\n return OfferOptionAddress.fromDto(dto);\n}\n","import * as walletConnectApi from '@/universal/api/frontline/wallet-connect';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type InternalLogger,\n internalLogger,\n} from '@/universal/core/shared/observability/internal-logger';\nimport type { OfferId } from '@/universal/types/offer';\nimport type { OfferOptionId } from '@/universal/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/universal/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/universal/types/wallet-ownership-challenge';\n\nexport type ListOptionAddressesParams = {\n offerId: OfferId;\n /** Offer option whose bindings to list. */\n offerOptionId: OfferOptionId;\n};\n\nexport type RemoveOptionAddressParams = {\n offerId: OfferId;\n /** Binding to remove, as returned by {@link WalletsNamespace.list}. */\n addressId: OfferOptionAddressId;\n};\n\n/**\n * The user's external wallets: proving ownership of one, binding it to an\n * offer option, and managing those bindings.\n *\n * Ownership proof is a provider-agnostic primitive — the swap flow uses the\n * same challenge to allow-list a wallet — so it lives here rather than being\n * duplicated per product namespace.\n *\n * Every method requires an authenticated user and throws\n * {@link NotAuthenticatedError} otherwise.\n */\nexport interface WalletsNamespace {\n /**\n * Creates a single-use challenge the user signs to prove they control a\n * wallet. Supports both `plain` and `siwe` challenges. Pass the signature of\n * the returned {@link WalletOwnershipChallenge.message} to\n * {@link connectExternal}.\n */\n createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n\n /**\n * Binds a proven external wallet to an offer option, using a signature of a\n * challenge from {@link createOwnershipChallenge}.\n */\n connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n\n /**\n * Lists the user's proven wallet bindings for one offer option — the single\n * bound address for an `external_wallet` option, or every allow-listed\n * wallet for a `whitelisted_wallet` option.\n */\n list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;\n\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n */\n remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;\n}\n\nexport class WalletsNamespaceImpl implements WalletsNamespace {\n private readonly log: InternalLogger;\n\n constructor(private readonly ctx: UniversalNamespaceContext) {\n this.log = internalLogger(ctx.logger, 'WALLETS');\n }\n\n async createOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n return this.log.wrap('createOwnershipChallenge', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(\n this.ctx.api,\n params\n );\n });\n }\n\n async connectExternal(\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n return this.log.wrap('connectExternal', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.connectExternalWallet(this.ctx.api, params);\n });\n }\n\n async list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]> {\n return this.log.wrap('list', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.ctx.api,\n params.offerId,\n params.offerOptionId\n );\n });\n }\n\n async remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress> {\n return this.log.wrap('remove', params, async () => {\n await this.ctx.ensureUserAuthenticated();\n return walletConnectApi.removeOptionAddress(\n this.ctx.api,\n params.offerId,\n params.addressId\n );\n });\n }\n}\n","import { ApiClient } from '@/server/core/api/api-client';\nimport {\n type ServerAuthNamespace,\n ServerAuthNamespaceImpl,\n type SessionStore,\n} from '@/server/core/server-auth-namespace';\nimport type { ServerNamespaceContext } from '@/server/core/server-namespace-context';\nimport {\n type ServerOffersNamespace,\n ServerOffersNamespaceImpl,\n} from '@/server/core/server-offers-namespace';\nimport {\n type ServerRequirementsNamespace,\n ServerRequirementsNamespaceImpl,\n} from '@/server/core/server-requirements-namespace';\nimport {\n API_VERSION,\n PUBLIC_API_BASE_URL,\n} from '@/universal/api/frontline/config';\nimport { NABU_BASE_URL } from '@/universal/api/nabu/config';\nimport { publicClients } from '@/universal/api/rpc/public-clients';\nimport {\n type CoinListTokenSaleNamespace,\n CoinListTokenSaleNamespaceImpl,\n} from '@/universal/core/checkout/coin-list/token-sale-namespace';\nimport {\n type OndoNamespace,\n OndoNamespaceImpl,\n} from '@/universal/core/checkout/ondo/ondo-namespace';\nimport {\n type SuperstateSwapNamespace,\n SuperstateSwapNamespaceImpl,\n} from '@/universal/core/checkout/superstate/swap-namespace';\nimport {\n type Erc20Namespace,\n Erc20NamespaceImpl,\n} from '@/universal/core/shared/blockchain/erc20/erc20-namespace';\nimport type { UniversalNamespaceContext } from '@/universal/core/shared/namespace-context';\nimport {\n type TokensNamespace,\n TokensNamespaceImpl,\n} from '@/universal/core/tokens/tokens-namespace';\nimport {\n type WalletsNamespace,\n WalletsNamespaceImpl,\n} from '@/universal/core/wallets/wallets-namespace';\nimport type { Config } from '@/universal/types/config';\nimport { NotAuthenticatedError } from '@/universal/types/errors';\nimport type { ClientSecret } from '@/universal/types/oauth';\nimport type { ClientCredentialsOAuth } from '@/universal/types/oauth-session';\n\n/** Buffer in seconds before expiry to consider token expired for refresh. */\nconst ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;\n\nexport interface ServerConfig extends Config {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Buffer in seconds before expiry to consider token expired for refresh. */\n readonly accessTokenExpiryBufferSeconds?: number;\n /**\n * Whether SDK will throw an exception in cases it can be silent.\n * For example, if token revokation on logout fails.\n */\n readonly strict?: boolean;\n}\n\n/**\n * Server-side CoinList SDK client.\n *\n * Functionality is grouped into namespaces — `coinlist.auth.getAccessToken()`,\n * `coinlist.offers.list()`, `coinlist.requirements.statuses(offerId)`.\n *\n * Operates in one of two modes depending on whether {@link SessionStore}\n * includes a `setSession` implementation:\n *\n * - **Writable store** (`setSession` provided) — full functionality: token\n * refresh, `auth.completeOAuth`, and `auth.logout` all work normally.\n *\n * - **Read-only store** (no `setSession`) — token refresh is skipped entirely,\n * meaning no network call is made and no refresh token is consumed.\n * `auth.completeOAuth` and `auth.logout` throw\n * {@link WritableSessionStoreRequiredError}. `auth.getAccessToken` may\n * return an expired token (see its docs). Use this mode in execution\n * contexts that can read the session but cannot write it back, such as\n * Next.js Server Components.\n *\n * Unless a namespace says otherwise, its methods require a user session and\n * throw {@link NotAuthenticatedError} when there is none.\n */\nexport interface CoinListServer {\n /**\n * OAuth session lifecycle: exchanging an authorization code, serving a valid\n * access token to the browser, minting app-level tokens, and logging out —\n * e.g. `coinlist.auth.getAccessToken()`.\n */\n readonly auth: ServerAuthNamespace;\n\n /**\n * The offer catalogue — e.g. `coinlist.offers.list()`. Every read also\n * accepts an app-level token from {@link ServerAuthNamespace.clientCredentials}\n * so it can run without a user session.\n */\n readonly offers: ServerOffersNamespace;\n\n /**\n * Offer requirements and the operations that satisfy them — e.g.\n * `coinlist.requirements.statuses(offerId)`. `forOffer` also accepts an\n * app-level token; the rest is per-user data and needs a user session.\n */\n readonly requirements: ServerRequirementsNamespace;\n\n /**\n * The user's external wallets: ownership proofs and offer-option bindings —\n * e.g. `coinlist.wallets.list({ offerId, offerOptionId })`.\n */\n readonly wallets: WalletsNamespace;\n\n /**\n * Generic ERC-20 reads (token allowance and balance) — e.g.\n * `coinlist.erc20.getBalance({ ... })`.\n */\n readonly erc20: Erc20Namespace;\n\n /**\n * Token-sale operations: listing, reading, and recording participations —\n * e.g. `coinlist.tokenSale.list()`. The on-chain `execute`\n * flow is client-only and is not exposed here.\n */\n readonly tokenSale: CoinListTokenSaleNamespace;\n\n /**\n * On-chain swap operations: quoting a swap, reading swap-contract state, and\n * allow-listing a proven wallet — e.g.\n * `coinlist.superstate.getOutputToken({ contractAddress, chain })`.\n */\n readonly superstate: SuperstateSwapNamespace;\n\n /**\n * Ondo swap reads: trading status and quoting. Both are free to poll.\n *\n * No CoinList fee is applied to a quote; see {@link OndoNamespace}.\n *\n * This is Ondo's whole surface for now — the wallet-driven half arrives with\n * ENG-1680 and will be client-only, since it needs a wallet to sign with.\n */\n readonly ondo: OndoNamespace;\n\n /**\n * Token display metadata (name, symbol, decimals, logos) from CoinList's\n * public token registry, keyed by chain + contract address — e.g.\n * `coinlist.tokens.get({ chain, address })` for an entry of\n * `Offer.tokens`, or `coinlist.tokens.list()` for the whole\n * catalogue in one request.\n *\n * Public and unauthenticated: unlike the other namespaces, its methods never\n * require a session, so it also works with a read-only store.\n */\n readonly tokens: TokensNamespace;\n}\n\nclass CoinListServerImpl implements CoinListServer {\n private readonly api: ApiClient;\n readonly auth: ServerAuthNamespace;\n readonly offers: ServerOffersNamespace;\n readonly requirements: ServerRequirementsNamespace;\n readonly wallets: WalletsNamespace;\n readonly erc20: Erc20Namespace;\n readonly tokenSale: CoinListTokenSaleNamespace;\n readonly superstate: SuperstateSwapNamespace;\n readonly ondo: OndoNamespace;\n readonly tokens: TokensNamespace;\n\n constructor(private readonly _config: ServerConfig) {\n const logger = _config.logger ?? null;\n this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n // When refresh=true the renewal middleware has received a 401 and wants a\n // fresh token. A read-only store cannot persist a new session, so return\n // null immediately — this tells the middleware to skip the retry rather\n // than re-sending with the same expired token and wasting a round-trip.\n (refresh) =>\n refresh && !this._config.sessionStore.setSession\n ? Promise.resolve(null)\n : this.auth.getAccessToken(),\n logger\n );\n this.auth = new ServerAuthNamespaceImpl(this.api, {\n ..._config,\n accessTokenExpiryBufferSeconds:\n _config.accessTokenExpiryBufferSeconds ??\n ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,\n strict: _config.strict ?? false,\n });\n\n const ctx: UniversalNamespaceContext & ServerNamespaceContext = {\n api: this.api,\n rpc: publicClients(this.api, _config.rpc, _config.logger ?? null),\n logger,\n ensureUserAuthenticated: () => this.ensureAuthenticated(undefined),\n ensureAuthenticated: (clientCreds) =>\n this.ensureAuthenticated(clientCreds),\n };\n this.offers = new ServerOffersNamespaceImpl(ctx);\n this.requirements = new ServerRequirementsNamespaceImpl(ctx);\n this.wallets = new WalletsNamespaceImpl(ctx);\n this.erc20 = new Erc20NamespaceImpl(ctx);\n this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);\n this.superstate = new SuperstateSwapNamespaceImpl(ctx);\n this.ondo = new OndoNamespaceImpl(ctx);\n this.tokens = new TokensNamespaceImpl(\n _config.tokensBaseUrl ?? NABU_BASE_URL,\n logger\n );\n }\n\n /**\n * An app-level token authenticates a request on its own; without one the\n * caller needs a user session.\n */\n private async ensureAuthenticated(\n clientCreds: ClientCredentialsOAuth | undefined\n ): Promise<void> {\n if (clientCreds) return;\n const token = await this.auth.getAccessToken();\n if (token === null) {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nexport function createCoinListServer(config: ServerConfig): CoinListServer {\n return new CoinListServerImpl(config);\n}\n","import { pino } from 'pino';\nimport {\n loggerOverPino,\n PINO_LEVEL,\n SDK_LOGGER_NAME,\n} from '@/universal/core/shared/observability/pino-logger';\nimport type { Logger, PinoLoggerOptions } from '@/universal/types/logger';\n\n/**\n * A {@link Logger} that writes newline-delimited JSON to stdout through pino.\n *\n * ```ts\n * createCoinListServer({\n * ...config,\n * logger: pinoServerLogger({ isDev: false, level: 'info' }),\n * });\n * ```\n *\n * The Node counterpart of {@link pinoClientLogger}, for a route handler, a BFF\n * or SSR. One line per record, which is what every log aggregator ingests\n * without configuration.\n *\n * ## What it deliberately does not do\n *\n * **No transport, and no `pino-pretty`.** A pino transport runs on a worker\n * thread through `thread-stream`, which every bundler has to be told about\n * (`serverExternalPackages` in Next) and which edge runtimes cannot run at\n * all. Pretty-printing is a pipe the host owns rather than a dependency the\n * SDK takes on their behalf:\n *\n * ```sh\n * node server.js | npx pino-pretty\n * ```\n *\n * **No environment-dependent formatting.** `isDev` decides which levels are\n * legal and nothing else, so a development record and a production record are\n * the same shape - what you debug is what you ship.\n *\n * If you already run pino, or want transports, redaction or `destination`,\n * implement {@link Logger} yourself: it is four methods over an event, and\n * `@opentelemetry/instrumentation-pino` patches the pino module rather than an\n * instance, so trace correlation reaches this logger either way.\n *\n * ## Production\n *\n * **Not advised in production**, the same as everywhere else this seam is\n * documented: the SDK's default answer is to leave {@link Config.logger}\n * undefined outside development, staging and incident reproduction. A backend\n * is the least bad place to disregard that - the records go to your process\n * and your sink rather than to a page the end user can read - but it is still\n * a disregard, and the retention and access questions become yours.\n *\n * If you run one, `isDev: false` restricts you to `'error'`, `'warn'` and\n * `'info'` - `{ isDev: false, level: 'debug' }` does not compile, see\n * {@link PinoLoggerOptions}. Those levels are redacted by construction, which\n * is a mechanism the SDK holds itself to; whether that clears your bar is a\n * judgement the SDK is not in a position to make for you.\n *\n * Holds no module-level state: every call builds its own pino instance, and\n * the level is fixed at construction, so two loggers never interfere. Fixed is\n * this implementation's choice, not the seam's - the SDK re-reads\n * {@link Logger.level} before every log call - so if you want a level you can\n * change at runtime, implement {@link Logger} over your own pino instance\n * rather than calling this.\n */\nexport function pinoServerLogger(options: PinoLoggerOptions): Logger {\n return loggerOverPino(\n // `name` as a child binding rather than pino's `name` option: the option\n // is honoured by pino's node build and silently dropped by its browser\n // build, so a binding is the only spelling that identifies the SDK in\n // both environments.\n pino({\n level: PINO_LEVEL[options.level],\n }).child({ name: SDK_LOGGER_NAME }),\n options.level\n );\n}\n","import type {\n DebugEvent,\n Logger,\n LogLevel,\n SafeEvent,\n} from '@/universal/types/logger';\n\n/**\n * The SDK's logging seam expressed over pino, minus the environment.\n *\n * Imports no pino - {@link PinoSink} is a structural type - so `@/universal`\n * stays pino-free and the `./universal` entry point costs a consumer nothing.\n * Both shipped implementations\n * ({@link pinoClientLogger}, {@link pinoServerLogger}) differ only in the pino\n * instance they construct; everything worth testing lives here.\n *\n * ## Nothing here may throw\n *\n * A {@link Logger} implementation is called inline, on the codepath of the\n * work it reports, and the SDK does not catch it - so a log line that fails to\n * render would turn a successful request into an exception. That risk is real\n * rather than theoretical: `'debug'` fields carry whatever the SDK was\n * handling, and this codebase routinely handles `bigint` (every uint256 on\n * every DTO), which `JSON.stringify` throws on. Response bodies may be\n * circular, params may hold functions, and a host's object may have a getter\n * that throws.\n *\n * So {@link toPinoRecord} is total by construction: every value is rendered\n * into something a JSON serialiser cannot refuse, every property read is\n * guarded, and the whole translation has a fallback. Pino is never handed a\n * value it could fail on.\n */\n\n/**\n * Flattens an event into the object pino merges into its output line.\n *\n * Flat rather than nested, because nesting is what a host has to un-nest\n * before they can facet on it: `scope`, the {@link LogBindings} and every\n * field sit at the top level, and only `cause` stays an object because its\n * arms are a closed union a host switches on.\n *\n * `msg` is **not** included: it is pino's own second argument.\n *\n * Never throws. A value it cannot render becomes a `<tag>` string rather than\n * an exception, and a translation that fails entirely degrades to a record\n * naming the failure.\n */\nexport function toPinoRecord(event: SafeEvent | DebugEvent): PinoRecord {\n try {\n const record: Record<string, unknown> = {};\n\n for (const key of ownKeys(event.fields)) {\n record[key] = readProperty(event.fields, key, 0, new WeakSet());\n }\n\n const cause = 'cause' in event ? event.cause : undefined;\n if (cause !== undefined) {\n record.cause = sanitize(cause, 0, new WeakSet());\n }\n\n // Last, so the stamped keys win. `scope` and the bindings are what a host\n // routes and filters on, and they are stamped by `internalLogger` rather\n // than written at a call site - so a field that happened to be named\n // `scope` or `op` must not be able to take their place.\n return { ...record, scope: event.scope, ...event.bindings };\n } catch (_) {\n // The event itself is malformed - a Proxy for `fields`, a frozen exotic\n // object. Report that rather than losing the line, and never rethrow.\n return { 'log.render': '<unrenderable event>' };\n }\n}\n\n/** What pino merges into one output line. */\nexport type PinoRecord = Readonly<Record<string, unknown>>;\n\n/**\n * The SDK's five levels in pino's vocabulary.\n *\n * `'none'` is pino's `'silent'`; the other four are the same word in both, and\n * deliberately so. The SDK does not adopt pino's seven because `'trace'` would\n * sit below `'debug'`, and the guarantee \"`debug` is unredacted and every\n * other level is not\" only closes while `'debug'` is the bottom.\n */\nexport const PINO_LEVEL = {\n none: 'silent',\n error: 'error',\n warn: 'warn',\n info: 'info',\n debug: 'debug',\n} as const satisfies Record<LogLevel, string>;\n\n/**\n * How deep a `'debug'` field is followed before it is summarised.\n *\n * A bound rather than a guess at what is deep enough: a self-referential\n * structure is already caught by the cycle check, but a legitimately deep DTO\n * would otherwise cost real time inside a log line.\n */\nconst MAX_DEPTH = 8;\n\n/**\n * Renders any value into something a JSON serialiser cannot refuse.\n *\n * `bigint` is the one that matters in practice - every uint256 the SDK handles\n * is one - but the rest are all reachable from a `'debug'` field: `undefined`\n * and functions from an operation's params, `NaN` from arithmetic, symbols\n * from a host's object.\n */\nfunction sanitize(\n value: unknown,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return value;\n case 'number':\n // `NaN` and the infinities serialise to `null`, which reads as \"absent\"\n // rather than \"not a number\". Name them instead.\n return Number.isFinite(value) ? value : String(value);\n case 'bigint':\n return value.toString();\n case 'undefined':\n return '<undefined>';\n case 'function':\n return '<function>';\n case 'symbol':\n return value.toString();\n case 'object':\n return value === null ? null : sanitizeObject(value, depth, seen);\n default:\n return '<unrenderable>';\n }\n}\n\nfunction sanitizeObject(\n value: object,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n if (seen.has(value)) return '<circular>';\n if (depth >= MAX_DEPTH) return '<max depth>';\n\n // `name`, `message` and `stack` are all non-enumerable, so an `Error` handed\n // to a structured sink as an object serialises to `{}`.\n if (value instanceof Error) return describeError(value);\n if (value instanceof Date) return describeDate(value);\n\n seen.add(value);\n try {\n if (Array.isArray(value)) {\n return value.map((_item, index) =>\n readProperty(value, String(index), depth, seen)\n );\n }\n\n const out: Record<string, unknown> = {};\n for (const key of ownKeys(value)) {\n out[key] = readProperty(value, key, depth, seen);\n }\n return out;\n } finally {\n // Removed on the way out, so a value referenced twice in a tree renders\n // twice. Only a genuine cycle is `<circular>`.\n seen.delete(value);\n }\n}\n\n/**\n * One property read, guarded. A getter may throw, and a log line is not\n * allowed to be the reason a request fails.\n */\nfunction readProperty(\n owner: object,\n key: string,\n depth: number,\n seen: WeakSet<object>\n): unknown {\n try {\n return sanitize((owner as Record<string, unknown>)[key], depth + 1, seen);\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/** Own enumerable keys, guarded: an exotic object may refuse to be enumerated. */\nfunction ownKeys(value: object): readonly string[] {\n try {\n return Object.keys(value);\n } catch (_) {\n return [];\n }\n}\n\nfunction describeError(error: Error): Record<string, unknown> {\n return {\n name: safeRead(() => error.name),\n message: safeRead(() => error.message),\n stack: safeRead(() => error.stack),\n };\n}\n\nfunction describeDate(date: Date): unknown {\n // An invalid `Date` throws from `toISOString`.\n return safeRead(() => date.toISOString());\n}\n\nfunction safeRead(read: () => unknown): unknown {\n try {\n const value = read();\n return typeof value === 'string' ? value : '<unreadable>';\n } catch (_) {\n return '<unreadable>';\n }\n}\n\n/**\n * The part of a pino logger this adapter uses.\n *\n * Structural rather than `import type { Logger } from 'pino'`, so that\n * `@/universal` takes no dependency on pino at all. A real pino instance - node\n * or browser build - satisfies it.\n */\nexport type PinoSink = {\n debug(record: PinoRecord, msg: string): void;\n info(record: PinoRecord, msg: string): void;\n warn(record: PinoRecord, msg: string): void;\n error(record: PinoRecord, msg: string): void;\n};\n\n/**\n * The `name` binding every SDK line carries, so a partner can separate the\n * SDK's output from their own in a shared aggregator without matching on\n * `scope`.\n *\n * Applied through `pino.child({ name })` rather than pino's `name` *option*,\n * which its browser build ignores. The browser lane's spec is what caught\n * that, and is what keeps it caught.\n */\nexport const SDK_LOGGER_NAME = '@coinlist-co/react';\n\n/**\n * Adapts a pino instance into the {@link Logger} the SDK consumes.\n *\n * **Total, and that is the point.** The SDK calls a `Logger` inline and does\n * not catch it, so an exception raised while reporting a successful request\n * would fail that request. Three things could raise one - the event lambda\n * itself, rendering the event, and the sink - and all three are caught here.\n * A render failure is reported through the sink rather than swallowed, since a\n * log line that silently vanishes is a bug nobody finds; if the sink is what\n * broke, there is nowhere left to report it and the error stops here.\n *\n * **The level is fixed here, and that is this adapter's choice rather than the\n * seam's.** {@link InternalLogger} calls {@link Logger.level} before *every*\n * log call and caches nothing, so a host-implemented `Logger` reading a mutable\n * field has a level they can change at runtime. This adapter captures `level`\n * instead, and the pino instance it wraps is built with a fixed one - so\n * `Logger.level` is a constant lookup and two loggers never interfere. A host\n * who wants to turn `'debug'` on without rebuilding implements {@link Logger}\n * directly over their own pino instance; the port is four methods and this\n * function is the worked example.\n */\nexport function loggerOverPino(sink: PinoSink, level: LogLevel): Logger {\n return {\n level: () => level,\n debug: (event) => emit(sink, 'debug', event),\n info: (event) => emit(sink, 'info', event),\n warn: (event) => emit(sink, 'warn', event),\n error: (event) => emit(sink, 'error', event),\n };\n}\n\nfunction emit(\n sink: PinoSink,\n method: keyof PinoSink,\n event: () => SafeEvent | DebugEvent\n): void {\n try {\n const value = event();\n sink[method](toPinoRecord(value), value.msg);\n } catch (error) {\n reportRenderFailure(sink, error);\n }\n}\n\nfunction reportRenderFailure(sink: PinoSink, error: unknown): void {\n try {\n sink.error(\n { 'error.type': error instanceof Error ? error.name : typeof error },\n 'log event failed to render'\n );\n } catch (_) {\n // The sink itself threw. There is nowhere left to report this, and the SDK\n // is on the other side of the call that got us here.\n }\n}\n"],"mappings":"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","names":["http","base","requestId","import_viem","import_viem","import_viem","import_viem","import_viem"]}
|