@gala-chain/gswap-sdk 2.0.0 → 2.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/browser/classes/apply_results.js.map +1 -1
- package/dist/browser/classes/assets.js.map +1 -1
- package/dist/browser/classes/dex_fees.js +1 -1
- package/dist/browser/classes/dex_fees.js.map +1 -1
- package/dist/browser/classes/gateway.js +1 -1
- package/dist/browser/classes/gateway.js.map +1 -1
- package/dist/browser/classes/gdex_stream.js +1 -1
- package/dist/browser/classes/gdex_stream.js.map +1 -1
- package/dist/browser/classes/gswap.js +1 -1
- package/dist/browser/classes/gswap.js.map +1 -1
- package/dist/browser/classes/gswap_error_catalog.js +1 -1
- package/dist/browser/classes/gswap_error_catalog.js.map +1 -1
- package/dist/browser/classes/gswap_error_phase_table.js +1 -1
- package/dist/browser/classes/gswap_error_phase_table.js.map +1 -1
- package/dist/browser/classes/gswap_sdk_error.js +1 -1
- package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
- package/dist/browser/classes/http_client.js.map +1 -1
- package/dist/browser/classes/leaderboard.js.map +1 -1
- package/dist/browser/classes/market.js.map +1 -1
- package/dist/browser/classes/onramper.js.map +1 -1
- package/dist/browser/classes/pending_swap_fate.js.map +1 -1
- package/dist/browser/classes/pending_swaps.js +1 -1
- package/dist/browser/classes/pending_swaps.js.map +1 -1
- package/dist/browser/classes/pools.js +1 -1
- package/dist/browser/classes/pools.js.map +1 -1
- package/dist/browser/classes/positions.js +1 -1
- package/dist/browser/classes/positions.js.map +1 -1
- package/dist/browser/classes/quoting.js +1 -1
- package/dist/browser/classes/quoting.js.map +1 -1
- package/dist/browser/classes/shadow_submit.js.map +1 -1
- package/dist/browser/classes/storage_adapters.js.map +1 -1
- package/dist/browser/classes/submitted_transaction.js +1 -1
- package/dist/browser/classes/submitted_transaction.js.map +1 -1
- package/dist/browser/classes/swaps.js +1 -1
- package/dist/browser/classes/swaps.js.map +1 -1
- package/dist/browser/classes/symbols.js +1 -1
- package/dist/browser/classes/symbols.js.map +1 -1
- package/dist/browser/types/env.js.map +1 -1
- package/dist/browser/types/fees.js.map +1 -1
- package/dist/browser/types/market.js.map +1 -1
- package/dist/browser/utils/chain_contract.js +2 -0
- package/dist/browser/utils/chain_contract.js.map +1 -0
- package/dist/browser/utils/classification.js.map +1 -1
- package/dist/browser/utils/confirmation_schedule.js.map +1 -1
- package/dist/browser/utils/confirmation_state.js.map +1 -1
- package/dist/browser/utils/debug.js.map +1 -1
- package/dist/browser/utils/dto_builders.js.map +1 -1
- package/dist/browser/utils/failure_classification.js +1 -1
- package/dist/browser/utils/failure_classification.js.map +1 -1
- package/dist/browser/utils/failure_guards.js +1 -1
- package/dist/browser/utils/failure_guards.js.map +1 -1
- package/dist/browser/utils/lenient.js.map +1 -1
- package/dist/browser/utils/ordering.js.map +1 -1
- package/dist/browser/utils/reconnection.js +1 -1
- package/dist/browser/utils/reconnection.js.map +1 -1
- package/dist/browser/utils/resolve_pre_send.js.map +1 -1
- package/dist/browser/utils/server_message.js.map +1 -1
- package/dist/browser/utils/shadow_errors.js.map +1 -1
- package/dist/browser/utils/submit_state.js.map +1 -1
- package/dist/browser/utils/tick_align.js.map +1 -1
- package/dist/browser/utils/tick_math.js.map +1 -1
- package/dist/browser/utils/tick_range.js.map +1 -1
- package/dist/browser/utils/ticks.js.map +1 -1
- package/dist/browser/utils/validation.js.map +1 -1
- package/dist/index.cjs +23 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.mjs +23 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/defineProperty.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPrimitive.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/toPropertyKey.js +0 -0
- /package/dist/browser/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.154.0}/helpers/esm/typeof.js +0 -0
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["asRecord","trimTrailingSlash","asRecord","signalOption"],"sources":["../src/utils/confirmation_schedule.ts","../src/utils/server_message.ts","../src/classes/gswap_error_catalog.ts","../src/classes/gswap_error_phase_table.ts","../src/classes/gswap_sdk_error.ts","../src/classes/apply_results.ts","../src/types/fees.ts","../src/utils/tick_range.ts","../src/utils/tick_math.ts","../src/utils/validation.ts","../src/classes/assets.ts","../src/classes/dex_fees.ts","../src/utils/shadow_errors.ts","../src/classes/submitted_transaction.ts","../src/classes/gateway.ts","../src/types/env.ts","../src/utils/debug.ts","../src/utils/reconnection.ts","../src/classes/gdex_stream.ts","../src/classes/http_client.ts","../src/utils/lenient.ts","../src/classes/leaderboard.ts","../src/types/market.ts","../src/classes/market.ts","../src/classes/onramper.ts","../src/utils/ordering.ts","../src/utils/resolve_pre_send.ts","../src/classes/symbols.ts","../src/classes/pools.ts","../src/utils/tick_align.ts","../src/utils/ticks.ts","../src/utils/dto_builders.ts","../src/classes/positions.ts","../src/classes/quoting.ts","../src/classes/shadow_submit.ts","../src/classes/swaps.ts","../src/classes/gswap.ts","../src/utils/classification.ts","../src/utils/failure_classification.ts","../src/classes/pending_swap_fate.ts","../src/classes/pending_swaps.ts","../src/classes/storage_adapters.ts","../src/utils/confirmation_state.ts","../src/utils/failure_guards.ts","../src/utils/submit_state.ts"],"sourcesContent":["import type { ConfirmOptions } from '../types/confirm_options.js';\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst MIN_POLL_INTERVAL_MS = 500;\nconst MAX_BACKOFF_MS = 8_000;\n\n/** The pacing of confirmation reads: one initial delay, then jittered exponential backoff. */\nexport interface ConfirmationSchedule {\n /**\n * Waits for the next read. Resolves `true` when the caller should read, `false` when the\n * deadline leaves no room for another read. The very first call always resolves `true` (at\n * least one read is made, even when the deadline is already past). Rejects with the abort\n * error when the caller's signal aborts, before or during the wait.\n */\n waitForRead(retryAfterMs?: number): Promise<boolean>;\n}\n\n/**\n * Builds the schedule for one `confirm()` call. `abortError` creates the error thrown when\n * `options.signal` aborts, so each confirmation kind keeps its own error type and details.\n */\nexport function createConfirmationSchedule(\n options: ConfirmOptions | undefined,\n defaultInitialDelayMs: number,\n abortError: (cause?: unknown) => Error,\n): ConfirmationSchedule {\n const timeoutMs = Math.max(0, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n const pollIntervalMs = Math.max(\n MIN_POLL_INTERVAL_MS,\n options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,\n );\n const initialDelayMs = Math.max(0, options?.initialDelayMs ?? defaultInitialDelayMs);\n const signal = options?.signal;\n const deadline = Date.now() + timeoutMs;\n let firstRead = true;\n let attempt = 0;\n return {\n async waitForRead(retryAfterMs?: number): Promise<boolean> {\n throwIfAborted(signal, abortError);\n if (firstRead) {\n firstRead = false;\n const remaining = Math.max(0, deadline - Date.now());\n await delay(Math.min(initialDelayMs, remaining), signal, abortError);\n return true;\n }\n const backoff = Math.min(MAX_BACKOFF_MS, pollIntervalMs * 2 ** Math.min(attempt, 5));\n attempt += 1;\n const waitMs = retryAfterMs === undefined ? jitter(backoff) : Math.max(0, retryAfterMs);\n if (Date.now() + waitMs > deadline) return false;\n await delay(waitMs, signal, abortError);\n return true;\n },\n };\n}\n\n/** Throws `abortError(signal.reason)` when the signal has aborted. */\nexport function throwIfAborted(\n signal: AbortSignal | undefined,\n abortError: (cause?: unknown) => Error,\n): void {\n if (signal?.aborted === true) throw abortError(signal.reason);\n}\n\nfunction delay(\n milliseconds: number,\n signal: AbortSignal | undefined,\n abortError: (cause?: unknown) => Error,\n): Promise<void> {\n if (signal?.aborted === true) return Promise.reject(abortError(signal.reason));\n return new Promise((resolve, reject) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(abortError(signal?.reason));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, milliseconds);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction jitter(milliseconds: number): number {\n return Math.max(0, Math.round(milliseconds * (0.9 + Math.random() * 0.2)));\n}\n","import type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\nfunction nonEmptyString(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const field = (value as Record<string, unknown>)[property];\n return typeof field === 'string' && field !== '' ? field : undefined;\n}\n\n/**\n * The human message a failing JSON body carries, as the server wrote it: the first non-empty\n * string of `message`, `Message`, `error.message`, `error.Message` (NestJS, the gateway filter\n * and the chain each use one of these shapes), else `''`. A body that is not JSON (an HTML 502\n * page, an empty body), or whose `message` is not a string (a validation error's list), has no\n * message. This is the single reader behind every `serverMessage` param.\n *\n * The text is DATA from the server, not SDK text: it is English, unstable, and may be empty. The\n * SDK exposes it so an app can relay it or ignore it; it is never part of `error.message`.\n */\nexport function serverMessageOfBody(body: unknown): string {\n const nested =\n typeof body === 'object' && body !== null\n ? (body as Record<string, unknown>)['error']\n : undefined;\n return (\n nonEmptyString(body, 'message') ??\n nonEmptyString(body, 'Message') ??\n nonEmptyString(nested, 'message') ??\n nonEmptyString(nested, 'Message') ??\n ''\n );\n}\n\n/**\n * The message the server put in a failing answer: the `serverMessage` param of a code that relays\n * it, else the message of the JSON body ({@link serverMessageOfBody}). Internal: the SDK reads it\n * ONLY to classify a failure (a quote that says \"no pools\"); it is English from the server, never\n * part of the SDK's own `message`, and not exported from the package.\n */\nexport function readServerMessage(error: GSwapSDKError): string | undefined {\n const params: Readonly<Record<string, string | number | boolean>> = error.params;\n const fromParams = params['serverMessage'];\n if (typeof fromParams === 'string' && fromParams !== '') return fromParams;\n const fromBody = serverMessageOfBody(error.body);\n return fromBody === '' ? undefined : fromBody;\n}\n","/**\n * The catalog of every error code gswap-sdk ITSELF throws (the DEX codes): the SINGLE source of\n * truth for its `code`, the named parameters it carries and the English template its `message` is\n * generated from. The codes of the signing, transport and wallet layer (`INVALID_PRIVATE_KEY`,\n * `REQUEST_TIMEOUT`, `SIGNING_FAILED`, `TYPED_DATA_*`, ...) live in `@gala-chain/gala-core-sdk`'s\n * `GALA_ERROR_CATALOG`; no code is defined in both. A `GSwapSDKError` can carry a code of either\n * catalog (`GSwapErrorCode` is the union), and reads its template from both.\n *\n * - `code` is the only discriminator. It is stable: apps branch on it, never on message text.\n * - `params` are the named placeholders of the error: a flat object of primitives (string,\n * number, boolean) that an app feeds to its own localization (i18next, ICU, FormatJS).\n * Raw server payloads are never params (they are `error.body` / `error.bodyText`), and no\n * secret (private key, signature, raw DTO) ever is.\n * - `template` is English with `{placeholder}` markers. `error.message` is generated from it\n * and the params, so the two cannot drift. It is for logs and developers: it is not stable and\n * must not be shown to users or matched on.\n *\n * Every placeholder in a template is a declared param and every declared param is a placeholder,\n * except the few `unrendered` params that carry server text for the app and are kept out of\n * `message` on purpose (pinned by tests/error_catalog.test.ts). Facts that are not placeholders (HTTP status, URL,\n * `uniqueKey`, transaction ids, the raw body, the cause) are typed properties of the error, see\n * `GalaErrorContext`.\n */\n\nimport {\n GALA_ERROR_CATALOG,\n type ErrorParamsOf,\n type GalaErrorCatalogEntry,\n type GalaErrorCode,\n} from '@gala-chain/gala-core-sdk';\n\n/**\n * Why the outcome of a write submission is unknown (`SUBMISSION_OUTCOME_UNKNOWN.params.reason`).\n * Both say the same thing about the swap (it MAY have been queued: never resubmit under a fresh\n * key, confirm `error.uniqueKey` instead) and differ only in what happened to the request.\n *\n * - `timeout`: the POST exceeded the gateway's timeout; the request may still be running.\n * - `transport`: the POST failed before an HTTP answer was read (offline, connection reset, DNS,\n * CORS, a body that broke off). The bytes may have reached the server and been queued, so this\n * does NOT prove the swap was not sent.\n */\nexport const SUBMISSION_OUTCOME_UNKNOWN_REASONS = ['timeout', 'transport'] as const;\n\n/** One member of {@link SUBMISSION_OUTCOME_UNKNOWN_REASONS}. */\nexport type SubmissionOutcomeUnknownReason = (typeof SUBMISSION_OUTCOME_UNKNOWN_REASONS)[number];\n\n/** The fee tiers as they appear in `INVALID_FEE.allowed`. */\nexport const ALLOWED_FEE_TIERS_TEXT = '0,500,3000,10000';\n\n/** The whole DEX catalog. Add a code here before throwing it anywhere in gswap-sdk. */\nexport const GSWAP_ERROR_CATALOG = {\n // ---------------------------------------------------------------------------------- transport\n HTTP_ERROR: {\n phase: 'post_send',\n template: 'Unexpected HTTP error {status} from {url}.',\n params: { status: 'number', url: 'string', serverMessage: 'string' },\n unrendered: ['serverMessage'],\n },\n UPDATE_REQUIRED: {\n phase: 'post_send',\n template:\n 'The backend refused this app version and requires an update (HTTP {status}); nothing was queued.',\n params: { status: 'number' },\n },\n REQUEST_FAILED: {\n phase: 'in_flight',\n template: 'The {operation} request failed.',\n params: { operation: 'string' },\n },\n\n // ----------------------------------------------------------------------------------- gateway\n METHOD_NOT_SUPPORTED: {\n phase: 'pre_send',\n template: 'The method {method} is not supported; swaps are queued through RequestTrade.',\n params: { method: 'string' },\n },\n SUBMISSION_OUTCOME_UNKNOWN: {\n phase: 'in_flight',\n template:\n 'The submission outcome is unknown ({reason}): the request may have reached the gateway. Confirm before retrying.',\n params: { reason: SUBMISSION_OUTCOME_UNKNOWN_REASONS },\n },\n GATEWAY_REPORTED_ERROR: {\n phase: 'post_send',\n template: 'The gateway reported an error for this write: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n GATEWAY_DATA_MISSING: {\n phase: 'post_send',\n template: 'The gateway response is missing its data object.',\n params: {},\n },\n GATEWAY_MODE_INVALID: {\n phase: 'post_send',\n template:\n 'Gateway response must contain data.mode=\"sync\" with data.result, or data.mode=\"queued\".',\n params: {},\n },\n GATEWAY_SYNC_REQUEST_TRADE: {\n phase: 'post_send',\n template:\n 'The gateway executed RequestTrade synchronously, which this SDK refuses; RequestTrade must be queued.',\n params: {},\n },\n MISSING_UNIQUE_KEY: {\n phase: 'post_send',\n template:\n 'The gateway acknowledged RequestTrade without echoing its uniqueKey, so it cannot be tied to the signed request.',\n params: {},\n },\n UNIQUE_KEY_MISMATCH: {\n phase: 'post_send',\n template: 'Gateway response data.uniqueKey must match the signed RequestTrade uniqueKey.',\n params: {},\n },\n SHADOW_NOT_QUEUED: {\n phase: 'post_send',\n template: 'The swap backend did not queue the shadow request.',\n params: {},\n },\n SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: {\n phase: 'pre_send',\n template:\n 'A shadow submission needs a walletAddress (the X-Wallet-Address header): pass one to the GSwap constructor or to this call.',\n params: {},\n },\n METHOD_NOT_ALLOWED: {\n phase: 'post_send',\n template: 'The gateway does not expose this contract method: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SIGNATURE_INVALID: {\n phase: 'post_send',\n template: 'The gateway could not verify the signature: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SIGNER_MISMATCH: {\n phase: 'post_send',\n template:\n 'The recovered signer does not match an actor named by the operation: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n DTO_INVALID: {\n phase: 'post_send',\n template: 'The gateway rejected the DTO shape: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n BOUNDS_VIOLATION: {\n phase: 'post_send',\n template: 'The gateway rejected a numeric, tick, symbol or range bound: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SYMBOL_CONFLICT: {\n phase: 'post_send',\n template: 'The CreatePool symbol is already owned by another class: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n RATE_LIMITED: {\n phase: 'post_send',\n template: 'The gateway rate-limited this signer: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n CHAIN_DISPATCH_FAILED: {\n phase: 'post_send',\n template: 'The chain dispatch failed (chain error key \"{errorKey}\"): {serverMessage}',\n params: { errorKey: 'string', serverMessage: 'string' },\n },\n GATEWAY_REJECTED: {\n phase: 'post_send',\n template: 'Gateway rejected {gatewayCode}: {serverMessage}',\n params: { gatewayCode: 'string', serverMessage: 'string' },\n },\n CHAIN_REJECTED: {\n phase: 'post_send',\n template: 'GalaChain error {errorKey}: {serverMessage}',\n params: { errorKey: 'string', serverMessage: 'string' },\n },\n INVALID_CHAIN_RESPONSE: {\n phase: 'post_send',\n template: 'Backend returned an invalid {resource}.',\n params: { resource: 'string' },\n },\n INVALID_POSITION_RESPONSE: {\n phase: 'post_send',\n template: 'Backend returned an invalid position ({reason}).',\n params: { reason: 'string' },\n },\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: {\n phase: 'post_send',\n template:\n 'Transaction confirmation timed out; the trade may still apply. Confirm the same uniqueKey again later instead of resubmitting.',\n params: {},\n },\n CONFIRMATION_ABORTED: {\n phase: 'post_send',\n template: 'Transaction confirmation was aborted.',\n params: {},\n },\n CONFIRMATION_FAILED: {\n phase: 'post_send',\n template: 'Transaction confirmation failed with HTTP {status}.',\n params: { status: 'number', serverMessage: 'string' },\n unrendered: ['serverMessage'],\n },\n CONFIRMATION_MALFORMED: {\n phase: 'post_send',\n template: 'Transaction confirmation returned a malformed body.',\n params: {},\n },\n CONFIRMATION_KEY_MISMATCH: {\n phase: 'post_send',\n template: 'Apply result key did not match the requested key.',\n params: {},\n },\n\n // ----------------------------------------------------------------------------------- services\n NO_SIGNER: {\n phase: 'pre_send',\n template: 'This method requires a signer. Please provide a signer to the GSwap constructor.',\n params: {},\n },\n NO_WALLET_ADDRESS: {\n phase: 'post_send',\n template:\n 'Cannot confirm this write: no walletAddress was provided to the GSwap constructor, so the resulting position cannot be looked up to confirm it landed on chain.',\n params: {},\n },\n NO_POOL_AVAILABLE: {\n phase: 'post_send',\n template: 'No pool is available for {tokenIn}/{tokenOut} (fee tier {fee}).',\n params: { tokenIn: 'string', tokenOut: 'string', fee: 'string' },\n },\n INSUFFICIENT_LIQUIDITY: {\n phase: 'post_send',\n template:\n 'The selected pool has insufficient liquidity for {tokenIn}/{tokenOut} (fee tier {fee}).',\n params: { tokenIn: 'string', tokenOut: 'string', fee: 'string' },\n },\n UNKNOWN_TOKEN: {\n phase: 'pre_send',\n template: 'Token {token} is not registered on the DEX contract: it has no trading symbol.',\n params: { token: 'string' },\n },\n SYMBOL_NOT_FOUND: {\n phase: 'pre_send',\n template: 'Token {token} could not be resolved to a trading symbol.',\n params: { token: 'string' },\n },\n STREAM_API_KEY_UNUSABLE: {\n phase: 'pre_send',\n template:\n 'GdexStreamConfig.apiKey needs a non-empty key and an explicit webSocketImpl that accepts upgrade headers as its third argument (the \"ws\" package, or React Native). A browser WebSocket cannot send x-api-key, so the key would be silently dropped.',\n params: {},\n },\n STREAM_WEBSOCKET_UNAVAILABLE: {\n phase: 'pre_send',\n template:\n 'GdexStreamService requires a standards-compatible WebSocket constructor. Node.js versions before 22 must provide one with config.webSocketImpl (for example, from the \"ws\" package).',\n params: {},\n },\n STREAM_NOT_CONNECTED: {\n phase: 'pre_send',\n template: 'GDEX stream is not connected. Call connect() first.',\n params: {},\n },\n STREAM_DISCONNECTED: {\n phase: 'in_flight',\n template: 'GDEX stream disconnected.',\n params: {},\n },\n STREAM_REQUEST_TIMEOUT: {\n phase: 'in_flight',\n template: 'GDEX request \"{method}\" timed out after {timeoutMs} ms.',\n params: { method: 'string', timeoutMs: 'number' },\n },\n STREAM_CONNECT_FAILED: {\n phase: 'in_flight',\n template: 'Failed to connect to GDEX stream at {url}.',\n params: { url: 'string' },\n },\n STREAM_CLOSED_BEFORE_CONNECT: {\n phase: 'in_flight',\n template: 'GDEX stream closed before connecting (code {closeCode}).',\n params: { closeCode: 'number' },\n },\n STREAM_CONNECTION_CLOSED: {\n phase: 'in_flight',\n template: 'GDEX stream connection closed (code {closeCode}).',\n params: { closeCode: 'number' },\n },\n\n // ------------------------------------------------------------------------------ wallet / keys\n TOKEN_RESOLUTION_FAILED: {\n phase: 'pre_send',\n template: 'Token {token} could not be looked up; nothing was sent.',\n params: { token: 'string' },\n },\n MISSING_WALLET_ADDRESS: {\n phase: 'pre_send',\n template:\n 'Invalid wallet address: No wallet address provided. Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK.',\n params: {},\n },\n\n // ------------------------------------------------------------------------ input validation\n NON_CANONICAL_PAIR: {\n phase: 'pre_send',\n template:\n 'The pair {token0}/{token1} is not in canonical order: token0 must sort before token1.',\n params: { token0: 'string', token1: 'string' },\n },\n UNORDERABLE_SYMBOLS: {\n phase: 'pre_send',\n template: 'Unable to order trading symbols: expected a pair of symbols, got {received}.',\n params: { received: 'string' },\n },\n INVALID_TOKEN_CLASS_KEY: {\n phase: 'pre_send',\n template:\n 'Invalid token class key \"{tokenClassKey}\": expected a collection followed by category, type and additionalKey',\n params: { tokenClassKey: 'string' },\n },\n INCOMPLETE_TOKEN_CLASS_KEY: {\n phase: 'pre_send',\n template: 'Token class key \"{compositeKey}\" is missing {part}.',\n params: { compositeKey: 'string', part: 'string' },\n },\n INVALID_TRADING_SYMBOL: {\n phase: 'pre_send',\n template:\n 'Invalid trading symbol \"{symbol}\": must be 1-32 ASCII letters and digits and not a reserved word (Token, Unit, none).',\n params: { symbol: 'string' },\n },\n NO_VALID_TRADING_SYMBOL: {\n phase: 'pre_send',\n template:\n 'No valid trading symbol for token class {classKey}: \"{displaySymbol}\" is not an acceptable symbol and none is registered',\n params: { classKey: 'string', displaySymbol: 'string' },\n },\n TOKEN_SYMBOL_NOT_REGISTERED: {\n phase: 'pre_send',\n template:\n 'Token {token} is not registered in the trading-symbol registry yet; pass token0Symbol/token1Symbol (the token class symbol) to propose one. A symbol cannot be derived from a class key.',\n params: { token: 'string' },\n },\n SYMBOL_DISAGREES_WITH_REGISTRY: {\n phase: 'pre_send',\n template:\n 'Supplied symbol {suppliedSymbol} for {token} disagrees with the registered trading symbol {registeredSymbol}.',\n params: { token: 'string', suppliedSymbol: 'string', registeredSymbol: 'string' },\n },\n CREATE_POOL_NEEDS_CLASS_KEY: {\n phase: 'pre_send',\n template:\n 'createPool needs each token as a class key; {token} is a bare trading symbol, which does not carry one.',\n params: { token: 'string' },\n },\n AMOUNT_IS_JS_NUMBER: {\n phase: 'pre_send',\n template: 'Invalid {field}: use a decimal string or BigNumber, not a JavaScript number',\n params: { field: 'string' },\n },\n AMOUNT_NOT_FINITE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be a finite number (got {value})',\n params: { field: 'string', value: 'string' },\n },\n AMOUNT_NOT_POSITIVE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be positive (got {value})',\n params: { field: 'string', value: 'string' },\n },\n AMOUNT_NEGATIVE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must not be negative (got {value})',\n params: { field: 'string', value: 'string' },\n },\n PRICE_VALUES_IS_JS_NUMBER: {\n phase: 'pre_send',\n template:\n 'Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers',\n params: {},\n },\n INVALID_PRICE_VALUES: {\n phase: 'pre_send',\n template:\n 'Invalid price values: all prices must be finite and positive (spot {spotPrice}, lower {lowerPrice}, upper {upperPrice})',\n params: { spotPrice: 'string', lowerPrice: 'string', upperPrice: 'string' },\n },\n INVALID_PRICE_RANGE: {\n phase: 'pre_send',\n template:\n 'Invalid price range: lower price {lowerPrice} must be less than or equal to upper price {upperPrice}',\n params: { lowerPrice: 'string', upperPrice: 'string' },\n },\n INVALID_PRICE_BOUNDS: {\n phase: 'pre_send',\n template:\n 'Price bounds must be finite and positive (minPrice {minPrice}, maxPrice {maxPrice}).',\n params: { minPrice: 'string', maxPrice: 'string' },\n },\n PRICE_BOUNDS_ORDER: {\n phase: 'pre_send',\n template: 'minPrice {minPrice} must be less than or equal to maxPrice {maxPrice}.',\n params: { minPrice: 'string', maxPrice: 'string' },\n },\n INVALID_STARTING_PRICE: {\n phase: 'pre_send',\n template: 'Starting price must be finite and positive (got {value}).',\n params: { value: 'string' },\n },\n INVALID_SQRT_PRICE: {\n phase: 'pre_send',\n template: 'Cannot invert a non-positive sqrt price ({sqrtPrice}).',\n params: { sqrtPrice: 'string' },\n },\n INVALID_TOKEN_DECIMALS: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be a non-negative integer (got {value})',\n params: { field: 'string', value: 'number' },\n },\n TICKS_NOT_INTEGERS: {\n phase: 'pre_send',\n template: 'Invalid tick values: ticks must be integers (got {tickLower} and {tickUpper})',\n params: { tickLower: 'number', tickUpper: 'number' },\n },\n INVALID_TICK_RANGE: {\n phase: 'pre_send',\n template: 'Invalid tick range: tickLower {tickLower} must be less than tickUpper {tickUpper}',\n params: { tickLower: 'number', tickUpper: 'number' },\n },\n TICKS_OUT_OF_BOUNDS: {\n phase: 'pre_send',\n template:\n 'Invalid tick range: ticks {tickLower} and {tickUpper} must be between {minTick} and {maxTick}',\n params: { tickLower: 'number', tickUpper: 'number', minTick: 'number', maxTick: 'number' },\n },\n TICKS_NOT_ALIGNED: {\n phase: 'pre_send',\n template: 'Ticks {tickLower} and {tickUpper} must be aligned to spacing {spacing}.',\n params: { tickLower: 'number', tickUpper: 'number', spacing: 'number' },\n },\n INVALID_TICK_SPACING: {\n phase: 'pre_send',\n template: 'Invalid tick spacing: must be a positive integer (got {value})',\n params: { value: 'number' },\n },\n INVALID_FEE: {\n phase: 'pre_send',\n template: 'Invalid {field}: {value} is not a supported fee tier; must be one of {allowed}.',\n params: { field: 'string', value: 'number', allowed: 'string' },\n },\n EXACT_AMOUNT_REQUIRED: {\n phase: 'pre_send',\n template: '{field} is required for this swap.',\n params: { field: 'string' },\n },\n EXACTLY_ONE_OF_REQUIRED: {\n phase: 'pre_send',\n template: 'Provide exactly one of {first} or {second}.',\n params: { first: 'string', second: 'string' },\n },\n AT_MOST_ONE_OF_ALLOWED: {\n phase: 'pre_send',\n template: 'Provide at most one of {first} or {second}.',\n params: { first: 'string', second: 'string' },\n },\n POOL_MISMATCH: {\n phase: 'pre_send',\n template:\n 'tokenIn {tokenIn} and tokenOut {tokenOut} must be the two tokens of the pinned pool {poolToken0}/{poolToken1}.',\n params: {\n tokenIn: 'string',\n tokenOut: 'string',\n poolToken0: 'string',\n poolToken1: 'string',\n },\n },\n INVALID_DTO: {\n phase: 'pre_send',\n template: '{method} DTO field {field} is invalid (expected {expected}).',\n params: { method: 'string', field: 'string', expected: 'string' },\n },\n DTO_NOT_CANONICAL: {\n phase: 'pre_send',\n template:\n 'The {method} DTO is not in the form the SDK builders produce; build it with the matching build function and submit that.',\n params: { method: 'string' },\n },\n SEARCH_TOO_LONG: {\n phase: 'pre_send',\n template: 'search must be at most {maxLength} characters (got {length}).',\n params: { length: 'number', maxLength: 'number' },\n },\n INVALID_SORT_BY: {\n phase: 'pre_send',\n template: 'sortBy \"{value}\" is not allowed; it must be one of {allowed}.',\n params: { value: 'string', allowed: 'string' },\n },\n INVALID_SORT_ORDER: {\n phase: 'pre_send',\n template: 'sortOrder \"{value}\" is not allowed; it must be asc or desc.',\n params: { value: 'string' },\n },\n INVALID_PAGE: {\n phase: 'pre_send',\n template: 'page must be an integer of at least 1 (got {value}).',\n params: { value: 'number' },\n },\n INVALID_LIMIT: {\n phase: 'pre_send',\n template: 'limit must be an integer from {min} to {max} (got {value}).',\n params: { value: 'number', min: 'number', max: 'number' },\n },\n INVALID_MARKET_TOKEN: {\n phase: 'pre_send',\n template:\n 'A market read names a token by a symbol or class key of 1 to 120 letters, digits and . _ $ + / : | - characters (got \"{token}\").',\n params: { token: 'string' },\n },\n INVALID_TIMEFRAME: {\n phase: 'pre_send',\n template: 'timeframe \"{value}\" is not allowed; it must be one of {allowed}.',\n params: { value: 'string', allowed: 'string' },\n },\n INVALID_SEASON_ID: {\n phase: 'pre_send',\n template: 'seasonId must be an integer of at least 1 (got {value}).',\n params: { value: 'string' },\n },\n INVALID_POLL_INTERVAL: {\n phase: 'pre_send',\n template: 'intervalMs must be a finite number of milliseconds of at least 1 (got {value}).',\n params: { value: 'string' },\n },\n} as const satisfies Record<string, GalaErrorCatalogEntry>;\n\n/** Every code a `GSwapSDKError` can carry: the core codes and gswap-sdk's own DEX codes. */\nexport type GSwapErrorCode = GalaErrorCode | keyof typeof GSWAP_ERROR_CATALOG;\n\n/** Both catalogs as one type: a code of either reads its entry here. */\ntype GSwapCatalog = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** The named params of one error code (core or DEX): a flat object of primitives (or closed string tokens). */\nexport type GSwapErrorParams<C extends GSwapErrorCode> = ErrorParamsOf<GSwapCatalog, C>;\n\n/**\n * The catalog `GSwapSDKError` reads templates and phases from: core's entries and the DEX entries,\n * merged (never redefined: the two key sets are disjoint, pinned by tests/error_catalog.test.ts).\n */\nexport const GSWAP_SDK_ERROR_ENTRIES: Readonly<Record<GSwapErrorCode, GalaErrorCatalogEntry>> = {\n ...GALA_ERROR_CATALOG,\n ...GSWAP_ERROR_CATALOG,\n};\n\n/**\n * The English template of every DEX error code, `{placeholder}` markers included. An optional seed\n * or fallback for an app's own translations; the SDK's `message` is generated from it. The core\n * codes' templates are `galaErrorTemplates` from `@gala-chain/gala-core-sdk`: an app that seeds\n * every code a `GSwapSDKError` can carry merges the two.\n */\nexport const gswapErrorTemplates: { readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: string } =\n Object.fromEntries(\n Object.entries(GSWAP_ERROR_CATALOG).map(([code, entry]) => [code, entry.template]),\n ) as { readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: string };\n","import {\n GALA_ERROR_PHASE_BY_CODE,\n isGalaCatalogCode,\n type FailureView,\n type GalaErrorPhase,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from './gswap_error_catalog.js';\n\n/**\n * The phase of every DEX catalog code, WITHOUT the catalog. The failure guards (`classifyFailure`,\n * `mayHaveBeenQueued`, ...) need only a code's phase, and the catalog's English templates are\n * ~15 kB: reading the phase from here keeps an app shell that imports a guard from loading them.\n * The catalog entry is still where a code is declared; this table is checked against it AT\n * COMPILE TIME, in both directions (a missing code, an extra code or a different phase is a type\n * error), so the two cannot drift. The core codes' phases are core's `GALA_ERROR_PHASE_BY_CODE`.\n */\nexport const GSWAP_ERROR_PHASE_BY_CODE = {\n HTTP_ERROR: 'post_send',\n UPDATE_REQUIRED: 'post_send',\n REQUEST_FAILED: 'in_flight',\n METHOD_NOT_SUPPORTED: 'pre_send',\n SUBMISSION_OUTCOME_UNKNOWN: 'in_flight',\n GATEWAY_REPORTED_ERROR: 'post_send',\n GATEWAY_DATA_MISSING: 'post_send',\n GATEWAY_MODE_INVALID: 'post_send',\n GATEWAY_SYNC_REQUEST_TRADE: 'post_send',\n MISSING_UNIQUE_KEY: 'post_send',\n UNIQUE_KEY_MISMATCH: 'post_send',\n SHADOW_NOT_QUEUED: 'post_send',\n SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: 'pre_send',\n METHOD_NOT_ALLOWED: 'post_send',\n SIGNATURE_INVALID: 'post_send',\n SIGNER_MISMATCH: 'post_send',\n DTO_INVALID: 'post_send',\n BOUNDS_VIOLATION: 'post_send',\n SYMBOL_CONFLICT: 'post_send',\n RATE_LIMITED: 'post_send',\n CHAIN_DISPATCH_FAILED: 'post_send',\n GATEWAY_REJECTED: 'post_send',\n CHAIN_REJECTED: 'post_send',\n INVALID_CHAIN_RESPONSE: 'post_send',\n INVALID_POSITION_RESPONSE: 'post_send',\n CONFIRMATION_TIMEOUT: 'post_send',\n CONFIRMATION_ABORTED: 'post_send',\n CONFIRMATION_FAILED: 'post_send',\n CONFIRMATION_MALFORMED: 'post_send',\n CONFIRMATION_KEY_MISMATCH: 'post_send',\n NO_SIGNER: 'pre_send',\n NO_WALLET_ADDRESS: 'post_send',\n NO_POOL_AVAILABLE: 'post_send',\n INSUFFICIENT_LIQUIDITY: 'post_send',\n UNKNOWN_TOKEN: 'pre_send',\n SYMBOL_NOT_FOUND: 'pre_send',\n STREAM_API_KEY_UNUSABLE: 'pre_send',\n STREAM_WEBSOCKET_UNAVAILABLE: 'pre_send',\n STREAM_NOT_CONNECTED: 'pre_send',\n STREAM_DISCONNECTED: 'in_flight',\n STREAM_REQUEST_TIMEOUT: 'in_flight',\n STREAM_CONNECT_FAILED: 'in_flight',\n STREAM_CLOSED_BEFORE_CONNECT: 'in_flight',\n STREAM_CONNECTION_CLOSED: 'in_flight',\n TOKEN_RESOLUTION_FAILED: 'pre_send',\n MISSING_WALLET_ADDRESS: 'pre_send',\n NON_CANONICAL_PAIR: 'pre_send',\n UNORDERABLE_SYMBOLS: 'pre_send',\n INVALID_TOKEN_CLASS_KEY: 'pre_send',\n INCOMPLETE_TOKEN_CLASS_KEY: 'pre_send',\n INVALID_TRADING_SYMBOL: 'pre_send',\n NO_VALID_TRADING_SYMBOL: 'pre_send',\n TOKEN_SYMBOL_NOT_REGISTERED: 'pre_send',\n SYMBOL_DISAGREES_WITH_REGISTRY: 'pre_send',\n CREATE_POOL_NEEDS_CLASS_KEY: 'pre_send',\n AMOUNT_IS_JS_NUMBER: 'pre_send',\n AMOUNT_NOT_FINITE: 'pre_send',\n AMOUNT_NOT_POSITIVE: 'pre_send',\n AMOUNT_NEGATIVE: 'pre_send',\n PRICE_VALUES_IS_JS_NUMBER: 'pre_send',\n INVALID_PRICE_VALUES: 'pre_send',\n INVALID_PRICE_RANGE: 'pre_send',\n INVALID_PRICE_BOUNDS: 'pre_send',\n PRICE_BOUNDS_ORDER: 'pre_send',\n INVALID_STARTING_PRICE: 'pre_send',\n INVALID_SQRT_PRICE: 'pre_send',\n INVALID_TOKEN_DECIMALS: 'pre_send',\n TICKS_NOT_INTEGERS: 'pre_send',\n INVALID_TICK_RANGE: 'pre_send',\n TICKS_OUT_OF_BOUNDS: 'pre_send',\n TICKS_NOT_ALIGNED: 'pre_send',\n INVALID_TICK_SPACING: 'pre_send',\n INVALID_FEE: 'pre_send',\n EXACT_AMOUNT_REQUIRED: 'pre_send',\n EXACTLY_ONE_OF_REQUIRED: 'pre_send',\n AT_MOST_ONE_OF_ALLOWED: 'pre_send',\n POOL_MISMATCH: 'pre_send',\n INVALID_DTO: 'pre_send',\n DTO_NOT_CANONICAL: 'pre_send',\n SEARCH_TOO_LONG: 'pre_send',\n INVALID_SORT_BY: 'pre_send',\n INVALID_SORT_ORDER: 'pre_send',\n INVALID_PAGE: 'pre_send',\n INVALID_LIMIT: 'pre_send',\n INVALID_MARKET_TOKEN: 'pre_send',\n INVALID_TIMEFRAME: 'pre_send',\n INVALID_SEASON_ID: 'pre_send',\n INVALID_POLL_INTERVAL: 'pre_send',\n} as const satisfies {\n readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: (typeof GSWAP_ERROR_CATALOG)[C]['phase'];\n};\n\n/** True for a DEX code (gswap-sdk's own catalog). */\nfunction isDexCatalogCode(code: string): code is keyof typeof GSWAP_ERROR_PHASE_BY_CODE {\n return Object.hasOwn(GSWAP_ERROR_PHASE_BY_CODE, code);\n}\n\n/** True for a code a `GSwapSDKError` can carry: a core code or a DEX code. */\nexport function isCatalogCode(code: string): code is GSwapErrorCode {\n return isGalaCatalogCode(code) || isDexCatalogCode(code);\n}\n\n/**\n * The phase of a view: the one it states, else the catalog's phase for its code (core's or the\n * DEX catalog's), else `undefined`.\n */\nexport function phaseOfView(view: FailureView): GalaErrorPhase | undefined {\n if (view.phase !== undefined) return view.phase;\n if (isGalaCatalogCode(view.code)) return GALA_ERROR_PHASE_BY_CODE[view.code];\n return isDexCatalogCode(view.code) ? GSWAP_ERROR_PHASE_BY_CODE[view.code] : undefined;\n}\n","import {\n GalaSDKError,\n parseJson,\n toFailureView,\n type GalaChainTokenClassKey,\n type GalaErrorContext,\n type HTTPResponse,\n} from '@gala-chain/gala-core-sdk';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport {\n GSWAP_SDK_ERROR_ENTRIES,\n type GSwapErrorCode,\n type GSwapErrorParams,\n} from './gswap_error_catalog.js';\nimport { phaseOfView } from './gswap_error_phase_table.js';\n\n/**\n * The HTTP status of a version wall: the backend refuses an app version that is too old (HTTP 426\n * Upgrade Required). It is `UPDATE_REQUIRED` on every request the SDK sends, whatever else the body\n * says; a confirmation read keeps `CONFIRMATION_FAILED` because the write it confirms may be applied.\n */\nexport const UPDATE_REQUIRED_STATUS = 426;\n\n/** What {@link GSwapSDKError.fromStatus} may be told about the HTTP answer. */\nexport interface GSwapStatusErrorOptions {\n /** The URL the request went to. */\n url?: string | undefined;\n /** The signed `uniqueKey` of the WRITE the answer is for; its presence makes this a write. */\n uniqueKey?: string | undefined;\n /** Say it outright: `true` for a write (needs `uniqueKey`), `false` for a read. */\n write?: boolean | undefined;\n /** The server's own text, for `HTTP_ERROR.params.serverMessage` (`''` when none). */\n serverMessage?: string | undefined;\n /** The response body, kept as `error.body` (or `bodyText` for a string). */\n body?: unknown;\n /** How long the server asked to wait (`Retry-After`), in milliseconds. */\n retryAfterMs?: number | undefined;\n}\n\n/**\n * Error raised by gswap-sdk for validation, gateway, chain, or transaction failures. It is a\n * `GalaSDKError` (`@gala-chain/gala-core-sdk`), and can carry any code of the core catalog or of\n * gswap-sdk's own DEX catalog: the signing, transport and wallet failures of a gswap flow are core\n * codes, thrown either as a `GSwapSDKError` by gswap-sdk or as a plain `GalaSDKError` by core\n * itself (a signer, the fetch requestor). Catch both with `isGSwapError` (or core's `isGalaError`);\n * `instanceof GSwapSDKError` alone misses the second kind.\n *\n * Branch on {@link code} (stable) and render {@link params} through your own localization.\n * {@link message} is English generated from the catalog template for logs and developers: it\n * is not stable and must never be shown to a user or matched on.\n */\nexport class GSwapSDKError<C extends GSwapErrorCode = GSwapErrorCode> extends GalaSDKError<\n C,\n GSwapErrorParams<C>\n> {\n /** Core's catalog entries and the DEX entries: a `GSwapSDKError` can carry a code of either. */\n public static override readonly catalog = GSWAP_SDK_ERROR_ENTRIES;\n\n constructor(code: C, params: GSwapErrorParams<C>, context: GalaErrorContext = {}) {\n super(code, params, context);\n this.name = 'GSwapSDKError';\n }\n\n /**\n * True when the failure means \"that market, pool or position does not exist\" rather than\n * \"something went wrong\": an HTTP 404, a pair with no pool at any fee tier\n * (`NO_POOL_AVAILABLE`), or a token the DEX contract has no trading symbol for\n * (`UNKNOWN_TOKEN`). A pool that exists but is too thin (`INSUFFICIENT_LIQUIDITY`) is NOT\n * not-found.\n */\n public override get notFound(): boolean {\n return super.notFound || this.code === 'NO_POOL_AVAILABLE' || this.code === 'UNKNOWN_TOKEN';\n }\n\n /** Create the standard missing-signer error. */\n public static noSignerError(): GSwapSDKError<'NO_SIGNER'> {\n return new GSwapSDKError('NO_SIGNER', {});\n }\n\n /** Create the error used when confirming a position write without a configured wallet address. */\n public static noWalletAddressError(): GSwapSDKError<'NO_WALLET_ADDRESS'> {\n return new GSwapSDKError('NO_WALLET_ADDRESS', {});\n }\n\n /**\n * Create the error used when no pool can quote the requested pair. `source` is the backend\n * answer that said so; its status and body are kept.\n */\n public static noPoolAvailableError(\n tokenIn: GalaChainTokenClassKey | string,\n tokenOut: GalaChainTokenClassKey | string,\n fee?: number,\n source?: GSwapSDKError,\n ): GSwapSDKError<'NO_POOL_AVAILABLE'> {\n return new GSwapSDKError(\n 'NO_POOL_AVAILABLE',\n { tokenIn: tokenText(tokenIn), tokenOut: tokenText(tokenOut), fee: feeText(fee) },\n sourceContext(source),\n );\n }\n\n /** Create the error used when a pool lacks liquidity for a quote. `source` as for {@link noPoolAvailableError}. */\n public static insufficientLiquidityError(\n tokenIn: GalaChainTokenClassKey | string,\n tokenOut: GalaChainTokenClassKey | string,\n fee?: number,\n source?: GSwapSDKError,\n ): GSwapSDKError<'INSUFFICIENT_LIQUIDITY'> {\n return new GSwapSDKError(\n 'INSUFFICIENT_LIQUIDITY',\n { tokenIn: tokenText(tokenIn), tokenOut: tokenText(tokenOut), fee: feeText(fee) },\n sourceContext(source),\n );\n }\n\n /**\n * Convert a chain-gateway bounce into a typed SDK error: the gateway's own code when the SDK\n * knows it, `GATEWAY_REJECTED` (with the code as `params.gatewayCode`) when it does not.\n * `serverMessage` is the gateway's English text: for logs, not for a user interface. For\n * `CHAIN_DISPATCH_FAILED`, `params.errorKey` is the chain's `ErrorKey` from the body's\n * top-level `errorKey` (`''` when the gateway sent none): map it, not the text.\n */\n public static fromGatewayBounce(\n gatewayCode: string,\n serverMessage: string,\n status: number,\n body: unknown,\n url: string,\n retryAfterMs?: number,\n uniqueKey?: string,\n ): GSwapSDKError {\n const context: GalaErrorContext = { status, body, url, retryAfterMs, uniqueKey };\n const params = { serverMessage };\n switch (gatewayCode) {\n case 'METHOD_NOT_ALLOWED':\n return new GSwapSDKError('METHOD_NOT_ALLOWED', params, context);\n case 'SIGNATURE_INVALID':\n return new GSwapSDKError('SIGNATURE_INVALID', params, context);\n case 'SIGNER_MISMATCH':\n return new GSwapSDKError('SIGNER_MISMATCH', params, context);\n case 'DTO_INVALID':\n return new GSwapSDKError('DTO_INVALID', params, context);\n case 'BOUNDS_VIOLATION':\n return new GSwapSDKError('BOUNDS_VIOLATION', params, context);\n case 'SYMBOL_CONFLICT':\n return new GSwapSDKError('SYMBOL_CONFLICT', params, context);\n case 'RATE_LIMITED':\n return new GSwapSDKError('RATE_LIMITED', params, context);\n case 'CHAIN_DISPATCH_FAILED':\n // The gateway adds the chain's own machine-readable key as a top-level `errorKey`, only\n // when the chain supplied one; an older gateway sends none, which is the empty string.\n return new GSwapSDKError(\n 'CHAIN_DISPATCH_FAILED',\n { ...params, errorKey: getStringProperty(body, 'errorKey') ?? '' },\n context,\n );\n default:\n return new GSwapSDKError('GATEWAY_REJECTED', { gatewayCode, serverMessage }, context);\n }\n }\n\n /** Convert a GalaChain `Status: 0` response into a typed SDK error. */\n public static fromChainError(\n errorKey: string,\n serverMessage: string,\n context?: GalaErrorContext,\n ): GSwapSDKError<'CHAIN_REJECTED'> {\n return new GSwapSDKError('CHAIN_REJECTED', { errorKey, serverMessage }, context);\n }\n\n /**\n * Create the error used when a token is not registered by the current DEX contract. `source` is\n * the backend answer that said so (a quote); its status, body and url are kept.\n */\n public static unknownTokenError(\n token: GalaChainTokenClassKey | string,\n source?: GSwapSDKError,\n ): GSwapSDKError<'UNKNOWN_TOKEN'> {\n return new GSwapSDKError('UNKNOWN_TOKEN', { token: tokenText(token) }, sourceContext(source));\n }\n\n /** Create the error used when apply-results confirmation does not arrive in time. */\n public static confirmationTimeoutError(\n uniqueKey: string,\n cause?: unknown,\n ): GSwapSDKError<'CONFIRMATION_TIMEOUT'> {\n return new GSwapSDKError('CONFIRMATION_TIMEOUT', {}, { uniqueKey, cause });\n }\n\n /**\n * Builds, synchronously, the error the SDK itself throws for an HTTP answer of this `status`\n * that has no gateway or chain code: `UPDATE_REQUIRED` for the version wall (426, whatever\n * else is true), `HTTP_ERROR` for every other status. It is for an app that holds a resolved\n * HTTP answer the SDK did not read (a v1 endpoint, an interceptor's rejection) and wants the\n * SDK's classification of it (`classifyFailure`) instead of building the error by hand.\n *\n * Reads and writes differ exactly as they do in the gateway (`classifyFailure`): a WRITE\n * carries the signed `uniqueKey` (the handle to confirm it), a READ carries none. Pass\n * `uniqueKey` for a write, or `write: true` with it; `write: false` builds a read and drops any\n * `uniqueKey`. `write: true` without a non-empty `uniqueKey` throws `INVALID_UNIQUE_KEY`: a\n * write error with no key would be classified as a read, which is a different answer. Either\n * way an answer was read, so the phase is `post_send`.\n *\n * @example\n * ```ts\n * const read = GSwapSDKError.fromStatus(503, { url });\n * classifyFailure(read); // { outcome: 'transient', retryable: true }\n * const write = GSwapSDKError.fromStatus(503, { url, uniqueKey });\n * classifyFailure(write); // { outcome: 'unknown', retryable: false }: it may have been queued\n * classifyFailure(GSwapSDKError.fromStatus(426)); // invalid_input: only an update helps\n * ```\n */\n public static fromStatus(\n status: number,\n options: GSwapStatusErrorOptions = {},\n ): GSwapSDKError<'UPDATE_REQUIRED' | 'HTTP_ERROR'> {\n const { url, uniqueKey, write, serverMessage, body, retryAfterMs } = options;\n const isWrite = write ?? (uniqueKey !== undefined && uniqueKey !== '');\n if (isWrite && (uniqueKey === undefined || uniqueKey === '')) {\n throw new GSwapSDKError('INVALID_UNIQUE_KEY', { uniqueKey: uniqueKey ?? '' });\n }\n const context: GalaErrorContext = {\n status,\n body,\n url,\n retryAfterMs,\n uniqueKey: isWrite ? uniqueKey : undefined,\n write: isWrite,\n phase: 'post_send',\n };\n return status === UPDATE_REQUIRED_STATUS\n ? new GSwapSDKError('UPDATE_REQUIRED', { status }, context)\n : new GSwapSDKError(\n 'HTTP_ERROR',\n { status, url: url ?? '', serverMessage: serverMessage ?? '' },\n context,\n );\n }\n\n /** Convert an unexpected HTTP response into an SDK error. */\n public static async fromErrorResponse(\n url: string,\n response: HTTPResponse,\n ): Promise<GSwapSDKError> {\n const bodyText = await response.text();\n const bodyJson: unknown = parseJson(bodyText);\n const errorObject = getObjectProperty(bodyJson, 'error');\n const errorKey = getStringProperty(errorObject, 'ErrorKey');\n const message = getStringProperty(errorObject, 'Message');\n // Every request that goes through `HttpClient` is a READ (a quote, a list, an apply-results\n // GET); writes go through the gateway, which builds its own errors with the signed key.\n const context: GalaErrorContext = {\n status: response.status,\n body: bodyJson ?? bodyText,\n url,\n write: false,\n };\n\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError('UPDATE_REQUIRED', { status: response.status }, context);\n }\n\n if (errorKey !== undefined && message !== undefined) {\n return new GSwapSDKError('CHAIN_REJECTED', { errorKey, serverMessage: message }, context);\n }\n\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: serverMessageOfBody(bodyJson) },\n context,\n );\n }\n}\n\n/** A token as the text a param carries: a string as is, a class key as its `$` composite. */\nfunction tokenText(token: GalaChainTokenClassKey | string): string {\n return typeof token === 'string'\n ? token\n : [token.collection, token.category, token.type, token.additionalKey].join('$');\n}\n\nfunction feeText(fee: number | undefined): string {\n return fee === undefined ? 'any' : String(fee);\n}\n\n/**\n * The HTTP facts of the error a classified error was derived from. An error derived from a\n * backend answer is `post_send`: the answer was read.\n */\nfunction sourceContext(source: GSwapSDKError | undefined): GalaErrorContext {\n if (source === undefined) return {};\n return {\n status: source.status,\n body: source.body ?? source.bodyText,\n url: source.url,\n phase: 'post_send',\n write: source.write,\n };\n}\n\n/** Any thrown value that is an SDK error of a gswap flow, narrowed to the union of every code. */\nexport type AnyGSwapError = { [C in GSwapErrorCode]: GSwapSDKError<C> }[GSwapErrorCode];\n\n/**\n * True when `value` is an SDK error a gswap flow can throw and, when `code` is given, carries\n * exactly that code. With a code, `error.params` narrows to that code's params.\n *\n * It recognises every `GalaSDKError` (`instanceof`), not only a `GSwapSDKError`: the signing,\n * transport and wallet failures of a gswap flow come from `@gala-chain/gala-core-sdk` (a signer,\n * the fetch requestor), carry a core code, and are core `GalaSDKError`s. For such an error the\n * fields are exactly a `GSwapSDKError`'s (`notFound` differs only for the DEX not-found codes,\n * which core never throws), so the narrowing holds for everything a gswap flow throws.\n *\n * @example\n * ```ts\n * if (isGSwapError(error, 'NON_CANONICAL_PAIR')) {\n * t('errors.NON_CANONICAL_PAIR', error.params); // { token0, token1 }\n * }\n * ```\n */\nexport function isGSwapError(value: unknown): value is AnyGSwapError;\nexport function isGSwapError<C extends GSwapErrorCode>(\n value: unknown,\n code: C,\n): value is GSwapSDKError<C>;\nexport function isGSwapError(value: unknown, code?: GSwapErrorCode): boolean {\n return value instanceof GalaSDKError && (code === undefined || value.code === code);\n}\n\n/**\n * True when `value` is an SDK error that was thrown BEFORE anything was transmitted\n * (`error.phase === 'pre_send'`): validation, symbol resolution, the signer, the wallet, a key\n * provider. A write that failed this way cannot have been queued, so the failure never calls for\n * \"confirm before you retry\". Every failure of an app-supplied callback that runs BEFORE the\n * request leaves reaches you as an SDK error of this kind (`SIGNING_FAILED`,\n * `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original error as `cause`), so an app\n * never needs an error class of its own to tell \"nothing was sent\" apart.\n *\n * Whether to offer Retry is `classifyFailure(error).retryable`, not this: a pre-send validation\n * error is pre-send too, and repeating the same call fails the same way.\n *\n * It also answers for a plain-object view of an SDK error (`{ code, phase? }`, see\n * `FailureView`): the view's own `phase`, else the catalog's phase for its `code` (a core code or\n * a DEX code). It is a plain `boolean`, not a type guard (a view is not a `GSwapSDKError`); use\n * `isGSwapError` to narrow.\n *\n * @example\n * ```ts\n * if (isPreSendError(error)) markNothingSent(); // no pending swap to confirm\n * ```\n */\nexport function isPreSendError(value: unknown): boolean {\n const view = toFailureView(value);\n return view !== undefined && phaseOfView(view) === 'pre_send';\n}\n\n/** Narrow an object property without trusting a cast at a network boundary. */\nexport function getObjectProperty(\n value: unknown,\n property: string,\n): Record<string, unknown> | undefined {\n if (typeof value !== 'object' || value === null || !(property in value)) return undefined;\n const propertyValue = (value as Record<string, unknown>)[property];\n return typeof propertyValue === 'object' && propertyValue !== null\n ? (propertyValue as Record<string, unknown>)\n : undefined;\n}\n\n/** Read a string property from an unknown object. */\nexport function getStringProperty(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null || !(property in value)) return undefined;\n const propertyValue = (value as Record<string, unknown>)[property];\n return typeof propertyValue === 'string' ? propertyValue : undefined;\n}\n","import {\n buildRequestHeaders,\n fetchRequestor,\n isValidUniqueKey,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, TradeExecution } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport type { GSwapErrorCode, GSwapErrorParams } from './gswap_error_catalog.js';\nimport { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/**\n * The AutoApplier waits at least 2 s before applying and the apply lands ~6-8 s after the\n * acknowledgement, so a read at t=0 is a guaranteed 404.\n */\nconst DEFAULT_INITIAL_DELAY_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * The outcome of a queued RequestTrade that could not be delivered as an {@link AppliedTrade}.\n * `code` says why:\n *\n * - `CONFIRMATION_TIMEOUT`: no terminal result before the deadline. The trade may still apply;\n * confirm the same `uniqueKey` again later and never resubmit.\n * - `CONFIRMATION_ABORTED`: the caller's `signal` aborted. Nothing is known about the outcome.\n * - `CONFIRMATION_FAILED`: the apply-results read got a terminal HTTP status (`params.status`;\n * `params.serverMessage` is the failing body's own message, `''` when it had none: server\n * text is data, relay it or ignore it). The outcome is unknown.\n * - `CONFIRMATION_MALFORMED` / `CONFIRMATION_KEY_MISMATCH`: the apply result is not a usable\n * answer for this key. The outcome is unknown.\n * - `INVALID_UNIQUE_KEY`: the key is not a valid apply-results key; nothing was read. TERMINAL:\n * no retry can ever succeed (the SDK never signs such a key, so a stored one is corrupt), so a\n * resume loop must forget the swap. `PendingSwapStore.list` already prunes such entries.\n * - `CHAIN_REJECTED`: the chain REJECTED the trade; `params.errorKey` is the chain `ErrorKey` (or\n * `CHAIN_ERROR`) and `params.serverMessage` its English message.\n *\n * `uniqueKey` is always set and, where known, `requestTransactionId`, `applyTransactionId`,\n * `blockNumber`, `status`, `body`, `url` and the last transport `cause`.\n */\nexport class AppliedTradeError<C extends GSwapErrorCode = GSwapErrorCode> extends GSwapSDKError<C> {\n constructor(code: C, params: GSwapErrorParams<C>, context: GalaErrorContext = {}) {\n super(code, params, context);\n this.name = 'AppliedTradeError';\n }\n}\n\n/** The transport and backend a confirmation reads from. */\nexport interface ApplyResultsClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com` (no trailing path). */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-read timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /** Request headers of the poll (`userAgent`, `headers`); see {@link WireOptions}. */\n wire?: WireOptions | undefined;\n}\n\n/** What identifies the queued trade to confirm. */\nexport interface AppliedTradeInput {\n uniqueKey: string;\n /** The transaction id of the queued request, carried through to the result; `null` if unknown. */\n requestTransactionId: string | null;\n}\n\n/**\n * Polls `GET /v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract` until the\n * queued RequestTrade reaches a terminal state.\n *\n * Pacing: wait `initialDelayMs` (default 3 s), then read; on 404, 429, 500, 502, 503, 504 or a\n * transport error wait with jittered exponential backoff (`pollIntervalMs` doubling to 8 s,\n * `Retry-After` honored as seconds or an HTTP date) until `timeoutMs`. Any other status is\n * terminal. At least one read is always made.\n *\n * @returns The applied trade.\n * @throws AppliedTradeError - see its documentation for every `code`.\n * @example\n * ```ts\n * const applied = await confirmAppliedTrade(\n * { dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' },\n * { uniqueKey, requestTransactionId: null },\n * { initialDelayMs: 0, timeoutMs: 60_000, signal: controller.signal },\n * );\n * ```\n */\nexport async function confirmAppliedTrade(\n client: ApplyResultsClient,\n input: AppliedTradeInput,\n options?: ConfirmOptions,\n): Promise<AppliedTrade> {\n const { uniqueKey } = input;\n if (!isValidUniqueKey(uniqueKey)) {\n throw new AppliedTradeError(\n 'INVALID_UNIQUE_KEY',\n { uniqueKey: String(uniqueKey) },\n { uniqueKey },\n );\n }\n const requestor = client.httpRequestor ?? fetchRequestor;\n const requestTimeoutMs = client.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const signal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new AppliedTradeError('CONFIRMATION_ABORTED', {}, { uniqueKey, cause });\n const url = `${client.dexBackendBaseUrl.replace(/\\/$/u, '')}/v1/chain/apply-results/${encodeURIComponent(uniqueKey)}?channel=asset&contract=dex-contract`;\n\n const schedule = createConfirmationSchedule(options, DEFAULT_INITIAL_DELAY_MS, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n\n while (true) {\n throwIfAborted(signal, abortError);\n let response: HTTPResponse;\n let body: unknown;\n try {\n response = await requestWithTimeout(\n requestor,\n url,\n {\n method: 'GET',\n headers: buildRequestHeaders(client.wire),\n ...(signal === undefined ? {} : { signal }),\n },\n requestTimeoutMs,\n );\n body = await readResponseBody(response);\n } catch (error: unknown) {\n throwIfAborted(signal, abortError);\n lastError = error;\n if (!(await schedule.waitForRead())) break;\n continue;\n }\n throwIfAborted(signal, abortError);\n\n if (response.status === 200) return readAppliedResult(input, response, body, url);\n\n if (response.status === 404 || response.status === 429 || isTransient(response.status)) {\n const retryAfter = response.status === 429 ? readRetryAfter(response) : undefined;\n if (!(await schedule.waitForRead(retryAfter))) break;\n continue;\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_FAILED',\n { status: response.status, serverMessage: serverMessageOfBody(body) },\n { uniqueKey, status: response.status, body, url },\n );\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_TIMEOUT',\n {},\n { uniqueKey, requestTransactionId: input.requestTransactionId, url, cause: lastError },\n );\n}\n\nfunction readAppliedResult(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTrade {\n const { uniqueKey } = input;\n const record = asRecord(body);\n const responseKey = record?.['uniqueKey'] ?? record?.['UniqueKey'];\n if (typeof responseKey === 'string' && responseKey !== uniqueKey) {\n throw new AppliedTradeError(\n 'CONFIRMATION_KEY_MISMATCH',\n {},\n { uniqueKey, status: response.status, body, url },\n );\n }\n const status = record?.['Status'];\n const applyTransactionId = readHeader(response, 'x-apply-transaction-id') ?? null;\n const blockNumber = readBlockNumberHeader(response, 'x-apply-block-number') ?? null;\n if (status === 0) {\n const errorKey = getStringProperty(record, 'ErrorKey') ?? 'CHAIN_ERROR';\n const chainMessage = getStringProperty(record, 'Message') ?? '';\n throw new AppliedTradeError(\n 'CHAIN_REJECTED',\n { errorKey, serverMessage: chainMessage },\n {\n uniqueKey,\n requestTransactionId: input.requestTransactionId,\n applyTransactionId,\n blockNumber,\n status: response.status,\n body,\n url,\n },\n );\n }\n if (status !== 1) throw malformed(input, response, body, url);\n const result = parseTradeExecution(record?.['Data']);\n if (result === undefined) throw malformed(input, response, body, url);\n return {\n uniqueKey,\n transactionId: applyTransactionId,\n blockNumber,\n requestTransactionId: input.requestTransactionId,\n result,\n };\n}\n\nfunction malformed(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTradeError<'CONFIRMATION_MALFORMED'> {\n return new AppliedTradeError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey: input.uniqueKey, status: response.status, body, url },\n );\n}\n\nfunction parseTradeExecution(value: unknown): TradeExecution | undefined {\n const record = asRecord(value);\n if (\n record === undefined ||\n typeof record['token0'] !== 'string' ||\n typeof record['token1'] !== 'string' ||\n typeof record['fee'] !== 'number'\n ) {\n return undefined;\n }\n const optionalFields = [\n 'sell0Qty',\n 'sell1Qty',\n 'buy0Qty',\n 'buy1Qty',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n ] as const;\n for (const field of optionalFields) {\n if (field in record && typeof record[field] !== 'string') return undefined;\n }\n return {\n token0: record['token0'],\n token1: record['token1'],\n fee: record['fee'],\n ...Object.fromEntries(\n optionalFields.flatMap((field) =>\n typeof record[field] === 'string' ? [[field, record[field]]] : [],\n ),\n ),\n };\n}\n\nfunction isTransient(status: number): boolean {\n return status === 500 || status === 502 || status === 503 || status === 504;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n","/**\n * Fee tiers for pools.\n */\nexport enum FEE_TIER {\n /** No trading fee. */\n PERCENT_00_00 = 0,\n /** 0.05% fee tier */\n PERCENT_00_05 = 500,\n /** 0.3% fee tier */\n PERCENT_00_30 = 3000,\n /** 1.0% fee tier */\n PERCENT_01_00 = 10000,\n}\n\n/** Tick spacing required by the current GalaChainDex contract for each fee tier. */\nexport const TICK_SPACING_BY_FEE: Readonly<Record<FEE_TIER, number>> = {\n [FEE_TIER.PERCENT_00_00]: 200,\n [FEE_TIER.PERCENT_00_05]: 10,\n [FEE_TIER.PERCENT_00_30]: 60,\n [FEE_TIER.PERCENT_01_00]: 200,\n};\n\n/** All fee tiers supported by the current GalaChainDex contract. */\nexport const ALL_FEE_TIERS: readonly FEE_TIER[] = [\n FEE_TIER.PERCENT_00_00,\n FEE_TIER.PERCENT_00_05,\n FEE_TIER.PERCENT_00_30,\n FEE_TIER.PERCENT_01_00,\n];\n","/**\n * Whether a pool's current tick lies inside a position's range, by the contract's own rule. This\n * module imports nothing, so an app shell (a position badge, a filter) pays for a few dozen bytes.\n */\n\n/** A tick as the chain and the backends write it: a number, or the decimal string of one. */\nexport type TickInput = number | string;\n\nfunction integerTickOf(tick: TickInput): number {\n if (typeof tick === 'string') return tick.trim() === '' ? Number.NaN : Number(tick);\n return tick;\n}\n\n/**\n * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick\n * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule\n * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a\n * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out\n * of range: the position is entirely token1 there, and a swap through the tick has crossed it.\n *\n * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than\n * the pool's price), not a rounded display value. A tick may be a number or the decimal string a\n * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a\n * fraction) makes the answer `false`: an app that must tell \"not loaded yet\" from \"out of range\"\n * checks for the missing value itself first.\n *\n * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both\n * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is\n * then in range at the upper edge (the contract says it is not), and two representations of the\n * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which\n * derives the tick the way the contract does and then applies this rule.\n *\n * @example\n * ```ts\n * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive\n * isTickInRange(60, -60, 60); // false: the upper tick is exclusive\n * ```\n */\nexport function isTickInRange(\n currentTick: TickInput,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n const current = integerTickOf(currentTick);\n const lower = integerTickOf(tickLower);\n const upper = integerTickOf(tickUpper);\n if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) {\n return false;\n }\n return current >= lower && current < upper;\n}\n","import BigNumber from 'bignumber.js';\nimport { Decimal } from 'decimal.js';\nimport { isTickInRange, type TickInput } from './tick_range.js';\n\n/**\n * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the\n * conversions between ticks and prices, and nothing that validates a range. It imports only the\n * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog\n * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an\n * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of\n * error templates. A value that cannot be computed is `NaN`, never an exception.\n */\n\n/** Minimum tick supported by GalaChainDex. */\nexport const GC_MIN_TICK = -887272;\n/** Maximum tick supported by GalaChainDex. */\nexport const GC_MAX_TICK = 887272;\n\nconst DexMath = BigNumber.clone({\n DECIMAL_PLACES: 60,\n ROUNDING_MODE: BigNumber.ROUND_DOWN,\n});\n/** `decimal.js` at the 60 significant digits the contract's price math is exact to. */\nexport const DexDecimal = Decimal.clone({ precision: 60 });\n\n/** Convert a tick to the corresponding square-root price. */\nexport function tickToSqrtPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick / 2).toString());\n}\n\n/** Return the greatest tick whose square-root price is no greater than the input. */\nexport function sqrtPriceToTick(sqrtPrice: BigNumber.Value): number {\n let value: BigNumber;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this function's contract is to signal an invalid input via NaN, not\n // to throw, so an unparseable value is just another case for the guard below.\n value = new DexMath(sqrtPrice);\n } catch {\n return Number.NaN;\n }\n if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return Number.NaN;\n\n const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);\n if (!Number.isFinite(approximate)) return Number.NaN;\n // Clamp the seed before the correction loops below — an unclamped seed derived from an\n // out-of-range sqrtPrice (extreme but finite, e.g. 1e20) leaves the loops running past\n // GC_MIN_TICK/GC_MAX_TICK for a long time; an infinite (overflowed) seed would never\n // enter the increasing loop and never terminate the decreasing one.\n let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));\n while (tick < GC_MAX_TICK && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;\n while (tick > GC_MIN_TICK && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;\n return tick;\n}\n\n/**\n * The token1/token0 price at `tick`: `1.0001 ** tick`, exact to 60 significant digits (the lower\n * edge of the tick's price range; `tickToSqrtPrice(tick) ** 2`). A tick outside the contract's\n * bounds is still computed; ask `assertTickRange` first when that matters. A non-integer tick is\n * computed as given.\n *\n * Use `.toNumber()` for a display value (it differs from `Math.exp(tick * Math.log(1.0001))` in\n * the last digits of a double: that expression multiplies in floating point first).\n */\nexport function tickToPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick).toString());\n}\n\n/**\n * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that\n * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as\n * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater\n * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,\n * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly\n * on `tickUpper`'s price is not, and no float rounding can flip either.\n *\n * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing\n * about the position, so an app that must show a neutral state checks for the missing price\n * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.\n *\n * @example\n * ```ts\n * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);\n * ```\n */\nexport function isSqrtPriceInRange(\n sqrtPrice: BigNumber.Value,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);\n}\n\n/** How {@link tickFromPrice} turns the exact logarithm into an integer tick. */\nexport interface TickFromPriceOptions {\n /**\n * `'floor'` (default): the greatest tick whose price is no greater than `price`, which is how\n * the contract places a price. `'nearest'`: the closest tick, a half rounding away from zero.\n * That is what a price INPUT wants (a person types a price, the field snaps to the nearest\n * tick), and it differs from `'floor'` for any price in the upper half of a tick's range.\n */\n rounding?: 'floor' | 'nearest' | undefined;\n}\n\n/**\n * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price\n * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that\n * is not positive and finite.\n */\nexport function tickFromPrice(price: BigNumber.Value, options: TickFromPriceOptions = {}): number {\n const priceText =\n typeof price === 'string'\n ? price\n : typeof price === 'number'\n ? price.toString()\n : BigNumber.isBigNumber(price)\n ? price.toString()\n : 'NaN';\n const value = new DexDecimal(priceText);\n if (!value.isFinite() || value.lessThanOrEqualTo(0)) return Number.NaN;\n if (!Number.isFinite(value.toNumber())) return Number.NaN;\n const exact = value.ln().dividedBy(new DexDecimal(1.0001).ln());\n const tick = (options.rounding === 'nearest' ? exact.round() : exact.floor()).toNumber();\n return Number.isFinite(tick) ? tick : Number.NaN;\n}\n","import { galaChainUserRef, isGalaError } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\n/**\n * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.\n *\n * @param amount - The amount to check.\n * @param parameterName - The field name reported in the error's `params.field`.\n * @param allowZero - Accept zero (default `false`).\n * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero\n * when `allowZero` is false) or `AMOUNT_NEGATIVE`.\n */\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\n/**\n * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and\n * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.\n *\n * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.\n */\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\n/**\n * Validates a token's decimals: a non-negative integer.\n *\n * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).\n */\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\n/**\n * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within\n * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see\n * `assertTickRange`).\n *\n * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.\n */\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\n/**\n * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).\n *\n * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).\n */\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\n/**\n * Validates a tick spacing: a positive integer.\n *\n * @throws GSwapSDKError `INVALID_TICK_SPACING`.\n */\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\n/**\n * The GalaChain user reference an owner, user or wallet address names, in the one spelling the\n * gateway and the swap backend accept: `eth|<EIP-55 checksummed digits>` for an Ethereum account\n * (given as `eth|<40 hex>` in any casing, `0x<40 hex>` or bare hex), `client|<id>` as written.\n * `eth|0x<hex>` is not an address form. This is `galaChainUserRef` of\n * `@gala-chain/gala-core-sdk`, the one implementation; only the error for a spelling that is no\n * address at all is this package's. Every place this SDK puts a user identity on the wire goes\n * through it, so what is signed, sent and compared on the backend (`owner === position.owner`,\n * strict) is always the chain's own spelling.\n *\n * @param value - The identity the caller gave.\n * @param field - The field name reported in the error's `params.field`.\n * @throws GalaSDKError core's `INVALID_ETH_USER_REF_PREFIX` (passed through as it is: its message\n * says an `eth|` reference takes the 40 hex digits with no `0x` and names the correct spelling,\n * `params.expected`) for `eth|0x...`; GSwapSDKError `INVALID_WALLET_ADDRESS` for anything else, a\n * mixed-case spelling whose casing is not the EIP-55 checksum included (a typo); nothing is\n * signed or sent.\n */\nexport function userRef(value: unknown, field: string): string {\n try {\n return galaChainUserRef(value, field);\n } catch (cause: unknown) {\n if (isGalaError(cause) && cause.code === 'INVALID_ETH_USER_REF_PREFIX') throw cause;\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field, value: String(value) });\n }\n}\n\n/**\n * {@link userRef} of an address that must be there.\n *\n * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS`; core's\n * `INVALID_ETH_USER_REF_PREFIX` for `eth|0x...` (see {@link userRef}).\n */\nexport function requireUserRef(address: string | undefined, field: string): string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n return userRef(address, field);\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n","import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { requireUserRef } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n const address = requireUserRef(ownerAddress, 'walletAddress');\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value, write: false },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n","import {\n buildRequestHeaders,\n createUniqueKey,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n signPreSend,\n type GalaChainSigner,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto,\n // Core's RN-safe mint (`getRandomValues`, never `randomUUID`, which Hermes lacks).\n uniqueKey: createUniqueKey(uniqueKeyPrefix),\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = client.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n );\n const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n if (contract === 'dex-contract' && (status === 403 || status === 404)) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n","import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError, isGSwapError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Failures of the shadow (dark) path carry that fact, so an app can apply its own policy (no\n * Retry, no public fallback) without tracking which call it made. An SDK error gets `shadow: true`;\n * a non-SDK object that escapes the path (an app requestor's own rejection) is remembered in a\n * WeakSet, which `isShadowError` reads. Nothing here changes what an error means, only where it\n * came from.\n */\nconst shadowRejections = new WeakSet<object>();\n\n/**\n * True when `value` is a failure of the shadow (dark) path: an SDK error with `shadow: true`, a\n * plain-object view of one (`{ code, shadow: true }`, see `FailureView`), or a non-SDK object (a requestor's own rejection) that escaped `swapShadow`, `submitSwapShadow` or\n * `ChainGateway.submitShadow`. A primitive that was thrown (`throw 'x'`) cannot be remembered, so\n * it is never shadow; an app that cares tracks the call it made.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { retryable } = classifyFailure(error);\n * offerRetry(retryable && !isShadowError(error)); // never retry a dark swap in public\n * }\n * ```\n */\nexport function isShadowError(value: unknown): boolean {\n if (isGSwapError(value)) return value.shadow;\n if (toFailureView(value)?.shadow === true) return true;\n return typeof value === 'object' && value !== null && shadowRejections.has(value);\n}\n\n/**\n * The same failure, marked as shadow. An SDK error is COPIED (same code, params, status, body,\n * url, ids, cause, phase, read/write, wallet code and stack), never mutated: one error object can\n * be shared by several callers (a registry read many swaps wait on), and only the shadow caller's\n * copy is shadow. Everything the deciders read is carried over, so the copy classifies exactly as\n * the original (a failed READ stays a read, never a \"maybe queued\" write).\n */\nfunction asShadowError(error: unknown): unknown {\n if (isGSwapError(error)) {\n if (error.shadow) return error;\n const copy = new GSwapSDKError(error.code, error.params, {\n status: error.status,\n body: error.body ?? error.bodyText,\n url: error.url,\n uniqueKey: error.uniqueKey,\n requestTransactionId: error.requestTransactionId,\n applyTransactionId: error.applyTransactionId,\n blockNumber: error.blockNumber,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n phase: error.phase,\n write: error.write,\n walletCode: error.walletCode,\n shadow: true,\n });\n if (error.stack !== undefined) copy.stack = error.stack;\n return copy;\n }\n if (typeof error === 'object' && error !== null) shadowRejections.add(error);\n return error;\n}\n\n/** Runs one shadow operation and marks whatever it throws as shadow (see {@link isShadowError}). */\nexport async function shadowFailures<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error: unknown) {\n throw asShadowError(error);\n }\n}\n","import { armTimeout, type HttpRequestor, type WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\n\n/** Result of one position-confirmation poll. */\nexport type PositionConfirmationResult =\n { confirmed: true; position: Position | null } | { confirmed: false; position?: Position | null };\n\n/** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */\nexport class SubmittedTransaction<TConfirmation = AppliedTrade | Position | null> {\n /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */\n public readonly method: string;\n /** The write's durable correlation key: persist it, and confirm from it alone later. */\n public readonly uniqueKey: string;\n /** The request transaction id the gateway reported, or `null` when it gave none. */\n public readonly transactionId: string | null;\n /** The block of the transaction, when the answer carried one; otherwise `null`. */\n public readonly blockNumber: number | null;\n /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */\n public readonly mode: 'sync' | 'queued';\n /**\n * What the gateway's answer established: `'executed'` for `mode: 'sync'`, `'queued'` for\n * `mode: 'queued'` (accepted, NOT executed: `await confirm()` for the outcome). A refused answer\n * never becomes a transaction, so there is no `'rejected'` here; see {@link classifySubmitEnvelope}\n * for classifying a raw envelope.\n */\n public readonly status: SubmitStatus;\n /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */\n public readonly result: unknown;\n /**\n * The gateway's whole JSON answer as it came (`{ status, message, error, data }`), for an app\n * that hands the backend's own envelope to its callers; `undefined` for a transaction built from\n * a uniqueKey alone.\n */\n public readonly envelope: unknown;\n private readonly backendBaseUrl: string;\n private readonly requestor: HttpRequestor;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n private readonly positionConfirmation:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n\n /** Construct a submitted transaction from a successful gateway response.\n *\n * @example\n * ```ts\n * const transaction = new SubmittedTransaction({\n * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',\n * transactionId: 'request-tx', result: undefined,\n * dexBackendBaseUrl: 'https://dex.example', httpRequestor,\n * });\n * ```\n */\n constructor(options: {\n method: string;\n uniqueKey: string;\n transactionId: string | null;\n mode: 'sync' | 'queued';\n result: unknown;\n dexBackendBaseUrl: string;\n httpRequestor: HttpRequestor;\n blockNumber?: number | null | undefined;\n envelope?: unknown;\n requestTimeoutMs?: number | undefined;\n /** Wire options of the apply-results polls `confirm()` makes. */\n wire?: WireOptions | undefined;\n positionConfirmation?:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n }) {\n this.method = options.method;\n this.uniqueKey = options.uniqueKey;\n this.transactionId = options.transactionId;\n this.blockNumber = options.blockNumber ?? null;\n this.mode = options.mode;\n this.status = options.mode === 'queued' ? 'queued' : 'executed';\n this.result = options.result;\n this.envelope = options.envelope;\n this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestor = options.httpRequestor;\n this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n this.wire = options.wire;\n this.positionConfirmation = options.positionConfirmation;\n }\n\n /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.\n *\n * For RequestTrade, calling this method is required to learn the outcome: the queued\n * acknowledgement proves acceptance, not execution.\n *\n * Every failure is the write's (it carries `uniqueKey`, so `mayHaveBeenQueued` is true): a\n * re-read that cannot succeed is `CONFIRMATION_FAILED` (a terminal HTTP status) or\n * `CONFIRMATION_MALFORMED` (an unusable answer); one that may (no answer, a 5xx, 404, 408,\n * 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error\n * as `cause`. Confirm the same transaction again; never resubmit the write.\n *\n * @example\n * ```ts\n * const applied = await submitted.confirm({ initialDelayMs: 3_000 });\n * ```\n */\n public async confirm(options?: ConfirmOptions): Promise<TConfirmation> {\n if (this.method === 'RequestTrade') {\n return this.confirmApplied(options) as Promise<TConfirmation>;\n }\n return this.confirmPosition(options) as Promise<TConfirmation>;\n }\n\n private confirmApplied(options?: ConfirmOptions): Promise<AppliedTrade> {\n return confirmAppliedTrade(\n {\n dexBackendBaseUrl: this.backendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.requestTimeoutMs,\n wire: this.wire,\n },\n { uniqueKey: this.uniqueKey, requestTransactionId: this.transactionId },\n options,\n );\n }\n\n /** Confirm a liquidity write against the position's observable effect.\n *\n * @returns The position after the write, or `null` for a confirmed full close.\n * @example\n * ```ts\n * const position = await submitted.confirm({ timeoutMs: 60_000 });\n * ```\n */\n private async confirmPosition(options?: ConfirmOptions): Promise<Position | null> {\n if (this.positionConfirmation === undefined) throw GSwapSDKError.noWalletAddressError();\n // A liquidity write has already executed when the gateway answers, so the first re-read\n // happens immediately unless the caller asks for a delay.\n const callerSignal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new GSwapSDKError('CONFIRMATION_ABORTED', {}, { uniqueKey: this.uniqueKey, cause });\n const schedule = createConfirmationSchedule(options, 0, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n while (true) {\n const controller = new AbortController();\n const disarm = armTimeout(controller, this.requestTimeoutMs);\n const forwardAbort = (): void => controller.abort();\n callerSignal?.addEventListener('abort', forwardAbort, { once: true });\n try {\n const result = await this.positionConfirmation(controller.signal);\n if (result.confirmed) return result.position;\n } catch (error: unknown) {\n throwIfAborted(callerSignal, abortError);\n // The write was accepted, so a failed re-read says nothing about it, and the read's own\n // error must never reach the caller: a read failure means \"retry the read\", and a\n // retried WRITE could apply twice. As on the trade path: a terminal answer is\n // CONFIRMATION_FAILED / CONFIRMATION_MALFORMED, anything else is read again until the\n // deadline, then CONFIRMATION_TIMEOUT. Each carries the write's uniqueKey (a write's).\n const terminal = terminalPositionReadFailure(this.uniqueKey, error);\n if (terminal !== undefined) throw terminal;\n lastError = error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);\n }\n}\n\n/** HTTP answers a confirmation reads again (as the apply-results poll does), not terminal ones. */\nfunction isRetriedStatus(status: number): boolean {\n return status === 404 || status === 408 || status === 429 || status >= 500;\n}\n\n/**\n * The confirmation error for a position re-read that failed TERMINALLY (an answer that reading\n * again cannot change), or `undefined` when it is worth reading again.\n */\nfunction terminalPositionReadFailure(uniqueKey: string, error: unknown): GSwapSDKError | undefined {\n if (!isGSwapError(error)) return undefined;\n if (error.code === 'INVALID_POSITION_RESPONSE' || error.code === 'INVALID_CHAIN_RESPONSE') {\n return new GSwapSDKError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n const status = error.status;\n if (\n (error.code === 'HTTP_ERROR' || error.code === 'UPDATE_REQUIRED') &&\n status !== undefined &&\n !isRetriedStatus(status)\n ) {\n const serverMessage = (error.params as Record<string, unknown>)['serverMessage'];\n return new GSwapSDKError(\n 'CONFIRMATION_FAILED',\n { status, serverMessage: typeof serverMessage === 'string' ? serverMessage : '' },\n { uniqueKey, status, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n return undefined;\n}\n","import {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport { userRef } from '../utils/validation.js';\nimport type { SubmissionOutcomeUnknownReason } from './gswap_error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress =\n options.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = this.walletOf(options);\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so the swap backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = this.walletOf(options);\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is the one the Gala web apps send: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n /**\n * The `X-Wallet-Address` of a write: the per-call wallet or the gateway's, in the gateway's\n * spelling (`eth|<EIP-55>`, `client|<id>` as written). A per-call wallet that is no user\n * reference is refused before anything is sent.\n */\n private walletOf(options: ChainSubmitOptions | undefined): string | undefined {\n return options?.walletAddress === undefined\n ? this.walletAddress\n : userRef(options.walletAddress, 'walletAddress');\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GalaErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GalaErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n","/** SDK deployment environment. */\nexport type GSwapEnv = 'prod' | 'stage';\n\n/** Backend URLs used by one SDK deployment environment. */\nexport interface GSwapEnvironmentConfig {\n dexBackendBaseUrl: string;\n /** The realtime stream endpoint (raw WebSocket, JSON-RPC 2.0). */\n dexBackendWsUrl: string;\n}\n\n/** Built-in GalaSwap deployment environments. */\nexport const GSWAP_ENVIRONMENTS: Readonly<Record<GSwapEnv, GSwapEnvironmentConfig>> = {\n prod: {\n dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com',\n dexBackendWsUrl: 'wss://dex-backend-prod1.defi.gala.com/ws',\n },\n stage: {\n dexBackendBaseUrl: 'https://swap-backend.stage.defi.ovh.gala.com',\n dexBackendWsUrl: 'wss://swap-backend.stage.defi.ovh.gala.com/ws',\n },\n};\n","import debug from 'debug';\n\nexport const debugLog = debug('GSWAP_SDK');\n","/** Options for {@link ReconnectionBackoff}. */\nexport interface ReconnectionBackoffOptions {\n /** Attempts allowed before giving up. */\n maxAttempts: number;\n /** Delay before the first attempt, in milliseconds. */\n baseDelayMs: number;\n /** Ceiling the doubling delay never exceeds, in milliseconds. */\n maxDelayMs?: number;\n}\n\n/** Counts reconnect attempts and doubles the delay between them, up to a ceiling. */\nexport class ReconnectionBackoff {\n private attempts = 0;\n private delayMs: number;\n private readonly maxDelayMs: number;\n\n constructor(private readonly options: ReconnectionBackoffOptions) {\n this.delayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs ?? 30_000;\n }\n\n /** Whether another attempt is allowed. */\n shouldRetry(): boolean {\n return this.attempts < this.options.maxAttempts;\n }\n\n /** The delay to wait before the next attempt. */\n nextDelayMs(): number {\n return this.delayMs;\n }\n\n /** Record that an attempt is being made, and double the next delay. */\n recordAttempt(): void {\n this.attempts += 1;\n this.delayMs = Math.min(this.delayMs * 2, this.maxDelayMs);\n }\n\n /** Forget every attempt: the connection is healthy again. */\n reset(): void {\n this.attempts = 0;\n this.delayMs = this.options.baseDelayMs;\n }\n\n get attemptCount(): number {\n return this.attempts;\n }\n\n get maxAttempts(): number {\n return this.options.maxAttempts;\n }\n}\n","import { GSWAP_ENVIRONMENTS } from '../types/env.js';\nimport { debugLog } from '../utils/debug.js';\nimport { userRef } from '../utils/validation.js';\nimport { ReconnectionBackoff } from '../utils/reconnection.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nconst GDEX_SUBPROTOCOL = 'gdex.jsonrpc.v1';\nconst RATE_LIMITED = -32003;\nconst MAX_RESUBSCRIBE_RATE_RETRIES = 5;\nconst WEBSOCKET_OPEN = 1;\n\n/** Options for {@link GdexStreamService}. */\nexport interface GdexStreamConfig {\n /** Stream endpoint. Defaults to production (`wss://dex-backend-prod1.defi.gala.com/ws`). */\n url?: string | undefined;\n /** Reconnect attempts after an unexpected close. Default 5. */\n reconnectAttempts?: number | undefined;\n /** Delay before the first reconnect attempt; doubles each attempt. Default 2000 ms. */\n reconnectDelayMs?: number | undefined;\n /** How long a request waits for its response. Default 15000 ms. */\n requestTimeoutMs?: number | undefined;\n /**\n * A standards-compatible WebSocket constructor. Required on Node.js older than 22, which has no\n * global `WebSocket` (pass the one from the `ws` package).\n */\n webSocketImpl?: unknown;\n /**\n * Presents `x-api-key` on the WebSocket upgrade request, which the swap backend uses to serve the\n * PRIVILEGED view (shadow swaps with the wallet unredacted). Without it, or with a wrong key, the\n * connection is simply public: the server never says whether a privileged mode exists.\n *\n * It must travel as an HTTP header, because the server reads no other credential, and a browser\n * `WebSocket` cannot set headers. So this option needs a constructor that accepts them as its\n * third argument (`{ headers }`): the `ws` package on Node.js, or React Native's built-in\n * `WebSocket`. It therefore REQUIRES `webSocketImpl` (the platform default is never assumed to\n * honor headers, and a key that is silently dropped would look like a working privileged\n * connection); the constructor throws otherwise. Use it from server-side code only: a key\n * shipped inside a browser or app bundle is not a secret. Browser clients stay public.\n */\n apiKey?: string | undefined;\n}\n\n/** The channels of the realtime stream. */\nexport type GdexChannel = 'pool' | 'balance' | 'poolCreated' | 'swap' | 'liquidity' | 'blocks';\n\n/** A pool named by its two token class keys (pipe form) and fee tier. */\nexport interface GdexPoolKey {\n token0ClassKey: string;\n token1ClassKey: string;\n fee: number;\n}\n\n/** A pool named either by its key or by its hash (`v2:<poolRef>` for a v2 pool). */\nexport type GdexPoolSelector = { pool: GdexPoolKey } | { poolHash: string };\n\n/** Options common to every subscription. */\nexport interface GdexSubscribeOptions {\n /** Send the current state right after the subscribe response. */\n snapshot?: boolean | undefined;\n /** Trim each event to these fields; identity and envelope fields always stay. */\n fields?: string[] | undefined;\n}\n\n/** Filters for {@link GdexStreamService.subscribeLiquidity}; all optional. */\nexport interface GdexLiquidityFilter {\n /** Only this pool, named by its key. */\n pool?: GdexPoolKey | undefined;\n /** Only this pool, named by its hash (`v2:<poolRef>` for a v2 pool). */\n poolHash?: string | undefined;\n /** Only events for this LP wallet (the position's owner). */\n owner?: string | undefined;\n /** Only this transaction. */\n transactionId?: string | undefined;\n /** Contract version filter. */\n version?: 'v1' | 'v2' | 'all' | undefined;\n}\n\n/** One committed add, remove or collect, as the `liquidity` channel reports it. */\nexport interface GdexLiquidityEvent {\n version: 'v1' | 'v2';\n pool: GdexPoolKey;\n poolHash: string;\n transactionId: string;\n /** `add`, `remove` or `collect`. */\n action: 'add' | 'remove' | 'collect';\n /** The position's owner (the LP wallet). */\n owner: string;\n /** v1: the position id. v2: the chain position key `<pool>|<tickLow>|<tickHigh>|<owner>`. */\n positionId?: string;\n tickLower?: number;\n tickUpper?: number;\n /** v2 only: the position's liquidity after the operation; `\"0\"` means it is closed. */\n liquidityAfter?: string;\n /** Principal moved: deposited by an add, withdrawn by a remove, `\"0\"` for a collect. */\n amount0: string;\n amount1: string;\n /** Fees paid out. v2: always present (`\"0\"` for an add). v1: present on a collect only. */\n fees0?: string;\n fees1?: string;\n /** v2 only. */\n token0Symbol?: string;\n token1Symbol?: string;\n blockNumber: number;\n timestamp: string;\n}\n\nconst LIQUIDITY_ACTIONS: readonly unknown[] = ['add', 'remove', 'collect'];\n\n/** Whether a stream payload carries every field of a {@link GdexLiquidityEvent}. */\nexport function isGdexLiquidityEvent(\n value: Record<string, unknown>,\n): value is Record<string, unknown> & GdexLiquidityEvent {\n const { pool } = value;\n return (\n (value['version'] === 'v1' || value['version'] === 'v2') &&\n typeof pool === 'object' &&\n pool !== null &&\n typeof value['poolHash'] === 'string' &&\n typeof value['transactionId'] === 'string' &&\n LIQUIDITY_ACTIONS.includes(value['action']) &&\n typeof value['owner'] === 'string' &&\n typeof value['amount0'] === 'string' &&\n typeof value['amount1'] === 'string' &&\n typeof value['blockNumber'] === 'number' &&\n typeof value['timestamp'] === 'string'\n );\n}\n\n/** A live subscription. */\nexport interface GdexSubscription {\n subscriptionId: string;\n unsubscribe(): Promise<void>;\n}\n\n/** A JSON-RPC error answered by the stream. */\nexport class GdexStreamError extends Error {\n /** The JSON-RPC error code. */\n readonly code: number;\n /** The error's optional `data` member, as the server sent it. */\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = 'GdexStreamError';\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\ninterface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code?: number; reason?: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\ninterface WebSocketConstructor {\n new (\n url: string,\n protocols?: string | string[],\n options?: { headers: Record<string, string> },\n ): WebSocketLike;\n}\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: Error): void;\n timeout: ReturnType<typeof setTimeout>;\n /**\n * Runs SYNCHRONOUSLY when the response frame is handled, before any frame that follows it in\n * the same read. Subscriptions register here: the server writes a snapshot right after the\n * subscribe response, and a runtime that delivers both frames without yielding to microtasks\n * (Node's `ws` does, for frames in one chunk) would otherwise drop the snapshot because the\n * awaiting caller has not registered the subscription yet.\n */\n onResult?: ((value: unknown) => void) | undefined;\n}\n\ntype EventCallback = (event: Record<string, unknown>) => void;\n\ninterface ActiveSubscription {\n serverId: string;\n readonly params: Record<string, unknown>;\n readonly callback: EventCallback;\n readonly handle: MutableGdexSubscription;\n active: boolean;\n}\n\ninterface MutableGdexSubscription extends GdexSubscription {\n subscriptionId: string;\n}\n\nfunction readSubscriptionId(value: unknown): string {\n const id =\n typeof value === 'object' && value !== null\n ? (value as { subscriptionId?: unknown }).subscriptionId\n : undefined;\n if (typeof id !== 'string') {\n throw new GdexStreamError(-32603, 'GDEX subscribe response is missing its subscriptionId');\n }\n return id;\n}\n\ninterface JsonRpcResponse {\n id?: unknown;\n method?: unknown;\n result?: unknown;\n error?: { code?: unknown; message?: unknown; data?: unknown };\n params?: unknown;\n}\n\n/**\n * Client for the gSwap realtime stream (gdex WebSocket Protocol v1): JSON-RPC 2.0 over one raw\n * WebSocket, with automatic reconnect and resubscribe.\n *\n * @example\n * ```typescript\n * const stream = new GdexStreamService();\n * await stream.connect();\n * await stream.subscribeLiquidity(event => console.log(event.action, event.owner), {\n * owner: 'client|618ae395c1c653111d3315be',\n * });\n * ```\n */\nexport class GdexStreamService {\n private readonly url: string;\n private readonly requestTimeoutMs: number;\n private readonly apiKey: string | undefined;\n private readonly webSocketConstructor: WebSocketConstructor;\n private readonly backoff: ReconnectionBackoff;\n private socket: WebSocketLike | undefined;\n private connectPromise: Promise<void> | undefined;\n private nextRequestId = 0;\n private readonly pending = new Map<number, PendingRequest>();\n private readonly subscriptionsByServerId = new Map<string, ActiveSubscription>();\n private readonly activeSubscriptions = new Set<ActiveSubscription>();\n private intentionalClose = false;\n private reconnecting = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n private reconnectDelayResolve: (() => void) | undefined;\n\n constructor(config: GdexStreamConfig = {}) {\n this.url = config.url ?? GSWAP_ENVIRONMENTS.prod.dexBackendWsUrl;\n this.requestTimeoutMs = config.requestTimeoutMs ?? 15_000;\n this.backoff = new ReconnectionBackoff({\n maxAttempts: config.reconnectAttempts ?? 5,\n baseDelayMs: config.reconnectDelayMs ?? 2_000,\n });\n\n const implementation =\n config.webSocketImpl ?? (globalThis as { WebSocket?: unknown }).WebSocket;\n if (typeof implementation !== 'function') {\n throw new GSwapSDKError('STREAM_WEBSOCKET_UNAVAILABLE', {});\n }\n this.webSocketConstructor = implementation as WebSocketConstructor;\n if (config.apiKey !== undefined) {\n if (config.apiKey === '' || config.webSocketImpl === undefined) {\n throw new GSwapSDKError('STREAM_API_KEY_UNUSABLE', {});\n }\n this.apiKey = config.apiKey;\n }\n }\n\n /** Open the connection. Resolves at once when already connected. */\n connect(): Promise<void> {\n if (this.isConnected()) return Promise.resolve();\n if (this.connectPromise) return this.connectPromise;\n this.intentionalClose = false;\n this.clearReconnectTimer();\n this.connectPromise = this.openSocket();\n return this.connectPromise;\n }\n\n /** Close the connection and stop reconnecting. */\n disconnect(): void {\n this.intentionalClose = true;\n this.reconnecting = false;\n this.clearReconnectTimer();\n this.rejectPending(new GSwapSDKError('STREAM_DISCONNECTED', {}));\n const socket = this.socket;\n this.socket = undefined;\n this.connectPromise = undefined;\n socket?.close(1000, 'client disconnect');\n }\n\n /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */\n isConnected(): boolean {\n return this.socket?.readyState === WEBSOCKET_OPEN;\n }\n\n /** Raw JSON-RPC escape hatch. */\n request<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {\n return this.send<T>(method, params);\n }\n\n private send<T>(\n method: string,\n params: Record<string, unknown> | undefined,\n onResult?: (value: unknown) => void,\n ): Promise<T> {\n if (!this.isConnected() || !this.socket) {\n return Promise.reject(new GSwapSDKError('STREAM_NOT_CONNECTED', {}));\n }\n\n const id = ++this.nextRequestId;\n const frame: Record<string, unknown> = { jsonrpc: '2.0', id, method };\n if (params !== undefined) frame['params'] = params;\n\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(id);\n reject(\n new GSwapSDKError('STREAM_REQUEST_TIMEOUT', { method, timeoutMs: this.requestTimeoutMs }),\n );\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve: (value) => resolve(value as T), reject, timeout, onResult });\n\n try {\n this.socket?.send(JSON.stringify(frame));\n } catch (error) {\n clearTimeout(timeout);\n this.pending.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */\n serverInfo(): Promise<Record<string, unknown>> {\n return this.request('gdex_serverInfo');\n }\n\n /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */\n ping(): Promise<{ pong: boolean; serverTime: string }> {\n return this.request('gdex_ping');\n }\n\n /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */\n getPool(selector: GdexPoolSelector): Promise<Record<string, unknown>> {\n return this.request('gdex_getPool', selector);\n }\n\n /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */\n async getBalance(owner: string, tokenClassKey?: string): Promise<Record<string, unknown>> {\n const ref = userRef(owner, 'owner');\n return this.request(\n 'gdex_getBalance',\n tokenClassKey === undefined ? { owner: ref } : { owner: ref, tokenClassKey },\n );\n }\n\n /**\n * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the\n * returned `bookmark` back in as `bookmark` for the next page.\n */\n async getPositions(opts: {\n owner: string;\n pool?: GdexPoolKey;\n poolHash?: string;\n limit?: number;\n bookmark?: string;\n }): Promise<{ positions: Record<string, unknown>[]; bookmark: string }> {\n return this.request('gdex_getPositions', { ...opts, owner: userRef(opts.owner, 'owner') });\n }\n\n /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */\n getBlockHeight(): Promise<{ blockNumber: number; timestamp: string }> {\n return this.request('gdex_getBlockHeight');\n }\n\n /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */\n quote(params: {\n tokenIn: string;\n tokenOut: string;\n fee?: number;\n amountIn?: string;\n amountOut?: string;\n }): Promise<Record<string, unknown>> {\n return this.request('gdex_quote', params);\n }\n\n /** `gdex_getToken`: the server's record of one token class, as it sends it. */\n getToken(tokenClassKey: string): Promise<Record<string, unknown>> {\n return this.request('gdex_getToken', { tokenClassKey });\n }\n\n /** One event per committed swap. Omit the pool to receive every pool's swaps. */\n subscribeSwaps(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & {\n pool?: GdexPoolKey;\n poolHash?: string;\n transactionId?: string;\n } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('swap', cb, opts);\n }\n\n /**\n * State changes of one pool (price, tick, reserves, liquidity). These events carry no acting wallet:\n * on v2 `creator` is whoever created the pool, not whoever just traded or added liquidity. For\n * \"who did it\", use {@link subscribeLiquidity} (`owner`) or {@link subscribeSwaps} (`sender`).\n */\n subscribePool(\n selector: GdexPoolSelector,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('pool', cb, { ...selector, ...opts });\n }\n\n /** Balance changes of one wallet. */\n async subscribeBalances(\n owner: string,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('balance', cb, { owner: userRef(owner, 'owner'), ...opts });\n }\n\n /** Each newly created pool. */\n subscribePoolCreated(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('poolCreated', cb, opts);\n }\n\n /**\n * One event per committed AddLiquidity, RemoveLiquidity and CollectPositionFees, on both contract\n * versions. Every filter is optional; with none, every liquidity event arrives. These events never\n * appear on {@link subscribeSwaps}. There is no snapshot: read positions with {@link getPositions}.\n * Deduplicate by `transactionId` plus `positionId`: a v1 BatchSubmit can hold several operations\n * under one transaction id.\n */\n async subscribeLiquidity(\n cb: (event: GdexLiquidityEvent) => void,\n opts: GdexSubscribeOptions & GdexLiquidityFilter = {},\n ): Promise<GdexSubscription> {\n const filter =\n opts.owner === undefined ? opts : { ...opts, owner: userRef(opts.owner, 'owner') };\n return this.subscribe(\n 'liquidity',\n (event) => {\n if (isGdexLiquidityEvent(event)) cb(event);\n else debugLog('Ignoring a malformed liquidity event from the GDEX stream');\n },\n filter,\n );\n }\n\n /** Each block-height advance. */\n subscribeBlocks(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('blocks', cb, opts);\n }\n\n private openSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let opened = false;\n const socket =\n this.apiKey === undefined\n ? new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL)\n : new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL, {\n headers: { 'x-api-key': this.apiKey },\n });\n this.socket = socket;\n\n socket.onopen = () => {\n if (this.socket !== socket) return;\n opened = true;\n this.connectPromise = undefined;\n if (!this.reconnecting) this.backoff.reset();\n debugLog('Connected to GDEX stream');\n resolve();\n };\n socket.onmessage = (event) => this.handleMessage(event.data);\n socket.onerror = () => {\n if (!opened) reject(new GSwapSDKError('STREAM_CONNECT_FAILED', { url: this.url }));\n };\n socket.onclose = (event) => {\n if (this.socket !== socket) return;\n this.socket = undefined;\n this.connectPromise = undefined;\n if (!opened) {\n reject(new GSwapSDKError('STREAM_CLOSED_BEFORE_CONNECT', { closeCode: event.code ?? 0 }));\n }\n this.rejectPending(\n new GSwapSDKError('STREAM_CONNECTION_CLOSED', { closeCode: event.code ?? 0 }),\n );\n if (!this.intentionalClose && !this.reconnecting) this.startReconnectLoop();\n };\n });\n }\n\n private handleMessage(data: unknown): void {\n if (typeof data !== 'string') {\n debugLog('Ignoring non-text GDEX WebSocket frame');\n return;\n }\n\n let message: JsonRpcResponse;\n try {\n message = JSON.parse(data) as JsonRpcResponse;\n } catch {\n debugLog('Ignoring invalid JSON from GDEX stream');\n return;\n }\n\n if (typeof message.id === 'number') {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timeout);\n this.pending.delete(message.id);\n if (message.error) {\n const code = typeof message.error.code === 'number' ? message.error.code : -32603;\n const errorMessage =\n typeof message.error.message === 'string' ? message.error.message : 'GDEX request failed';\n pending.reject(new GdexStreamError(code, errorMessage, message.error.data));\n } else {\n try {\n pending.onResult?.(message.result);\n } catch (error) {\n pending.reject(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n pending.resolve(message.result);\n }\n return;\n }\n\n if (message.method !== 'gdex_subscription' || !this.isRecord(message.params)) return;\n const subscriptionId = message.params['subscription'];\n const result = message.params['result'];\n if (typeof subscriptionId !== 'string' || !this.isRecord(result)) return;\n const subscription = this.subscriptionsByServerId.get(subscriptionId);\n if (!subscription?.active) return;\n try {\n subscription.callback(result);\n } catch (error) {\n debugLog('GDEX subscription callback failed', error);\n }\n }\n\n private async subscribe(\n channel: GdexChannel,\n callback: EventCallback,\n options: object,\n ): Promise<GdexSubscription> {\n const params: Record<string, unknown> = { channel, ...options };\n const handle: MutableGdexSubscription = {\n subscriptionId: '',\n unsubscribe: async () => this.unsubscribe(subscription),\n };\n const subscription: ActiveSubscription = {\n serverId: '',\n params,\n callback,\n handle,\n active: true,\n };\n // Registered inside the response handler, not after the await: see PendingRequest.onResult.\n await this.send('gdex_subscribe', params, (value) => {\n const serverId = readSubscriptionId(value);\n subscription.serverId = serverId;\n handle.subscriptionId = serverId;\n this.activeSubscriptions.add(subscription);\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n return handle;\n }\n\n private async unsubscribe(subscription: ActiveSubscription): Promise<void> {\n if (!subscription.active) return;\n subscription.active = false;\n this.activeSubscriptions.delete(subscription);\n this.subscriptionsByServerId.delete(subscription.serverId);\n if (this.isConnected()) {\n await this.request('gdex_unsubscribe', { subscriptionId: subscription.serverId });\n }\n }\n\n private startReconnectLoop(): void {\n if (this.reconnecting || this.intentionalClose) return;\n this.reconnecting = true;\n void this.reconnectLoop();\n }\n\n private async reconnectLoop(): Promise<void> {\n while (!this.intentionalClose && this.backoff.shouldRetry()) {\n const delay = this.backoff.nextDelayMs();\n this.backoff.recordAttempt();\n debugLog(\n `GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${delay}ms`,\n );\n await this.waitForReconnectDelay(delay);\n // `disconnect()` can run while the asynchronous delay is pending.\n if (this.intentionalClose) break;\n\n try {\n await this.openSocket();\n await this.resubscribeAll();\n this.backoff.reset();\n this.reconnecting = false;\n return;\n } catch (error) {\n debugLog(\n `GDEX reconnect failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n this.reconnecting = false;\n if (!this.intentionalClose) debugLog('GDEX reconnection attempts exhausted');\n }\n\n private async resubscribeAll(): Promise<void> {\n this.subscriptionsByServerId.clear();\n for (const subscription of this.activeSubscriptions) {\n if (!subscription.active) continue;\n const params = { ...subscription.params, snapshot: true };\n const result = await this.resubscribeWithRateLimitRetry(params, (value) => {\n const serverId = readSubscriptionId(value);\n // The consumer can unsubscribe while the asynchronous subscribe request is pending.\n if (!subscription.active) return;\n subscription.serverId = serverId;\n subscription.handle.subscriptionId = serverId;\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n if (!subscription.active) {\n await this.request('gdex_unsubscribe', { subscriptionId: result.subscriptionId });\n }\n }\n }\n\n private async resubscribeWithRateLimitRetry(\n params: Record<string, unknown>,\n onResult: (value: unknown) => void,\n ): Promise<{ subscriptionId: string }> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.send('gdex_subscribe', params, onResult);\n } catch (error) {\n if (\n !(error instanceof GdexStreamError) ||\n error.code !== RATE_LIMITED ||\n attempt >= MAX_RESUBSCRIBE_RATE_RETRIES\n ) {\n throw error;\n }\n const retryAfterMs = this.readRetryAfterMs(error.data);\n debugLog(`GDEX resubscribe rate limited; retrying in ${retryAfterMs}ms`);\n await new Promise<void>((resolve) => setTimeout(resolve, retryAfterMs));\n }\n }\n }\n\n private waitForReconnectDelay(delay: number): Promise<void> {\n return new Promise((resolve) => {\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = undefined;\n this.reconnectDelayResolve = undefined;\n resolve();\n }, delay);\n this.reconnectDelayResolve = resolve;\n });\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer !== undefined) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n const resolve = this.reconnectDelayResolve;\n this.reconnectDelayResolve = undefined;\n resolve?.();\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n private readRetryAfterMs(data: unknown): number {\n if (\n !this.isRecord(data) ||\n typeof data['retryAfterMs'] !== 'number' ||\n data['retryAfterMs'] < 0\n )\n return 1_000;\n return data['retryAfterMs'];\n }\n\n private isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n","import {\n buildQueryString,\n buildRequestHeaders,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { debugLog } from '../utils/debug.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nexport class HttpClient {\n /**\n * Create an HTTP client around fetch or an injected requestor. `wire` selects the query\n * encoding and the `User-Agent` (see {@link WireOptions}).\n */\n constructor(\n private readonly httpRequestor: HttpRequestor = fetchRequestor,\n private readonly timeoutMs = 30_000,\n private readonly wire: WireOptions = {},\n ) {}\n\n private async sendRequest<TReturnType>(\n method: 'POST' | 'GET',\n baseUrl: string,\n basePath: string,\n endpoint: string,\n body?: unknown,\n options?: Pick<RequestInit, 'signal'>,\n ): Promise<TReturnType> {\n const url = `${baseUrl}${basePath}${endpoint}`;\n debugLog(`Sending request to ${url} with body:`, body);\n\n const hasBody = Boolean(body);\n const response = await requestWithTimeout(\n this.httpRequestor,\n url,\n {\n method,\n // Content-Type describes a body, so a GET carries none: it also keeps a browser's\n // cross-origin GET a simple request instead of forcing a CORS preflight.\n headers: buildRequestHeaders(this.wire, { json: hasBody }),\n ...(hasBody ? { body: JSON.stringify(body) } : {}),\n ...(options?.signal === undefined ? {} : { signal: options.signal }),\n },\n this.timeoutMs,\n // Every request of this client is a read (writes go through ChainGateway): a timeout or a\n // transport failure is a read's, as its HTTP errors are (`fromErrorResponse`).\n { write: false },\n );\n\n if (!response.ok) {\n throw await GSwapSDKError.fromErrorResponse(url, response);\n }\n\n const json = await readResponseBody(response);\n debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);\n\n return json as TReturnType;\n }\n\n /** Send a JSON POST request and decode its response. */\n async sendPostRequest<TReturnType>(\n baseUrl: string,\n basePath: string,\n endpoint: string,\n body: unknown,\n ): Promise<TReturnType> {\n return this.sendRequest('POST', baseUrl, basePath, endpoint, body);\n }\n\n /** Send a GET request with URL-encoded query parameters and decode its response. */\n async sendGetRequest<TReturnType>(\n baseUrl: string,\n basePath: string,\n endpoint: string,\n params?: Record<string, string>,\n options?: Pick<RequestInit, 'signal'>,\n ): Promise<TReturnType> {\n const endpointWithParams = params\n ? `${endpoint}?${buildQueryString(params, this.wire.queryEncoding)}`\n : endpoint;\n\n return this.sendRequest('GET', baseUrl, basePath, endpointWithParams, undefined, options);\n }\n}\n","import { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** One row of a list answer that the SDK skipped because it was not usable. */\nexport interface InvalidEntry {\n /** Which read the row came from. */\n source: 'pools' | 'symbols' | 'positions' | 'prices' | 'priceSeries' | 'seasons' | 'leaderboard';\n /**\n * Position of the row in the answer's array; for `prices` (an answer keyed by token), the\n * position of the token in the list asked for.\n */\n index: number;\n /** The row exactly as the backend sent it. */\n entry: unknown;\n /** Why it was skipped, in words. */\n reason: string;\n}\n\n/**\n * Called once per skipped row, in order, before the read resolves. It is a diagnostics hook: what it\n * does, or throws, never changes the result of the read.\n */\nexport type InvalidEntryHandler = (invalid: InvalidEntry) => void;\n\n/** The outcome of reading one row. */\nexport type EntryParse<T> = { ok: true; value: T } | { ok: false; reason: string };\n\n/** A usable row. */\nexport function entryOk<T>(value: T): EntryParse<T> {\n return { ok: true, value };\n}\n\n/** An unusable row, with the reason it is reported under. */\nexport function entryRejected<T>(reason: string): EntryParse<T> {\n return { ok: false, reason };\n}\n\n/**\n * Reads a list answer row by row: a row that cannot be used is skipped and reported, instead of\n * rejecting the whole list because of one bad row. An answer that is not a list at all is still\n * `INVALID_CHAIN_RESPONSE` (a read's: `write: false`): nothing in it can be trusted.\n */\nexport function readEntries<T>(\n source: InvalidEntry['source'],\n data: unknown,\n parse: (entry: unknown) => EntryParse<T>,\n onInvalidEntry?: InvalidEntryHandler,\n): T[] {\n if (!Array.isArray(data)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: `${source} list` },\n { body: data, write: false },\n );\n }\n const rows: T[] = [];\n (data as unknown[]).forEach((entry, index) => {\n const parsed = parse(entry);\n if (parsed.ok) {\n rows.push(parsed.value);\n return;\n }\n try {\n onInvalidEntry?.({ source, index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n });\n return rows;\n}\n\n/** A plain JSON object (not null, not an array). */\nexport function asEntryRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** A finite number, or a non-empty numeric string, as a number; otherwise `undefined`. */\nexport function finiteNumberOf(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n","import type {\n LeaderboardEntry,\n LeaderboardSeason,\n MasteryTitle,\n SeasonLeaderboard,\n} from '../types/market.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/** Options of every leaderboard read. */\nexport interface LeaderboardReadOptions {\n signal?: AbortSignal | undefined;\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** Options of the reads that pick the season running now. */\nexport interface CurrentSeasonOptions extends LeaderboardReadOptions {\n /** The instant \"now\" is (default: the current time). */\n now?: Date | undefined;\n}\n\n/**\n * The swap backend's trading-competition reads: seasons (`GET /leaderboard/seasons`) and a\n * season's rankings (`GET /leaderboard?seasonId=`). Public reads: no signer, no wallet. A row that\n * is not usable is skipped and reported to `onInvalidEntry`; an answer that is not the expected\n * list is `INVALID_CHAIN_RESPONSE`.\n */\nexport class Leaderboard {\n /**\n * Creates a leaderboard service. `options.onInvalidEntry` is told about every season or entry\n * row that was skipped as unusable.\n *\n * @example\n * ```ts\n * const leaderboard = new Leaderboard('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {}\n\n /**\n * Every active season, in the backend's order (newest first).\n *\n * @example\n * ```ts\n * const seasons = await gSwap.leaderboard.getSeasons();\n * console.log(seasons.map((season) => season.name));\n * ```\n */\n public async getSeasons(options?: LeaderboardReadOptions): Promise<LeaderboardSeason[]> {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/leaderboard',\n '/seasons',\n undefined,\n signalOption(options),\n );\n return readEntries(\n 'seasons',\n response,\n parseSeason,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n }\n\n /**\n * The season running at `options.now` (default: now; `start` and `end` both count as inside),\n * or `null` between seasons. When seasons overlap, the first in the backend's order.\n *\n * @example\n * ```ts\n * const season = await gSwap.leaderboard.getCurrentSeason();\n * console.log(season === null ? 'no season running' : season.name);\n * ```\n */\n public async getCurrentSeason(options?: CurrentSeasonOptions): Promise<LeaderboardSeason | null> {\n const now = (options?.now ?? new Date()).getTime();\n const seasons = await this.getSeasons(options);\n return (\n seasons.find((season) => season.start.getTime() <= now && now <= season.end.getTime()) ?? null\n );\n }\n\n /**\n * A season's rankings (the backend's top 100 wallets). `seasonId` must be an integer of at\n * least 1 (`INVALID_SEASON_ID` before anything is sent); a season with no rankings, or none at\n * all, is an empty list.\n *\n * @example\n * ```ts\n * const { entries } = await gSwap.leaderboard.getLeaderboard(1);\n * console.log(entries[0]?.wallet, entries[0]?.totalXp);\n * ```\n */\n public async getLeaderboard(\n seasonId: number,\n options?: LeaderboardReadOptions,\n ): Promise<SeasonLeaderboard> {\n if (typeof seasonId !== 'number' || !Number.isSafeInteger(seasonId) || seasonId < 1) {\n throw new GSwapSDKError('INVALID_SEASON_ID', { value: String(seasonId) });\n }\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/leaderboard',\n '',\n { seasonId: String(seasonId) },\n signalOption(options),\n );\n const rows = asEntryRecord(response)?.['leaderboard'];\n if (!Array.isArray(rows)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'leaderboard' },\n { body: response, write: false },\n );\n }\n const entries = readEntries(\n 'leaderboard',\n rows,\n parseEntry,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n return { seasonId, entries };\n }\n\n /**\n * The rankings of the season running at `options.now` (see\n * {@link Leaderboard.getCurrentSeason}), or `null` between seasons.\n *\n * @example\n * ```ts\n * const current = await gSwap.leaderboard.getCurrentLeaderboard();\n * if (current !== null) console.log(current.seasonId, current.entries.length);\n * ```\n */\n public async getCurrentLeaderboard(\n options?: CurrentSeasonOptions,\n ): Promise<SeasonLeaderboard | null> {\n const season = await this.getCurrentSeason(options);\n return season === null ? null : this.getLeaderboard(season.id, options);\n }\n}\n\nfunction signalOption(\n options: LeaderboardReadOptions | undefined,\n): { signal: AbortSignal } | undefined {\n return options?.signal === undefined ? undefined : { signal: options.signal };\n}\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1 ? value : undefined;\n}\n\nfunction isoDate(value: unknown): Date | undefined {\n if (typeof value !== 'string') return undefined;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nfunction parseSeason(entry: unknown): EntryParse<LeaderboardSeason> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const id = positiveInteger(record['id']);\n if (id === undefined) return entryRejected('id is not an integer of at least 1');\n const name = record['name'];\n if (typeof name !== 'string') return entryRejected('name is not a string');\n const start = isoDate(record['start']);\n const end = isoDate(record['end']);\n if (start === undefined || end === undefined) return entryRejected('start or end is not a date');\n if (start.getTime() > end.getTime()) return entryRejected('start is after end');\n const rulesId = record['rules_id'];\n if (typeof rulesId !== 'number' || !Number.isSafeInteger(rulesId) || rulesId < 0) {\n return entryRejected('rules_id is not an integer');\n }\n return entryOk({ id, name, start, end, rulesId });\n}\n\n/** A non-negative decimal, as the backend's DECIMAL columns are serialized (or a finite number). */\nconst DECIMAL = /^\\d+(?:\\.\\d+)?$/u;\n\nfunction decimalOf(value: unknown): string | undefined {\n // A number is accepted only when it prints as a plain decimal (never `1e+21`).\n const text = typeof value === 'number' ? String(value) : value;\n return typeof text === 'string' && DECIMAL.test(text) ? text : undefined;\n}\n\nfunction parseTitle(value: unknown): MasteryTitle | undefined {\n const record = asEntryRecord(value);\n if (record === undefined) return undefined;\n const { name, type, order } = record;\n if (typeof name !== 'string' || typeof type !== 'string') return undefined;\n if (typeof order !== 'number' || !Number.isFinite(order)) return undefined;\n return { name, type, order };\n}\n\nfunction parseEntry(entry: unknown): EntryParse<LeaderboardEntry> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const wallet = record['wallet'];\n if (typeof wallet !== 'string' || wallet === '') return entryRejected('wallet is not a string');\n const rank = positiveInteger(record['rank']);\n if (rank === undefined) return entryRejected('rank is not an integer of at least 1');\n // The backend leaves total_xp out for a ranked wallet it has no XP breakdown for.\n const rawTotal = record['total_xp'];\n const totalXp = rawTotal === undefined || rawTotal === null ? null : decimalOf(rawTotal);\n if (totalXp === undefined) return entryRejected('total_xp is not a decimal');\n const distributionPercent = decimalOf(record['distribution_percent']);\n const liquidityXp = decimalOf(record['liquidity_xp']);\n const tradingXp = decimalOf(record['trading_xp']);\n if (distributionPercent === undefined || liquidityXp === undefined || tradingXp === undefined) {\n return entryRejected('distribution_percent, liquidity_xp or trading_xp is not a decimal');\n }\n const rawTitles = record['mastery_titles'];\n if (!Array.isArray(rawTitles)) return entryRejected('mastery_titles is not a list');\n const masteryTitles: MasteryTitle[] = [];\n for (const raw of rawTitles as unknown[]) {\n const title = parseTitle(raw);\n if (title === undefined) return entryRejected('a mastery title is not { name, type, order }');\n masteryTitles.push(title);\n }\n return entryOk({\n wallet,\n rank,\n totalXp,\n distributionPercent,\n liquidityXp,\n tradingXp,\n masteryTitles,\n });\n}\n","/**\n * The swap backend's market data and trading-competition reads: what `GSwap.market` and\n * `GSwap.leaderboard` return. Values are the backend's, unconverted: USD prices as numbers, times\n * as unix seconds or `Date`s, XP as decimal strings.\n */\n\n/** The windows `GET /market/price-series` serves (the backend refuses any other with a 400). */\nexport const PRICE_SERIES_TIMEFRAMES = ['1D', '1W', '1M', '1Y', 'ALL'] as const;\n\n/** One member of {@link PRICE_SERIES_TIMEFRAMES}. */\nexport type PriceSeriesTimeframe = (typeof PRICE_SERIES_TIMEFRAMES)[number];\n\n/** The most tokens one `GET /market/price` request may name (the backend's limit). */\nexport const MARKET_PRICE_BATCH_LIMIT = 500;\n\n/** One token's market price, as `GET /market/price` answered it. */\nexport interface MarketPrice {\n /** The id the price was asked for: the token string as given, or an object key's `$` form. */\n token: string;\n /** USD price; `null` when the backend knows the token but has no price for it. */\n price: number | null;\n /** 24-hour change in percent (`-2.1` is -2.1 %); `null` when unknown. */\n change24h: number | null;\n /** Whether the token is on the backend's CoinGecko list (what the swap app's \"trending\" uses). */\n listed: boolean;\n}\n\n/** One point of a price series. */\nexport interface PriceSeriesPoint {\n /** Unix time in seconds. */\n time: number;\n /** USD price at `time`. */\n price: number;\n}\n\n/** A token's USD price line, as `GET /market/price-series` answered it. */\nexport interface PriceSeries {\n /** The id the series was asked for: the token string as given, or an object key's `$` form. */\n token: string;\n timeframe: PriceSeriesTimeframe;\n /** In the backend's order (oldest first). Empty for a token the backend has no prices for. */\n prices: PriceSeriesPoint[];\n /** USD price now; `null` when unknown. */\n currentPrice: number | null;\n /** 24-hour change in percent; `null` when unknown. */\n change24h: number | null;\n}\n\n/**\n * Totals across every current-contract pool, as `GET /v2/trade/volume` answered them. USD amounts;\n * a delta is a fraction (`-0.11` is 11 % less than the previous period, `0` when that period had\n * no volume), not a percentage.\n */\nexport interface VolumeSummary {\n tvl: number;\n volume1d: number;\n volume7d: number;\n volume30d: number;\n /** Number of trades in the last 24 hours. */\n trades1d: number;\n volume1dDelta: number;\n volume7dDelta: number;\n volume30dDelta: number;\n}\n\n/** A trading-competition season, as `GET /leaderboard/seasons` answered it. */\nexport interface LeaderboardSeason {\n id: number;\n name: string;\n /** First instant of the season. */\n start: Date;\n /** Last instant of the season (inclusive). */\n end: Date;\n /** The scoring rules the season uses. */\n rulesId: number;\n}\n\n/** An achievement shown on a leaderboard entry. */\nexport interface MasteryTitle {\n name: string;\n /** For example `trade` or `liquidity`; the backend's own word, passed on as it is. */\n type: string;\n /** Display order. */\n order: number;\n}\n\n/** One wallet's row on a season's leaderboard. */\nexport interface LeaderboardEntry {\n wallet: string;\n /** 1 for the top wallet. */\n rank: number;\n /** Decimal string; `null` when the backend has no XP breakdown for the wallet yet. */\n totalXp: string | null;\n /** The wallet's share of the season's XP, in percent, as a decimal string (`'12.34'`). */\n distributionPercent: string;\n liquidityXp: string;\n tradingXp: string;\n masteryTitles: MasteryTitle[];\n}\n\n/** A season's leaderboard (the backend returns at most its top 100 wallets). */\nexport interface SeasonLeaderboard {\n seasonId: number;\n entries: LeaderboardEntry[];\n}\n","import { compositeKeyOf, isTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport {\n MARKET_PRICE_BATCH_LIMIT,\n PRICE_SERIES_TIMEFRAMES,\n type MarketPrice,\n type PriceSeries,\n type PriceSeriesPoint,\n type PriceSeriesTimeframe,\n type VolumeSummary,\n} from '../types/market.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * The ids `GET /market/price` and `GET /market/price-series` accept (the backend's own allowlist):\n * a symbol, or a class key in the `$` or `|` form. A comma would split the price request.\n */\nconst MARKET_TOKEN_PATTERN = /^[A-Za-z0-9._$+/:|-]{1,120}$/u;\n\n/** Options of every market read. */\nexport interface MarketReadOptions {\n signal?: AbortSignal | undefined;\n}\n\n/** Options of {@link Market.getPrices} and {@link Market.getPriceSeries}. */\nexport interface MarketListOptions extends MarketReadOptions {\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/**\n * Market data from the swap backend: USD prices (`GET /market/price`), price series\n * (`GET /market/price-series`) and the platform volume totals (`GET /v2/trade/volume`). Public\n * reads: no signer, no wallet.\n *\n * A token is named by a symbol (`GALA`) or a class key (`GALA$Unit$none$none`,\n * `GALA|Unit|none|none` or the object). The backend answers each token under the exact id it was\n * asked for, so the answer is read back under that id: a token the backend has no entry for is\n * `undefined`, never another token's price.\n */\nexport class Market {\n /**\n * Creates a market service. `options.onInvalidEntry` is told about every price or price point\n * that was skipped as unusable.\n *\n * @example\n * ```ts\n * const market = new Market('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {}\n\n /**\n * USD prices of 1 to 500 tokens, in the order asked (a token named twice is asked for once).\n * The ids go in as many requests as their length needs (see {@link MARKET_PRICE_QUERY_BYTES}),\n * one after another; any request failing fails the call. A token the backend did not answer\n * for is `undefined`; one it answered for unusably is `undefined` too, and reported to\n * `onInvalidEntry`. An answer that is not an object is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const [gala, gusdc] = await gSwap.market.getPrices(['GALA$Unit$none$none', 'GUSDC$Unit$none$none']);\n * console.log(gala?.price, gusdc?.price);\n * ```\n */\n public async getPrices(\n tokens: readonly TokenRef[],\n options?: MarketListOptions,\n ): Promise<Array<MarketPrice | undefined>> {\n if (!Array.isArray(tokens) || tokens.length < 1 || tokens.length > MARKET_PRICE_BATCH_LIMIT) {\n throw new GSwapSDKError('INVALID_TOKEN_BATCH', {\n method: 'getPrices',\n count: Array.isArray(tokens) ? tokens.length : 0,\n max: MARKET_PRICE_BATCH_LIMIT,\n });\n }\n const ids = tokens.map(marketTokenOf);\n // One request per batch, one after another (the endpoint allows 60 a minute): each batch's\n // answer is read under the ids that batch asked for, never another batch's.\n const answered = new Map<string, unknown>();\n for (const batch of priceBatches([...new Set(ids)])) {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/market',\n '/price',\n { assetIds: batch.join(',') },\n signalOption(options),\n );\n const answer = asEntryRecord(response);\n if (answer === undefined) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'market prices' },\n { body: response, write: false },\n );\n }\n for (const id of batch) {\n if (Object.hasOwn(answer, id)) answered.set(id, answer[id]);\n }\n }\n const onInvalidEntry = options?.onInvalidEntry ?? this.options.onInvalidEntry;\n return ids.map((id, index) => {\n if (!answered.has(id)) return undefined;\n const entry = answered.get(id);\n const parsed = parseMarketPrice(id, entry);\n if (parsed.ok) return parsed.value;\n try {\n onInvalidEntry?.({ source: 'prices', index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n return undefined;\n });\n }\n\n /**\n * The USD price of one token, or `undefined` when the backend has no entry for it (see\n * {@link Market.getPrices}).\n *\n * @example\n * ```ts\n * const gala = await gSwap.market.getPrice('GALA$Unit$none$none');\n * if (gala?.price != null) console.log(`GALA: $${gala.price}`);\n * ```\n */\n public async getPrice(\n token: TokenRef,\n options?: MarketListOptions,\n ): Promise<MarketPrice | undefined> {\n const [price] = await this.getPrices([token], options);\n return price;\n }\n\n /**\n * A token's USD price line for one window (1D, 1W, 1M, 1Y or ALL; any other is\n * `INVALID_TIMEFRAME` before anything is sent). The whole series in one answer, oldest first; a\n * token the backend has no prices for is an empty series. An unusable point is skipped and\n * reported to `onInvalidEntry`; an answer that is not a series is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W');\n * console.log(series.prices.length, series.currentPrice);\n * ```\n */\n public async getPriceSeries(\n token: TokenRef,\n timeframe: PriceSeriesTimeframe,\n options?: MarketListOptions,\n ): Promise<PriceSeries> {\n if (!(PRICE_SERIES_TIMEFRAMES as readonly unknown[]).includes(timeframe)) {\n throw new GSwapSDKError('INVALID_TIMEFRAME', {\n value: String(timeframe),\n allowed: PRICE_SERIES_TIMEFRAMES.join(', '),\n });\n }\n const id = marketTokenOf(token);\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/market',\n '/price-series',\n { token: id, timeframe },\n signalOption(options),\n );\n const answer = asEntryRecord(response);\n const currentPrice = answer === undefined ? undefined : nullableFinite(answer['currentPrice']);\n const change24h = answer === undefined ? undefined : nullableFinite(answer['change24h']);\n if (\n answer === undefined ||\n !Array.isArray(answer['prices']) ||\n currentPrice === undefined ||\n change24h === undefined\n ) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'price series' },\n { body: response, write: false },\n );\n }\n const prices = readEntries(\n 'priceSeries',\n answer['prices'],\n parsePricePoint,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n return { token: id, timeframe, prices, currentPrice, change24h };\n }\n\n /**\n * TVL, volume and trade totals across every current-contract pool. Every field must be a finite\n * number, or the answer is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const volume = await gSwap.market.getVolumeSummary();\n * console.log(`24h: $${volume.volume1d.toFixed(0)} (${(volume.volume1dDelta * 100).toFixed(1)} %)`);\n * ```\n */\n public async getVolumeSummary(options?: MarketReadOptions): Promise<VolumeSummary> {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/v2/trade',\n '/volume',\n undefined,\n signalOption(options),\n );\n const summary = parseVolumeSummary(asEntryRecord(asEntryRecord(response)?.['data']));\n if (summary === undefined) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'volume summary' },\n { body: response, write: false },\n );\n }\n return summary;\n }\n}\n\n/**\n * The most query bytes one `GET /market/price` carries. The backend refuses a request line over\n * 16 KB (Node's default header limit: 300 launchpad keys, 17.7 KB encoded, answer HTTP 431,\n * recorded on prod 2026-10-13), so a long list is split well under it (about 135 launchpad keys\n * per request, 270 short ones).\n */\nexport const MARKET_PRICE_QUERY_BYTES = 8_000;\n\n/**\n * The ids in request-sized batches: at most {@link MARKET_PRICE_BATCH_LIMIT} ids and\n * {@link MARKET_PRICE_QUERY_BYTES} of encoded `assetIds` each (the standard encoding's size, the\n * larger of the two, with a `%2C` per id).\n */\nexport function priceBatches(ids: readonly string[]): string[][] {\n const batches: string[][] = [];\n let batch: string[] = [];\n let bytes = 0;\n for (const id of ids) {\n const size = encodeURIComponent(id).length + 3;\n if (\n batch.length > 0 &&\n (bytes + size > MARKET_PRICE_QUERY_BYTES || batch.length === MARKET_PRICE_BATCH_LIMIT)\n ) {\n batches.push(batch);\n batch = [];\n bytes = 0;\n }\n batch.push(id);\n bytes += size;\n }\n if (batch.length > 0) batches.push(batch);\n return batches;\n}\n\n/**\n * The id a market read sends for a token: a string as given (a symbol or a class key in either\n * form), an object key in its `$` form. Anything the backend's allowlist refuses is refused here.\n */\nfunction marketTokenOf(token: TokenRef): string {\n if (typeof token !== 'string') {\n if (!isTokenClassKey(token)) {\n throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', {\n tokenClassKey: describeValue(token),\n });\n }\n return checkedMarketToken(compositeKeyOf(token));\n }\n return checkedMarketToken(token);\n}\n\nfunction checkedMarketToken(id: string): string {\n if (!MARKET_TOKEN_PATTERN.test(id)) {\n throw new GSwapSDKError('INVALID_MARKET_TOKEN', { token: id });\n }\n return id;\n}\n\nfunction describeValue(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction signalOption(options: MarketReadOptions | undefined): { signal: AbortSignal } | undefined {\n return options?.signal === undefined ? undefined : { signal: options.signal };\n}\n\n/** A finite number, `null` for `null`, `undefined` for anything else (an unusable value). */\nfunction nullableFinite(value: unknown): number | null | undefined {\n if (value === null) return null;\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction parseMarketPrice(token: string, entry: unknown): EntryParse<MarketPrice> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const price = nullableFinite(record['price']);\n if (price === undefined || (price !== null && price < 0)) {\n return entryRejected('price is not a non-negative number or null');\n }\n const change24h = nullableFinite(record['change24h']);\n if (change24h === undefined) return entryRejected('change24h is not a number or null');\n const listed = record['listed'];\n if (typeof listed !== 'boolean') return entryRejected('listed is not a boolean');\n return entryOk({ token, price, change24h, listed });\n}\n\nfunction parsePricePoint(entry: unknown): EntryParse<PriceSeriesPoint> {\n const record = asEntryRecord(entry);\n const time = finite(record?.['time']);\n const price = finite(record?.['price']);\n if (time === undefined || !Number.isInteger(time) || time < 0) {\n return entryRejected('time is not unix seconds');\n }\n if (price === undefined || price < 0) return entryRejected('price is not a non-negative number');\n return entryOk({ time, price });\n}\n\nconst VOLUME_FIELDS = [\n 'tvl',\n 'volume1d',\n 'volume7d',\n 'volume30d',\n 'trades1d',\n 'volume1dDelta',\n 'volume7dDelta',\n 'volume30dDelta',\n] as const satisfies ReadonlyArray<keyof VolumeSummary>;\n\nfunction parseVolumeSummary(data: Record<string, unknown> | undefined): VolumeSummary | undefined {\n if (data === undefined) return undefined;\n const summary: Partial<Record<keyof VolumeSummary, number>> = {};\n for (const field of VOLUME_FIELDS) {\n const value = finite(data[field]);\n if (value === undefined) return undefined;\n summary[field] = value;\n }\n const trades = summary.trades1d;\n if (trades === undefined || !Number.isInteger(trades) || trades < 0) return undefined;\n return summary as VolumeSummary;\n}\n","import type { HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { asEntryRecord } from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\n\n/** What the Onramper widget does. */\nexport const ONRAMPER_MODES = ['buy', 'sell', 'swap'] as const;\n\n/** One of {@link ONRAMPER_MODES}. */\nexport type OnramperMode = (typeof ONRAMPER_MODES)[number];\n\n/**\n * The request of {@link Onramper.generateWidgetUrl}: the fields of the swap backend's\n * `GenerateWidgetUrlDto`, no others (the backend refuses a field it does not know). A field left\n * out is the backend's default (`mode` `buy`, `defaultFiat` `USD`, `defaultAmount` 100,\n * `sellDefaultAmount` 1, `onlyCryptoNetworks` `gala`, `defaultPaymentMethod` `creditcard`,\n * `networkPrefix` `gala_gala`).\n */\nexport interface OnramperWidgetRequest {\n /** The wallet that receives the crypto, sent as given (the backend accepts `0x…` or `eth|…` Ethereum addresses and `client|…` aliases, and canonicalizes them). */\n walletAddress: string;\n mode?: OnramperMode | undefined;\n defaultFiat?: string | undefined;\n /** The fiat amount the widget opens with (the backend accepts 15 to 15 000, at most 2 decimals). */\n defaultAmount?: number | undefined;\n /** The crypto amount a sell opens with (0.000001 to 1 000 000, at most 18 decimals). */\n sellDefaultAmount?: number | undefined;\n onlyCryptoNetworks?: string | undefined;\n defaultPaymentMethod?: string | undefined;\n defaultCrypto?: string | undefined;\n onlyPaymentMethods?: string | undefined;\n excludePaymentMethods?: string | undefined;\n onlyFiat?: string | undefined;\n excludeFiat?: string | undefined;\n isAddressEditable?: string | undefined;\n networkPrefix?: string | undefined;\n}\n\n/** The request fields that are text, besides `walletAddress` and `mode`. */\nconst TEXT_FIELDS = [\n 'defaultFiat',\n 'onlyCryptoNetworks',\n 'defaultPaymentMethod',\n 'defaultCrypto',\n 'onlyPaymentMethods',\n 'excludePaymentMethods',\n 'onlyFiat',\n 'excludeFiat',\n 'isAddressEditable',\n 'networkPrefix',\n] as const;\n\n/** The request fields that are amounts. */\nconst AMOUNT_FIELDS = ['defaultAmount', 'sellDefaultAmount'] as const;\n\nconst METHOD = 'onramper.generateWidgetUrl';\n\nfunction invalidField(field: string, expected: string): GSwapSDKError {\n return new GSwapSDKError('INVALID_DTO', { method: METHOD, field, expected });\n}\n\n/**\n * The body to send: the fields the caller gave, checked. A field left out (or `undefined`) is not\n * sent, so the backend's default applies. An amount that is not a finite number is refused here:\n * `JSON.stringify` would turn `NaN` into `null`, which the backend reads as \"not given\" and\n * silently replaces with its default amount.\n */\nfunction widgetBody(request: OnramperWidgetRequest): Record<string, string | number> {\n if (typeof request !== 'object' || request === null) {\n throw invalidField('request', 'an object');\n }\n if (typeof request.walletAddress !== 'string' || request.walletAddress.trim() === '') {\n throw invalidField('walletAddress', 'a non-empty string');\n }\n const body: Record<string, string | number> = { walletAddress: request.walletAddress };\n if (request.mode !== undefined) {\n if (!(ONRAMPER_MODES as readonly unknown[]).includes(request.mode)) {\n throw invalidField('mode', ONRAMPER_MODES.join(', '));\n }\n body['mode'] = request.mode;\n }\n for (const field of TEXT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'string') throw invalidField(field, 'a string');\n body[field] = value;\n }\n for (const field of AMOUNT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw invalidField(field, 'a finite number, 0 or more');\n }\n body[field] = value;\n }\n return body;\n}\n\n/** The widget URL of the backend's `{ status, error, message, data: { url } }` answer. */\nfunction widgetUrlOf(response: unknown): string {\n const data = asEntryRecord(asEntryRecord(response)?.['data']);\n const url = data?.['url'];\n if (typeof url === 'string' && url !== '') {\n try {\n // Only to know it is an absolute URL; the backend's text is returned as it is.\n void new URL(url);\n return url;\n } catch {\n // Falls through to the invalid-answer error below.\n }\n }\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'onramper widget url' },\n { body: response, write: false },\n );\n}\n\n/**\n * The swap backend's Onramper (fiat on-ramp) widget URL. The route is PUBLIC: the request carries\n * no `Authorization` header and no signature, whatever session the app has, so no token can leak to\n * it. The backend signs the wallet into the URL; the app adds its own look (theme query parameters)\n * to the returned URL.\n */\nexport class Onramper {\n /**\n * Creates the service. To get one without building a whole {@link GSwap} client, use\n * {@link createOnramper}.\n *\n * @example\n * ```ts\n * const onramper = new Onramper('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Asks the backend for a signed Onramper widget URL for `request.walletAddress`.\n *\n * @returns The widget URL.\n * @throws GSwapSDKError `INVALID_DTO` (before anything is sent: no wallet address, an unknown\n * `mode`, a text field that is not text, an amount that is not a finite number of 0 or more),\n * `HTTP_ERROR` (the backend refused: `serverMessage` is its message, e.g. \"Failed to generate\n * widget URL. Check server configuration.\" for a 500, its validation message for a 400, the\n * throttle for a 429), `REQUEST_FAILED` (no answer), `INVALID_CHAIN_RESPONSE` (an answer without\n * a usable `data.url`).\n *\n * @example\n * ```ts\n * const url = await gSwap.onramper.generateWidgetUrl({\n * walletAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n * defaultCrypto: 'gala',\n * onlyCryptoNetworks: 'gala',\n * mode: 'buy',\n * });\n * window.open(url);\n * ```\n */\n public async generateWidgetUrl(request: OnramperWidgetRequest): Promise<string> {\n const body = widgetBody(request);\n const response = await this.httpClient.sendPostRequest<unknown>(\n this.dexBackendBaseUrl,\n '/api/v1/onramper',\n '/generate-widget-url',\n body,\n );\n return widgetUrlOf(response);\n }\n}\n\n/** Options of {@link createOnramper}. */\nexport interface OnramperOptions {\n /** The swap backend's base URL (no trailing slash needed). */\n dexBackendBaseUrl: string;\n /** Your own HTTP requestor instead of `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000). */\n timeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the requests. */\n wire?: WireOptions | undefined;\n}\n\n/**\n * An {@link Onramper} for a swap backend, without building a {@link GSwap} client (no signer, no\n * wallet, no pool or stream services): the call for an app that only needs the widget URL.\n *\n * @example\n * ```ts\n * import { createOnramper } from '@gala-chain/gswap-sdk';\n *\n * const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' });\n * const url = await onramper.generateWidgetUrl({ walletAddress, mode: 'buy' });\n * ```\n */\nexport function createOnramper(options: OnramperOptions): Onramper {\n return new Onramper(\n options.dexBackendBaseUrl.replace(/\\/$/u, ''),\n new HttpClient(options.httpRequestor, options.timeoutMs, options.wire),\n );\n}\n","import { splitClassKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** A symbol or a GalaChain token class key accepted by v2 operations. */\nexport type TokenRef = string | GalaChainTokenClassKey;\n\n/** Return two trading symbols in the contract's plain-string order. */\nexport function orderSymbols(a: string, b: string): [string, string] {\n return a < b ? [a, b] : [b, a];\n}\n\n/** Read an ordered symbol pair from a tuple or object returned by a boundary helper.\n *\n * @example\n * ```ts\n * const pair = readOrderedSymbols(['GALA', 'GUSDC']);\n * console.log(pair.token0);\n * ```\n */\nexport function readOrderedSymbols(value: unknown): { token0: string; token1: string } {\n if (Array.isArray(value) && value.length >= 2) {\n const token0 = (value as unknown[])[0];\n const token1 = (value as unknown[])[1];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n if (typeof value === 'object' && value !== null) {\n const record = value as Record<string, unknown>;\n const token0 = record['token0'];\n const token1 = record['token1'];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n throw new GSwapSDKError('UNORDERABLE_SYMBOLS', {\n received: Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value,\n });\n}\n\n/**\n * Parse a pipe- or dollar-separated token class key.\n *\n * The LAST three segments are always `category`, `type` and `additionalKey`; everything before\n * them is the `collection`. Parsing from the right is required because real collections contain\n * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`\n * shifts every field. Nothing here says anything about the token's symbol: a class key carries\n * no symbol, which must come from the token class or trading-symbol registry.\n *\n * @example\n * ```ts\n * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'\n * ```\n */\nexport function parseTokenClassKey(tokenClassKey: TokenRef): GalaChainTokenClassKey {\n if (typeof tokenClassKey === 'object') {\n return {\n collection: tokenClassKey.collection,\n category: tokenClassKey.category,\n type: tokenClassKey.type,\n additionalKey: tokenClassKey.additionalKey,\n };\n }\n\n const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes('|') ? '|' : '$');\n if (parsed === undefined) throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', { tokenClassKey });\n return parsed;\n}\n","import { isGalaError } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry\n * through the app's HTTP stack) on the \"nothing was sent\" boundary, like core's `signPreSend` does\n * for the signer. A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED` (`token` names\n * what was being resolved, the original is `cause`); an SDK error of any product (every one is a\n * `GalaSDKError`, core's transport errors included) passes through.\n *\n * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.\n */\nexport async function resolvePreSend<T>(token: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (cause: unknown) {\n throw isGalaError(cause)\n ? cause\n : new GSwapSDKError('TOKEN_RESOLUTION_FAILED', { token }, { cause });\n }\n}\n","import {\n compositeKeyOf,\n type GalaChainTokenClassKey,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { TradingSymbol } from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { orderSymbols, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport { isProposableTradingSymbol } from '../utils/validation.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { ChainGateway } from './gateway.js';\nimport { HttpClient } from './http_client.js';\n\nconst SYMBOL_CACHE_TTL_MS = 60_000;\n\n/** Symbol registry client for the current GalaChainDex contract. */\nexport class Symbols {\n private cachedSymbols: TradingSymbol[] | undefined;\n private cachedAt = 0;\n private refreshInFlight: Promise<TradingSymbol[]> | undefined;\n\n private readonly http: HttpClient;\n\n /**\n * Create a symbol service backed by the swap backend. `onInvalidEntry` is told about every\n * registry row that was skipped as unusable (see {@link InvalidEntryHandler}).\n */\n constructor(\n private readonly gateway: Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n },\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs, gateway.wire);\n }\n\n /**\n * List all registered GalaChainDex trading symbols, cached for 60 seconds. A registry row that\n * is not a usable symbol is skipped (and reported to `onInvalidEntry`) instead of failing the\n * whole list.\n */\n public async list(): Promise<TradingSymbol[]> {\n if (this.cachedSymbols !== undefined && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) {\n return this.cachedSymbols;\n }\n if (this.refreshInFlight !== undefined) return this.refreshInFlight;\n this.refreshInFlight = this.http\n .sendGetRequest<{ data: unknown }>(this.gateway.dexBackendBaseUrl, '/v2/trade', '/symbols')\n .then((response) =>\n readEntries('symbols', response.data, parseTradingSymbol, this.options.onInvalidEntry),\n )\n .then((symbols) => {\n this.cachedSymbols = symbols;\n this.cachedAt = Date.now();\n return symbols;\n })\n .finally(() => {\n this.refreshInFlight = undefined;\n });\n return this.refreshInFlight;\n }\n\n /** Invalidate the cached symbol registry after a write changes registration state.\n *\n * @example\n * ```ts\n * gSwap.symbols.invalidate();\n * ```\n */\n public invalidate(): void {\n this.cachedSymbols = undefined;\n this.cachedAt = 0;\n }\n\n /** Force one registry refresh, bypassing the cache.\n *\n * @example\n * ```ts\n * const symbols = await gSwap.symbols.refresh();\n * ```\n */\n public async refresh(): Promise<TradingSymbol[]> {\n this.invalidate();\n // list() would otherwise return an ALREADY in-flight refresh that started before this\n // call (built from pre-invalidation state) — bypassing it too is what makes this\n // actually force a fresh fetch, not just satisfy the cache-freshness check.\n this.refreshInFlight = undefined;\n return this.list();\n }\n\n /** Resolve a symbol or token class key to its registered symbol metadata. */\n public async resolve(ref: TokenRef): Promise<TradingSymbol> {\n let symbols = await this.list();\n const composite =\n typeof ref === 'string'\n ? isCompositeKey(ref)\n ? compositeKeyOf(parseTokenClassKey(ref))\n : undefined\n : compositeKeyOf(ref);\n const resolved = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (resolved === undefined) {\n symbols = await this.refresh();\n const refreshed = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (refreshed === undefined) throw GSwapSDKError.unknownTokenError(ref);\n return refreshed;\n }\n return resolved;\n }\n\n /**\n * The trading symbol to put in a token's first CreatePool.\n *\n * 1. The symbol ALREADY registered for exactly this class key, if any: proposing another one\n * fails the gateway's registry-conflict check.\n * 2. Otherwise `displaySymbol` (the token's curated symbol), when it is proposable\n * ({@link isProposableTradingSymbol}).\n * 3. Otherwise a `NO_VALID_TRADING_SYMBOL` error: a symbol is never derived from the key (BNB's collection is\n * `GBNB`, a launchpad token's is the reserved word `Token`).\n *\n * `registryFailure: 'ignore'` treats an unreachable registry as an empty one and falls through\n * to step 2 (the gateway still rejects a conflicting symbol); the default `'throw'` propagates\n * the failure.\n *\n * @example\n * ```ts\n * const symbol = await gSwap.symbols.proposeSymbol(\n * { collection: 'GALA_TEST1', category: 'Unit', type: 'none', additionalKey: 'none' },\n * 'GALATEST',\n * );\n * ```\n */\n public async proposeSymbol(\n classKey: GalaChainTokenClassKey,\n displaySymbol: string,\n options: { registryFailure?: 'throw' | 'ignore' | undefined } = {},\n ): Promise<string> {\n let registry: TradingSymbol[] = [];\n try {\n registry = await this.list();\n } catch (error: unknown) {\n if (options.registryFailure !== 'ignore') throw error;\n }\n const wanted = compositeKeyOf(classKey);\n const registered = registry.find(\n (entry) =>\n entry.collection === classKey.collection &&\n entry.category === classKey.category &&\n entry.type === classKey.type &&\n entry.additionalKey === classKey.additionalKey,\n );\n if (registered !== undefined) return registered.symbol;\n if (isProposableTradingSymbol(displaySymbol)) return displaySymbol;\n throw new GSwapSDKError('NO_VALID_TRADING_SYMBOL', { classKey: wanted, displaySymbol });\n }\n\n /** Resolve and put two token references in canonical trading-symbol order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{\n token0: TradingSymbol;\n token1: TradingSymbol;\n flipped: boolean;\n }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n return {\n token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,\n token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,\n flipped: token0Symbol !== resolvedA.symbol,\n };\n }\n}\n\n/** Reads one registry row: all four class-key parts, a symbol and non-negative integer decimals. */\nfunction parseTradingSymbol(value: unknown): EntryParse<TradingSymbol> {\n const entry = asEntryRecord(value);\n if (entry === undefined) return entryRejected('the row is not an object');\n const { symbol, collection, category, type, additionalKey, decimals } = entry;\n if (typeof symbol !== 'string') return entryRejected('symbol is not a string');\n if (symbol.length === 0) return entryRejected('symbol is empty');\n if (typeof collection !== 'string') return entryRejected('collection is not a string');\n if (typeof category !== 'string') return entryRejected('category is not a string');\n if (typeof type !== 'string') return entryRejected('type is not a string');\n if (typeof additionalKey !== 'string') return entryRejected('additionalKey is not a string');\n if (typeof decimals !== 'number' || !Number.isInteger(decimals) || decimals < 0) {\n return entryRejected('decimals is not a non-negative integer');\n }\n return entryOk({ symbol, collection, category, type, additionalKey, decimals });\n}\n\nfunction isCompositeKey(ref: string): boolean {\n return ref.includes('|') || ref.includes('$');\n}\n\n/**\n * What the services need from a token resolver: how a token reference becomes a trading symbol,\n * and whether requests carry the caller's references untouched. {@link Symbols} is the registry\n * resolver (one `GET /v2/trade/symbols`, cached); {@link CanonicalSymbols} is the offline one.\n */\nexport interface TokenResolver {\n resolve(ref: TokenRef): Promise<TradingSymbol>;\n /**\n * True when reads send the caller's token references verbatim (a symbol, or a composite key as\n * the caller wrote it) and let the backend resolve and orient the pair — no registry request\n * and no client-side ordering or tick flip.\n */\n readonly passthrough?: boolean | undefined;\n}\n\n/** A token reference as the caller wrote it: a string verbatim, a class key as its `$` composite. */\nexport function rawTokenOf(ref: TokenRef): string {\n return typeof ref === 'string' ? ref : compositeKeyOf(ref);\n}\n\n/** The trading symbol of a reference, or `SYMBOL_NOT_FOUND` when the resolver has none. */\nexport async function tradingSymbolOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n const resolved = await resolvePreSend(rawTokenOf(ref), () => resolver.resolve(ref));\n if (resolved.symbol.length > 0) return resolved.symbol;\n throw new GSwapSDKError('SYMBOL_NOT_FOUND', { token: rawTokenOf(ref) });\n}\n\n/** What a read request names a token by: the reference itself in pass-through mode, else its symbol. */\nexport async function queryTokenOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n return resolver.passthrough === true ? rawTokenOf(ref) : tradingSymbolOf(resolver, ref);\n}\n\n/**\n * The offline resolver for apps that already hold the backend's canonical trading symbols (from\n * `/quote`, `/add-liq-estimate`, a position row) and must not make a registry request of their own.\n *\n * - `resolve` accepts a bare trading symbol and returns it as is; a class key (object, `$` or `|`\n * form) is not a symbol and is refused as `UNKNOWN_TOKEN`. `createPool` relies on that refusal to\n * fall back to the symbols its caller supplies.\n * - `orderPair` orders two symbols by plain string comparison, as the contract does.\n * - Reads are pass-through (see {@link TokenResolver.passthrough}): the caller's references go on\n * the wire verbatim, composite keys included, and the backend orients the pair.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, new CanonicalSymbols(), signer, walletAddress);\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '10' });\n * ```\n */\nexport class CanonicalSymbols implements TokenResolver {\n public readonly passthrough = true;\n\n /** Resolve a bare trading symbol to itself. */\n public resolve(ref: TokenRef): Promise<TradingSymbol> {\n if (typeof ref === 'string' && !isCompositeKey(ref)) {\n return Promise.resolve({\n symbol: ref,\n collection: '',\n category: '',\n type: '',\n additionalKey: '',\n decimals: 0,\n });\n }\n return Promise.reject(GSwapSDKError.unknownTokenError(ref));\n }\n\n /** Put two symbols in canonical (string) order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{ token0: TradingSymbol; token1: TradingSymbol; flipped: boolean }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [first] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n const flipped = first !== resolvedA.symbol;\n return {\n token0: flipped ? resolvedB : resolvedA,\n token1: flipped ? resolvedA : resolvedB,\n flipped,\n };\n }\n\n /** There is no registry state to drop. */\n public invalidate(): void {\n // Nothing is cached: every answer is derived from the reference itself.\n }\n}\n","import type { FEE_TIER } from '../types/fees.js';\nimport type { CompositePool, PoolInfo, PoolListInfo, Slot0 } from '../types/v2_results.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n finiteNumberOf,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { orderSymbols, readOrderedSymbols, type TokenRef } from '../utils/ordering.js';\nimport type { ChainGateway } from './gateway.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, rawTokenOf, tradingSymbolOf, type TokenResolver } from './symbols.js';\nimport { validateFee } from '../utils/validation.js';\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\ntype PoolGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** The sort keys of `GET /v2/trade/pools`. */\nexport type PoolSortBy = 'tvl' | 'volume1d' | 'volume30d';\n\n/** Options of {@link Pools.getPools}. Omit all of `search`, `sortBy`, `sortOrder`, `page`, `limit` for the full, unsorted list. */\nexport interface PoolListOptions {\n signal?: AbortSignal | undefined;\n /** Case-insensitive match on the pair's symbols; `A/B` or `A B` matches either order. At most 64 characters. */\n search?: string | undefined;\n sortBy?: PoolSortBy | undefined;\n sortOrder?: 'asc' | 'desc' | undefined;\n /** 1-based page number; only meaningful together with `limit`. */\n page?: number | undefined;\n /** Rows per page, 1-1000; omitted returns every row. */\n limit?: number | undefined;\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** Options of {@link Pools.watchNewPools}. */\nexport interface WatchNewPoolsOptions {\n /** Milliseconds between polls (default 30 000; a finite number of at least 1). */\n intervalMs?: number | undefined;\n /** Report only a pool whose `tvlUsd` is at least this (a pool without `tvlUsd` counts as 0). */\n minTvl?: number | undefined;\n /** Report only a pool with one of these symbols as `token0` or `token1`. */\n tokens?: readonly string[] | undefined;\n /** Told about a poll that failed and about an `onPool` that threw; polling goes on either way. */\n onError?: ((error: unknown) => void) | undefined;\n}\n\n/** Read-only pool and current-price access for the current GalaChainDex contract. */\nexport class Pools {\n /**\n * Creates a pool service. `options.onInvalidEntry` is told about every pool row that was\n * skipped as unusable (see {@link InvalidEntryHandler}).\n *\n * @example\n * ```ts\n * const pools = new Pools(gateway, symbols);\n * ```\n */\n constructor(\n private readonly gateway: PoolGateway,\n private readonly symbols: TokenResolver,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Fetches current-contract pools from the swap backend, optionally searched, sorted and paged\n * by the backend. A row that is not a usable pool is skipped and reported to `onInvalidEntry`\n * instead of failing the whole list; an answer that is not a list at all is\n * `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const top = await service.getPools({ sortBy: 'tvl', sortOrder: 'desc', page: 1, limit: 8 });\n * console.log(top.length);\n * ```\n */\n public async getPools(options?: PoolListOptions): Promise<PoolListInfo[]> {\n const response = await this.http.sendGetRequest<BackendEnvelope<unknown>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/pools',\n poolListParams(options),\n options?.signal === undefined ? undefined : { signal: options.signal },\n );\n return readEntries(\n 'pools',\n response.data,\n parsePoolListInfo,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n }\n\n /**\n * Watches for pools created from now on, by polling {@link Pools.getPools} every `intervalMs`\n * (the polling alternative to the realtime stream's `GSwap.stream.subscribePoolCreated`, for a\n * client that cannot hold a WebSocket open). The first answer is the baseline: a pool that\n * existed then is never reported. Each later pool is judged once, when it first appears, against\n * `minTvl` and `tokens`. A poll never overlaps the previous one (a tick that finds one still in\n * flight is skipped), and nothing is reported after the returned function stops the watcher.\n *\n * @example\n * ```ts\n * const stop = gSwap.pools.watchNewPools((pool) => console.log('new pool', pool.poolRef), {\n * intervalMs: 60_000,\n * tokens: ['GALA'],\n * });\n * // later\n * stop();\n * ```\n */\n public watchNewPools(\n onPool: (pool: PoolListInfo) => void,\n options: WatchNewPoolsOptions = {},\n ): () => void {\n const intervalMs = options.intervalMs ?? 30_000;\n if (typeof intervalMs !== 'number' || !Number.isFinite(intervalMs) || intervalMs < 1) {\n throw new GSwapSDKError('INVALID_POLL_INTERVAL', { value: String(intervalMs) });\n }\n let known: Set<string> | undefined;\n let stopped = false;\n let polling = false;\n const report = (error: unknown): void => {\n try {\n options.onError?.(error);\n } catch {\n // A diagnostics hook must not stop the watcher.\n }\n };\n const wanted = (pool: PoolListInfo): boolean =>\n (options.minTvl === undefined || (pool.tvlUsd ?? 0) >= options.minTvl) &&\n (options.tokens === undefined ||\n options.tokens.includes(pool.token0) ||\n options.tokens.includes(pool.token1));\n const poll = async (): Promise<void> => {\n if (stopped || polling) return;\n polling = true;\n try {\n const pools = await this.getPools();\n if (known === undefined) {\n known = new Set(pools.map((pool) => pool.poolRef));\n return;\n }\n for (const pool of pools) {\n if (stopped) return;\n if (known.has(pool.poolRef)) continue;\n known.add(pool.poolRef);\n if (!wanted(pool)) continue;\n try {\n onPool(pool);\n } catch (error: unknown) {\n report(error);\n }\n }\n } catch (error: unknown) {\n if (!stopped) report(error);\n } finally {\n polling = false;\n }\n };\n void poll();\n const timer = setInterval(() => void poll(), intervalMs);\n return () => {\n stopped = true;\n clearInterval(timer);\n };\n }\n\n /**\n * Fetches one pool from the backend, preserving whether the request order was flipped.\n *\n * @example\n * ```ts\n * const pool = await service.getPool('GUSDC', 'GALA', 3000);\n * console.log(pool.flippedFromRequest);\n * ```\n */\n public async getPool(token0: TokenRef, token1: TokenRef, fee: FEE_TIER): Promise<PoolInfo> {\n validateFee(fee);\n return this.getBackend<PoolInfo>('/pool', await this.backendParams(token0, token1, fee));\n }\n\n /**\n * Fetches the current sqrt price, price, and tick for one pool.\n *\n * @example\n * ```ts\n * const slot0 = await service.getSlot0('GALA', 'GUSDC', 3000);\n * console.log(slot0.tick);\n * ```\n */\n public async getSlot0(token0: TokenRef, token1: TokenRef, fee: FEE_TIER): Promise<Slot0> {\n validateFee(fee);\n return this.getBackend<Slot0>('/slot0', await this.backendParams(token0, token1, fee));\n }\n\n /**\n * Fetches the complete chain composite pool snapshot, in canonical symbol order.\n *\n * @example\n * ```ts\n * const composite = await service.getCompositePool('GALA', 'GUSDC', 3000);\n * console.log(composite.positions?.length ?? 0);\n * ```\n */\n public async getCompositePool(\n token0: TokenRef,\n token1: TokenRef,\n fee: FEE_TIER,\n ): Promise<CompositePool> {\n validateFee(fee);\n if (this.symbols.passthrough === true) {\n return this.getBackend<CompositePool>('/composite-pool', {\n token0: rawTokenOf(token0),\n token1: rawTokenOf(token1),\n fee: String(fee),\n });\n }\n const first = await tradingSymbolOf(this.symbols, token0);\n const second = await tradingSymbolOf(this.symbols, token1);\n const ordered = readOrderedSymbols(orderSymbols(first, second));\n return this.getBackend<CompositePool>('/composite-pool', {\n token0: ordered.token0,\n token1: ordered.token1,\n fee: String(fee),\n });\n }\n\n private async backendParams(\n token0: TokenRef,\n token1: TokenRef,\n fee: FEE_TIER,\n ): Promise<Record<string, string>> {\n return {\n token0: await queryTokenOf(this.symbols, token0),\n token1: await queryTokenOf(this.symbols, token1),\n fee: String(fee),\n };\n }\n\n private async getBackend<T>(endpoint: string, params: Record<string, string>): Promise<T> {\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<T>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n );\n return response.data;\n } catch (error: unknown) {\n // Any SDK error passes through, core's transport errors (`REQUEST_TIMEOUT`,\n // `TRANSPORT_ERROR`, a plain `GalaSDKError`) included: only a foreign failure is wrapped.\n if (isGSwapError(error)) throw error;\n throw new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'pool' },\n { cause: error, write: false },\n );\n }\n }\n}\n\nconst SORT_KEYS: readonly string[] = ['tvl', 'volume1d', 'volume30d'];\nconst MAX_SEARCH_LENGTH = 64;\nconst MAX_PAGE_SIZE = 1000;\n\n/** The pool-list query, in the order the apps write it: search, sortBy, sortOrder, page, limit. */\nfunction poolListParams(options: PoolListOptions | undefined): Record<string, string> | undefined {\n if (options === undefined) return undefined;\n const params: Record<string, string> = {};\n if (options.search !== undefined) {\n if (options.search.length > MAX_SEARCH_LENGTH) {\n throw new GSwapSDKError('SEARCH_TOO_LONG', {\n length: options.search.length,\n maxLength: MAX_SEARCH_LENGTH,\n });\n }\n params['search'] = options.search;\n }\n if (options.sortBy !== undefined) {\n if (!SORT_KEYS.includes(options.sortBy)) {\n throw new GSwapSDKError('INVALID_SORT_BY', {\n value: String(options.sortBy),\n allowed: SORT_KEYS.join(','),\n });\n }\n params['sortBy'] = options.sortBy;\n }\n if (options.sortOrder !== undefined) {\n if (options.sortOrder !== 'asc' && options.sortOrder !== 'desc') {\n throw new GSwapSDKError('INVALID_SORT_ORDER', { value: String(options.sortOrder) });\n }\n params['sortOrder'] = options.sortOrder;\n }\n if (options.page !== undefined) {\n if (!Number.isInteger(options.page) || options.page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: options.page });\n }\n params['page'] = String(options.page);\n }\n if (options.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > MAX_PAGE_SIZE) {\n throw new GSwapSDKError('INVALID_LIMIT', {\n value: options.limit,\n min: 1,\n max: MAX_PAGE_SIZE,\n });\n }\n params['limit'] = String(options.limit);\n }\n return Object.keys(params).length === 0 ? undefined : params;\n}\n\nconst OPTIONAL_POOL_STRINGS = [\n 'poolName',\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'creator',\n 'price',\n 'sqrtPrice',\n 'token0Tvl',\n 'token1Tvl',\n] as const;\n\nconst OPTIONAL_POOL_NUMBERS = [\n 'tickSpacing',\n 'protocolFees',\n 'tradingFees',\n 'tick',\n 'volume1d',\n 'volume7d',\n 'volume30d',\n 'trades1d',\n 'fee24h',\n 'token0Price',\n 'token1Price',\n] as const;\n\n/** Fields the apps accept as a number or a numeric string (the wallet does `Number(row.x)`). */\nconst NUMERIC_POOL_FIELDS = ['fee', 'tvlUsd', 'apr1d'] as const;\n\n/**\n * Reads one pool-list row the way the apps do: the identity (`token0`, `token1`, `poolRef`) and\n * `fee` must be usable, every other field is optional but, when present, must have its type.\n * `fee`, `tvlUsd` and `apr1d` may arrive as numeric strings and are returned as numbers. Fields\n * the SDK does not know are kept.\n */\nfunction parsePoolListInfo(entry: unknown): EntryParse<PoolListInfo> {\n const row = asEntryRecord(entry);\n if (row === undefined) return entryRejected('the row is not an object');\n for (const key of ['token0', 'token1', 'poolRef'] as const) {\n if (typeof row[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n if (row['contractVersion'] !== undefined && row['contractVersion'] !== 'v2') {\n return entryRejected('contractVersion is not v2');\n }\n const normalized: Record<string, unknown> = { ...row };\n for (const key of NUMERIC_POOL_FIELDS) {\n const raw = row[key];\n if (raw === undefined && key !== 'fee') continue;\n const value = finiteNumberOf(raw);\n if (value === undefined) return entryRejected(`${key} is not a number`);\n normalized[key] = value;\n }\n for (const key of OPTIONAL_POOL_STRINGS) {\n if (row[key] !== undefined && typeof row[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n for (const key of OPTIONAL_POOL_NUMBERS) {\n const value = row[key];\n if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value))) {\n return entryRejected(`${key} is not a number`);\n }\n }\n return entryOk(normalized as unknown as PoolListInfo);\n}\n","/**\n * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an\n * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error\n * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they\n * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.\n */\n\n/** True for a tick spacing the contract can use: a positive integer. The one definition. */\nexport function hasValidSpacing(spacing: number): boolean {\n return Number.isInteger(spacing) && spacing > 0;\n}\n\n/**\n * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`\n * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose\n * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,\n * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use\n * it) gives the same value and throws for the bad spacing.\n *\n * @example\n * ```ts\n * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero\n * alignTickDownOrNaN(100, 0); // NaN\n * ```\n */\nexport function alignTickDownOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : Number.NaN;\n}\n\n/**\n * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that\n * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See\n * {@link alignTickDownOrNaN}.\n */\nexport function alignTickUpOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : Number.NaN;\n}\n","import { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport { alignTickDownOrNaN, alignTickUpOrNaN, hasValidSpacing } from './tick_align.js';\nimport { DexDecimal, GC_MAX_TICK, GC_MIN_TICK, sqrtPriceToTick } from './tick_math.js';\n\n/**\n * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,\n * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,\n * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which\n * does not import the error class or the catalog; import it from the package entry as usual.\n */\n\n/** Align a tick down to the nearest multiple of a positive spacing. */\nexport function alignTickDown(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickDownOrNaN(tick, spacing);\n}\n\n/** Align a tick up to the nearest multiple of a positive spacing. */\nexport function alignTickUp(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickUpOrNaN(tick, spacing);\n}\n\n/** Validate a position range against the global tick bounds and fee-tier spacing. */\nexport function assertTickRange(lower: number, upper: number, fee: FEE_TIER): void {\n const spacing = TICK_SPACING_BY_FEE[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n if (!Number.isInteger(lower) || !Number.isInteger(upper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower: lower, tickUpper: upper });\n }\n if (lower >= upper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower: lower, tickUpper: upper });\n }\n if (lower < GC_MIN_TICK || upper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower: lower,\n tickUpper: upper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n if (lower % spacing !== 0 || upper % spacing !== 0) {\n throw new GSwapSDKError('TICKS_NOT_ALIGNED', {\n tickLower: lower,\n tickUpper: upper,\n spacing,\n });\n }\n}\n\nfunction assertSpacing(spacing: number): void {\n if (!hasValidSpacing(spacing)) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: spacing });\n }\n}\n\n/** A pool's current price in the frame of the request that asked for it. */\nexport interface FramedSlot0 {\n /** The square-root price, token1 per token0 in the REQUESTED order. */\n sqrtPrice: string;\n /** The greatest tick whose square-root price is no greater than `sqrtPrice`. */\n tick: number;\n}\n\n/**\n * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's\n * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse\n * order the price is inverted here (at 60 significant digits, so a very large or very small\n * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the\n * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks\n * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).\n *\n * @example\n * ```ts\n * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);\n * const { sqrtPrice, tick } = frameSlot0(slot0);\n * ```\n */\nexport function frameSlot0(slot0: {\n sqrtPrice: string;\n tick: number;\n flippedFromRequest?: boolean | undefined;\n}): FramedSlot0 {\n if (slot0.flippedFromRequest !== true) return { sqrtPrice: slot0.sqrtPrice, tick: slot0.tick };\n const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));\n if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_SQRT_PRICE', { sqrtPrice: slot0.sqrtPrice });\n }\n const sqrtPrice = inverted.toString();\n return { sqrtPrice, tick: sqrtPriceToTick(sqrtPrice) };\n}\n","import { assertUniqueKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount, SwapAmount } from '../types/amounts.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n RequestTradeDTO,\n} from '../types/v2_dtos.js';\nimport { assertTickRange } from './ticks.js';\nimport {\n assertCanonicalPair,\n isProposableTradingSymbol,\n validateFee,\n validateNumericAmount,\n} from './validation.js';\n\n// The pure builders of every v2 write DTO. They validate, canonicalize decimals\n// (`BigNumber#toFixed`) and fix the key order, and nothing else: no network, no signer, no\n// clock, no randomness — the `uniqueKey` is an input. The `Swaps` and `Positions` services call\n// exactly these functions, so a DTO an app builds here (to show in an approval popup, to sign on\n// another device, to submit later) is the DTO the services would have built.\n//\n// Inputs are already CANONICAL: `token0 < token1` by plain string comparison, ticks and prices in\n// that orientation. Orienting a caller's pair (and inverting its ticks and price) is the\n// services' job; a reversed pair is refused (`NON_CANONICAL_PAIR`) rather than silently signed.\n\nconst decimalString = (amount: NumericAmount): string => new BigNumber(amount).toFixed();\n\n/** The pool a RequestTrade trades in, its fee tier, the `uniqueKey` and what is traded. */\nexport type RequestTradeInput = {\n /** Canonical pool symbols: `token0 < token1`. Take them from a quote verbatim. */\n token0: string;\n token1: string;\n fee: number;\n /** Which side of the pool is sold: `true` when the input token is `token0`. */\n tokenInIsToken0: boolean;\n uniqueKey: string;\n} & SwapAmount;\n\n/**\n * Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or\n * `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the\n * side's slippage bound and an optional `priceLimit`. Key order is\n * `token0, token1, fee, uniqueKey`, then the one quantity, then the slippage bound, then\n * `priceLimit`.\n *\n * @example\n * ```ts\n * const dto = buildRequestTradeDto({\n * token0: quote.token0Symbol, token1: quote.token1Symbol,\n * tokenInIsToken0: quote.tokenInIsToken0, fee: quote.fee,\n * uniqueKey: createUniqueKey('galaswap-operation-'),\n * exactIn: '100', amountOutMinimum: '14',\n * });\n * ```\n */\nexport function buildRequestTradeDto(input: RequestTradeInput): RequestTradeDTO {\n validateFee(input.fee);\n assertCanonicalPair(input.token0, input.token1);\n assertUniqueKey(input.uniqueKey);\n const dto: Record<string, unknown> = {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n uniqueKey: input.uniqueKey,\n };\n if ('exactIn' in input) {\n const exactIn = input.exactIn;\n if (exactIn === undefined) {\n throw new GSwapSDKError('EXACT_AMOUNT_REQUIRED', { field: 'exactIn' });\n }\n validateNumericAmount(exactIn, 'exactIn');\n dto[input.tokenInIsToken0 ? 'sell0Qty' : 'sell1Qty'] = decimalString(exactIn);\n if (input.amountOutMinimum !== undefined) {\n validateNumericAmount(input.amountOutMinimum, 'amountOutMinimum', true);\n dto['amountOutMinimum'] = decimalString(input.amountOutMinimum);\n }\n } else {\n const exactOut = input.exactOut;\n if (exactOut === undefined) {\n throw new GSwapSDKError('EXACT_AMOUNT_REQUIRED', { field: 'exactOut' });\n }\n validateNumericAmount(exactOut, 'exactOut');\n dto[input.tokenInIsToken0 ? 'buy1Qty' : 'buy0Qty'] = decimalString(exactOut);\n if (input.amountInMaximum !== undefined) {\n validateNumericAmount(input.amountInMaximum, 'amountInMaximum', true);\n dto['amountInMaximum'] = decimalString(input.amountInMaximum);\n }\n }\n if (input.priceLimit !== undefined) {\n validateNumericAmount(input.priceLimit, 'priceLimit');\n dto['priceLimit'] = decimalString(input.priceLimit);\n }\n return dto as unknown as RequestTradeDTO;\n}\n\n/** A canonical pool position: the pair, fee tier, tick range and the attempt's `uniqueKey`. */\nexport interface PoolPositionInput {\n token0: string;\n token1: string;\n fee: number;\n tickLower: number;\n tickUpper: number;\n uniqueKey: string;\n}\n\nfunction assertPoolPosition(input: PoolPositionInput): void {\n validateFee(input.fee);\n assertCanonicalPair(input.token0, input.token1);\n assertTickRange(input.tickLower, input.tickUpper, input.fee);\n assertUniqueKey(input.uniqueKey);\n}\n\n/** Exactly one canonical deposit side. */\nexport type AddLiquidityInput = PoolPositionInput &\n (\n | { depositQuantityToken0: NumericAmount; depositQuantityToken1?: undefined }\n | { depositQuantityToken0?: undefined; depositQuantityToken1: NumericAmount }\n );\n\n/**\n * Builds the AddLiquidity DTO: exactly one of `depositQuantityToken0` / `depositQuantityToken1`\n * (the other side is derived on chain). Key order: `token0, token1, fee, tickLower, tickUpper,\n * uniqueKey, <deposit>`.\n */\nexport function buildAddLiquidityDto(input: AddLiquidityInput): AddLiquidityDTO {\n assertPoolPosition(input);\n const side = onlyOne(\n input.depositQuantityToken0,\n input.depositQuantityToken1,\n 'depositQuantityToken0',\n 'depositQuantityToken1',\n );\n if (side === undefined) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'depositQuantityToken0',\n second: 'depositQuantityToken1',\n });\n }\n validateNumericAmount(side.amount, side.name);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n [side.name]: decimalString(side.amount),\n } as AddLiquidityDTO;\n}\n\n/** At most one canonical withdrawal side; neither closes the position. */\nexport type RemoveLiquidityInput = PoolPositionInput & {\n withdrawalQuantityToken0?: NumericAmount | undefined;\n withdrawalQuantityToken1?: NumericAmount | undefined;\n};\n\n/**\n * Builds the RemoveLiquidity DTO: at most one of `withdrawalQuantityToken0` /\n * `withdrawalQuantityToken1`; omitting both closes the position and sweeps its fees.\n */\nexport function buildRemoveLiquidityDto(input: RemoveLiquidityInput): RemoveLiquidityDTO {\n assertPoolPosition(input);\n const side = onlyOne(\n input.withdrawalQuantityToken0,\n input.withdrawalQuantityToken1,\n 'withdrawalQuantityToken0',\n 'withdrawalQuantityToken1',\n true,\n );\n if (side !== undefined) validateNumericAmount(side.amount, side.name);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n ...(side === undefined ? {} : { [side.name]: decimalString(side.amount) }),\n };\n}\n\n/** Builds the CollectPositionFees DTO (the contract sweeps all of a position's fees). */\nexport function buildCollectPositionFeesDto(input: PoolPositionInput): CollectPositionFeesDTO {\n assertPoolPosition(input);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n };\n}\n\n/** A CreatePool in canonical orientation, with exactly one starting price. */\nexport type CreatePoolInput = {\n token0Key: GalaChainTokenClassKey;\n token1Key: GalaChainTokenClassKey;\n /** The symbols to register; `token0Symbol < token1Symbol` and both proposable. */\n token0Symbol: string;\n token1Symbol: string;\n fee: number;\n /** Optional display name; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n uniqueKey: string;\n} & (\n | { startingPrice: NumericAmount; startingSqrtPrice?: undefined }\n | { startingPrice?: undefined; startingSqrtPrice: NumericAmount }\n);\n\n/**\n * Builds the CreatePool DTO. Key order: `token0Key, token1Key, fee, startingPrice |\n * startingSqrtPrice, token0Symbol, token1Symbol, uniqueKey, name, isPrivate, privateAccess`.\n * Prices are those of the canonical pair (token1 per token0); a price quoted the other way round\n * is inverted by the caller before it gets here.\n */\nexport function buildCreatePoolDto(input: CreatePoolInput): CreatePoolDTO {\n validateFee(input.fee);\n assertUniqueKey(input.uniqueKey);\n assertCanonicalPair(input.token0Symbol, input.token1Symbol);\n for (const symbol of [input.token0Symbol, input.token1Symbol]) {\n if (!isProposableTradingSymbol(symbol)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol });\n }\n }\n for (const key of [input.token0Key, input.token1Key]) assertClassKey(key);\n const price = onlyOne(\n input.startingPrice,\n input.startingSqrtPrice,\n 'startingPrice',\n 'startingSqrtPrice',\n );\n if (price === undefined) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n if (typeof price.amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: price.name });\n }\n const parsed = new BigNumber(price.amount);\n if (!parsed.isFinite() || parsed.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(price.amount) });\n }\n return {\n token0Key: input.token0Key,\n token1Key: input.token1Key,\n fee: input.fee,\n [price.name]: parsed.toFixed(),\n token0Symbol: input.token0Symbol,\n token1Symbol: input.token1Symbol,\n uniqueKey: input.uniqueKey,\n // An empty name is \"no name\", as the Gala web app's builder treats it (its form yields '').\n ...(input.name === undefined || input.name === '' ? {} : { name: input.name }),\n ...(input.isPrivate === undefined ? {} : { isPrivate: input.isPrivate }),\n ...(input.privateAccess === undefined ? {} : { privateAccess: input.privateAccess }),\n } as CreatePoolDTO;\n}\n\nfunction assertClassKey(key: GalaChainTokenClassKey): void {\n for (const part of ['collection', 'category', 'type', 'additionalKey'] as const) {\n if (typeof key[part] !== 'string' || key[part].length === 0) {\n throw new GSwapSDKError('INCOMPLETE_TOKEN_CLASS_KEY', {\n compositeKey: [key.collection, key.category, key.type, key.additionalKey].join('$'),\n part,\n });\n }\n }\n}\n\n/**\n * Of two mutually exclusive fields, the one that is set (`undefined` when neither is);\n * both set is an error (`AT_MOST_ONE_OF_ALLOWED` or `EXACTLY_ONE_OF_REQUIRED`), and so is\n * neither unless `allowNeither`.\n */\nfunction onlyOne<T>(\n first: T | undefined,\n second: T | undefined,\n firstName: string,\n secondName: string,\n allowNeither = false,\n): { name: string; amount: T } | undefined {\n if (first !== undefined && second !== undefined) {\n throw allowNeither\n ? new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: firstName, second: secondName })\n : new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', { first: firstName, second: secondName });\n }\n if (first !== undefined) return { name: firstName, amount: first };\n if (second !== undefined) return { name: secondName, amount: second };\n return undefined;\n}\n\n/** The methods whose DTOs the builders produce. */\nexport type V2WriteMethod =\n 'RequestTrade' | 'AddLiquidity' | 'RemoveLiquidity' | 'CollectPositionFees' | 'CreatePool';\n\ntype DtoExpectation =\n 'string' | 'number' | 'boolean' | 'class_key' | 'string_array' | 'exactly_once';\n\nfunction invalidDto(\n method: string,\n field: string,\n expected: DtoExpectation,\n): GSwapSDKError<'INVALID_DTO'> {\n return new GSwapSDKError('INVALID_DTO', { method, field, expected });\n}\n\n/**\n * Rebuilds a DTO from its own fields with the builder of its method: the canonical form of the\n * DTO, with the same validation. Key order and decimal text are the builder's.\n */\nfunction rebuildV2Dto(\n method: V2WriteMethod,\n dto: Record<string, unknown>,\n): Record<string, unknown> {\n const text = (field: string): string => {\n const value = dto[field];\n if (typeof value !== 'string') throw invalidDto(method, field, 'string');\n return value;\n };\n const integer = (field: string): number => {\n const value = dto[field];\n if (typeof value !== 'number') throw invalidDto(method, field, 'number');\n return value;\n };\n const optionalText = (field: string): string | undefined =>\n dto[field] === undefined ? undefined : text(field);\n const classKey = (field: string): GalaChainTokenClassKey => {\n const value = dto[field];\n if (typeof value !== 'object' || value === null) throw invalidDto(method, field, 'class_key');\n const key = value as Record<string, unknown>;\n const part = (name: string): string => {\n if (typeof key[name] !== 'string') throw invalidDto(method, `${field}.${name}`, 'string');\n return key[name];\n };\n return {\n collection: part('collection'),\n category: part('category'),\n type: part('type'),\n additionalKey: part('additionalKey'),\n };\n };\n // The pool pair is not a field of CreatePool, so these are read per method, not up front.\n const base = () => ({ token0: text('token0'), token1: text('token1'), fee: integer('fee') });\n const uniqueKey = text('uniqueKey');\n const position = () => ({\n ...base(),\n uniqueKey,\n tickLower: integer('tickLower'),\n tickUpper: integer('tickUpper'),\n });\n switch (method) {\n case 'RequestTrade': {\n const qty = ['sell0Qty', 'sell1Qty', 'buy0Qty', 'buy1Qty'].filter(\n (f) => dto[f] !== undefined,\n );\n const [field] = qty;\n if (qty.length !== 1 || field === undefined) {\n throw invalidDto(method, 'sell0Qty|sell1Qty|buy0Qty|buy1Qty', 'exactly_once');\n }\n const tokenInIsToken0 = field === 'sell0Qty' || field === 'buy1Qty';\n const shared = { ...base(), uniqueKey, tokenInIsToken0 };\n const priceLimit = optionalText('priceLimit');\n return field.startsWith('sell')\n ? buildRequestTradeDto({\n ...shared,\n exactIn: text(field),\n amountOutMinimum: optionalText('amountOutMinimum'),\n priceLimit,\n })\n : buildRequestTradeDto({\n ...shared,\n exactOut: text(field),\n amountInMaximum: optionalText('amountInMaximum'),\n priceLimit,\n });\n }\n case 'AddLiquidity': {\n const token0Side = optionalText('depositQuantityToken0');\n const token1Side = optionalText('depositQuantityToken1');\n return buildAddLiquidityDto({\n ...position(),\n ...(token0Side === undefined\n ? { depositQuantityToken1: token1Side as string }\n : { depositQuantityToken0: token0Side }),\n });\n }\n case 'RemoveLiquidity':\n return buildRemoveLiquidityDto({\n ...position(),\n withdrawalQuantityToken0: optionalText('withdrawalQuantityToken0'),\n withdrawalQuantityToken1: optionalText('withdrawalQuantityToken1'),\n });\n case 'CollectPositionFees':\n return buildCollectPositionFeesDto(position());\n case 'CreatePool': {\n const price = optionalText('startingPrice');\n const sqrtPrice = optionalText('startingSqrtPrice');\n const privateAccess = dto['privateAccess'];\n if (\n privateAccess !== undefined &&\n (!Array.isArray(privateAccess) || privateAccess.some((entry) => typeof entry !== 'string'))\n ) {\n throw invalidDto(method, 'privateAccess', 'string_array');\n }\n if (dto['isPrivate'] !== undefined && typeof dto['isPrivate'] !== 'boolean') {\n throw invalidDto(method, 'isPrivate', 'boolean');\n }\n return buildCreatePoolDto({\n token0Key: classKey('token0Key'),\n token1Key: classKey('token1Key'),\n token0Symbol: text('token0Symbol'),\n token1Symbol: text('token1Symbol'),\n fee: integer('fee'),\n uniqueKey,\n name: optionalText('name'),\n isPrivate: dto['isPrivate'],\n privateAccess: privateAccess as string[] | undefined,\n ...(price === undefined\n ? { startingSqrtPrice: sqrtPrice as string }\n : { startingPrice: price }),\n });\n }\n }\n}\n\n/**\n * Asserts that `dto` is EXACTLY what the builder of `method` produces for its own fields — the\n * same fields, canonical decimal text, builder key order, nothing extra (no `signature`). The\n * `submit*` methods use it so that what an app showed a user (a DTO it built) is byte for byte\n * what gets signed; a DTO edited by hand, or built elsewhere, is refused rather than signed.\n *\n * @throws GSwapSDKError `INVALID_DTO` or `DTO_NOT_CANONICAL`.\n */\nexport function assertCanonicalV2Dto(method: V2WriteMethod, dto: Record<string, unknown>): void {\n const rebuilt = rebuildV2Dto(method, dto);\n if (JSON.stringify(rebuilt) !== JSON.stringify(dto)) {\n throw new GSwapSDKError('DTO_NOT_CANONICAL', { method });\n }\n}\n","import {\n assertUniqueKey,\n compositeKeyOf,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport type { ChainGateway, ChainSubmitOptions } from './gateway.js';\nimport type { PositionConfirmationResult, SubmittedTransaction } from './submitted_transaction.js';\nimport { HttpClient } from './http_client.js';\nimport { rawTokenOf, type Symbols, type TokenResolver } from './symbols.js';\nimport type { NumericAmount, PriceIn } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n} from '../types/v2_dtos.js';\nimport type {\n AddLiquidityEstimate,\n Position,\n RemoveLiquidityEstimate,\n} from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { type TokenRef, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport {\n isProposableTradingSymbol,\n validateFee,\n userRef,\n validateNumericAmount,\n} from '../utils/validation.js';\nimport { tickFromPrice } from '../utils/tick_math.js';\nimport { alignTickDown, alignTickUp, assertTickRange } from '../utils/ticks.js';\nimport {\n assertCanonicalV2Dto,\n buildAddLiquidityDto,\n buildCollectPositionFeesDto,\n buildCreatePoolDto,\n buildRemoveLiquidityDto,\n} from '../utils/dto_builders.js';\n\ntype PositionGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n submit: (\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<Position | null>>;\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\ntype PositionSymbols = TokenResolver & Pick<Symbols, 'orderPair'> & { invalidate?: () => void };\n\n/** Options of {@link Positions}: the `uniqueKey` prefix and a handler for skipped list rows. */\nexport interface PositionsOptions extends UniqueKeyOptions {\n /** Told about every position row of a list that was skipped as unusable. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** A write's optional attempt identity. */\ninterface UniqueKeyArg {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing, or to retry the SAME\n * attempt after a lost response; never reuse it for another write.\n */\n uniqueKey?: string | undefined;\n}\n\n/** Arguments of {@link Positions.addLiquidityByTicks} and {@link Positions.buildAddLiquidity}. */\nexport interface AddLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n /** Whether `amount` is of `token0` as the caller passed it (not of the canonical token0). */\n amountIsToken0: boolean;\n}\n\n/** Arguments of {@link Positions.removeLiquidity} and {@link Positions.buildRemoveLiquidity}. */\nexport interface RemoveLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n /** Withdraw this much of the caller's `token0`; give at most one of `amount0` / `amount1`. */\n amount0?: NumericAmount | undefined;\n amount1?: NumericAmount | undefined;\n}\n\n/** Arguments of {@link Positions.collectPositionFees} and {@link Positions.buildCollectPositionFees}. */\nexport interface CollectPositionFeesArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Arguments of {@link Positions.createPool} and {@link Positions.buildCreatePool}. */\nexport interface CreatePoolArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n token0Symbol?: string | undefined;\n token1Symbol?: string | undefined;\n fee: FEE_TIER;\n startingPrice?: NumericAmount | undefined;\n startingSqrtPrice?: NumericAmount | undefined;\n /** Optional pool display name, sent as the DTO's `name`; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n}\n\n/** The pool position a liquidity DTO names, as its confirmation needs it. */\nfunction identityOf(\n dto: Pick<CollectPositionFeesDTO, 'token0' | 'token1' | 'fee' | 'tickLower' | 'tickUpper'>,\n): PositionIdentity {\n return {\n token0: dto.token0,\n token1: dto.token1,\n fee: dto.fee,\n tickLower: dto.tickLower,\n tickUpper: dto.tickUpper,\n };\n}\n\n/**\n * The outcome of {@link Positions.readPosition}. Only `not_found` is chain-confirmed absence (the\n * backend answers HTTP 404 only when the chain itself found no such position); `unknown` is \"no\n * evidence either way\" — a transport failure, a gateway timeout, any other error status or an\n * answer that is not a position — and must never be read as a removal.\n */\nexport type PositionRead =\n | { kind: 'found'; data: Position }\n | { kind: 'not_found' }\n | { kind: 'unknown'; error: GSwapSDKError };\n\ninterface BackendEnvelope<TData> {\n data: TData;\n}\n\ninterface AddLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n liquidity: string;\n token0Symbol: string;\n token1Symbol: string;\n tickLower: number;\n tickUpper: number;\n amountIsCanonicalToken0: boolean;\n}\n\ninterface RemoveLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n}\n\ninterface ResolvedCreateToken {\n symbol: string;\n classKey: ReturnType<typeof parseTokenClassKey>;\n}\n\ninterface PositionIdentity {\n token0: string;\n token1: string;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Tells `submit()` how to prove a write's own effect for `SubmittedTransaction.confirm()`. */\ntype PositionSubmitConfirmation =\n | { kind: 'add' | 'removePartial' | 'removeFull' | 'collect'; identity: PositionIdentity }\n | { kind: 'createPool'; token0: string; token1: string; fee: FEE_TIER };\n\n/**\n * Manages current-contract concentrated-liquidity positions.\n *\n * @example\n * ```typescript\n * const positions = gSwap.positions;\n * const mine = await positions.getUserPositions('client|012345678901234567890123');\n * console.log(mine.length);\n * ```\n */\nexport class Positions {\n constructor(\n private readonly gateway: PositionGateway,\n private readonly symbols: PositionSymbols,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: PositionsOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n this.onInvalidEntry = options.onInvalidEntry;\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly http: HttpClient;\n private readonly uniqueKeyPrefix: string;\n private readonly onInvalidEntry: InvalidEntryHandler | undefined;\n\n /**\n * Gets all current-contract positions owned by an address.\n *\n * @param owner - GalaChain owner identity.\n * @returns Enriched positions from the v2 trade backend, token images included. A row that is\n * not a usable position is skipped and reported to `onInvalidEntry`.\n * @example\n * ```typescript\n * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');\n * ```\n */\n async getUserPositions(owner: string): Promise<Position[]> {\n const response = await this.get<unknown>('/positions', { user: userRef(owner, 'owner') });\n return readEntries('positions', response.data, parsePosition, this.onInvalidEntry);\n }\n\n /**\n * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.\n * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.\n *\n * @param args - Pair, owner, fee, and position tick range.\n * @returns The position, or `null` when the backend returns 404.\n * @example\n * ```typescript\n * const position = await gSwap.positions.getPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async getPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<Position | null> {\n const response = await this.getNullable<unknown>(\n '/position',\n await this.positionParams(args),\n signal,\n );\n return response === null ? null : readPositionBody(response.data);\n }\n\n /**\n * Reads one position and classifies the outcome instead of throwing: `found` with the position\n * (fees included), `not_found` (the backend's HTTP 404, which it sends only when the chain\n * itself has no such position) or `unknown` (any other failure, carried as `error`). Use it\n * to confirm a write: `unknown` is \"no evidence either way\", never a confirmed absence.\n *\n * Only the caller's own abort rethrows. With a pass-through resolver ({@link CanonicalSymbols})\n * the pair and ticks go to the backend exactly as given and the backend orients them.\n *\n * @example\n * ```typescript\n * const read = await gSwap.positions.readPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * if (read.kind === 'found') console.log(read.data.fees0);\n * ```\n */\n async readPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<PositionRead> {\n try {\n const position = await this.getPosition(args, signal);\n return position === null ? { kind: 'not_found' } : { kind: 'found', data: position };\n } catch (error: unknown) {\n if (signal?.aborted === true) throw error;\n return {\n kind: 'unknown',\n error: isGSwapError(error)\n ? error\n : new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'position' },\n { cause: error, write: false },\n ),\n };\n }\n }\n\n /**\n * The `/position` query: canonical symbols and canonical ticks after a client-side flip, or,\n * for a pass-through resolver, the caller's references and ticks untouched.\n */\n private async positionParams(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n }): Promise<Record<string, string>> {\n // The backend matches `owner` against the chain's position owner with strict equality, so\n // only the chain's own spelling (`eth|<EIP-55>`) finds a position.\n const owner = userRef(args.owner, 'owner');\n if (this.symbols.passthrough === true) {\n return {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n owner,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n };\n }\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n return {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: `${args.fee}`,\n owner,\n tickLower: `${ticks.tickLower}`,\n tickUpper: `${ticks.tickUpper}`,\n };\n }\n\n /**\n * Estimates the other token amount and resulting liquidity for a deposit.\n *\n * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.\n * @returns Backend liquidity estimate.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async estimateAddLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n amountIsToken0: boolean;\n }): Promise<AddLiquidityEstimate> {\n validateNumericAmount(args.amount, 'amount');\n const response = await this.get<AddLiquidityEstimateWire>('/add-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n amount: new BigNumber(args.amount).toFixed(),\n amountIsToken0: String(args.amountIsToken0),\n });\n return response.data;\n }\n\n /**\n * Estimates token amounts released by burning liquidity.\n *\n * @param args - Pair, tick range, fee tier, and liquidity quantity.\n * @returns Estimated token0 and token1 quantities.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateRemoveLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, liquidity: '1000',\n * });\n * ```\n */\n async estimateRemoveLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n liquidity: NumericAmount;\n }): Promise<RemoveLiquidityEstimate> {\n validateNumericAmount(args.liquidity, 'liquidity');\n const response = await this.get<RemoveLiquidityEstimateWire>('/remove-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n liquidity: new BigNumber(args.liquidity).toFixed(),\n });\n return response.data;\n }\n\n /**\n * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.\n *\n * @param args - Pair, fee, range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByTicks({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * await tx.confirm();\n * ```\n */\n async addLiquidityByTicks(args: AddLiquidityArgs) {\n return this.submitAddLiquidity(await this.buildAddLiquidity(args));\n }\n\n /**\n * Builds the AddLiquidity DTO that {@link addLiquidityByTicks} would sign, without signing or\n * sending it: to show in an approval popup, or to sign elsewhere. Submit exactly this DTO with\n * {@link submitAddLiquidity}. The pure counterpart, with canonical inputs and no resolution,\n * is `buildAddLiquidityDto`.\n *\n * @example\n * ```typescript\n * const dto = await gSwap.positions.buildAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async buildAddLiquidity(args: AddLiquidityArgs): Promise<AddLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n // Caller-facing checks first, so a refusal names the caller's own argument (`amount`).\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n validateNumericAmount(args.amount, 'amount');\n const base = {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n };\n return pair.flipped !== args.amountIsToken0\n ? buildAddLiquidityDto({ ...base, depositQuantityToken0: args.amount })\n : buildAddLiquidityDto({ ...base, depositQuantityToken1: args.amount });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildAddLiquidity} or `buildAddLiquidityDto`; it must\n * be exactly what the builder produces. The returned transaction confirms by proving the\n * position's liquidity grew.\n */\n async submitAddLiquidity(dto: AddLiquidityDTO) {\n assertCanonicalV2Dto('AddLiquidity', dto);\n return this.submit('AddLiquidity', dto, { kind: 'add', identity: identityOf(dto) });\n }\n\n /**\n * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.\n * The resulting range is therefore no narrower than the requested price interval.\n *\n * @param args - Pair, fee, price range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByPrice({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async addLiquidityByPrice(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n minPrice: PriceIn;\n maxPrice: PriceIn;\n amount: NumericAmount;\n amountIsToken0: boolean;\n /** The attempt's `uniqueKey`; default a fresh one (see {@link AddLiquidityArgs.uniqueKey}). */\n uniqueKey?: string | undefined;\n }) {\n validateFee(args.fee);\n this.rejectNumber(args.minPrice, 'minPrice');\n this.rejectNumber(args.maxPrice, 'maxPrice');\n const minPrice = new BigNumber(args.minPrice);\n const maxPrice = new BigNumber(args.maxPrice);\n if (\n !minPrice.isFinite() ||\n !maxPrice.isFinite() ||\n minPrice.isLessThanOrEqualTo(0) ||\n maxPrice.isLessThanOrEqualTo(0)\n ) {\n throw new GSwapSDKError('INVALID_PRICE_BOUNDS', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n if (minPrice.isGreaterThan(maxPrice)) {\n throw new GSwapSDKError('PRICE_BOUNDS_ORDER', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n const spacing = this.tickSpacing(args.fee);\n const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);\n const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);\n return this.addLiquidityByTicks({\n token0: args.token0,\n token1: args.token1,\n fee: args.fee,\n tickLower,\n tickUpper,\n amount: args.amount,\n amountIsToken0: args.amountIsToken0,\n uniqueKey: args.uniqueKey,\n });\n }\n\n /**\n * Removes liquidity by withdrawing at most one canonical token quantity.\n * Omitting both amounts closes the position and sweeps all accrued fees.\n *\n * @param args - Pair, fee, range, and optional caller-side withdrawal amount.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.removeLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async removeLiquidity(args: RemoveLiquidityArgs) {\n return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(args));\n }\n\n /**\n * Builds the RemoveLiquidity DTO that {@link removeLiquidity} would sign, without signing or\n * sending it. Submit exactly this DTO with {@link submitRemoveLiquidity}. The pure counterpart\n * is `buildRemoveLiquidityDto`.\n */\n async buildRemoveLiquidity(args: RemoveLiquidityArgs): Promise<RemoveLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n if (args.amount0 !== undefined && args.amount1 !== undefined) {\n throw new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: 'amount0', second: 'amount1' });\n }\n if (args.amount0 !== undefined) validateNumericAmount(args.amount0, 'amount0');\n if (args.amount1 !== undefined) validateNumericAmount(args.amount1, 'amount1');\n // The caller's amount0 / amount1 follow the caller's pair; the DTO's follow the canonical one.\n const [canonical0, canonical1] = pair.flipped\n ? [args.amount1, args.amount0]\n : [args.amount0, args.amount1];\n return buildRemoveLiquidityDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n withdrawalQuantityToken0: canonical0,\n withdrawalQuantityToken1: canonical1,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildRemoveLiquidity} or `buildRemoveLiquidityDto`;\n * it must be exactly what the builder produces. A DTO with no withdrawal quantity closes the\n * position, and the returned transaction then confirms by proving the position is gone.\n */\n async submitRemoveLiquidity(dto: RemoveLiquidityDTO) {\n assertCanonicalV2Dto('RemoveLiquidity', dto);\n const isFullClose =\n dto.withdrawalQuantityToken0 === undefined && dto.withdrawalQuantityToken1 === undefined;\n return this.submit('RemoveLiquidity', dto, {\n kind: isFullClose ? 'removeFull' : 'removePartial',\n identity: identityOf(dto),\n });\n }\n\n /**\n * Collects all accrued fees for a position; the contract does not support partial collection.\n *\n * @param args - Pair, fee, and tick range identifying the position.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.collectPositionFees({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async collectPositionFees(args: CollectPositionFeesArgs) {\n return this.submitCollectPositionFees(await this.buildCollectPositionFees(args));\n }\n\n /**\n * Builds the CollectPositionFees DTO that {@link collectPositionFees} would sign, without\n * signing or sending it. Submit exactly this DTO with {@link submitCollectPositionFees}. The\n * pure counterpart is `buildCollectPositionFeesDto`.\n */\n async buildCollectPositionFees(args: CollectPositionFeesArgs): Promise<CollectPositionFeesDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n return buildCollectPositionFeesDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCollectPositionFees} or\n * `buildCollectPositionFeesDto`; it must be exactly what the builder produces.\n */\n async submitCollectPositionFees(dto: CollectPositionFeesDTO) {\n assertCanonicalV2Dto('CollectPositionFees', dto);\n return this.submit('CollectPositionFees', dto, { kind: 'collect', identity: identityOf(dto) });\n }\n\n /**\n * Creates a pool, resolving registered trading symbols.\n * Reversed symbol order inverts the supplied starting price or square-root price.\n *\n * A token class key carries no symbol, so for a token being proposed into the v2\n * trading-symbol registry for the first time (no existing pool has registered it yet) the\n * caller MUST pass `token0Symbol`/`token1Symbol` (the token class's symbol, from the token\n * list or FetchTokenClasses). The SDK never derives a symbol from the key, and throws a\n * TOKEN_SYMBOL_NOT_REGISTERED error when an unregistered token has none. For an already-registered token a\n * supplied symbol must match the registered one.\n *\n * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.createPool({\n * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,\n * startingPrice: '0.15',\n * });\n * ```\n */\n async createPool(args: CreatePoolArgs) {\n return this.submitCreatePool(await this.buildCreatePool(args));\n }\n\n /**\n * Builds the CreatePool DTO that {@link createPool} would sign, without signing or sending it:\n * symbols resolved or proposed, the pair put in canonical order and the price inverted when it\n * was reversed. Submit exactly this DTO with {@link submitCreatePool}. The pure counterpart,\n * with canonical inputs, is `buildCreatePoolDto`.\n */\n async buildCreatePool(args: CreatePoolArgs): Promise<CreatePoolDTO> {\n const hasPrice = args.startingPrice !== undefined;\n const hasSqrtPrice = args.startingSqrtPrice !== undefined;\n if (hasPrice === hasSqrtPrice) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n validateFee(args.fee);\n const [tokenA, tokenB] = await Promise.all([\n this.resolveCreateToken(args.token0, args.token0Symbol),\n this.resolveCreateToken(args.token1, args.token1Symbol),\n ]);\n const flipped = tokenA.symbol > tokenB.symbol;\n const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];\n const sourcePriceInput = hasPrice\n ? (args.startingPrice as NumericAmount)\n : (args.startingSqrtPrice as NumericAmount);\n this.rejectNumber(sourcePriceInput, hasPrice ? 'startingPrice' : 'startingSqrtPrice');\n const sourcePrice = new BigNumber(sourcePriceInput);\n if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(sourcePriceInput) });\n }\n const canonicalPrice = flipped ? new BigNumber(1).dividedBy(sourcePrice) : sourcePrice;\n const shared = {\n token0Key: token0.classKey,\n token1Key: token1.classKey,\n token0Symbol: token0.symbol,\n token1Symbol: token1.symbol,\n fee: args.fee,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n name: args.name,\n isPrivate: args.isPrivate,\n privateAccess: args.privateAccess,\n };\n return hasPrice\n ? buildCreatePoolDto({ ...shared, startingPrice: canonicalPrice })\n : buildCreatePoolDto({ ...shared, startingSqrtPrice: canonicalPrice });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCreatePool} or `buildCreatePoolDto`; it must be\n * exactly what the builder produces. The returned transaction confirms by the pool existing, and\n * the cached symbol registry is dropped, since the pool may have registered new symbols.\n */\n async submitCreatePool(dto: CreatePoolDTO) {\n assertCanonicalV2Dto('CreatePool', dto);\n const transaction = await this.submit('CreatePool', dto, {\n kind: 'createPool',\n token0: dto.token0Symbol,\n token1: dto.token1Symbol,\n fee: dto.fee,\n });\n this.symbols.invalidate?.();\n return transaction;\n }\n\n private async submit(\n method: string,\n dto: Record<string, unknown>,\n confirmation?: PositionSubmitConfirmation,\n ) {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const signed = await signPreSend(this.signer, method, dto);\n const submitOptions =\n this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n const owner = this.walletAddress;\n const positionConfirmation = await this.buildPositionConfirmation(confirmation, owner);\n const options: ChainSubmitOptions = {\n ...submitOptions,\n ...(positionConfirmation === undefined ? {} : { positionConfirmation }),\n };\n return this.gateway.submit(method, signed, options);\n }\n\n /**\n * Builds a confirmation closure that proves the write's own effect, not just that a\n * position row exists (true before most of these writes run too, for any operation on a\n * pre-existing position — existence alone would false-confirm before the write executes,\n * and would never confirm a full close, whose whole point is that the position stops\n * existing).\n *\n * The \"before\" state is read here, before the write is sent. Liquidity writes execute\n * synchronously, so by the time `confirm()` first polls the effect has already landed: a\n * baseline taken on that first poll would already include it, and an add or partial remove\n * would never be seen to change and would time out. Only a full close needs no baseline\n * (it waits for the position to disappear). If the baseline read fails the write is still\n * sent and the closure falls back to taking the baseline on its first poll.\n */\n private async buildPositionConfirmation(\n confirmation: PositionSubmitConfirmation | undefined,\n owner: string | undefined,\n ): Promise<((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined> {\n if (confirmation === undefined) return undefined;\n\n if (confirmation.kind === 'createPool') {\n const { token0, token1, fee } = confirmation;\n return async (signal) => {\n const pool = await this.getNullable<unknown>(\n '/pool',\n { token0, token1, fee: `${fee}` },\n signal,\n );\n return pool === null ? { confirmed: false } : { confirmed: true, position: null };\n };\n }\n\n if (owner === undefined) return undefined;\n const { kind, identity } = confirmation;\n const toBaseline = (current: Position | null) => ({\n liquidity: new BigNumber(current?.liquidity ?? 0),\n fees: new BigNumber(current?.fees0 ?? 0).plus(new BigNumber(current?.fees1 ?? 0)),\n });\n let baseline: { liquidity: BigNumber; fees: BigNumber } | undefined;\n if (kind !== 'removeFull') {\n try {\n baseline = toBaseline(await this.getPosition({ ...identity, owner }));\n } catch {\n baseline = undefined;\n }\n }\n\n return async (signal) => {\n const current = await this.getPosition({ ...identity, owner }, signal);\n\n if (baseline === undefined) {\n // First poll only establishes the baseline to compare future polls against — it can\n // never itself be the confirmed outcome (nothing has been observed to change yet).\n baseline = toBaseline(current);\n // A full close starting from \"already gone\" (e.g. a retried confirm after the position\n // was already swept) is confirmed immediately rather than waiting for a change that\n // already happened.\n return kind === 'removeFull' && current === null\n ? { confirmed: true, position: null }\n : { confirmed: false };\n }\n\n switch (kind) {\n case 'add':\n return current !== null &&\n new BigNumber(current.liquidity).isGreaterThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removePartial':\n return current !== null && new BigNumber(current.liquidity).isLessThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removeFull':\n return current === null ? { confirmed: true, position: null } : { confirmed: false };\n case 'collect': {\n if (current === null) return { confirmed: false };\n const currentFees = new BigNumber(current.fees0 ?? 0).plus(\n new BigNumber(current.fees1 ?? 0),\n );\n if (currentFees.isLessThan(baseline.fees)) return { confirmed: true, position: current };\n // Nothing to sweep in the first place — a legitimate no-op collect never moves\n // fees, so \"still zero\" is the confirmed outcome, not an unconfirmed one.\n if (baseline.fees.isZero() && currentFees.isZero())\n return { confirmed: true, position: current };\n return { confirmed: false };\n }\n }\n };\n }\n\n private async get<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData>> {\n return this.http.sendGetRequest<BackendEnvelope<TData>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n signal === undefined ? undefined : { signal },\n );\n }\n\n private async getNullable<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData> | null> {\n try {\n return await this.get<TData>(endpoint, params, signal);\n } catch (error: unknown) {\n if (this.isNotFound(error)) return null;\n throw error;\n }\n }\n\n private isNotFound(error: unknown): boolean {\n return isGSwapError(error) && error.status === 404;\n }\n\n private canonicalTicks(tickLower: number, tickUpper: number, flipped: boolean) {\n return flipped ? { tickLower: -tickUpper, tickUpper: -tickLower } : { tickLower, tickUpper };\n }\n\n private tickSpacing(fee: number): number {\n const spacing = (TICK_SPACING_BY_FEE as Record<number, number>)[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n return spacing;\n }\n\n private rejectNumber(value: unknown, parameterName: string): void {\n if (typeof value === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n }\n\n /** The caller's `uniqueKey` (validated), else a fresh one. */\n private uniqueKeyFor(supplied: string | undefined): string {\n if (supplied === undefined) return createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(supplied);\n return supplied;\n }\n\n /**\n * The pair in canonical order. A resolver failure that is not an SDK error (an app's own\n * resolver, an app requestor's rejection during the registry read) is `TOKEN_RESOLUTION_FAILED`.\n */\n private orderPair(a: TokenRef, b: TokenRef) {\n return resolvePreSend(`${rawTokenOf(a)}/${rawTokenOf(b)}`, () => this.symbols.orderPair(a, b));\n }\n\n private async resolveCreateToken(\n ref: TokenRef,\n symbolOverride?: string,\n ): Promise<ResolvedCreateToken> {\n try {\n const lookupRef = typeof ref === 'object' ? compositeKeyOf(ref) : ref;\n const resolved = await resolvePreSend(rawTokenOf(ref), () => this.symbols.resolve(lookupRef));\n if (\n symbolOverride !== undefined &&\n symbolOverride !== '' &&\n symbolOverride !== resolved.symbol\n ) {\n throw new GSwapSDKError('SYMBOL_DISAGREES_WITH_REGISTRY', {\n token: rawTokenOf(ref),\n suppliedSymbol: symbolOverride,\n registeredSymbol: resolved.symbol,\n });\n }\n const suppliedClassKey = this.tryParseClassKey(ref);\n if (suppliedClassKey === undefined && resolved.collection === '') {\n // An offline resolver knows a bare symbol but not its class key; a pool needs the key.\n throw new GSwapSDKError('CREATE_POOL_NEEDS_CLASS_KEY', { token: rawTokenOf(ref) });\n }\n return {\n symbol: resolved.symbol,\n classKey:\n suppliedClassKey ??\n parseTokenClassKey({\n collection: resolved.collection,\n category: resolved.category,\n type: resolved.type,\n additionalKey: resolved.additionalKey,\n }),\n };\n } catch (error: unknown) {\n if (!isGSwapError(error, 'UNKNOWN_TOKEN')) {\n throw error;\n }\n let classKey: ReturnType<typeof parseTokenClassKey>;\n try {\n classKey = parseTokenClassKey(ref);\n } catch {\n throw error;\n }\n // First-time registration: a class key carries NO symbol (collection and symbol disagree\n // for many tokens, launchpad tokens all share collection `Token`, and some collections\n // contain `$`), so the symbol to propose must be supplied by the caller from the token\n // class / registry. Never derive it from the key.\n if (symbolOverride === undefined || symbolOverride === '') {\n throw new GSwapSDKError('TOKEN_SYMBOL_NOT_REGISTERED', { token: rawTokenOf(ref) });\n }\n if (!isProposableTradingSymbol(symbolOverride)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol: symbolOverride });\n }\n return { symbol: symbolOverride, classKey };\n }\n }\n\n private tryParseClassKey(ref: TokenRef): ReturnType<typeof parseTokenClassKey> | undefined {\n try {\n return parseTokenClassKey(ref);\n } catch {\n return undefined;\n }\n }\n}\n\nconst REQUIRED_POSITION_STRINGS = [\n 'token0Symbol',\n 'token1Symbol',\n 'owner',\n 'liquidity',\n 'amount0',\n 'amount1',\n] as const;\nconst REQUIRED_POSITION_NUMBERS = ['fee', 'tickLower', 'tickUpper'] as const;\nconst OPTIONAL_POSITION_STRINGS = [\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'sqrtPrice',\n 'fees0',\n 'fees1',\n] as const;\n\n/**\n * Reads one position row of `/positions` or `/position`: the pair, owner, range, liquidity and\n * amounts must be usable; the composite keys, token images, current tick and price, and the\n * escrowed fees are carried when present. `pool` is the pool reference (`poolRef` wins over\n * `pool`; `''` when the row names neither).\n */\nfunction parsePosition(value: unknown): EntryParse<Position> {\n const wire = asEntryRecord(value);\n if (wire === undefined) return entryRejected('the row is not an object');\n for (const key of REQUIRED_POSITION_STRINGS) {\n if (typeof wire[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n for (const key of REQUIRED_POSITION_NUMBERS) {\n const number = wire[key];\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n return entryRejected(`${key} is not a number`);\n }\n }\n if (typeof wire['inRange'] !== 'boolean') return entryRejected('inRange is not a boolean');\n for (const key of OPTIONAL_POSITION_STRINGS) {\n if (wire[key] !== undefined && typeof wire[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n const currentTick = wire['currentTick'];\n if (\n currentTick !== undefined &&\n (typeof currentTick !== 'number' || !Number.isFinite(currentTick))\n ) {\n return entryRejected('currentTick is not a number');\n }\n const pool = wire['poolRef'] ?? wire['pool'] ?? '';\n if (typeof pool !== 'string') return entryRejected('pool is not a string');\n const optional = Object.fromEntries(\n [...OPTIONAL_POSITION_STRINGS, 'currentTick' as const].flatMap((key) =>\n wire[key] === undefined ? [] : [[key, wire[key]]],\n ),\n );\n return entryOk({\n token0Symbol: wire['token0Symbol'] as string,\n token1Symbol: wire['token1Symbol'] as string,\n fee: wire['fee'] as number,\n tickLower: wire['tickLower'] as number,\n tickUpper: wire['tickUpper'] as number,\n liquidity: wire['liquidity'] as string,\n amount0: wire['amount0'] as string,\n amount1: wire['amount1'] as string,\n inRange: wire['inRange'],\n pool,\n owner: wire['owner'] as string,\n ...optional,\n });\n}\n\n/** The position inside a `/position` answer, or `INVALID_CHAIN_RESPONSE` when it is not one. */\nfunction readPositionBody(data: unknown): Position {\n const parsed = parsePosition(data);\n if (parsed.ok) return parsed.value;\n throw new GSwapSDKError(\n 'INVALID_POSITION_RESPONSE',\n { reason: parsed.reason },\n { body: data, write: false },\n );\n}\n","import BigNumber from 'bignumber.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport type { QuoteResult } from '../types/v2_results.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { validateNumericAmount } from '../utils/validation.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ChainGateway } from './gateway.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { readServerMessage } from '../utils/server_message.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, type TokenResolver } from './symbols.js';\n\ninterface QuoteWire {\n contractVersion: 'v2';\n fee: number;\n amountIn: string;\n amountOut: string;\n currentSqrtPrice?: string;\n newSqrtPrice?: string;\n currentPrice?: string;\n newPrice?: string;\n newTick: number;\n tradingFees: string;\n protocolFees: string;\n totalFees: string;\n feeTokenSymbol: string;\n token0Symbol: string;\n token1Symbol: string;\n tokenInIsToken0: boolean;\n}\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\n/** The transport a quote service reads through: the same shape `Pools` and `Symbols` take. */\ntype QuoteGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** Read-only quote service backed by the v2 offline quote engine. */\nexport class Quoting {\n /**\n * Creates a quote service.\n *\n * @example\n * ```ts\n * const quoting = new Quoting(gateway, symbols); // a ChainGateway, or any { dexBackendBaseUrl, httpRequestor }\n * ```\n */\n constructor(\n private readonly gateway: QuoteGateway,\n private readonly symbols: TokenResolver,\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Quotes the output for a positive exact-input amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');\n * console.log(quote.amountOut);\n * ```\n */\n public async quoteExactInput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountIn: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountIn, 'amountIn');\n return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString(amountIn) }, fee);\n }\n\n /**\n * Quotes the input for a positive exact-output amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);\n * console.log(quote.amountIn);\n * ```\n */\n public async quoteExactOutput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountOut: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountOut, 'amountOut');\n return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString(amountOut) }, fee);\n }\n\n private async quote(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amount: { amountIn: string } | { amountOut: string },\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateOptionalFee(fee);\n\n const params: Record<string, string> = {\n tokenIn: await queryTokenOf(this.symbols, tokenIn),\n tokenOut: await queryTokenOf(this.symbols, tokenOut),\n ...amount,\n };\n if (fee !== undefined) params['fee'] = String(fee);\n\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<QuoteWire>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/quote',\n params,\n );\n return mapQuote(response.data);\n } catch (error: unknown) {\n throw mapQuoteError(error, tokenIn, tokenOut, fee, {\n tokenIn: params['tokenIn'] ?? '',\n tokenOut: params['tokenOut'] ?? '',\n });\n }\n }\n}\n\nfunction mapQuote(value: unknown): QuoteResult {\n if (!isQuoteWire(value)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'quote' },\n { body: value, write: false },\n );\n }\n const wire = value;\n const currentPrice =\n wire.currentPrice !== undefined\n ? new BigNumber(wire.currentPrice)\n : orientPrice(wire.currentSqrtPrice!, wire.tokenInIsToken0);\n const newPrice =\n wire.newPrice !== undefined\n ? new BigNumber(wire.newPrice)\n : orientPrice(wire.newSqrtPrice!, wire.tokenInIsToken0);\n const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);\n\n return {\n contractVersion: wire.contractVersion,\n fee: wire.fee,\n amountIn: wire.amountIn,\n amountOut: wire.amountOut,\n ...(wire.currentSqrtPrice === undefined ? {} : { currentSqrtPrice: wire.currentSqrtPrice }),\n ...(wire.newSqrtPrice === undefined ? {} : { newSqrtPrice: wire.newSqrtPrice }),\n feeTier: wire.fee,\n newTick: wire.newTick,\n tradingFees: wire.tradingFees,\n protocolFees: wire.protocolFees,\n totalFees: wire.totalFees,\n feeTokenSymbol: wire.feeTokenSymbol,\n token0Symbol: wire.token0Symbol,\n token1Symbol: wire.token1Symbol,\n tokenInIsToken0: wire.tokenInIsToken0,\n currentPrice,\n newPrice,\n priceImpact,\n };\n}\n\n// The default BigNumber.DECIMAL_PLACES (20) underflows 1/poolPrice to exactly 0 for a\n// pool price above ~1e20 (a real, in-range price for a low-unit-value token quoted\n// against a high-value one) — 60dp matches the precision ticks.ts's DexMath already\n// uses for this same class of division.\nconst HighPrecision = BigNumber.clone({ DECIMAL_PLACES: 60 });\n\nfunction orientPrice(sqrtPrice: string, tokenInIsToken0: boolean): BigNumber {\n const poolPrice = new HighPrecision(sqrtPrice).pow(2);\n return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);\n}\n\nfunction isQuoteWire(value: unknown): value is QuoteWire {\n if (typeof value !== 'object' || value === null) return false;\n const wire = value as Record<string, unknown>;\n const requiredStrings = [\n 'amountIn',\n 'amountOut',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n 'feeTokenSymbol',\n 'token0Symbol',\n 'token1Symbol',\n ];\n return (\n wire['contractVersion'] === 'v2' &&\n typeof wire['fee'] === 'number' &&\n Number.isFinite(wire['fee']) &&\n requiredStrings.every((key) => typeof wire[key] === 'string') &&\n typeof wire['newTick'] === 'number' &&\n Number.isInteger(wire['newTick']) &&\n typeof wire['tokenInIsToken0'] === 'boolean' &&\n optionalPositiveDecimal(wire['currentSqrtPrice']) &&\n optionalPositiveDecimal(wire['newSqrtPrice']) &&\n optionalPositiveDecimal(wire['currentPrice']) &&\n optionalPositiveDecimal(wire['newPrice']) &&\n (wire['currentSqrtPrice'] !== undefined || wire['currentPrice'] !== undefined) &&\n (wire['newSqrtPrice'] !== undefined || wire['newPrice'] !== undefined)\n );\n}\n\nfunction optionalPositiveDecimal(value: unknown): boolean {\n if (value === undefined) return true;\n if (typeof value !== 'string') return false;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this validates an untrusted backend field, so an unparseable value\n // must fail validation cleanly (INVALID_CHAIN_RESPONSE), not throw raw.\n const decimal = new BigNumber(value);\n return decimal.isFinite() && decimal.isGreaterThan(0);\n } catch {\n return false;\n }\n}\n\n/**\n * The ways the backend says a pair has no market at all: no pool at ANY fee tier (\"No pools found\n * with sufficient liquidity\") or a missing pool (\"Pool does not exist on the new DEX contract\").\n * A pool that exists but is too thin says \"Insufficient liquidity: ...\" instead.\n */\nconst NO_MARKET_MESSAGE = /no pool|no pools|pool does not exist/iu;\n\n/**\n * A token the DEX contract never registered: the backend's symbol registry answers\n * `Token <token> has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`\n * with an HTTP 400, naming the token exactly as the quote request sent it. That is a different\n * fact from \"no pool for this pair\" (the token itself is unknown), so it is `UNKNOWN_TOKEN` with\n * the token, not `NO_POOL_AVAILABLE`. Token class keys and symbols contain no whitespace.\n */\nconst NO_SYMBOL_MESSAGE = /Token (\\S+) has no trading symbol on the new DEX contract/u;\n\n/** The token the quote request named in the form the caller gave it, else as the backend echoed it. */\nfunction unknownTokenOf(\n echoed: string,\n queried: { tokenIn: string; tokenOut: string },\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n): TokenRef {\n if (echoed === queried.tokenIn) return tokenIn;\n if (echoed === queried.tokenOut) return tokenOut;\n return echoed;\n}\n\nfunction mapQuoteError(\n error: unknown,\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER | undefined,\n queried: { tokenIn: string; tokenOut: string },\n): GSwapSDKError {\n if (isGSwapError(error)) {\n // The backend's own English is read ONLY to classify its answer; it is never surfaced. The\n // SDK's generated `message` is never matched: its templates are not a contract.\n const message = readServerMessage(error) ?? '';\n const unregistered = NO_SYMBOL_MESSAGE.exec(message)?.[1];\n if (unregistered !== undefined) {\n return GSwapSDKError.unknownTokenError(\n unknownTokenOf(unregistered, queried, tokenIn, tokenOut),\n error,\n );\n }\n if (error.status === 404 || NO_MARKET_MESSAGE.test(message)) {\n return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee, error);\n }\n if (error.status === 400 && /insufficient liquidity/iu.test(message)) {\n return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee, error);\n }\n return error;\n }\n return new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'quote' },\n { cause: error, write: false },\n );\n}\n\nfunction validateOptionalFee(fee: FEE_TIER | undefined): void {\n if (fee !== undefined && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: Number(fee),\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\nfunction toDecimalString(amount: NumericAmount): string {\n return new BigNumber(amount).toFixed();\n}\n","import { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/** The raw answer to a shadow (dark) write: every HTTP status resolves. */\nexport interface ShadowSubmitResult {\n httpStatus: number;\n /** Parsed JSON body, or the raw text when the body was not JSON. */\n body: unknown;\n}\n\n/**\n * Machine-readable codes the swap backend returns in a shadow failure body (`{ code, message }`, with\n * no `statusCode`; the HTTP status carries the number).\n *\n * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back\n * silently to a public swap.\n * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.\n * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;\n * `message` is the gateway's verbatim string.\n */\nexport const SHADOW_SUBMIT_CODES = [\n 'SHADOW_UNAVAILABLE',\n 'SHADOW_UNSUPPORTED_TYPE',\n 'SHADOW_RELAY_REJECTED',\n] as const;\n\n/** One member of {@link SHADOW_SUBMIT_CODES}. */\nexport type ShadowSubmitCode = (typeof SHADOW_SUBMIT_CODES)[number];\n\n/**\n * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text\n * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route\n * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow\n * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)\n * and `unknown`.\n */\nexport const SHADOW_FAILURE_KINDS = ['unavailable', 'disabled', 'rejected', 'unknown'] as const;\n\n/** One member of {@link SHADOW_FAILURE_KINDS}. */\nexport type ShadowFailureKind = (typeof SHADOW_FAILURE_KINDS)[number];\n\n/** A RequestTrade the gateway queued: the handle to confirm it with `confirmAppliedTrade`. */\nexport interface ShadowQueuedRequest {\n uniqueKey: string;\n requestTransactionId: string | null;\n}\n\n/** A shadow write the gateway refused or did not answer: `kind` says why (see {@link SHADOW_FAILURE_KINDS}). */\nexport type ShadowSubmitFailure =\n | { ok: false; kind: 'unavailable'; retryable: true }\n | { ok: false; kind: 'disabled'; retryable: false }\n | { ok: false; kind: 'rejected'; retryable: false; message: string }\n | { ok: false; kind: 'unknown'; retryable: false };\n\n/**\n * The normalized outcome of a shadow RequestTrade (a dark swap). A success (`ok: true`) ALWAYS\n * carries `queued`, the exact key the gateway acknowledged: a RequestTrade answer that does not\n * queue the signed key is not an outcome but a thrown `SHADOW_NOT_QUEUED`. So after `if (outcome.ok)`\n * the app reads `outcome.queued` with no `undefined` branch.\n */\nexport type ShadowSubmitOutcome =\n | {\n ok: true;\n /** The request transaction id (`''` when the gateway gave none). */\n bundleId: string;\n /** Confirm with `confirmAppliedTrade`. */\n queued: ShadowQueuedRequest;\n }\n | ShadowSubmitFailure;\n\n/**\n * The success of a shadow write that is NOT a RequestTrade and executed synchronously\n * (`mode: 'sync'`, a liquidity write): there is nothing queued to confirm, so `queued` is absent.\n */\nexport interface ShadowSyncSuccess {\n ok: true;\n /** The transaction id (`''` when the gateway gave none). */\n bundleId: string;\n queued?: undefined;\n}\n\n/** Maps an HTTP status to a failure kind: 503 retryable, 400 disabled, anything else unknown. */\nexport function classifyShadowSubmitStatus(status: number): ShadowFailureKind {\n if (status === 503) return 'unavailable';\n if (status === 400) return 'disabled';\n return 'unknown';\n}\n\n/**\n * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.\n * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway\n * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to \"disabled\".\n */\nexport function classifyShadowSubmitError(status: number, code?: string): ShadowFailureKind {\n if (code === 'SHADOW_UNAVAILABLE') return 'unavailable';\n if (code === 'SHADOW_RELAY_REJECTED') return 'rejected';\n if (code === 'SHADOW_UNSUPPORTED_TYPE') return 'disabled';\n return classifyShadowSubmitStatus(status);\n}\n\n/**\n * Normalizes a shadow write's raw answer. For `'RequestTrade'` the result is a\n * {@link ShadowSubmitOutcome}, whose success always has `queued`; any other method may also be a\n * {@link ShadowSyncSuccess} (no `queued`).\n *\n * A 2xx envelope with `error === false` is a success when it is a queued RequestTrade that\n * acknowledges the EXACT signed `uniqueKey`, or a synchronous (`mode: 'sync'`) liquidity write.\n * Everything else is classified as a failure from the status and the body's `code`.\n *\n * @throws GSwapSDKError SHADOW_NOT_QUEUED when a RequestTrade success does not queue the\n * signed `uniqueKey` (a synchronous or mismatched answer must never be accepted as a swap).\n */\nexport function readShadowSubmitOutcome(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess {\n const { httpStatus, body } = result;\n const envelope = asRecord(body);\n if (httpStatus >= 200 && httpStatus < 300 && envelope?.['error'] === false) {\n const data = asRecord(envelope['data']);\n const rawTransactionId =\n typeof data?.['transactionId'] === 'string' ? data['transactionId'] : undefined;\n if (method === 'RequestTrade') {\n const requestedKey = signedBody['uniqueKey'];\n if (\n data?.['mode'] !== 'queued' ||\n typeof requestedKey !== 'string' ||\n data['uniqueKey'] !== requestedKey\n ) {\n throw new GSwapSDKError(\n 'SHADOW_NOT_QUEUED',\n {},\n {\n status: httpStatus,\n body,\n shadow: true,\n ...(typeof requestedKey === 'string' ? { uniqueKey: requestedKey } : {}),\n },\n );\n }\n return {\n ok: true,\n bundleId: rawTransactionId ?? '',\n queued: { uniqueKey: requestedKey, requestTransactionId: rawTransactionId ?? null },\n };\n }\n if (data?.['mode'] === 'sync') return { ok: true, bundleId: rawTransactionId ?? '' };\n }\n\n const kind = classifyShadowSubmitError(httpStatus, getStringProperty(body, 'code'));\n if (kind === 'rejected') {\n return {\n ok: false,\n kind: 'rejected',\n retryable: false,\n message: getStringProperty(body, 'message') ?? '',\n };\n }\n return kind === 'unavailable'\n ? { ok: false, kind, retryable: true }\n : { ok: false, kind, retryable: false };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n","import {\n assertUniqueKey,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type HttpRequestor,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { SwapAmount } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { orderSymbols, readOrderedSymbols, type TokenRef } from '../utils/ordering.js';\nimport { assertCanonicalV2Dto, buildRequestTradeDto } from '../utils/dto_builders.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport { assertCanonicalPair, userRef, validateFee } from '../utils/validation.js';\nimport type { ChainSubmitOptions } from './gateway.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport {\n readShadowSubmitOutcome,\n type ShadowSubmitOutcome,\n type ShadowSubmitResult,\n} from './shadow_submit.js';\nimport { SubmittedTransaction } from './submitted_transaction.js';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { RequestTradeDTO } from '../types/v2_dtos.js';\nimport type { AppliedTrade, QuoteResult } from '../types/v2_results.js';\nimport { tradingSymbolOf, type TokenResolver } from './symbols.js';\n\ninterface SwapGateway {\n submit: (\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<AppliedTrade>>;\n submitShadow: (\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<ShadowSubmitResult>;\n readonly dexBackendBaseUrl: string;\n readonly httpRequestor: HttpRequestor;\n readonly requestTimeoutMs: number;\n readonly wire?: WireOptions | undefined;\n}\n\n/** The canonical pool a swap trades in, as a quote names it. */\nexport interface SwapPool {\n token0: string;\n token1: string;\n}\n\n/** Options of a swap. */\nexport interface SwapOptions {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing (to remember it, to\n * show it), or to retry the SAME attempt after a lost response; never reuse it for another trade.\n */\n uniqueKey?: string | undefined;\n /**\n * Pin the pool: take `token0` / `token1` verbatim from the quote the user saw, instead of\n * ordering `tokenIn` / `tokenOut` by string comparison. `tokenIn` and `tokenOut` must be exactly\n * these two symbols, and `token0` must sort before `token1`. See {@link swapRouteFromQuote}.\n */\n pool?: SwapPool | undefined;\n}\n\n/** Everything {@link Swaps.swap} needs to trade in the pool a quote priced. */\nexport interface SwapRoute {\n tokenIn: string;\n tokenOut: string;\n fee: FEE_TIER;\n pool: SwapPool;\n}\n\n/**\n * The route of a quote: its fee tier and pool, with `tokenIn` / `tokenOut` taken from\n * `tokenInIsToken0`, nothing re-derived. Use it to swap in exactly the pool a quote priced:\n *\n * @example\n * ```ts\n * const route = swapRouteFromQuote(quote);\n * await swaps.swap(route.tokenIn, route.tokenOut, route.fee, { exactIn: '100' }, { pool: route.pool });\n * ```\n */\nexport function swapRouteFromQuote(\n quote: Pick<QuoteResult, 'token0Symbol' | 'token1Symbol' | 'tokenInIsToken0' | 'fee'>,\n): SwapRoute {\n validateFee(quote.fee);\n assertCanonicalPair(quote.token0Symbol, quote.token1Symbol);\n const [tokenIn, tokenOut] = quote.tokenInIsToken0\n ? [quote.token0Symbol, quote.token1Symbol]\n : [quote.token1Symbol, quote.token0Symbol];\n return {\n tokenIn,\n tokenOut,\n fee: quote.fee,\n pool: { token0: quote.token0Symbol, token1: quote.token1Symbol },\n };\n}\n\n/** Executes queued current-contract RequestTrade operations through the Chain Gateway. */\nexport class Swaps {\n /**\n * Creates a swap service.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, symbols, signer, 'client|alice');\n * ```\n */\n constructor(\n private readonly gateway: SwapGateway,\n private readonly symbols: TokenResolver,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: UniqueKeyOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly uniqueKeyPrefix: string;\n\n /**\n * Signs and submits an exact-input or exact-output RequestTrade DTO. The returned transaction\n * is QUEUED; call `await tx.confirm()` to obtain the executed trade or chain rejection.\n *\n * @example\n * ```ts\n * const submitted = await swaps.swap('GALA', 'GUSDC', 3000, {\n * exactIn: '100',\n * amountOutMinimum: '14',\n * });\n * ```\n */\n public async swap(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>> {\n return this.submitSwap(await this.buildSwap(tokenIn, tokenOut, fee, amount, options));\n }\n\n /**\n * Signs and submits a SHADOW (dark) swap: the same RequestTrade as {@link swap}, relayed with\n * `X-Shadow: true` so the swap backend marks it private before it reaches the contract. Requires a\n * `walletAddress`. Resolves the normalized outcome instead of throwing on a gateway refusal:\n * `ok: false` carries `unavailable` (retryable), `disabled`, `rejected` (with the gateway's\n * message) or `unknown`. A success carries `queued`, to be confirmed with\n * `confirmSwap(queued.uniqueKey)`; never fall back to a public swap on failure. Whatever this\n * THROWS (a validation error, the signer, a lost connection, `SHADOW_NOT_QUEUED`) has\n * `error.shadow === true` (`isShadowError`), so an app can apply its dark-swap policy to it.\n *\n * @example\n * ```ts\n * const outcome = await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * if (outcome.ok) await swaps.confirmSwap(outcome.queued.uniqueKey);\n * ```\n */\n public async swapShadow(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<ShadowSubmitOutcome> {\n return shadowFailures(async () =>\n this.submitSwapShadow(await this.buildSwap(tokenIn, tokenOut, fee, amount, options)),\n );\n }\n\n /**\n * Builds the RequestTrade DTO that {@link swap} would sign, without signing or sending it: to\n * show in an approval popup, to remember its `uniqueKey`, or to sign elsewhere. Submit exactly\n * this DTO with {@link submitSwap}. The pure counterpart, with canonical inputs and no\n * resolution, is `buildRequestTradeDto`.\n *\n * @example\n * ```ts\n * const dto = await swaps.buildSwap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * showApproval(dto);\n * const submitted = await swaps.submitSwap(dto);\n * ```\n */\n public async buildSwap(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<RequestTradeDTO> {\n validateFee(fee);\n const uniqueKey = options?.uniqueKey ?? createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(uniqueKey);\n const tokenInSymbol = await tradingSymbolOf(this.symbols, tokenIn);\n const tokenOutSymbol = await tradingSymbolOf(this.symbols, tokenOut);\n const ordered = this.orientPool(tokenInSymbol, tokenOutSymbol, options?.pool);\n return buildRequestTradeDto({\n token0: ordered.token0,\n token1: ordered.token1,\n fee,\n tokenInIsToken0: tokenInSymbol === ordered.token0,\n uniqueKey,\n ...amount,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildSwap} or `buildRequestTradeDto`. The DTO must be\n * exactly what the builder produces (no signature, canonical decimals, builder key order), so\n * what an app showed is what gets signed.\n *\n * @example\n * ```ts\n * const submitted = await swaps.submitSwap(dto);\n * const applied = await submitted.confirm();\n * ```\n */\n public async submitSwap(dto: RequestTradeDTO): Promise<SubmittedTransaction<AppliedTrade>> {\n const signed = await this.signRequestTrade(dto);\n return this.gateway.submit('RequestTrade', signed, this.submitOptions());\n }\n\n /** Signs and shadow-submits a DTO built by {@link buildSwap}; see {@link swapShadow}. */\n public async submitSwapShadow(dto: RequestTradeDTO): Promise<ShadowSubmitOutcome> {\n return shadowFailures(async () => {\n const signed = await this.signRequestTrade(dto);\n const result = await this.gateway.submitShadow('RequestTrade', signed, this.submitOptions());\n return readShadowSubmitOutcome('RequestTrade', signed, result);\n });\n }\n\n private submitOptions(): ChainSubmitOptions {\n return this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n }\n\n private async signRequestTrade(dto: RequestTradeDTO): Promise<Record<string, unknown>> {\n assertCanonicalV2Dto('RequestTrade', dto);\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n return signPreSend(this.signer, 'RequestTrade', dto);\n }\n\n /** The pool's two symbols in contract order: the quote's own when pinned, else string order. */\n private orientPool(\n tokenInSymbol: string,\n tokenOutSymbol: string,\n pool: SwapPool | undefined,\n ): SwapPool {\n if (pool === undefined) {\n return readOrderedSymbols(orderSymbols(tokenInSymbol, tokenOutSymbol));\n }\n const sameSet =\n (tokenInSymbol === pool.token0 && tokenOutSymbol === pool.token1) ||\n (tokenInSymbol === pool.token1 && tokenOutSymbol === pool.token0);\n if (!sameSet) {\n throw new GSwapSDKError('POOL_MISMATCH', {\n tokenIn: tokenInSymbol,\n tokenOut: tokenOutSymbol,\n poolToken0: pool.token0,\n poolToken1: pool.token1,\n });\n }\n return { token0: pool.token0, token1: pool.token1 };\n }\n\n /**\n * Confirm a swap by its durable `uniqueKey` without resubmitting it. This is the recovery\n * path after a `CONFIRMATION_TIMEOUT`, a `SUBMISSION_OUTCOME_UNKNOWN`, a `409` replay\n * conflict, or a process restart: it reads the same apply-results record that\n * `SubmittedTransaction.confirm()` reads (retained for 7 days) and resolves the applied trade\n * or throws the chain's rejection. The first read happens immediately unless\n * `initialDelayMs` is given.\n *\n * @example\n * ```ts\n * const applied = await swaps.confirmSwap('galaswap-operation-2f1c…');\n * ```\n */\n public async confirmSwap(uniqueKey: string, options?: ConfirmOptions): Promise<AppliedTrade> {\n assertUniqueKey(uniqueKey);\n const transaction = new SubmittedTransaction<AppliedTrade>({\n method: 'RequestTrade',\n uniqueKey,\n transactionId: null,\n mode: 'queued',\n result: undefined,\n dexBackendBaseUrl: this.gateway.dexBackendBaseUrl,\n httpRequestor: this.gateway.httpRequestor,\n requestTimeoutMs: this.gateway.requestTimeoutMs,\n wire: this.gateway.wire,\n });\n return transaction.confirm({ initialDelayMs: 0, ...options });\n }\n}\n","import { Assets } from './assets.js';\nimport { DexFees } from './dex_fees.js';\nimport { ChainGateway } from './gateway.js';\nimport { GdexStreamService } from './gdex_stream.js';\nimport { HttpClient } from './http_client.js';\nimport { Leaderboard } from './leaderboard.js';\nimport { Market } from './market.js';\nimport { Onramper } from './onramper.js';\nimport { Pools } from './pools.js';\nimport { Positions } from './positions.js';\nimport { Quoting } from './quoting.js';\nimport type { GalaChainSigner, HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { CanonicalSymbols, Symbols } from './symbols.js';\nimport type { InvalidEntryHandler } from '../utils/lenient.js';\nimport { userRef } from '../utils/validation.js';\nimport { Swaps } from './swaps.js';\nimport type { GSwapEnv } from '../types/env.js';\nimport { GSWAP_ENVIRONMENTS } from '../types/env.js';\n\n/** Options for constructing a backend-routed SDK client. */\nexport interface GSwapOptions {\n /** Signs every write. Without one, reads work and any write throws `NO_SIGNER`. */\n signer?: GalaChainSigner | undefined;\n /**\n * The selected account, sent as `X-Wallet-Address` on writes (attribution only; the chain\n * recovers the signer from the signature). Required for shadow writes. Any spelling of an\n * Ethereum account (`eth|<40 hex>` in any casing, `0x...`, bare hex) is sent as `eth|<EIP-55>`,\n * `client|<id>` as written; a mixed-case spelling that is not the checksum is refused at\n * construction (`INVALID_WALLET_ADDRESS`), and `eth|0x...` (not an address form) is refused as\n * core's `INVALID_ETH_USER_REF_PREFIX`.\n */\n walletAddress?: string | undefined;\n /** `'stage'` or `'prod'` swap backend preset; defaults to `'prod'`. */\n env?: GSwapEnv | undefined;\n /** Overrides the preset's swap backend base URL (a test or private deployment). */\n dexBackendBaseUrl?: string | undefined;\n /** HTTP transport for every request; defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000); `Infinity` arms no timer. */\n chainCallTimeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the read requests (see {@link WireOptions}). */\n wire?: WireOptions | undefined;\n /**\n * How tokens are turned into trading symbols. `'registry'` (default) reads the symbol registry\n * once (`GET /v2/trade/symbols`, cached) and accepts symbols or class keys. `'canonical'` makes\n * no registry request: the caller passes the backend's canonical trading symbols (from a quote,\n * an estimate or a position), reads send tokens and ticks exactly as given (composite keys\n * included) and the backend orients the pair; see {@link CanonicalSymbols}.\n */\n symbolResolution?: 'registry' | 'canonical' | undefined;\n /**\n * Told about every row of a pool, symbol, position, price, price-series, season or leaderboard\n * answer that was skipped as unusable (see {@link InvalidEntryHandler}); without it such rows are\n * skipped silently.\n */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n /** Realtime stream endpoint. Defaults to the environment's, or is derived from `dexBackendBaseUrl`. */\n dexBackendWsUrl?: string | undefined;\n /** WebSocket constructor for the realtime stream; required on Node.js older than 22. */\n webSocketImpl?: unknown;\n /**\n * `x-api-key` for the privileged stream view; server-side only, and it requires `webSocketImpl`\n * (see `GdexStreamConfig.apiKey`).\n */\n streamApiKey?: string | undefined;\n /**\n * Prefix of every write's `uniqueKey` (`<prefix><uuid>`). Defaults to `galaswap-operation-`,\n * what the Gala Wallet and the gSwap web app send; the backend does not depend on it.\n */\n uniqueKeyPrefix?: string | undefined;\n}\n\n/**\n * Main entry point for the current GalaChainDex SDK: one client bundling the services that read\n * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,\n * `market`, `leaderboard`, `onramper`, `symbols`, `fees`, `stream`). See {@link GSwapOptions} for\n * configuration.\n */\nexport class GSwap {\n /** The swap backend base URL every request goes to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */\n public readonly chainCallTimeoutMs: number;\n /** The signer given at construction, if any. */\n public readonly signer: GalaChainSigner | undefined;\n /**\n * The account given at construction, if any, in the gateway's spelling (`eth|<EIP-55>`;\n * `client|<id>` as given).\n */\n public readonly walletAddress: string | undefined;\n /** The chain-gateway client every other service reads and writes through. */\n public readonly gateway: ChainGateway;\n /** The trading-symbol registry. */\n public readonly symbols: Symbols;\n /** Read-only exact-input and exact-output quotes. */\n public readonly quoting: Quoting;\n /** Pool, slot0 and composite-pool reads. */\n public readonly pools: Pools;\n /** Position reads, liquidity estimates and liquidity / pool-creation writes. */\n public readonly positions: Positions;\n /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */\n public readonly swaps: Swaps;\n /** User token balances. */\n public readonly assets: Assets;\n /** USD prices, price series and the platform volume totals. */\n public readonly market: Market;\n /** Trading-competition seasons and rankings. */\n public readonly leaderboard: Leaderboard;\n /** The Onramper (fiat on-ramp) widget URL. */\n public readonly onramper: Onramper;\n /** Network-fee quotes (DryRun) signed with this client's signer. */\n public readonly fees: DexFees;\n /** The realtime stream endpoint {@link GSwap.stream} connects to. */\n public readonly dexBackendWsUrl: string;\n private readonly webSocketImpl: unknown;\n private readonly streamApiKey: string | undefined;\n private streamClient: GdexStreamService | undefined;\n\n /**\n * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * const symbols = await gSwap.symbols.list();\n * ```\n */\n constructor(options?: GSwapOptions) {\n const environment = GSWAP_ENVIRONMENTS[options?.env ?? 'prod'];\n this.dexBackendBaseUrl = trimTrailingSlash(\n options?.dexBackendBaseUrl ?? environment.dexBackendBaseUrl,\n );\n this.chainCallTimeoutMs = options?.chainCallTimeoutMs ?? 30_000;\n this.signer = options?.signer;\n this.walletAddress =\n options?.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n\n const httpClient = new HttpClient(\n options?.httpRequestor,\n this.chainCallTimeoutMs,\n options?.wire,\n );\n this.gateway = new ChainGateway({\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n chainCallTimeoutMs: this.chainCallTimeoutMs,\n ...(options?.wire === undefined ? {} : { wire: options.wire }),\n ...(options?.httpRequestor === undefined ? {} : { httpRequestor: options.httpRequestor }),\n ...(this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress }),\n });\n const lenient = { onInvalidEntry: options?.onInvalidEntry };\n this.symbols = new Symbols(this.gateway, lenient);\n // The services resolve tokens through the registry by default; the offline resolver sends the\n // caller's canonical symbols and keys as they are and never reads the registry.\n const resolver =\n options?.symbolResolution === 'canonical' ? new CanonicalSymbols() : this.symbols;\n this.quoting = new Quoting(this.gateway, resolver);\n this.pools = new Pools(this.gateway, resolver, lenient);\n const keyOptions = { uniqueKeyPrefix: options?.uniqueKeyPrefix, ...lenient };\n this.positions = new Positions(\n this.gateway,\n resolver,\n this.signer,\n this.walletAddress,\n keyOptions,\n );\n this.swaps = new Swaps(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);\n this.assets = new Assets(this.dexBackendBaseUrl, httpClient);\n this.market = new Market(this.dexBackendBaseUrl, httpClient, lenient);\n this.leaderboard = new Leaderboard(this.dexBackendBaseUrl, httpClient, lenient);\n this.onramper = new Onramper(this.dexBackendBaseUrl, httpClient);\n this.fees = new DexFees(this.gateway, this.signer);\n this.dexBackendWsUrl =\n options?.dexBackendWsUrl ??\n (options?.dexBackendBaseUrl === undefined\n ? environment.dexBackendWsUrl\n : `${this.dexBackendBaseUrl.replace(/^http/u, 'ws')}/ws`);\n this.webSocketImpl = options?.webSocketImpl;\n this.streamApiKey = options?.streamApiKey;\n }\n\n /**\n * The realtime stream client for this environment (created on first use, not connected until you\n * call `connect()`).\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * await gSwap.stream.connect();\n * await gSwap.stream.subscribeLiquidity((event) => console.log(event.action, event.amount0));\n * ```\n */\n get stream(): GdexStreamService {\n this.streamClient ??= new GdexStreamService({\n url: this.dexBackendWsUrl,\n ...(this.webSocketImpl === undefined ? {} : { webSocketImpl: this.webSocketImpl }),\n ...(this.streamApiKey === undefined ? {} : { apiKey: this.streamApiKey }),\n });\n return this.streamClient;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n","import type { FailureOutcome } from '@gala-chain/gala-core-sdk';\n\n/**\n * The classification values an app shell may need on their own: what an outcome allows. This module\n * is deliberately tiny and imports nothing at run time (the outcome type is erased), so an app\n * shell that builds `classification('not_sent')` or reads `NOT_QUEUED_FINAL` loads a few hundred\n * bytes, not the table of error codes that lives with `classifyFailure`.\n */\n\n/** The result of `classifyFailure`. */\nexport interface FailureClassification {\n readonly outcome: FailureOutcome;\n /**\n * May the app offer the user Retry: repeat the operation as a NEW request (a fresh key for a\n * write) without any risk of applying it twice? Always `false` for `unknown` (confirm the same\n * key instead) and `invalid_input` (the same call fails again). It says a repeat is SAFE, not\n * that it will succeed, and it is the SDK's floor: an app may still withhold Retry (the\n * Gala Wallet does after a Dark swap: see `isShadowError`).\n */\n readonly retryable: boolean;\n}\n\n/**\n * The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the\n * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.\n */\nconst DEFAULT_RETRYABLE = {\n rejected: true,\n unknown: false,\n not_queued: true,\n not_sent: true,\n invalid_input: false,\n transient: true,\n} as const satisfies Record<FailureOutcome, boolean>;\n\n/**\n * Builds the classification the SDK itself gives an outcome, so an app that classifies a step of\n * its OWN (one that is not an SDK call) uses the SDK's type and its values instead of a\n * hard-coded `{ outcome, retryable }` literal. `retryable` is the SDK's default for that outcome\n * (`false` for `unknown` and `invalid_input`, `true` for the rest). Each call returns a new\n * object, safe to mutate or freeze.\n *\n * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the\n * SDK's own `not_queued` for a refusal the gateway will repeat is\n * `classification('not_queued', { retryable: false })` (also exported, frozen, as\n * {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one\n * that cannot have it, so only `false` is accepted.\n *\n * @example\n * ```ts\n * // The app refreshes a quote before it asks the SDK to sign; the refresh failed.\n * throw new AppSwapError(text, classification('not_sent'));\n * // The app refuses a request for a reason a repeat cannot fix.\n * throw new AppSwapError(text, classification('not_queued', { retryable: false }));\n * ```\n */\nexport function classification(\n outcome: FailureOutcome,\n options: { readonly retryable?: false } = {},\n): FailureClassification {\n return { outcome, retryable: options.retryable === false ? false : DEFAULT_RETRYABLE[outcome] };\n}\n\n/**\n * `classification('not_queued', { retryable: false })`: the gateway refused the write before\n * queueing it AND will refuse a repeat the same way (the version wall, a dark swap that did not\n * queue, an HTTP 4xx). Nothing is pending and Retry is not offered. It is frozen: use it as it is\n * (`classification: NOT_QUEUED_FINAL`) instead of spreading `classification('not_queued')` and\n * overriding `retryable`; `{ ...NOT_QUEUED_FINAL }` is a mutable copy.\n */\nexport const NOT_QUEUED_FINAL: Readonly<FailureClassification> = Object.freeze(\n classification('not_queued', { retryable: false }),\n);\n\n/**\n * `classification('not_sent')`: a step of the app's own failed before anything was signed or\n * sent (a quote refresh, a balance read), so nothing is pending and a repeat is safe.\n */\nexport function notSentClassification(): FailureClassification {\n return classification('not_sent');\n}\n","import {\n isWriteView,\n numberParamOf,\n stringParamOf,\n toFailureView,\n type FailureView,\n type GALA_ERROR_CATALOG,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport { isCatalogCode } from '../classes/gswap_error_phase_table.js';\nimport { classification, NOT_QUEUED_FINAL, type FailureClassification } from './classification.js';\n\n/**\n * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every\n * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing\n * else: the classification values live in `classification.ts`, the yes/no guards in\n * `failure_guards.ts`, and the error class and catalog are only named as types.\n */\n\nconst REJECTED: FailureClassification = classification('rejected');\nconst UNKNOWN: FailureClassification = classification('unknown');\nconst NOT_QUEUED: FailureClassification = classification('not_queued');\nconst NOT_SENT: FailureClassification = classification('not_sent');\nconst INVALID_INPUT: FailureClassification = classification('invalid_input');\nconst TRANSIENT: FailureClassification = classification('transient');\n\n/**\n * The classification of every code whose meaning does not depend on the failing answer. A code\n * missing here is a compile error (unless it is `pre_send`, see {@link CodeTable}), so adding a\n * catalog code forces a decision.\n */\nconst BY_CODE = {\n // ----------------------------------------------------------------------------------- transport\n REQUEST_TIMEOUT: TRANSIENT,\n TRANSPORT_ERROR: TRANSIENT,\n REQUEST_FAILED: TRANSIENT,\n\n // ------------------------------------------------------------------------------- write: unknown\n // No answer was read, or a 2xx answer that does not prove the write was queued under the signed\n // key: it may have been applied.\n SUBMISSION_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_REPORTED_ERROR: UNKNOWN,\n GATEWAY_DATA_MISSING: UNKNOWN,\n GATEWAY_MODE_INVALID: UNKNOWN,\n GATEWAY_SYNC_REQUEST_TRADE: UNKNOWN,\n MISSING_UNIQUE_KEY: UNKNOWN,\n UNIQUE_KEY_MISMATCH: UNKNOWN,\n // Core `GatewayWrites` (token-contract writes): no answer read, or a 2xx that proves nothing.\n GATEWAY_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_RESPONSE_INVALID: UNKNOWN,\n // Core `./bridge` (GalaConnect bridge writes): a 2xx without the id or hash the next step needs,\n // or no answer read after the request left.\n BRIDGE_RESPONSE_INVALID: UNKNOWN,\n BRIDGE_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n // Any failure after GalaConnect accepted a bridge-out request: the tokens may be locked, so\n // never a retry under a fresh key, whatever the inner failure (a BridgeTokenOut 429 included).\n BRIDGE_OUT_OUTCOME_UNKNOWN: UNKNOWN,\n // A bridge-in deposit that failed once it was being sent (sending, confirming, registering): the\n // funds may have left the wallet. A status wait that timed out: the bridge may still complete.\n BRIDGE_DEPOSIT_OUTCOME_UNKNOWN: UNKNOWN,\n BRIDGE_STATUS_TIMEOUT: UNKNOWN,\n\n // --------------------------------------------------------------------- write: refused, not queued\n SHADOW_NOT_QUEUED: NOT_QUEUED_FINAL,\n METHOD_NOT_ALLOWED: NOT_QUEUED,\n SIGNATURE_INVALID: NOT_QUEUED,\n SIGNER_MISMATCH: NOT_QUEUED,\n DTO_INVALID: NOT_QUEUED,\n BOUNDS_VIOLATION: NOT_QUEUED,\n SYMBOL_CONFLICT: NOT_QUEUED,\n RATE_LIMITED: NOT_QUEUED,\n GATEWAY_REJECTED: NOT_QUEUED,\n\n // ----------------------------------------------------------------------- the chain's own verdict\n CHAIN_REJECTED: REJECTED,\n\n // ----------------------------------------------------------------------- reads of backend data\n INVALID_CHAIN_RESPONSE: TRANSIENT,\n INVALID_POSITION_RESPONSE: TRANSIENT,\n // Core `GatewayReads` (unsigned token-contract reads): nothing is applied, so a refusal or an\n // unusable answer is worth another try; a class that does not exist, or a data set larger than\n // the caller allowed, needs a different request.\n GATEWAY_READ_REJECTED: TRANSIENT,\n GATEWAY_READ_RESPONSE_INVALID: TRANSIENT,\n // Core `./bridge` GalaConnect reads (configurations, fee, status): the same as a gateway read;\n // a symbol GalaConnect has no verified configuration for needs a different request.\n BRIDGE_READ_RESPONSE_INVALID: TRANSIENT,\n BRIDGE_TOKEN_NOT_FOUND: INVALID_INPUT,\n // A token the wrappable list does not have (or its counterpart, or a channel a wrap does not\n // move between): a different request is needed.\n TOKEN_NOT_WRAPPABLE: INVALID_INPUT,\n // A failed or unusable read of the external chain before a bridge-in deposit: nothing was sent.\n BRIDGE_CHAIN_READ_FAILED: TRANSIENT,\n TOKEN_CLASS_NOT_FOUND: INVALID_INPUT,\n PAGINATION_LIMIT_EXCEEDED: INVALID_INPUT,\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: UNKNOWN,\n CONFIRMATION_ABORTED: UNKNOWN,\n CONFIRMATION_FAILED: UNKNOWN,\n CONFIRMATION_MALFORMED: UNKNOWN,\n CONFIRMATION_KEY_MISMATCH: UNKNOWN,\n\n // ------------------------------------------------------------------------------ the realtime stream\n STREAM_DISCONNECTED: TRANSIENT,\n STREAM_REQUEST_TIMEOUT: TRANSIENT,\n STREAM_CONNECT_FAILED: TRANSIENT,\n STREAM_CLOSED_BEFORE_CONNECT: TRANSIENT,\n STREAM_CONNECTION_CLOSED: TRANSIENT,\n\n // ----------------------------------------------- pre-send: an app-supplied callback failed\n // The signer, the key provider or the token resolver threw before anything was transmitted. The\n // original error is `cause`. A repeat cannot apply anything twice.\n SIGNING_FAILED: NOT_SENT,\n KEY_PROVIDER_FAILED: NOT_SENT,\n TOKEN_RESOLUTION_FAILED: NOT_SENT,\n TOKEN_NAME_RESOLUTION_FAILED: NOT_SENT,\n\n // ------------------------------------------- the call cannot work as written, found AFTER an answer\n // (a pre_send code needs no row: it is `invalid_input` by default, see `CodeTable`)\n NO_WALLET_ADDRESS: INVALID_INPUT,\n NO_POOL_AVAILABLE: INVALID_INPUT,\n INSUFFICIENT_LIQUIDITY: INVALID_INPUT,\n} as const satisfies CodeTable;\n\n/** Both catalogs as one type: every code a `GSwapSDKError` can carry reads its entry here. */\ntype Catalogs = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** A code (core or DEX) whose catalog phase is `pre_send`. */\ntype PreSendCode = {\n [C in GSwapErrorCode]: Catalogs[C]['phase'] extends 'pre_send' ? C : never;\n}[GSwapErrorCode];\n\n/** The codes whose classification depends on the failing answer, not on a table row. */\ntype AnswerDependentCode =\n | 'HTTP_ERROR'\n | 'UPDATE_REQUIRED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'INVALID_PRIVATE_KEY'\n | 'GATEWAY_HTTP_ERROR'\n | 'GALACONNECT_HTTP_ERROR'\n | 'GATEWAY_WRITE_REJECTED'\n | 'BRIDGE_REQUEST_REJECTED';\n\n/**\n * Every code that is NOT `pre_send` needs a row (a new one is a compile error until it has one);\n * a `pre_send` code may have one (`SIGNING_FAILED` is `not_sent`). A `pre_send` code without a row\n * is `invalid_input`: nothing was transmitted, so it cannot be `unknown`, and it is not a\n * condition a repeat clears. That keeps the 90-odd validation codes out of the table, which is\n * what keeps `classifyFailure` small enough for an app shell.\n */\ntype CodeTable = {\n readonly [C in Exclude<GSwapErrorCode, PreSendCode | AnswerDependentCode>]: FailureClassification;\n} & {\n readonly [C in Exclude<PreSendCode, AnswerDependentCode>]?: FailureClassification;\n};\n\n/**\n * A key that is not valid is the input's fault (`invalid_input`), except `no_key_provided`: the\n * provider had nothing to give right now (a locked wallet, an empty slot). That is the same\n * situation as a provider that throws (`KEY_PROVIDER_FAILED`), and it clears once a key exists, so\n * it is `not_sent` and Retry is safe.\n */\nfunction classifyInvalidPrivateKey(view: FailureView): FailureClassification {\n return stringParamOf(view, 'reason') === 'no_key_provided' ? NOT_SENT : INVALID_INPUT;\n}\n\n/** The status of an HTTP failure: the one it carries, else its `status` param. */\nfunction statusOfView(view: FailureView): number | undefined {\n return view.status ?? numberParamOf(view, 'status');\n}\n\n/**\n * An HTTP failure with no gateway or chain code: its meaning depends on the status and on read vs\n * write. A view that states no status at all cannot be judged: `unknown`.\n */\nfunction classifyHttpError(view: FailureView): FailureClassification {\n const status = statusOfView(view);\n if (status === undefined) return UNKNOWN;\n if (isWriteView(view)) {\n // A gateway that answered 5xx or 408 may still have queued the write; 429 and 4xx did not.\n if (status === 429) return NOT_QUEUED;\n if (status === 408 || status >= 500) return UNKNOWN;\n return NOT_QUEUED_FINAL;\n }\n return status === 408 || status === 429 || status >= 500 ? TRANSIENT : INVALID_INPUT;\n}\n\n/**\n * A core `./bridge` GalaConnect HTTP failure: like {@link classifyHttpError}, except that a\n * WRITE answered 409 is `unknown`: GalaChain's \"this uniqueKey was already consumed\", after which\n * an earlier attempt under the key may be applied (a bridge-out that locked the tokens).\n */\nfunction classifyGalaConnectHttpError(view: FailureView): FailureClassification {\n return isWriteView(view) && statusOfView(view) === 409 ? UNKNOWN : classifyHttpError(view);\n}\n\n/**\n * The version wall (HTTP 426). On a write the gateway refused it before queueing anything, and a\n * repeat of the same app version is refused the same way, so it is `not_queued` with no Retry. On a\n * read nothing changed either, and only an update helps: `invalid_input`, no Retry. Both say \"show\n * the update screen\", not \"try again\".\n */\nfunction classifyUpdateRequired(view: FailureView): FailureClassification {\n return isWriteView(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;\n}\n\n/**\n * The chain dispatch failed. The gateway echoes the upstream status: 409 is \"this uniqueKey was\n * already consumed\" (the first attempt may be applied), 422 is the chain evaluating the write and\n * refusing it (definite), another 5xx is an upstream outage after which the write may have landed,\n * and a 4xx is a refusal before anything was queued.\n */\nfunction classifyChainDispatchFailed(view: FailureView): FailureClassification {\n const status = view.status;\n if (status === undefined || status === 409 || status >= 500) return UNKNOWN;\n return status === 422 ? REJECTED : NOT_QUEUED;\n}\n\n/**\n * GalaChain answered a core `GatewayWrites` token-contract write with a `Status` other than 1: the\n * chain's verdict, so the write was not applied (`rejected`), except where the verdict does not\n * prove that: a 409 is \"this uniqueKey was already consumed\" (an earlier attempt under it may be\n * applied), and a 5xx, or no status at all, cannot be judged.\n */\nfunction classifyGatewayWriteRejected(view: FailureView): FailureClassification {\n const status = view.status;\n return status === undefined || status === 409 || status >= 500 ? UNKNOWN : REJECTED;\n}\n\n/**\n * Classifies any thrown value from its code (and, for a few codes, its HTTP status), never from\n * message text, so an app does not have to re-derive \"may I offer Retry?\" and \"is the outcome\n * unknown?\" for every code. The decision for each code is in this module's table; a new catalog\n * code cannot be added without one.\n *\n * A failure BEFORE the request left (`error.phase === 'pre_send'`, `isPreSendError`) can never be\n * `unknown` or `rejected`: it is `invalid_input` (the input has to change) or `not_sent` (nothing\n * was transmitted; a repeat is safe). Every app-supplied callback the SDK calls before it sends\n * (the signer, the key provider, a token resolver) has its failure wrapped into such an error\n * (`SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original as `cause`),\n * so an app NEVER needs an error class of its own to say \"nothing was sent\": a locked wallet,\n * a declined signature and a failed lookup all arrive as `not_sent`, retryable.\n *\n * It accepts a `GSwapSDKError` or a plain-object VIEW of one ({@link FailureView}: `{ code,\n * params?, status?, uniqueKey?, ... }`, the shape of the wrapper an app builds from an SDK error;\n * `toFailureView` reads any value), and decides from the same fields, so an app does not need to\n * keep the original error to ask. `{ afterQueued: true }` says the write is already queued (the\n * step being classified is a confirmation): `retryable` is then always `false`.\n *\n * Anything that is not an SDK error or such a view, or a view whose `code` the catalog does not\n * define, is `{ outcome: 'unknown', retryable: false }`: the SDK\n * cannot say what happened, and refusing Retry is the safe answer. That is only what escapes AFTER\n * the request left (an app requestor that rejects with its own error, a callback of yours that\n * throws once bytes were sent). An error your own code raises BEFORE it calls the SDK says so\n * itself: give it a code of its own and `outcome` (`{ code: 'POSITION_STALE', outcome: 'not_sent'\n * }`), and the SDK answers with that outcome's classification and `mayHaveBeenQueued` is `false`.\n * The declared `outcome` is read only for a code the catalog does not define.\n *\n * A failure is a WRITE's unless it states `write: false` (`GSwapSDKError.write`, set for every\n * SDK read): see {@link FailureView}. A view that lost its `uniqueKey` is therefore still judged as\n * a write (a 5xx stays `unknown`), never as a retryable read.\n *\n * To learn that a failure came from the dark (shadow) path, read `error.shadow` (a typed field of\n * every `GSwapSDKError`) or call `isShadowError(error)`, which also covers a non-SDK object that\n * escaped `swapShadow` / `submitSwapShadow` / `ChainGateway.submitShadow`. The classification is\n * the same as on the public path; an app that withholds Retry or a public fallback after a dark\n * swap applies that policy on top of `retryable`.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { outcome, retryable } = classifyFailure(error);\n * if (outcome === 'unknown') keepPendingAndConfirm(error); // never a second swap\n * else if (retryable) offerRetry(); // a new request under a fresh key\n * }\n * ```\n */\nexport function classifyFailure(\n error: unknown,\n options: ClassifyFailureOptions = {},\n): FailureClassification {\n const result = classifyView(toFailureView(error));\n // A `rejected` outcome is the chain's definite no: the queued write was evaluated and NOT\n // applied, so a new request under a fresh key cannot double-apply it and Retry stays as it is.\n return options.afterQueued === true && result.outcome !== 'rejected'\n ? { ...result, retryable: false }\n : result;\n}\n\n/** Options of {@link classifyFailure}. */\nexport interface ClassifyFailureOptions {\n /**\n * The write is ALREADY queued (the gateway acknowledged it with this `uniqueKey`), and what is\n * being classified is a later step: confirming it, reading its apply result. Whatever the\n * outcome, `retryable` is then `false`: a NEW request would be a second trade, so the app\n * confirms the same key (or forgets it) and never offers \"Try again\". `outcome` is unchanged.\n *\n * The one exception is `rejected`: the chain evaluated the queued write and refused it (an\n * apply result of `Status: 0`, `CHAIN_REJECTED`; a 422 dispatch). That PROVES it was not\n * applied, so a new request under a fresh key cannot make a second trade, and `retryable`\n * keeps the answer it has without this option (`true`). Every outcome that does not prove\n * \"not applied\" (`unknown`, `transient`, `not_queued`, ...) is `false`.\n */\n afterQueued?: boolean | undefined;\n}\n\n/**\n * The classification of a failure view: the table decision for its code, the status-dependent\n * decision for the codes whose meaning needs it, and for a code the catalog does not define\n * (a wallet error, an ethers `ACTION_REJECTED`, a typo, an app's own error): `unknown` unless the\n * view DECLARES its `outcome` (an app's error, `{ code: 'POSITION_STALE', outcome: 'not_sent' }`),\n * then the SDK's own classification of that outcome. A value with no view is `unknown`.\n */\nfunction classifyView(view: FailureView | undefined): FailureClassification {\n if (view === undefined) return { ...UNKNOWN };\n if (!isCatalogCode(view.code)) {\n if (view.outcome === undefined) return { ...UNKNOWN };\n // Withhold-only: `retryable: false` removes Retry from the declared outcome, never adds it.\n return view.retryable === false\n ? classification(view.outcome, { retryable: false })\n : classification(view.outcome);\n }\n const { code } = view;\n // A core gateway HTTP failure without a chain envelope reads exactly like HTTP_ERROR (by its\n // status, and read vs write); so does a GalaConnect one, except a write's 409.\n if (code === 'HTTP_ERROR' || code === 'GATEWAY_HTTP_ERROR') {\n return { ...classifyHttpError(view) };\n }\n if (code === 'GALACONNECT_HTTP_ERROR') return { ...classifyGalaConnectHttpError(view) };\n // GalaChain's refusal of a core gateway or GalaConnect bridge write: by the chain's code.\n if (code === 'GATEWAY_WRITE_REJECTED' || code === 'BRIDGE_REQUEST_REJECTED') {\n return { ...classifyGatewayWriteRejected(view) };\n }\n if (code === 'UPDATE_REQUIRED') return { ...classifyUpdateRequired(view) };\n if (code === 'CHAIN_DISPATCH_FAILED') return { ...classifyChainDispatchFailed(view) };\n if (code === 'INVALID_PRIVATE_KEY') return { ...classifyInvalidPrivateKey(view) };\n const row: FailureClassification | undefined = (\n BY_CODE as Readonly<Partial<Record<GSwapErrorCode, FailureClassification>>>\n )[code];\n return { ...(row ?? INVALID_INPUT) };\n}\n\n/**\n * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is\n * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after\n * the request left, an acknowledgement that proves nothing, a gateway 409 or 5xx, a failed\n * confirmation). The app must keep `error.uniqueKey` and confirm it, and must NOT submit again\n * under a fresh key. Every other outcome (`rejected`, `not_queued`, `not_sent`, `invalid_input`,\n * `transient`) proves the write is not pending.\n *\n * A value the SDK cannot judge (an app requestor's own rejection after the request left) is\n * `unknown` too, so it is `true`; handle errors your own code raised BEFORE calling the SDK first.\n * Meant for the catch of a write; a read never has a pending key to keep.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * if (mayHaveBeenQueued(error)) keepPendingAndConfirm(error);\n * }\n * ```\n */\nexport function mayHaveBeenQueued(error: unknown): boolean {\n return classifyFailure(error).outcome === 'unknown';\n}\n","import { classifyFailure } from '../utils/failure_classification.js';\nimport type { FailureOutcome } from '@gala-chain/gala-core-sdk';\n\n/**\n * What to do with a pending swap after confirming it failed (the answer of\n * {@link pendingSwapFateFor}).\n *\n * - `forget`: the chain REFUSED the trade, so it did not happen. Drop it AND tell the user.\n * - `forget_quietly`: the confirmation can never succeed (the key is refused: `invalid_input`).\n * Drop it without claiming anything about the trade.\n * - `keep`: the trade may still have been applied (a timeout, a broken connection, a gateway\n * hiccup, anything not proven). Leave it pending and look again later.\n *\n * This module holds the decision and nothing of the store, so an app shell that only needs the\n * fate pays for `classifyFailure` and this table, not for `PendingSwapStore`.\n */\nexport const PENDING_SWAP_FATES = ['forget', 'forget_quietly', 'keep'] as const;\n\n/** One member of {@link PENDING_SWAP_FATES}. */\nexport type PendingSwapFate = (typeof PENDING_SWAP_FATES)[number];\n\n/**\n * The fate of a pending swap for each failure OUTCOME. Only a chain rejection proves the trade did\n * not happen; an input that can never be confirmed is dropped quietly; every other outcome leaves\n * the trade possibly applied. Typed over `FailureOutcome`, so a new outcome does not compile until\n * it is decided here.\n */\nconst FATE_OF_OUTCOME = {\n rejected: 'forget',\n invalid_input: 'forget_quietly',\n unknown: 'keep',\n not_queued: 'keep',\n not_sent: 'keep',\n transient: 'keep',\n} as const satisfies Record<FailureOutcome, PendingSwapFate>;\n\n/**\n * {@link pendingSwapFateFor} from an outcome the app already holds (for example the\n * `classifyFailure(error).outcome` it stored on its own failure wrapper). An outcome this SDK\n * version does not know (a newer SDK at run time) is `keep`: never forget what may have happened.\n */\nexport function pendingSwapFateOfOutcome(outcome: FailureOutcome): PendingSwapFate {\n return Object.hasOwn(FATE_OF_OUTCOME, outcome) ? FATE_OF_OUTCOME[outcome] : 'keep';\n}\n\n/**\n * The fate of a queued swap whose confirmation (`confirmAppliedTrade`) just failed with `error`,\n * from the SDK's classification alone: `forget` for a chain rejection (`rejected`), `forget_quietly`\n * for a key that can never be confirmed (`invalid_input`), `keep` for every other outcome\n * (`unknown`, `not_queued`, `not_sent`, `transient`) and for any value the SDK cannot judge. It\n * accepts an SDK error or a plain-object view of one (see `FailureView`). It replaces the\n * hand-written \"forget it or keep it\" table an app would otherwise keep.\n *\n * @example\n * ```ts\n * try {\n * await confirmAppliedTrade(client, swap);\n * } catch (error) {\n * if ((await store.settle(swap.uniqueKey, error)) === 'forget') tellTheUserItFailed();\n * }\n * ```\n */\nexport function pendingSwapFateFor(error: unknown): PendingSwapFate {\n return pendingSwapFateOfOutcome(classifyFailure(error, { afterQueued: true }).outcome);\n}\n","import { isValidUniqueKey } from '@gala-chain/gala-core-sdk';\nimport { pendingSwapFateFor, type PendingSwapFate } from './pending_swap_fate.js';\nimport type { StorageAdapter } from './storage_adapters.js';\n\n/** Default storage key; the stored value is a plain array of entries. */\nexport const PENDING_SWAPS_STORAGE_KEY = 'pendingSwaps.v1';\n\n/** Entries older than this are dropped the next time a wallet's swaps are listed. */\nexport const PENDING_SWAP_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** A RequestTrade that was accepted by the gateway but whose outcome has not been read yet. */\nexport interface PendingSwap {\n uniqueKey: string;\n requestTransactionId: string | null;\n /** The wallet (account) that submitted the swap; `list` filters by it. */\n wallet: string;\n token0Symbol: string;\n token1Symbol: string;\n /** Whether the swap was a shadow (\"dark\") swap. */\n isDarkSwap: boolean;\n /** Epoch milliseconds when the swap was queued. */\n createdAt: number;\n}\n\n/**\n * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).\n *\n * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.\n * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters\n * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`\n * before reading anything and always will, so keeping the entry would retry it forever. The\n * SDK never signs such a key; an entry like this is corrupt or foreign.\n * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the\n * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.\n * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a\n * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.\n */\nexport const PENDING_SWAP_PRUNE_REASONS = [\n 'expired',\n 'invalid_unique_key',\n 'chain_rejected',\n 'unconfirmable',\n] as const;\n\n/** One member of {@link PENDING_SWAP_PRUNE_REASONS}. */\nexport type PendingSwapPruneReason = (typeof PENDING_SWAP_PRUNE_REASONS)[number];\n\n/** A pending swap the store dropped, and why. */\nexport interface PrunedPendingSwap {\n swap: PendingSwap;\n reason: PendingSwapPruneReason;\n}\n\n/** Options for {@link PendingSwapStore}. */\nexport interface PendingSwapStoreOptions {\n /**\n * Called once per dropped entry (after the drop is persisted, for `list`; at once for a\n * `remember` that refuses an invalid key), so the app can tell the user or log why a swap it\n * was tracking is gone. Diagnostics only: what it does, or throws, never changes the store.\n */\n onPrune?: ((pruned: PrunedPendingSwap) => void) | undefined;\n /** Storage key. Default {@link PENDING_SWAPS_STORAGE_KEY}. */\n storageKey?: string | undefined;\n /**\n * The stored name of the dark-swap flag: `isDarkSwap` (default) or `shadow`, for storage written\n * by an older web app. Entries are always exposed to callers as `isDarkSwap`.\n */\n darkFlagField?: 'isDarkSwap' | 'shadow' | undefined;\n /**\n * Where `remember` puts a new entry in the stored array: `end` (default) or `start`.\n */\n insertAt?: 'end' | 'start' | undefined;\n /**\n * The order of `list`: `stored` (default: oldest first for `insertAt: 'end'`) or\n * `newest-first`.\n */\n listOrder?: 'stored' | 'newest-first' | undefined;\n /** Clock, in epoch milliseconds. Defaults to `Date.now`. */\n now?: (() => number) | undefined;\n}\n\n/**\n * Remembers queued swaps so their outcome can be confirmed after the UI, popup or service worker\n * that submitted them is gone (`confirmAppliedTrade` with the stored `uniqueKey`).\n *\n * Guarantees:\n * - Persistence is best effort and NEVER throws: a failing or missing storage must not turn an\n * accepted request into a client-side resubmission. `list` resolves `[]` when storage fails.\n * - Operations of one store instance are serialized, so concurrent `remember` / `forget` calls\n * cannot lose each other's write (read-modify-write over an async adapter). Two store instances\n * over the same storage (for example popup and service worker) are not coordinated.\n * - Entries that do not match the expected shape are ignored and dropped on the next write.\n * - Entries expire after seven days (an entry exactly seven days old is expired); `list` removes\n * them from storage.\n * - An entry whose `uniqueKey` is not a valid apply-results key is terminal, not pending:\n * `confirmAppliedTrade` fails it with `INVALID_UNIQUE_KEY` every time, so a resume loop would\n * retry it forever. `list` prunes it like an expired one, and `remember` refuses to save it;\n * both tell `onPrune` the reason (`PENDING_SWAP_PRUNE_REASONS`).\n * - New entries go to the end (or `insertAt: 'start'`); `list` returns the wallet's entries in\n * stored order (or `listOrder: 'newest-first'`).\n * - `storageKey`, `darkFlagField`, `insertAt` and `listOrder` adapt the stored layout to an\n * existing storage. JSON key order inside an entry is not preserved.\n *\n * Passing no `storage` yields a store that remembers nothing.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore({\n * get: async (key) => (await chrome.storage.local.get(key))[key],\n * set: (key, value) => chrome.storage.local.set({ [key]: value }),\n * });\n * await store.remember({ uniqueKey, requestTransactionId, wallet, token0Symbol: 'GALA',\n * token1Symbol: 'GUSDC', isDarkSwap: false, createdAt: Date.now() });\n * for (const swap of await store.list(wallet)) await confirmAppliedTrade(client, swap);\n * ```\n */\nexport class PendingSwapStore {\n private readonly storageKey: string;\n private readonly darkFlagField: 'isDarkSwap' | 'shadow';\n private readonly insertAt: 'end' | 'start';\n private readonly listOrder: 'stored' | 'newest-first';\n private readonly now: () => number;\n private readonly onPrune: ((pruned: PrunedPendingSwap) => void) | undefined;\n private queue: Promise<unknown> = Promise.resolve();\n\n constructor(\n private readonly storage: StorageAdapter | undefined,\n options: PendingSwapStoreOptions = {},\n ) {\n this.storageKey = options.storageKey ?? PENDING_SWAPS_STORAGE_KEY;\n this.darkFlagField = options.darkFlagField ?? 'isDarkSwap';\n this.insertAt = options.insertAt ?? 'end';\n this.listOrder = options.listOrder ?? 'stored';\n this.now = options.now ?? Date.now;\n this.onPrune = options.onPrune;\n }\n\n /**\n * Saves (or replaces, by `uniqueKey`) a pending swap. A swap whose `uniqueKey` is not a valid\n * apply-results key is not saved (it could never be confirmed); it is reported to `onPrune` as\n * `invalid_unique_key`.\n */\n public remember(swap: PendingSwap): Promise<void> {\n if (!isValidUniqueKey(swap.uniqueKey)) {\n this.report([{ swap, reason: 'invalid_unique_key' }]);\n return Promise.resolve();\n }\n return this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const others = current\n .filter((entry) => entry.uniqueKey !== swap.uniqueKey)\n .map(this.toStored);\n const stored = this.toStored(swap);\n await storage.set(\n this.storageKey,\n this.insertAt === 'end' ? [...others, stored] : [stored, ...others],\n );\n });\n }\n\n /** Removes a pending swap once its outcome is known. */\n public forget(uniqueKey: string): Promise<void> {\n return this.enqueue(async (storage) => {\n const current = await this.read(storage);\n await storage.set(\n this.storageKey,\n current.filter((entry) => entry.uniqueKey !== uniqueKey).map(this.toStored),\n );\n });\n }\n\n /**\n * Applies {@link pendingSwapFateFor} to a swap whose confirmation failed with `error`, and\n * returns the fate so the app can word it (tell the user on `forget`, say nothing on\n * `forget_quietly`, keep polling on `keep`):\n *\n * - `forget`: the entry is removed and `onPrune` hears `chain_rejected`.\n * - `forget_quietly`: the entry is removed and `onPrune` hears `unconfirmable`.\n * - `keep`: nothing changes and `onPrune` is not called.\n *\n * Like every store operation it is serialized and best effort: if storage fails the entry stays\n * (a later `settle` or `list` handles it) and the fate is still returned. A key that is not\n * stored (already forgotten) is not an error and `onPrune` is not called for it.\n */\n public async settle(uniqueKey: string, error: unknown): Promise<PendingSwapFate> {\n const fate = pendingSwapFateFor(error);\n if (fate === 'keep') return fate;\n const removed = await this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const swap = current.find((entry) => entry.uniqueKey === uniqueKey);\n if (swap === undefined) return undefined;\n await storage.set(\n this.storageKey,\n current.filter((entry) => entry.uniqueKey !== uniqueKey).map(this.toStored),\n );\n return swap;\n });\n if (removed !== undefined) {\n this.report([\n { swap: removed, reason: fate === 'forget' ? 'chain_rejected' : 'unconfirmable' },\n ]);\n }\n return fate;\n }\n\n /**\n * The wallet's pending swaps that can still be confirmed (see `listOrder`). Entries that never\n * can be are pruned from storage, for every wallet, and reported to `onPrune`: expired ones\n * (`expired`) and ones whose `uniqueKey` is not a valid apply-results key\n * (`invalid_unique_key`: `confirmAppliedTrade` would fail `INVALID_UNIQUE_KEY` on it forever).\n */\n public async list(wallet: string): Promise<PendingSwap[]> {\n const result = await this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const now = this.now();\n const pruned: PrunedPendingSwap[] = [];\n const kept: PendingSwap[] = [];\n for (const entry of current) {\n const reason = this.pruneReasonOf(entry, now);\n if (reason === undefined) kept.push(entry);\n else pruned.push({ swap: entry, reason });\n }\n if (pruned.length > 0) {\n await storage.set(this.storageKey, kept.map(this.toStored));\n this.report(pruned);\n }\n const mine = kept.filter((entry) => entry.wallet === wallet);\n return this.listOrder === 'newest-first'\n ? mine.sort((left, right) => right.createdAt - left.createdAt)\n : mine;\n });\n return result ?? [];\n }\n\n private pruneReasonOf(entry: PendingSwap, now: number): PendingSwapPruneReason | undefined {\n if (!isValidUniqueKey(entry.uniqueKey)) return 'invalid_unique_key';\n return now - entry.createdAt < PENDING_SWAP_EXPIRY_MS ? undefined : 'expired';\n }\n\n /** Tells `onPrune` about each dropped entry; the hook is diagnostics and cannot break the store. */\n private report(pruned: readonly PrunedPendingSwap[]): void {\n for (const entry of pruned) {\n try {\n this.onPrune?.(entry);\n } catch {\n // A diagnostics hook must not turn a store operation into a failure.\n }\n }\n }\n\n private enqueue<T>(operation: (storage: StorageAdapter) => Promise<T>): Promise<T | undefined> {\n const storage = this.storage;\n if (storage === undefined) return Promise.resolve(undefined);\n const run = this.queue.then(async () => {\n try {\n return await operation(storage);\n } catch {\n // Storage can be missing, full, or disappear while a context is closing. Persistence is\n // best effort by contract.\n return undefined;\n }\n });\n this.queue = run;\n return run;\n }\n\n private async read(storage: StorageAdapter): Promise<PendingSwap[]> {\n const value = await storage.get(this.storageKey);\n if (!Array.isArray(value)) return [];\n const entries: PendingSwap[] = [];\n for (const item of value as unknown[]) {\n const entry = this.fromStored(item);\n if (entry !== undefined) entries.push(entry);\n }\n return entries;\n }\n\n private readonly toStored = (swap: PendingSwap): Record<string, unknown> => ({\n uniqueKey: swap.uniqueKey,\n requestTransactionId: swap.requestTransactionId,\n wallet: swap.wallet,\n token0Symbol: swap.token0Symbol,\n token1Symbol: swap.token1Symbol,\n [this.darkFlagField]: swap.isDarkSwap,\n createdAt: swap.createdAt,\n });\n\n private fromStored(value: unknown): PendingSwap | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n const entry = value as Record<string, unknown>;\n const flag = entry[this.darkFlagField];\n const { uniqueKey, requestTransactionId, wallet, token0Symbol, token1Symbol, createdAt } =\n entry;\n if (\n typeof uniqueKey !== 'string' ||\n !(typeof requestTransactionId === 'string' || requestTransactionId === null) ||\n typeof wallet !== 'string' ||\n typeof token0Symbol !== 'string' ||\n typeof token1Symbol !== 'string' ||\n typeof flag !== 'boolean' ||\n typeof createdAt !== 'number' ||\n !Number.isFinite(createdAt)\n ) {\n return undefined;\n }\n return {\n uniqueKey,\n requestTransactionId,\n wallet,\n token0Symbol,\n token1Symbol,\n isDarkSwap: flag,\n createdAt,\n };\n }\n}\n","/**\n * Async key/value storage the pending-swap store persists through. It stores STRUCTURED VALUES\n * (the store never serializes), so each platform decides how a value lands on disk:\n *\n * - `chrome.storage.local`: `get: async (k) => (await chrome.storage.local.get(k))[k]`,\n * `set: (k, v) => chrome.storage.local.set({ [k]: v })`. This is the wallet's stored shape.\n * {@link storageAdapterFromChromeStorage} builds it.\n * - `localStorage` (a web app): JSON text under the key. {@link webStorageAdapter} builds it,\n * and returns CORRUPT JSON as a value (the raw string), not as a rejection: a value that is not\n * an array reads as \"no entries\" and the next write repairs it, whereas a `get` that rejects\n * forever makes every `remember` a no-op.\n * - React Native: AsyncStorage with the same JSON wrapping and the same corrupt-JSON rule.\n *\n * `get` resolves `undefined` for a missing key. Either method may reject; the store treats that\n * as \"storage unavailable\" and never lets it surface (see `PendingSwapStore`).\n *\n * This module imports nothing, so an app shell that only builds an adapter pays for the adapter.\n */\nexport interface StorageAdapter {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n}\n\n/**\n * The part of a `chrome.storage` area ({@link storageAdapterFromChromeStorage}) the adapter uses,\n * written structurally so the SDK needs no `chrome` types: `chrome.storage.local`,\n * `chrome.storage.session`, `browser.storage.local` (webextension-polyfill) and any object with\n * these two promise-returning methods satisfy it. It is the Manifest V3 promise form: the methods\n * are called WITHOUT a callback.\n */\nexport interface ChromeStorageAreaLike {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\n/**\n * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps\n * in: the value lands under the key as the structured value it is (the browser clones it; nothing\n * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the\n * store, which treats it as \"storage unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension\n * context) then fails only when the store touches storage, and that failure (a throw inside the\n * function) is the same \"storage unavailable\" rejection.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));\n * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));\n * ```\n */\nexport function storageAdapterFromChromeStorage(\n area: ChromeStorageAreaLike | (() => ChromeStorageAreaLike),\n): StorageAdapter {\n const areaNow = (): ChromeStorageAreaLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const items = await areaNow().get(key);\n return Object.hasOwn(items, key) ? items[key] : undefined;\n },\n async set(key, value) {\n await areaNow().set({ [key]: value });\n },\n };\n}\n\n/**\n * The part of a Web Storage area ({@link webStorageAdapter}) the adapter uses, written\n * structurally so the SDK needs no DOM types: `localStorage`, `sessionStorage` and any object with\n * these two synchronous methods (a React Native MMKV wrapper, a test double) satisfy it.\n */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape\n * a web app stores pending swaps in: the value lands under the key as JSON text. A missing key\n * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store\n * reads a value that is not an array as \"no entries\" and the next write repairs it, whereas a\n * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked\n * by the browser, quota exceeded on `setItem`) rejects, which the store treats as \"storage\n * unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: where `localStorage` does not exist (server rendering, a test, a blocked context)\n * the access throws inside the function, which is the same \"storage unavailable\" rejection, and\n * the module that builds the adapter still loads.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));\n * ```\n */\nexport function webStorageAdapter(area: WebStorageLike | (() => WebStorageLike)): StorageAdapter {\n const areaNow = (): WebStorageLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const raw = areaNow().getItem(key);\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n },\n async set(key, value) {\n areaNow().setItem(key, JSON.stringify(value));\n },\n };\n}\n","import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\n\n/**\n * Where a failed CONFIRMATION of a queued write stopped, as a closed set a screen can switch on:\n *\n * - `aborted`: the caller's own `AbortSignal` ended the wait (`CONFIRMATION_ABORTED`). The person\n * or the screen gave up waiting; the write may still land, and its `uniqueKey` is still the handle.\n * - `timeout`: the wait ran out before an apply result arrived (`CONFIRMATION_TIMEOUT`). The write\n * is still pending as far as anyone knows.\n * - `failed`: the apply-results read itself failed or answered something unusable\n * (`CONFIRMATION_FAILED`, `CONFIRMATION_MALFORMED`, `CONFIRMATION_KEY_MISMATCH`).\n *\n * All three are `unknown` to `classifyFailure`: never submit again, confirm the same key.\n */\nexport type ConfirmationState = 'aborted' | 'timeout' | 'failed';\n\n/** The state of every confirmation code (a typo is caught by the all-codes test). */\nconst STATE_OF_CODE = {\n CONFIRMATION_ABORTED: 'aborted',\n CONFIRMATION_TIMEOUT: 'timeout',\n CONFIRMATION_FAILED: 'failed',\n CONFIRMATION_MALFORMED: 'failed',\n CONFIRMATION_KEY_MISMATCH: 'failed',\n} as const satisfies Partial<Record<GSwapErrorCode, ConfirmationState>>;\n\n/**\n * The {@link ConfirmationState} of a failure, or `undefined` when it is not a failed confirmation.\n * Accepts an SDK error or a plain-object view of one (an app's wrapper with a `code`), and decides\n * from the code alone, so a screen never matches `'CONFIRMATION_ABORTED'` itself.\n *\n * @example\n * ```ts\n * switch (confirmationStateOf(error)) {\n * case 'aborted': return; // the person closed the dialog\n * case 'timeout': return showStillPending(error.uniqueKey);\n * case 'failed': return showCouldNotCheck(error.uniqueKey);\n * case undefined: return showFailure(error);\n * }\n * ```\n */\nexport function confirmationStateOf(error: unknown): ConfirmationState | undefined {\n const code = toFailureView(error)?.code;\n if (code === undefined) return undefined;\n return Object.entries(STATE_OF_CODE).find(([known]) => known === code)?.[1];\n}\n\n/** True when the wait for the apply result was ended by the caller's `AbortSignal`. */\nexport function isConfirmationAborted(error: unknown): boolean {\n return confirmationStateOf(error) === 'aborted';\n}\n\n/** True when the wait for the apply result ran out of time (`CONFIRMATION_TIMEOUT`). */\nexport function isConfirmationTimeout(error: unknown): boolean {\n return confirmationStateOf(error) === 'timeout';\n}\n","import { isWriteView, stringParamOf, toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure\n * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in\n * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased\n * at build time). An app shell that imports one of them pays for this module and nothing else.\n */\n\n/**\n * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a\n * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied\n * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting\n * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&\n * error.status === 409` and the regex on \"already saved\". Accepts an SDK error or a plain-object\n * view ({@link FailureView}: `code` and `status`); every other value is `false`.\n *\n * @example\n * ```ts\n * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);\n * ```\n */\nexport function isUniqueKeyConsumed(error: unknown): boolean {\n const view = toFailureView(error);\n return view?.code === 'CHAIN_DISPATCH_FAILED' && view.status === 409;\n}\n\nconst UNPROVEN_ACKNOWLEDGEMENT_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_DATA_MISSING',\n 'GATEWAY_MODE_INVALID',\n 'GATEWAY_SYNC_REQUEST_TRADE',\n 'MISSING_UNIQUE_KEY',\n 'UNIQUE_KEY_MISMATCH',\n];\n\n/**\n * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no\n * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.\n * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an\n * app shows is one line for all five (\"the backend did not confirm it queued the request\"), so\n * the app asks this instead of keeping its own list of the codes. A gateway that says\n * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.\n *\n * @example\n * ```ts\n * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);\n * ```\n */\nexport function isUnprovenAcknowledgement(error: unknown): boolean {\n return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);\n}\n\n/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */\nfunction isCodeIn(code: string, codes: readonly GSwapErrorCode[]): boolean {\n return codes.some((known) => known === code);\n}\n\n/**\n * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose\n * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet\n * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.\n */\nfunction hasCodeIn(error: unknown, codes: readonly GSwapErrorCode[]): boolean {\n const view = toFailureView(error);\n // `codes` holds catalog codes only, so membership already means \"a catalog code\": no table needed.\n return view !== undefined && isCodeIn(view.code, codes);\n}\n\n/**\n * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app\n * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made\n * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the\n * SDK knows, and `GATEWAY_REJECTED` for one it does not).\n */\nconst RELAYABLE_REFUSAL_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_REPORTED_ERROR',\n 'METHOD_NOT_ALLOWED',\n 'SIGNATURE_INVALID',\n 'SIGNER_MISMATCH',\n 'DTO_INVALID',\n 'BOUNDS_VIOLATION',\n 'SYMBOL_CONFLICT',\n 'RATE_LIMITED',\n 'CHAIN_DISPATCH_FAILED',\n 'GATEWAY_REJECTED',\n];\n\n/**\n * True when the error is a gateway refusal whose `params.serverMessage` an app may relay to the\n * person as the gateway sent it: `GATEWAY_REPORTED_ERROR`, the gateway bounces (`METHOD_NOT_ALLOWED`,\n * `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `BOUNDS_VIOLATION`, `SYMBOL_CONFLICT`,\n * `RATE_LIMITED`, `GATEWAY_REJECTED`) and `CHAIN_DISPATCH_FAILED`. The app shows `serverMessage` when\n * it is not empty and its own line when it is; the SDK's English `message` is never what to show.\n *\n * It accepts a plain-object view of an SDK error too ({@link FailureView}: an app's wrapper with a\n * `code`), and decides from the code in the same way. It narrows to `GSwapSDKError<...>` ONLY when\n * called with an SDK error; with an `unknown` or a view it answers `boolean` (narrow with\n * `isGSwapError` first, or read the view's own `params`).\n *\n * It is a test on the code alone, so it also holds for `CHAIN_DISPATCH_FAILED` with HTTP 409\n * (the `uniqueKey` was already consumed; `classifyFailure` says `unknown`): an app that words that\n * case itself (\"already submitted\", then confirm the key) checks `error.status === 409` BEFORE\n * relaying. It is false for `CHAIN_REJECTED` (the chain's verdict, worded by where it is shown: the\n * submit and confirm screens differ), for `HTTP_ERROR` (a proxy's page, not an answer to this\n * write) and for the five unproven acknowledgements (`isUnprovenAcknowledgement`: they carry no\n * server text).\n *\n * @example\n * ```ts\n * if (isRelayableRefusal(error)) show(error.params.serverMessage || t('swap.requestFailed'));\n * ```\n */\nexport function isRelayableRefusal(error: GSwapSDKError): error is GSwapSDKError<RelayableCode>;\nexport function isRelayableRefusal(error: unknown): boolean;\nexport function isRelayableRefusal(error: unknown): boolean {\n return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);\n}\n\n/** The codes {@link isRelayableRefusal} is true for. */\nexport type RelayableCode =\n | 'GATEWAY_REPORTED_ERROR'\n | 'METHOD_NOT_ALLOWED'\n | 'SIGNATURE_INVALID'\n | 'SIGNER_MISMATCH'\n | 'DTO_INVALID'\n | 'BOUNDS_VIOLATION'\n | 'SYMBOL_CONFLICT'\n | 'RATE_LIMITED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'GATEWAY_REJECTED';\n\n/**\n * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in\n * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements\n * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).\n * The outcome is `unknown` for all six. It replaces the app's own\n * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.\n */\nexport function isUninterpretedAnswer(error: unknown): boolean {\n return isUnprovenAcknowledgement(error) || hasCodeIn(error, ['GATEWAY_REPORTED_ERROR']);\n}\n\n/**\n * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,\n * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the\n * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's\n * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it\n * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent\n * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.\n *\n * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every\n * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named\n * param, so a stray field cannot pass for a chain verdict.\n *\n * @example\n * ```ts\n * const key = chainErrorKeyOf(error);\n * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);\n * ```\n */\nexport function chainErrorKeyOf(error: unknown): string | undefined {\n const view = toFailureView(error);\n if (view === undefined) return undefined;\n if (view.code !== 'CHAIN_REJECTED' && view.code !== 'CHAIN_DISPATCH_FAILED') return undefined;\n const errorKey = stringParamOf(view, 'errorKey');\n return errorKey === undefined || errorKey === '' ? undefined : errorKey;\n}\n\n/** Codes that mean \"there is no market for this\" however the app reached them. */\nconst NO_MARKET_CODES: readonly GSwapErrorCode[] = [\n 'NO_POOL_AVAILABLE',\n 'INSUFFICIENT_LIQUIDITY',\n 'UNKNOWN_TOKEN',\n];\n\n/**\n * True when a failure means \"there is no market to trade this pair\": `NO_POOL_AVAILABLE` (no pool\n * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX\n * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend\n * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||\n * notFound` list, so the empty-state (\"No market for this pair\") has one definition.\n *\n * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing\n * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every\n * other value is `false`.\n *\n * @example\n * ```ts\n * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);\n * ```\n */\nexport function isNoMarket(error: unknown): boolean {\n const view = toFailureView(error);\n if (view === undefined) return false;\n if (isCodeIn(view.code, NO_MARKET_CODES)) return true;\n return !isWriteView(view) && (view.notFound === true || view.status === 404);\n}\n","/**\n * What a write's gateway answer says about the write, as one vocabulary for every app.\n *\n * The gateway answers `{ status, message, error, data }`. `data.mode` is `'sync'` for a liquidity\n * write (its executed chain result is in `data.result`) and `'queued'` for a RequestTrade\n * acknowledgement (accepted, NOT executed: the outcome is read from apply-results with\n * `confirm()`). `error: true` is the gateway refusing the write.\n *\n * A {@link SubmittedTransaction} only exists for an answer the SDK accepted, so its\n * {@link SubmitStatus} is `'executed'` or `'queued'`; a refused answer is a thrown\n * {@link GSwapSDKError}. The predicates below classify a RAW envelope instead, for an app that\n * holds one (`SubmittedTransaction.envelope`, `GSwapSDKError.body`, a stored answer) and for the\n * answers that never became a transaction, so an app does not need its own copies of the\n * success, queued and rejected checks.\n */\n\n/** The state of an accepted write: executed on chain (`mode: 'sync'`) or queued (`mode: 'queued'`). */\nexport type SubmitStatus = 'executed' | 'queued';\n\n/**\n * How a raw gateway envelope classifies:\n *\n * - `'executed'`: `error === false` and `data.mode === 'sync'` (the executed result came back).\n * - `'queued'`: `error === false`, `data.mode === 'queued'` and `data.uniqueKey` is a string.\n * - `'rejected'`: no envelope at all, or `error === true`: a DEFINITE failure.\n * - `'unconfirmed'`: anything else (`error: false` with another or no `mode`, a queued answer\n * with no `uniqueKey`, an envelope with no boolean `error`): accepted, outcome not known. It is\n * NOT a rejection and must not be shown as one.\n *\n * The four are mutually exclusive and exhaustive.\n */\nexport type SubmitClassification = SubmitStatus | 'rejected' | 'unconfirmed';\n\n/** The `mode` of `envelope.data`, or `undefined` when there is no such field. */\nfunction modeOf(envelope: Record<string, unknown>): unknown {\n const data = envelope['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)['mode']\n : undefined;\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** True when the envelope is a definite failure: absent, or `error === true`. */\nexport function isSubmitRejected(envelope: unknown): boolean {\n if (!envelope) return true;\n return recordOf(envelope)?.['error'] === true;\n}\n\n/**\n * True when the envelope carries an executed result: `error === false` and `data.mode === 'sync'`.\n * A queued RequestTrade acknowledgement is deliberately NOT executed: its outcome is not known\n * until apply-results resolves.\n */\nexport function isSubmitExecuted(envelope: unknown): boolean {\n const record = recordOf(envelope);\n return record?.['error'] === false && modeOf(record) === 'sync';\n}\n\n/** True when the envelope acknowledges a `uniqueKey` as queued (`data.mode === 'queued'`). */\nexport function isSubmitQueued(envelope: unknown): boolean {\n const record = recordOf(envelope);\n if (record?.['error'] !== false || modeOf(record) !== 'queued') return false;\n return typeof recordOf(record['data'])?.['uniqueKey'] === 'string';\n}\n\n/** Classifies a raw gateway envelope; see {@link SubmitClassification}. */\nexport function classifySubmitEnvelope(envelope: unknown): SubmitClassification {\n if (isSubmitRejected(envelope)) return 'rejected';\n if (isSubmitExecuted(envelope)) return 'executed';\n if (isSubmitQueued(envelope)) return 'queued';\n return 'unconfirmed';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["asRecord","trimTrailingSlash","asRecord","signalOption"],"sources":["../src/utils/confirmation_schedule.ts","../src/utils/server_message.ts","../src/classes/gswap_error_catalog.ts","../src/classes/gswap_error_phase_table.ts","../src/classes/gswap_sdk_error.ts","../src/classes/apply_results.ts","../src/types/fees.ts","../src/utils/tick_range.ts","../src/utils/tick_math.ts","../src/utils/validation.ts","../src/classes/assets.ts","../src/classes/dex_fees.ts","../src/utils/chain_contract.ts","../src/utils/shadow_errors.ts","../src/classes/submitted_transaction.ts","../src/classes/gateway.ts","../src/types/env.ts","../src/utils/debug.ts","../src/utils/reconnection.ts","../src/classes/gdex_stream.ts","../src/classes/http_client.ts","../src/utils/lenient.ts","../src/classes/leaderboard.ts","../src/types/market.ts","../src/classes/market.ts","../src/classes/onramper.ts","../src/utils/ordering.ts","../src/utils/resolve_pre_send.ts","../src/classes/symbols.ts","../src/classes/pools.ts","../src/utils/tick_align.ts","../src/utils/ticks.ts","../src/utils/dto_builders.ts","../src/classes/positions.ts","../src/classes/quoting.ts","../src/classes/shadow_submit.ts","../src/classes/swaps.ts","../src/classes/gswap.ts","../src/utils/classification.ts","../src/utils/failure_classification.ts","../src/classes/pending_swap_fate.ts","../src/classes/pending_swaps.ts","../src/classes/storage_adapters.ts","../src/utils/confirmation_state.ts","../src/utils/failure_guards.ts","../src/utils/submit_state.ts"],"sourcesContent":["import type { ConfirmOptions } from '../types/confirm_options.js';\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst MIN_POLL_INTERVAL_MS = 500;\nconst MAX_BACKOFF_MS = 8_000;\n\n/** The pacing of confirmation reads: one initial delay, then jittered exponential backoff. */\nexport interface ConfirmationSchedule {\n /**\n * Waits for the next read. Resolves `true` when the caller should read, `false` when the\n * deadline leaves no room for another read. The very first call always resolves `true` (at\n * least one read is made, even when the deadline is already past). Rejects with the abort\n * error when the caller's signal aborts, before or during the wait.\n */\n waitForRead(retryAfterMs?: number): Promise<boolean>;\n}\n\n/**\n * Builds the schedule for one `confirm()` call. `abortError` creates the error thrown when\n * `options.signal` aborts, so each confirmation kind keeps its own error type and details.\n */\nexport function createConfirmationSchedule(\n options: ConfirmOptions | undefined,\n defaultInitialDelayMs: number,\n abortError: (cause?: unknown) => Error,\n): ConfirmationSchedule {\n const timeoutMs = Math.max(0, options?.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n const pollIntervalMs = Math.max(\n MIN_POLL_INTERVAL_MS,\n options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,\n );\n const initialDelayMs = Math.max(0, options?.initialDelayMs ?? defaultInitialDelayMs);\n const signal = options?.signal;\n const deadline = Date.now() + timeoutMs;\n let firstRead = true;\n let attempt = 0;\n return {\n async waitForRead(retryAfterMs?: number): Promise<boolean> {\n throwIfAborted(signal, abortError);\n if (firstRead) {\n firstRead = false;\n const remaining = Math.max(0, deadline - Date.now());\n await delay(Math.min(initialDelayMs, remaining), signal, abortError);\n return true;\n }\n const backoff = Math.min(MAX_BACKOFF_MS, pollIntervalMs * 2 ** Math.min(attempt, 5));\n attempt += 1;\n const waitMs = retryAfterMs === undefined ? jitter(backoff) : Math.max(0, retryAfterMs);\n if (Date.now() + waitMs > deadline) return false;\n await delay(waitMs, signal, abortError);\n return true;\n },\n };\n}\n\n/** Throws `abortError(signal.reason)` when the signal has aborted. */\nexport function throwIfAborted(\n signal: AbortSignal | undefined,\n abortError: (cause?: unknown) => Error,\n): void {\n if (signal?.aborted === true) throw abortError(signal.reason);\n}\n\nfunction delay(\n milliseconds: number,\n signal: AbortSignal | undefined,\n abortError: (cause?: unknown) => Error,\n): Promise<void> {\n if (signal?.aborted === true) return Promise.reject(abortError(signal.reason));\n return new Promise((resolve, reject) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(abortError(signal?.reason));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, milliseconds);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nfunction jitter(milliseconds: number): number {\n return Math.max(0, Math.round(milliseconds * (0.9 + Math.random() * 0.2)));\n}\n","import type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\nfunction nonEmptyString(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const field = (value as Record<string, unknown>)[property];\n return typeof field === 'string' && field !== '' ? field : undefined;\n}\n\n/**\n * The human message a failing JSON body carries, as the server wrote it: the first non-empty\n * string of `message`, `Message`, `error.message`, `error.Message` (NestJS, the gateway filter\n * and the chain each use one of these shapes), else `''`. A body that is not JSON (an HTML 502\n * page, an empty body), or whose `message` is not a string (a validation error's list), has no\n * message. This is the single reader behind every `serverMessage` param.\n *\n * The text is DATA from the server, not SDK text: it is English, unstable, and may be empty. The\n * SDK exposes it so an app can relay it or ignore it; it is never part of `error.message`.\n */\nexport function serverMessageOfBody(body: unknown): string {\n const nested =\n typeof body === 'object' && body !== null\n ? (body as Record<string, unknown>)['error']\n : undefined;\n return (\n nonEmptyString(body, 'message') ??\n nonEmptyString(body, 'Message') ??\n nonEmptyString(nested, 'message') ??\n nonEmptyString(nested, 'Message') ??\n ''\n );\n}\n\n/**\n * The message the server put in a failing answer: the `serverMessage` param of a code that relays\n * it, else the message of the JSON body ({@link serverMessageOfBody}). Internal: the SDK reads it\n * ONLY to classify a failure (a quote that says \"no pools\"); it is English from the server, never\n * part of the SDK's own `message`, and not exported from the package.\n */\nexport function readServerMessage(error: GSwapSDKError): string | undefined {\n const params: Readonly<Record<string, string | number | boolean>> = error.params;\n const fromParams = params['serverMessage'];\n if (typeof fromParams === 'string' && fromParams !== '') return fromParams;\n const fromBody = serverMessageOfBody(error.body);\n return fromBody === '' ? undefined : fromBody;\n}\n","/**\n * The catalog of every error code gswap-sdk ITSELF throws (the DEX codes): the SINGLE source of\n * truth for its `code`, the named parameters it carries and the English template its `message` is\n * generated from. The codes of the signing, transport and wallet layer (`INVALID_PRIVATE_KEY`,\n * `REQUEST_TIMEOUT`, `SIGNING_FAILED`, `TYPED_DATA_*`, ...) live in `@gala-chain/gala-core-sdk`'s\n * `GALA_ERROR_CATALOG`; no code is defined in both. A `GSwapSDKError` can carry a code of either\n * catalog (`GSwapErrorCode` is the union), and reads its template from both.\n *\n * - `code` is the only discriminator. It is stable: apps branch on it, never on message text.\n * - `params` are the named placeholders of the error: a flat object of primitives (string,\n * number, boolean) that an app feeds to its own localization (i18next, ICU, FormatJS).\n * Raw server payloads are never params (they are `error.body` / `error.bodyText`), and no\n * secret (private key, signature, raw DTO) ever is.\n * - `template` is English with `{placeholder}` markers. `error.message` is generated from it\n * and the params, so the two cannot drift. It is for logs and developers: it is not stable and\n * must not be shown to users or matched on.\n *\n * Every placeholder in a template is a declared param and every declared param is a placeholder,\n * except the few `unrendered` params that carry server text for the app and are kept out of\n * `message` on purpose (pinned by tests/error_catalog.test.ts). Facts that are not placeholders (HTTP status, URL,\n * `uniqueKey`, transaction ids, the raw body, the cause) are typed properties of the error, see\n * `GalaErrorContext`.\n */\n\nimport {\n GALA_ERROR_CATALOG,\n type ErrorParamsOf,\n type GalaErrorCatalogEntry,\n type GalaErrorCode,\n} from '@gala-chain/gala-core-sdk';\n\n/**\n * Why the outcome of a write submission is unknown (`SUBMISSION_OUTCOME_UNKNOWN.params.reason`).\n * Both say the same thing about the swap (it MAY have been queued: never resubmit under a fresh\n * key, confirm `error.uniqueKey` instead) and differ only in what happened to the request.\n *\n * - `timeout`: the POST exceeded the gateway's timeout; the request may still be running.\n * - `transport`: the POST failed before an HTTP answer was read (offline, connection reset, DNS,\n * CORS, a body that broke off). The bytes may have reached the server and been queued, so this\n * does NOT prove the swap was not sent.\n */\nexport const SUBMISSION_OUTCOME_UNKNOWN_REASONS = ['timeout', 'transport'] as const;\n\n/** One member of {@link SUBMISSION_OUTCOME_UNKNOWN_REASONS}. */\nexport type SubmissionOutcomeUnknownReason = (typeof SUBMISSION_OUTCOME_UNKNOWN_REASONS)[number];\n\n/** The fee tiers as they appear in `INVALID_FEE.allowed`. */\nexport const ALLOWED_FEE_TIERS_TEXT = '0,500,3000,10000';\n\n/** The whole DEX catalog. Add a code here before throwing it anywhere in gswap-sdk. */\nexport const GSWAP_ERROR_CATALOG = {\n // ---------------------------------------------------------------------------------- transport\n HTTP_ERROR: {\n phase: 'post_send',\n template: 'Unexpected HTTP error {status} from {url}.',\n params: { status: 'number', url: 'string', serverMessage: 'string' },\n unrendered: ['serverMessage'],\n },\n UPDATE_REQUIRED: {\n phase: 'post_send',\n template:\n 'The backend refused this app version and requires an update (HTTP {status}); nothing was queued.',\n params: { status: 'number' },\n },\n REQUEST_FAILED: {\n phase: 'in_flight',\n template: 'The {operation} request failed.',\n params: { operation: 'string' },\n },\n\n // ----------------------------------------------------------------------------------- gateway\n METHOD_NOT_SUPPORTED: {\n phase: 'pre_send',\n template: 'The method {method} is not supported; swaps are queued through RequestTrade.',\n params: { method: 'string' },\n },\n SUBMISSION_OUTCOME_UNKNOWN: {\n phase: 'in_flight',\n template:\n 'The submission outcome is unknown ({reason}): the request may have reached the gateway. Confirm before retrying.',\n params: { reason: SUBMISSION_OUTCOME_UNKNOWN_REASONS },\n },\n GATEWAY_REPORTED_ERROR: {\n phase: 'post_send',\n template: 'The gateway reported an error for this write: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n GATEWAY_DATA_MISSING: {\n phase: 'post_send',\n template: 'The gateway response is missing its data object.',\n params: {},\n },\n GATEWAY_MODE_INVALID: {\n phase: 'post_send',\n template:\n 'Gateway response must contain data.mode=\"sync\" with data.result, or data.mode=\"queued\".',\n params: {},\n },\n GATEWAY_SYNC_REQUEST_TRADE: {\n phase: 'post_send',\n template:\n 'The gateway executed RequestTrade synchronously, which this SDK refuses; RequestTrade must be queued.',\n params: {},\n },\n MISSING_UNIQUE_KEY: {\n phase: 'post_send',\n template:\n 'The gateway acknowledged RequestTrade without echoing its uniqueKey, so it cannot be tied to the signed request.',\n params: {},\n },\n UNIQUE_KEY_MISMATCH: {\n phase: 'post_send',\n template: 'Gateway response data.uniqueKey must match the signed RequestTrade uniqueKey.',\n params: {},\n },\n SHADOW_NOT_QUEUED: {\n phase: 'post_send',\n template: 'The swap backend did not queue the shadow request.',\n params: {},\n },\n SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: {\n phase: 'pre_send',\n template:\n 'A shadow submission needs a walletAddress (the X-Wallet-Address header): pass one to the GSwap constructor or to this call.',\n params: {},\n },\n METHOD_NOT_ALLOWED: {\n phase: 'post_send',\n template: 'The gateway does not expose this contract method: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SIGNATURE_INVALID: {\n phase: 'post_send',\n template: 'The gateway could not verify the signature: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SIGNER_MISMATCH: {\n phase: 'post_send',\n template:\n 'The recovered signer does not match an actor named by the operation: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n DTO_INVALID: {\n phase: 'post_send',\n template: 'The gateway rejected the DTO shape: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n DTO_OPERATION_MISMATCH: {\n phase: 'post_send',\n template:\n 'The signed DTO has no dtoOperation, or one that is not the call it was sent to: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n BOUNDS_VIOLATION: {\n phase: 'post_send',\n template: 'The gateway rejected a numeric, tick, symbol or range bound: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n SYMBOL_CONFLICT: {\n phase: 'post_send',\n template: 'The CreatePool symbol is already owned by another class: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n RATE_LIMITED: {\n phase: 'post_send',\n template: 'The gateway rate-limited this signer: {serverMessage}',\n params: { serverMessage: 'string' },\n },\n CHAIN_DISPATCH_FAILED: {\n phase: 'post_send',\n template: 'The chain dispatch failed (chain error key \"{errorKey}\"): {serverMessage}',\n params: { errorKey: 'string', serverMessage: 'string' },\n },\n GATEWAY_REJECTED: {\n phase: 'post_send',\n template: 'Gateway rejected {gatewayCode}: {serverMessage}',\n params: { gatewayCode: 'string', serverMessage: 'string' },\n },\n CHAIN_REJECTED: {\n phase: 'post_send',\n template: 'GalaChain error {errorKey}: {serverMessage}',\n params: { errorKey: 'string', serverMessage: 'string' },\n },\n INVALID_CHAIN_RESPONSE: {\n phase: 'post_send',\n template: 'Backend returned an invalid {resource}.',\n params: { resource: 'string' },\n },\n INVALID_POSITION_RESPONSE: {\n phase: 'post_send',\n template: 'Backend returned an invalid position ({reason}).',\n params: { reason: 'string' },\n },\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: {\n phase: 'post_send',\n template:\n 'Transaction confirmation timed out; the trade may still apply. Confirm the same uniqueKey again later instead of resubmitting.',\n params: {},\n },\n CONFIRMATION_ABORTED: {\n phase: 'post_send',\n template: 'Transaction confirmation was aborted.',\n params: {},\n },\n CONFIRMATION_FAILED: {\n phase: 'post_send',\n template: 'Transaction confirmation failed with HTTP {status}.',\n params: { status: 'number', serverMessage: 'string' },\n unrendered: ['serverMessage'],\n },\n CONFIRMATION_MALFORMED: {\n phase: 'post_send',\n template: 'Transaction confirmation returned a malformed body.',\n params: {},\n },\n CONFIRMATION_KEY_MISMATCH: {\n phase: 'post_send',\n template: 'Apply result key did not match the requested key.',\n params: {},\n },\n\n // ----------------------------------------------------------------------------------- services\n NO_SIGNER: {\n phase: 'pre_send',\n template: 'This method requires a signer. Please provide a signer to the GSwap constructor.',\n params: {},\n },\n NO_WALLET_ADDRESS: {\n phase: 'post_send',\n template:\n 'Cannot confirm this write: no walletAddress was provided to the GSwap constructor, so the resulting position cannot be looked up to confirm it landed on chain.',\n params: {},\n },\n NO_POOL_AVAILABLE: {\n phase: 'post_send',\n template: 'No pool is available for {tokenIn}/{tokenOut} (fee tier {fee}).',\n params: { tokenIn: 'string', tokenOut: 'string', fee: 'string' },\n },\n INSUFFICIENT_LIQUIDITY: {\n phase: 'post_send',\n template:\n 'The selected pool has insufficient liquidity for {tokenIn}/{tokenOut} (fee tier {fee}).',\n params: { tokenIn: 'string', tokenOut: 'string', fee: 'string' },\n },\n UNKNOWN_TOKEN: {\n phase: 'pre_send',\n template: 'Token {token} is not registered on the DEX contract: it has no trading symbol.',\n params: { token: 'string' },\n },\n SYMBOL_NOT_FOUND: {\n phase: 'pre_send',\n template: 'Token {token} could not be resolved to a trading symbol.',\n params: { token: 'string' },\n },\n STREAM_API_KEY_UNUSABLE: {\n phase: 'pre_send',\n template:\n 'GdexStreamConfig.apiKey needs a non-empty key and an explicit webSocketImpl that accepts upgrade headers as its third argument (the \"ws\" package, or React Native). A browser WebSocket cannot send x-api-key, so the key would be silently dropped.',\n params: {},\n },\n STREAM_WEBSOCKET_UNAVAILABLE: {\n phase: 'pre_send',\n template:\n 'GdexStreamService requires a standards-compatible WebSocket constructor. Node.js versions before 22 must provide one with config.webSocketImpl (for example, from the \"ws\" package).',\n params: {},\n },\n STREAM_NOT_CONNECTED: {\n phase: 'pre_send',\n template: 'GDEX stream is not connected. Call connect() first.',\n params: {},\n },\n STREAM_DISCONNECTED: {\n phase: 'in_flight',\n template: 'GDEX stream disconnected.',\n params: {},\n },\n STREAM_REQUEST_TIMEOUT: {\n phase: 'in_flight',\n template: 'GDEX request \"{method}\" timed out after {timeoutMs} ms.',\n params: { method: 'string', timeoutMs: 'number' },\n },\n STREAM_CONNECT_FAILED: {\n phase: 'in_flight',\n template: 'Failed to connect to GDEX stream at {url}.',\n params: { url: 'string' },\n },\n STREAM_CLOSED_BEFORE_CONNECT: {\n phase: 'in_flight',\n template: 'GDEX stream closed before connecting (code {closeCode}).',\n params: { closeCode: 'number' },\n },\n STREAM_CONNECTION_CLOSED: {\n phase: 'in_flight',\n template: 'GDEX stream connection closed (code {closeCode}).',\n params: { closeCode: 'number' },\n },\n\n // ------------------------------------------------------------------------------ wallet / keys\n TOKEN_RESOLUTION_FAILED: {\n phase: 'pre_send',\n template: 'Token {token} could not be looked up; nothing was sent.',\n params: { token: 'string' },\n },\n MISSING_WALLET_ADDRESS: {\n phase: 'pre_send',\n template:\n 'Invalid wallet address: No wallet address provided. Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK.',\n params: {},\n },\n\n // ------------------------------------------------------------------------ input validation\n NON_CANONICAL_PAIR: {\n phase: 'pre_send',\n template:\n 'The pair {token0}/{token1} is not in canonical order: token0 must sort before token1.',\n params: { token0: 'string', token1: 'string' },\n },\n UNORDERABLE_SYMBOLS: {\n phase: 'pre_send',\n template: 'Unable to order trading symbols: expected a pair of symbols, got {received}.',\n params: { received: 'string' },\n },\n INVALID_TOKEN_CLASS_KEY: {\n phase: 'pre_send',\n template:\n 'Invalid token class key \"{tokenClassKey}\": expected a collection followed by category, type and additionalKey',\n params: { tokenClassKey: 'string' },\n },\n INCOMPLETE_TOKEN_CLASS_KEY: {\n phase: 'pre_send',\n template: 'Token class key \"{compositeKey}\" is missing {part}.',\n params: { compositeKey: 'string', part: 'string' },\n },\n INVALID_TRADING_SYMBOL: {\n phase: 'pre_send',\n template:\n 'Invalid trading symbol \"{symbol}\": must be 1-32 ASCII letters and digits and not a reserved word (Token, Unit, none).',\n params: { symbol: 'string' },\n },\n NO_VALID_TRADING_SYMBOL: {\n phase: 'pre_send',\n template:\n 'No valid trading symbol for token class {classKey}: \"{displaySymbol}\" is not an acceptable symbol and none is registered',\n params: { classKey: 'string', displaySymbol: 'string' },\n },\n TOKEN_SYMBOL_NOT_REGISTERED: {\n phase: 'pre_send',\n template:\n 'Token {token} is not registered in the trading-symbol registry yet; pass token0Symbol/token1Symbol (the token class symbol) to propose one. A symbol cannot be derived from a class key.',\n params: { token: 'string' },\n },\n SYMBOL_DISAGREES_WITH_REGISTRY: {\n phase: 'pre_send',\n template:\n 'Supplied symbol {suppliedSymbol} for {token} disagrees with the registered trading symbol {registeredSymbol}.',\n params: { token: 'string', suppliedSymbol: 'string', registeredSymbol: 'string' },\n },\n CREATE_POOL_NEEDS_CLASS_KEY: {\n phase: 'pre_send',\n template:\n 'createPool needs each token as a class key; {token} is a bare trading symbol, which does not carry one.',\n params: { token: 'string' },\n },\n AMOUNT_IS_JS_NUMBER: {\n phase: 'pre_send',\n template: 'Invalid {field}: use a decimal string or BigNumber, not a JavaScript number',\n params: { field: 'string' },\n },\n AMOUNT_NOT_FINITE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be a finite number (got {value})',\n params: { field: 'string', value: 'string' },\n },\n AMOUNT_NOT_POSITIVE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be positive (got {value})',\n params: { field: 'string', value: 'string' },\n },\n AMOUNT_NEGATIVE: {\n phase: 'pre_send',\n template: 'Invalid {field}: must not be negative (got {value})',\n params: { field: 'string', value: 'string' },\n },\n PRICE_VALUES_IS_JS_NUMBER: {\n phase: 'pre_send',\n template:\n 'Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers',\n params: {},\n },\n INVALID_PRICE_VALUES: {\n phase: 'pre_send',\n template:\n 'Invalid price values: all prices must be finite and positive (spot {spotPrice}, lower {lowerPrice}, upper {upperPrice})',\n params: { spotPrice: 'string', lowerPrice: 'string', upperPrice: 'string' },\n },\n INVALID_PRICE_RANGE: {\n phase: 'pre_send',\n template:\n 'Invalid price range: lower price {lowerPrice} must be less than or equal to upper price {upperPrice}',\n params: { lowerPrice: 'string', upperPrice: 'string' },\n },\n INVALID_PRICE_BOUNDS: {\n phase: 'pre_send',\n template:\n 'Price bounds must be finite and positive (minPrice {minPrice}, maxPrice {maxPrice}).',\n params: { minPrice: 'string', maxPrice: 'string' },\n },\n PRICE_BOUNDS_ORDER: {\n phase: 'pre_send',\n template: 'minPrice {minPrice} must be less than or equal to maxPrice {maxPrice}.',\n params: { minPrice: 'string', maxPrice: 'string' },\n },\n INVALID_STARTING_PRICE: {\n phase: 'pre_send',\n template: 'Starting price must be finite and positive (got {value}).',\n params: { value: 'string' },\n },\n INVALID_SQRT_PRICE: {\n phase: 'pre_send',\n template: 'Cannot invert a non-positive sqrt price ({sqrtPrice}).',\n params: { sqrtPrice: 'string' },\n },\n INVALID_TOKEN_DECIMALS: {\n phase: 'pre_send',\n template: 'Invalid {field}: must be a non-negative integer (got {value})',\n params: { field: 'string', value: 'number' },\n },\n TICKS_NOT_INTEGERS: {\n phase: 'pre_send',\n template: 'Invalid tick values: ticks must be integers (got {tickLower} and {tickUpper})',\n params: { tickLower: 'number', tickUpper: 'number' },\n },\n INVALID_TICK_RANGE: {\n phase: 'pre_send',\n template: 'Invalid tick range: tickLower {tickLower} must be less than tickUpper {tickUpper}',\n params: { tickLower: 'number', tickUpper: 'number' },\n },\n TICKS_OUT_OF_BOUNDS: {\n phase: 'pre_send',\n template:\n 'Invalid tick range: ticks {tickLower} and {tickUpper} must be between {minTick} and {maxTick}',\n params: { tickLower: 'number', tickUpper: 'number', minTick: 'number', maxTick: 'number' },\n },\n TICKS_NOT_ALIGNED: {\n phase: 'pre_send',\n template: 'Ticks {tickLower} and {tickUpper} must be aligned to spacing {spacing}.',\n params: { tickLower: 'number', tickUpper: 'number', spacing: 'number' },\n },\n INVALID_TICK_SPACING: {\n phase: 'pre_send',\n template: 'Invalid tick spacing: must be a positive integer (got {value})',\n params: { value: 'number' },\n },\n INVALID_FEE: {\n phase: 'pre_send',\n template: 'Invalid {field}: {value} is not a supported fee tier; must be one of {allowed}.',\n params: { field: 'string', value: 'number', allowed: 'string' },\n },\n EXACT_AMOUNT_REQUIRED: {\n phase: 'pre_send',\n template: '{field} is required for this swap.',\n params: { field: 'string' },\n },\n EXACTLY_ONE_OF_REQUIRED: {\n phase: 'pre_send',\n template: 'Provide exactly one of {first} or {second}.',\n params: { first: 'string', second: 'string' },\n },\n AT_MOST_ONE_OF_ALLOWED: {\n phase: 'pre_send',\n template: 'Provide at most one of {first} or {second}.',\n params: { first: 'string', second: 'string' },\n },\n POOL_MISMATCH: {\n phase: 'pre_send',\n template:\n 'tokenIn {tokenIn} and tokenOut {tokenOut} must be the two tokens of the pinned pool {poolToken0}/{poolToken1}.',\n params: {\n tokenIn: 'string',\n tokenOut: 'string',\n poolToken0: 'string',\n poolToken1: 'string',\n },\n },\n INVALID_DTO: {\n phase: 'pre_send',\n template: '{method} DTO field {field} is invalid (expected {expected}).',\n params: { method: 'string', field: 'string', expected: 'string' },\n },\n DTO_NOT_CANONICAL: {\n phase: 'pre_send',\n template:\n 'The {method} DTO is not in the form the SDK builders produce; build it with the matching build function and submit that.',\n params: { method: 'string' },\n },\n SEARCH_TOO_LONG: {\n phase: 'pre_send',\n template: 'search must be at most {maxLength} characters (got {length}).',\n params: { length: 'number', maxLength: 'number' },\n },\n INVALID_SORT_BY: {\n phase: 'pre_send',\n template: 'sortBy \"{value}\" is not allowed; it must be one of {allowed}.',\n params: { value: 'string', allowed: 'string' },\n },\n INVALID_SORT_ORDER: {\n phase: 'pre_send',\n template: 'sortOrder \"{value}\" is not allowed; it must be asc or desc.',\n params: { value: 'string' },\n },\n INVALID_PAGE: {\n phase: 'pre_send',\n template: 'page must be an integer of at least 1 (got {value}).',\n params: { value: 'number' },\n },\n INVALID_LIMIT: {\n phase: 'pre_send',\n template: 'limit must be an integer from {min} to {max} (got {value}).',\n params: { value: 'number', min: 'number', max: 'number' },\n },\n INVALID_MARKET_TOKEN: {\n phase: 'pre_send',\n template:\n 'A market read names a token by a symbol or class key of 1 to 120 letters, digits and . _ $ + / : | - characters (got \"{token}\").',\n params: { token: 'string' },\n },\n INVALID_TIMEFRAME: {\n phase: 'pre_send',\n template: 'timeframe \"{value}\" is not allowed; it must be one of {allowed}.',\n params: { value: 'string', allowed: 'string' },\n },\n INVALID_SEASON_ID: {\n phase: 'pre_send',\n template: 'seasonId must be an integer of at least 1 (got {value}).',\n params: { value: 'string' },\n },\n INVALID_POLL_INTERVAL: {\n phase: 'pre_send',\n template: 'intervalMs must be a finite number of milliseconds of at least 1 (got {value}).',\n params: { value: 'string' },\n },\n} as const satisfies Record<string, GalaErrorCatalogEntry>;\n\n/** Every code a `GSwapSDKError` can carry: the core codes and gswap-sdk's own DEX codes. */\nexport type GSwapErrorCode = GalaErrorCode | keyof typeof GSWAP_ERROR_CATALOG;\n\n/** Both catalogs as one type: a code of either reads its entry here. */\ntype GSwapCatalog = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** The named params of one error code (core or DEX): a flat object of primitives (or closed string tokens). */\nexport type GSwapErrorParams<C extends GSwapErrorCode> = ErrorParamsOf<GSwapCatalog, C>;\n\n/**\n * The catalog `GSwapSDKError` reads templates and phases from: core's entries and the DEX entries,\n * merged (never redefined: the two key sets are disjoint, pinned by tests/error_catalog.test.ts).\n */\nexport const GSWAP_SDK_ERROR_ENTRIES: Readonly<Record<GSwapErrorCode, GalaErrorCatalogEntry>> = {\n ...GALA_ERROR_CATALOG,\n ...GSWAP_ERROR_CATALOG,\n};\n\n/**\n * The English template of every DEX error code, `{placeholder}` markers included. An optional seed\n * or fallback for an app's own translations; the SDK's `message` is generated from it. The core\n * codes' templates are `galaErrorTemplates` from `@gala-chain/gala-core-sdk`: an app that seeds\n * every code a `GSwapSDKError` can carry merges the two.\n */\nexport const gswapErrorTemplates: { readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: string } =\n Object.fromEntries(\n Object.entries(GSWAP_ERROR_CATALOG).map(([code, entry]) => [code, entry.template]),\n ) as { readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: string };\n","import {\n GALA_ERROR_PHASE_BY_CODE,\n isGalaCatalogCode,\n type FailureView,\n type GalaErrorPhase,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from './gswap_error_catalog.js';\n\n/**\n * The phase of every DEX catalog code, WITHOUT the catalog. The failure guards (`classifyFailure`,\n * `mayHaveBeenQueued`, ...) need only a code's phase, and the catalog's English templates are\n * ~15 kB: reading the phase from here keeps an app shell that imports a guard from loading them.\n * The catalog entry is still where a code is declared; this table is checked against it AT\n * COMPILE TIME, in both directions (a missing code, an extra code or a different phase is a type\n * error), so the two cannot drift. The core codes' phases are core's `GALA_ERROR_PHASE_BY_CODE`.\n */\nexport const GSWAP_ERROR_PHASE_BY_CODE = {\n HTTP_ERROR: 'post_send',\n UPDATE_REQUIRED: 'post_send',\n REQUEST_FAILED: 'in_flight',\n METHOD_NOT_SUPPORTED: 'pre_send',\n SUBMISSION_OUTCOME_UNKNOWN: 'in_flight',\n GATEWAY_REPORTED_ERROR: 'post_send',\n GATEWAY_DATA_MISSING: 'post_send',\n GATEWAY_MODE_INVALID: 'post_send',\n GATEWAY_SYNC_REQUEST_TRADE: 'post_send',\n MISSING_UNIQUE_KEY: 'post_send',\n UNIQUE_KEY_MISMATCH: 'post_send',\n SHADOW_NOT_QUEUED: 'post_send',\n SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: 'pre_send',\n METHOD_NOT_ALLOWED: 'post_send',\n SIGNATURE_INVALID: 'post_send',\n SIGNER_MISMATCH: 'post_send',\n DTO_INVALID: 'post_send',\n DTO_OPERATION_MISMATCH: 'post_send',\n BOUNDS_VIOLATION: 'post_send',\n SYMBOL_CONFLICT: 'post_send',\n RATE_LIMITED: 'post_send',\n CHAIN_DISPATCH_FAILED: 'post_send',\n GATEWAY_REJECTED: 'post_send',\n CHAIN_REJECTED: 'post_send',\n INVALID_CHAIN_RESPONSE: 'post_send',\n INVALID_POSITION_RESPONSE: 'post_send',\n CONFIRMATION_TIMEOUT: 'post_send',\n CONFIRMATION_ABORTED: 'post_send',\n CONFIRMATION_FAILED: 'post_send',\n CONFIRMATION_MALFORMED: 'post_send',\n CONFIRMATION_KEY_MISMATCH: 'post_send',\n NO_SIGNER: 'pre_send',\n NO_WALLET_ADDRESS: 'post_send',\n NO_POOL_AVAILABLE: 'post_send',\n INSUFFICIENT_LIQUIDITY: 'post_send',\n UNKNOWN_TOKEN: 'pre_send',\n SYMBOL_NOT_FOUND: 'pre_send',\n STREAM_API_KEY_UNUSABLE: 'pre_send',\n STREAM_WEBSOCKET_UNAVAILABLE: 'pre_send',\n STREAM_NOT_CONNECTED: 'pre_send',\n STREAM_DISCONNECTED: 'in_flight',\n STREAM_REQUEST_TIMEOUT: 'in_flight',\n STREAM_CONNECT_FAILED: 'in_flight',\n STREAM_CLOSED_BEFORE_CONNECT: 'in_flight',\n STREAM_CONNECTION_CLOSED: 'in_flight',\n TOKEN_RESOLUTION_FAILED: 'pre_send',\n MISSING_WALLET_ADDRESS: 'pre_send',\n NON_CANONICAL_PAIR: 'pre_send',\n UNORDERABLE_SYMBOLS: 'pre_send',\n INVALID_TOKEN_CLASS_KEY: 'pre_send',\n INCOMPLETE_TOKEN_CLASS_KEY: 'pre_send',\n INVALID_TRADING_SYMBOL: 'pre_send',\n NO_VALID_TRADING_SYMBOL: 'pre_send',\n TOKEN_SYMBOL_NOT_REGISTERED: 'pre_send',\n SYMBOL_DISAGREES_WITH_REGISTRY: 'pre_send',\n CREATE_POOL_NEEDS_CLASS_KEY: 'pre_send',\n AMOUNT_IS_JS_NUMBER: 'pre_send',\n AMOUNT_NOT_FINITE: 'pre_send',\n AMOUNT_NOT_POSITIVE: 'pre_send',\n AMOUNT_NEGATIVE: 'pre_send',\n PRICE_VALUES_IS_JS_NUMBER: 'pre_send',\n INVALID_PRICE_VALUES: 'pre_send',\n INVALID_PRICE_RANGE: 'pre_send',\n INVALID_PRICE_BOUNDS: 'pre_send',\n PRICE_BOUNDS_ORDER: 'pre_send',\n INVALID_STARTING_PRICE: 'pre_send',\n INVALID_SQRT_PRICE: 'pre_send',\n INVALID_TOKEN_DECIMALS: 'pre_send',\n TICKS_NOT_INTEGERS: 'pre_send',\n INVALID_TICK_RANGE: 'pre_send',\n TICKS_OUT_OF_BOUNDS: 'pre_send',\n TICKS_NOT_ALIGNED: 'pre_send',\n INVALID_TICK_SPACING: 'pre_send',\n INVALID_FEE: 'pre_send',\n EXACT_AMOUNT_REQUIRED: 'pre_send',\n EXACTLY_ONE_OF_REQUIRED: 'pre_send',\n AT_MOST_ONE_OF_ALLOWED: 'pre_send',\n POOL_MISMATCH: 'pre_send',\n INVALID_DTO: 'pre_send',\n DTO_NOT_CANONICAL: 'pre_send',\n SEARCH_TOO_LONG: 'pre_send',\n INVALID_SORT_BY: 'pre_send',\n INVALID_SORT_ORDER: 'pre_send',\n INVALID_PAGE: 'pre_send',\n INVALID_LIMIT: 'pre_send',\n INVALID_MARKET_TOKEN: 'pre_send',\n INVALID_TIMEFRAME: 'pre_send',\n INVALID_SEASON_ID: 'pre_send',\n INVALID_POLL_INTERVAL: 'pre_send',\n} as const satisfies {\n readonly [C in keyof typeof GSWAP_ERROR_CATALOG]: (typeof GSWAP_ERROR_CATALOG)[C]['phase'];\n};\n\n/** True for a DEX code (gswap-sdk's own catalog). */\nfunction isDexCatalogCode(code: string): code is keyof typeof GSWAP_ERROR_PHASE_BY_CODE {\n return Object.hasOwn(GSWAP_ERROR_PHASE_BY_CODE, code);\n}\n\n/** True for a code a `GSwapSDKError` can carry: a core code or a DEX code. */\nexport function isCatalogCode(code: string): code is GSwapErrorCode {\n return isGalaCatalogCode(code) || isDexCatalogCode(code);\n}\n\n/**\n * The phase of a view: the one it states, else the catalog's phase for its code (core's or the\n * DEX catalog's), else `undefined`.\n */\nexport function phaseOfView(view: FailureView): GalaErrorPhase | undefined {\n if (view.phase !== undefined) return view.phase;\n if (isGalaCatalogCode(view.code)) return GALA_ERROR_PHASE_BY_CODE[view.code];\n return isDexCatalogCode(view.code) ? GSWAP_ERROR_PHASE_BY_CODE[view.code] : undefined;\n}\n","import {\n GalaSDKError,\n parseJson,\n toFailureView,\n type GalaChainTokenClassKey,\n type GalaErrorContext,\n type HTTPResponse,\n} from '@gala-chain/gala-core-sdk';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport {\n GSWAP_SDK_ERROR_ENTRIES,\n type GSwapErrorCode,\n type GSwapErrorParams,\n} from './gswap_error_catalog.js';\nimport { phaseOfView } from './gswap_error_phase_table.js';\n\n/**\n * The HTTP status of a version wall: the backend refuses an app version that is too old (HTTP 426\n * Upgrade Required). It is `UPDATE_REQUIRED` on every request the SDK sends, whatever else the body\n * says; a confirmation read keeps `CONFIRMATION_FAILED` because the write it confirms may be applied.\n */\nexport const UPDATE_REQUIRED_STATUS = 426;\n\n/** What {@link GSwapSDKError.fromStatus} may be told about the HTTP answer. */\nexport interface GSwapStatusErrorOptions {\n /** The URL the request went to. */\n url?: string | undefined;\n /** The signed `uniqueKey` of the WRITE the answer is for; its presence makes this a write. */\n uniqueKey?: string | undefined;\n /** Say it outright: `true` for a write (needs `uniqueKey`), `false` for a read. */\n write?: boolean | undefined;\n /** The server's own text, for `HTTP_ERROR.params.serverMessage` (`''` when none). */\n serverMessage?: string | undefined;\n /** The response body, kept as `error.body` (or `bodyText` for a string). */\n body?: unknown;\n /** How long the server asked to wait (`Retry-After`), in milliseconds. */\n retryAfterMs?: number | undefined;\n}\n\n/**\n * Error raised by gswap-sdk for validation, gateway, chain, or transaction failures. It is a\n * `GalaSDKError` (`@gala-chain/gala-core-sdk`), and can carry any code of the core catalog or of\n * gswap-sdk's own DEX catalog: the signing, transport and wallet failures of a gswap flow are core\n * codes, thrown either as a `GSwapSDKError` by gswap-sdk or as a plain `GalaSDKError` by core\n * itself (a signer, the fetch requestor). Catch both with `isGSwapError` (or core's `isGalaError`);\n * `instanceof GSwapSDKError` alone misses the second kind.\n *\n * Branch on {@link code} (stable) and render {@link params} through your own localization.\n * {@link message} is English generated from the catalog template for logs and developers: it\n * is not stable and must never be shown to a user or matched on.\n */\nexport class GSwapSDKError<C extends GSwapErrorCode = GSwapErrorCode> extends GalaSDKError<\n C,\n GSwapErrorParams<C>\n> {\n /** Core's catalog entries and the DEX entries: a `GSwapSDKError` can carry a code of either. */\n public static override readonly catalog = GSWAP_SDK_ERROR_ENTRIES;\n\n constructor(code: C, params: GSwapErrorParams<C>, context: GalaErrorContext = {}) {\n super(code, params, context);\n this.name = 'GSwapSDKError';\n }\n\n /**\n * True when the failure means \"that market, pool or position does not exist\" rather than\n * \"something went wrong\": an HTTP 404, a pair with no pool at any fee tier\n * (`NO_POOL_AVAILABLE`), or a token the DEX contract has no trading symbol for\n * (`UNKNOWN_TOKEN`). A pool that exists but is too thin (`INSUFFICIENT_LIQUIDITY`) is NOT\n * not-found.\n */\n public override get notFound(): boolean {\n return super.notFound || this.code === 'NO_POOL_AVAILABLE' || this.code === 'UNKNOWN_TOKEN';\n }\n\n /** Create the standard missing-signer error. */\n public static noSignerError(): GSwapSDKError<'NO_SIGNER'> {\n return new GSwapSDKError('NO_SIGNER', {});\n }\n\n /** Create the error used when confirming a position write without a configured wallet address. */\n public static noWalletAddressError(): GSwapSDKError<'NO_WALLET_ADDRESS'> {\n return new GSwapSDKError('NO_WALLET_ADDRESS', {});\n }\n\n /**\n * Create the error used when no pool can quote the requested pair. `source` is the backend\n * answer that said so; its status and body are kept.\n */\n public static noPoolAvailableError(\n tokenIn: GalaChainTokenClassKey | string,\n tokenOut: GalaChainTokenClassKey | string,\n fee?: number,\n source?: GSwapSDKError,\n ): GSwapSDKError<'NO_POOL_AVAILABLE'> {\n return new GSwapSDKError(\n 'NO_POOL_AVAILABLE',\n { tokenIn: tokenText(tokenIn), tokenOut: tokenText(tokenOut), fee: feeText(fee) },\n sourceContext(source),\n );\n }\n\n /** Create the error used when a pool lacks liquidity for a quote. `source` as for {@link noPoolAvailableError}. */\n public static insufficientLiquidityError(\n tokenIn: GalaChainTokenClassKey | string,\n tokenOut: GalaChainTokenClassKey | string,\n fee?: number,\n source?: GSwapSDKError,\n ): GSwapSDKError<'INSUFFICIENT_LIQUIDITY'> {\n return new GSwapSDKError(\n 'INSUFFICIENT_LIQUIDITY',\n { tokenIn: tokenText(tokenIn), tokenOut: tokenText(tokenOut), fee: feeText(fee) },\n sourceContext(source),\n );\n }\n\n /**\n * Convert a chain-gateway bounce into a typed SDK error: the gateway's own code when the SDK\n * knows it, `GATEWAY_REJECTED` (with the code as `params.gatewayCode`) when it does not.\n * `serverMessage` is the gateway's English text: for logs, not for a user interface. For\n * `CHAIN_DISPATCH_FAILED`, `params.errorKey` is the chain's `ErrorKey` from the body's\n * top-level `errorKey` (`''` when the gateway sent none): map it, not the text.\n */\n public static fromGatewayBounce(\n gatewayCode: string,\n serverMessage: string,\n status: number,\n body: unknown,\n url: string,\n retryAfterMs?: number,\n uniqueKey?: string,\n ): GSwapSDKError {\n const context: GalaErrorContext = { status, body, url, retryAfterMs, uniqueKey };\n const params = { serverMessage };\n switch (gatewayCode) {\n case 'METHOD_NOT_ALLOWED':\n return new GSwapSDKError('METHOD_NOT_ALLOWED', params, context);\n case 'SIGNATURE_INVALID':\n return new GSwapSDKError('SIGNATURE_INVALID', params, context);\n case 'SIGNER_MISMATCH':\n return new GSwapSDKError('SIGNER_MISMATCH', params, context);\n case 'DTO_INVALID':\n return new GSwapSDKError('DTO_INVALID', params, context);\n case 'DTO_OPERATION_MISMATCH':\n return new GSwapSDKError('DTO_OPERATION_MISMATCH', params, context);\n case 'BOUNDS_VIOLATION':\n return new GSwapSDKError('BOUNDS_VIOLATION', params, context);\n case 'SYMBOL_CONFLICT':\n return new GSwapSDKError('SYMBOL_CONFLICT', params, context);\n case 'RATE_LIMITED':\n return new GSwapSDKError('RATE_LIMITED', params, context);\n case 'CHAIN_DISPATCH_FAILED':\n // The gateway adds the chain's own machine-readable key as a top-level `errorKey`, only\n // when the chain supplied one; an older gateway sends none, which is the empty string.\n return new GSwapSDKError(\n 'CHAIN_DISPATCH_FAILED',\n { ...params, errorKey: getStringProperty(body, 'errorKey') ?? '' },\n context,\n );\n default:\n return new GSwapSDKError('GATEWAY_REJECTED', { gatewayCode, serverMessage }, context);\n }\n }\n\n /** Convert a GalaChain `Status: 0` response into a typed SDK error. */\n public static fromChainError(\n errorKey: string,\n serverMessage: string,\n context?: GalaErrorContext,\n ): GSwapSDKError<'CHAIN_REJECTED'> {\n return new GSwapSDKError('CHAIN_REJECTED', { errorKey, serverMessage }, context);\n }\n\n /**\n * Create the error used when a token is not registered by the current DEX contract. `source` is\n * the backend answer that said so (a quote); its status, body and url are kept.\n */\n public static unknownTokenError(\n token: GalaChainTokenClassKey | string,\n source?: GSwapSDKError,\n ): GSwapSDKError<'UNKNOWN_TOKEN'> {\n return new GSwapSDKError('UNKNOWN_TOKEN', { token: tokenText(token) }, sourceContext(source));\n }\n\n /** Create the error used when apply-results confirmation does not arrive in time. */\n public static confirmationTimeoutError(\n uniqueKey: string,\n cause?: unknown,\n ): GSwapSDKError<'CONFIRMATION_TIMEOUT'> {\n return new GSwapSDKError('CONFIRMATION_TIMEOUT', {}, { uniqueKey, cause });\n }\n\n /**\n * Builds, synchronously, the error the SDK itself throws for an HTTP answer of this `status`\n * that has no gateway or chain code: `UPDATE_REQUIRED` for the version wall (426, whatever\n * else is true), `HTTP_ERROR` for every other status. It is for an app that holds a resolved\n * HTTP answer the SDK did not read (a v1 endpoint, an interceptor's rejection) and wants the\n * SDK's classification of it (`classifyFailure`) instead of building the error by hand.\n *\n * Reads and writes differ exactly as they do in the gateway (`classifyFailure`): a WRITE\n * carries the signed `uniqueKey` (the handle to confirm it), a READ carries none. Pass\n * `uniqueKey` for a write, or `write: true` with it; `write: false` builds a read and drops any\n * `uniqueKey`. `write: true` without a non-empty `uniqueKey` throws `INVALID_UNIQUE_KEY`: a\n * write error with no key would be classified as a read, which is a different answer. Either\n * way an answer was read, so the phase is `post_send`.\n *\n * @example\n * ```ts\n * const read = GSwapSDKError.fromStatus(503, { url });\n * classifyFailure(read); // { outcome: 'transient', retryable: true }\n * const write = GSwapSDKError.fromStatus(503, { url, uniqueKey });\n * classifyFailure(write); // { outcome: 'unknown', retryable: false }: it may have been queued\n * classifyFailure(GSwapSDKError.fromStatus(426)); // invalid_input: only an update helps\n * ```\n */\n public static fromStatus(\n status: number,\n options: GSwapStatusErrorOptions = {},\n ): GSwapSDKError<'UPDATE_REQUIRED' | 'HTTP_ERROR'> {\n const { url, uniqueKey, write, serverMessage, body, retryAfterMs } = options;\n const isWrite = write ?? (uniqueKey !== undefined && uniqueKey !== '');\n if (isWrite && (uniqueKey === undefined || uniqueKey === '')) {\n throw new GSwapSDKError('INVALID_UNIQUE_KEY', { uniqueKey: uniqueKey ?? '' });\n }\n const context: GalaErrorContext = {\n status,\n body,\n url,\n retryAfterMs,\n uniqueKey: isWrite ? uniqueKey : undefined,\n write: isWrite,\n phase: 'post_send',\n };\n return status === UPDATE_REQUIRED_STATUS\n ? new GSwapSDKError('UPDATE_REQUIRED', { status }, context)\n : new GSwapSDKError(\n 'HTTP_ERROR',\n { status, url: url ?? '', serverMessage: serverMessage ?? '' },\n context,\n );\n }\n\n /** Convert an unexpected HTTP response into an SDK error. */\n public static async fromErrorResponse(\n url: string,\n response: HTTPResponse,\n ): Promise<GSwapSDKError> {\n const bodyText = await response.text();\n const bodyJson: unknown = parseJson(bodyText);\n const errorObject = getObjectProperty(bodyJson, 'error');\n const errorKey = getStringProperty(errorObject, 'ErrorKey');\n const message = getStringProperty(errorObject, 'Message');\n // Every request that goes through `HttpClient` is a READ (a quote, a list, an apply-results\n // GET); writes go through the gateway, which builds its own errors with the signed key.\n const context: GalaErrorContext = {\n status: response.status,\n body: bodyJson ?? bodyText,\n url,\n write: false,\n };\n\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError('UPDATE_REQUIRED', { status: response.status }, context);\n }\n\n if (errorKey !== undefined && message !== undefined) {\n return new GSwapSDKError('CHAIN_REJECTED', { errorKey, serverMessage: message }, context);\n }\n\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: serverMessageOfBody(bodyJson) },\n context,\n );\n }\n}\n\n/** A token as the text a param carries: a string as is, a class key as its `$` composite. */\nfunction tokenText(token: GalaChainTokenClassKey | string): string {\n return typeof token === 'string'\n ? token\n : [token.collection, token.category, token.type, token.additionalKey].join('$');\n}\n\nfunction feeText(fee: number | undefined): string {\n return fee === undefined ? 'any' : String(fee);\n}\n\n/**\n * The HTTP facts of the error a classified error was derived from. An error derived from a\n * backend answer is `post_send`: the answer was read.\n */\nfunction sourceContext(source: GSwapSDKError | undefined): GalaErrorContext {\n if (source === undefined) return {};\n return {\n status: source.status,\n body: source.body ?? source.bodyText,\n url: source.url,\n phase: 'post_send',\n write: source.write,\n };\n}\n\n/** Any thrown value that is an SDK error of a gswap flow, narrowed to the union of every code. */\nexport type AnyGSwapError = { [C in GSwapErrorCode]: GSwapSDKError<C> }[GSwapErrorCode];\n\n/**\n * True when `value` is an SDK error a gswap flow can throw and, when `code` is given, carries\n * exactly that code. With a code, `error.params` narrows to that code's params.\n *\n * It recognises every `GalaSDKError` (`instanceof`), not only a `GSwapSDKError`: the signing,\n * transport and wallet failures of a gswap flow come from `@gala-chain/gala-core-sdk` (a signer,\n * the fetch requestor), carry a core code, and are core `GalaSDKError`s. For such an error the\n * fields are exactly a `GSwapSDKError`'s (`notFound` differs only for the DEX not-found codes,\n * which core never throws), so the narrowing holds for everything a gswap flow throws.\n *\n * @example\n * ```ts\n * if (isGSwapError(error, 'NON_CANONICAL_PAIR')) {\n * t('errors.NON_CANONICAL_PAIR', error.params); // { token0, token1 }\n * }\n * ```\n */\nexport function isGSwapError(value: unknown): value is AnyGSwapError;\nexport function isGSwapError<C extends GSwapErrorCode>(\n value: unknown,\n code: C,\n): value is GSwapSDKError<C>;\nexport function isGSwapError(value: unknown, code?: GSwapErrorCode): boolean {\n return value instanceof GalaSDKError && (code === undefined || value.code === code);\n}\n\n/**\n * True when `value` is an SDK error that was thrown BEFORE anything was transmitted\n * (`error.phase === 'pre_send'`): validation, symbol resolution, the signer, the wallet, a key\n * provider. A write that failed this way cannot have been queued, so the failure never calls for\n * \"confirm before you retry\". Every failure of an app-supplied callback that runs BEFORE the\n * request leaves reaches you as an SDK error of this kind (`SIGNING_FAILED`,\n * `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original error as `cause`), so an app\n * never needs an error class of its own to tell \"nothing was sent\" apart.\n *\n * Whether to offer Retry is `classifyFailure(error).retryable`, not this: a pre-send validation\n * error is pre-send too, and repeating the same call fails the same way.\n *\n * It also answers for a plain-object view of an SDK error (`{ code, phase? }`, see\n * `FailureView`): the view's own `phase`, else the catalog's phase for its `code` (a core code or\n * a DEX code). It is a plain `boolean`, not a type guard (a view is not a `GSwapSDKError`); use\n * `isGSwapError` to narrow.\n *\n * @example\n * ```ts\n * if (isPreSendError(error)) markNothingSent(); // no pending swap to confirm\n * ```\n */\nexport function isPreSendError(value: unknown): boolean {\n const view = toFailureView(value);\n return view !== undefined && phaseOfView(view) === 'pre_send';\n}\n\n/** Narrow an object property without trusting a cast at a network boundary. */\nexport function getObjectProperty(\n value: unknown,\n property: string,\n): Record<string, unknown> | undefined {\n if (typeof value !== 'object' || value === null || !(property in value)) return undefined;\n const propertyValue = (value as Record<string, unknown>)[property];\n return typeof propertyValue === 'object' && propertyValue !== null\n ? (propertyValue as Record<string, unknown>)\n : undefined;\n}\n\n/** Read a string property from an unknown object. */\nexport function getStringProperty(value: unknown, property: string): string | undefined {\n if (typeof value !== 'object' || value === null || !(property in value)) return undefined;\n const propertyValue = (value as Record<string, unknown>)[property];\n return typeof propertyValue === 'string' ? propertyValue : undefined;\n}\n","import {\n buildRequestHeaders,\n fetchRequestor,\n isValidUniqueKey,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, TradeExecution } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport type { GSwapErrorCode, GSwapErrorParams } from './gswap_error_catalog.js';\nimport { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/**\n * The AutoApplier waits at least 2 s before applying and the apply lands ~6-8 s after the\n * acknowledgement, so a read at t=0 is a guaranteed 404.\n */\nconst DEFAULT_INITIAL_DELAY_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * The outcome of a queued RequestTrade that could not be delivered as an {@link AppliedTrade}.\n * `code` says why:\n *\n * - `CONFIRMATION_TIMEOUT`: no terminal result before the deadline. The trade may still apply;\n * confirm the same `uniqueKey` again later and never resubmit.\n * - `CONFIRMATION_ABORTED`: the caller's `signal` aborted. Nothing is known about the outcome.\n * - `CONFIRMATION_FAILED`: the apply-results read got a terminal HTTP status (`params.status`;\n * `params.serverMessage` is the failing body's own message, `''` when it had none: server\n * text is data, relay it or ignore it). The outcome is unknown.\n * - `CONFIRMATION_MALFORMED` / `CONFIRMATION_KEY_MISMATCH`: the apply result is not a usable\n * answer for this key. The outcome is unknown.\n * - `INVALID_UNIQUE_KEY`: the key is not a valid apply-results key; nothing was read. TERMINAL:\n * no retry can ever succeed (the SDK never signs such a key, so a stored one is corrupt), so a\n * resume loop must forget the swap. `PendingSwapStore.list` already prunes such entries.\n * - `CHAIN_REJECTED`: the chain REJECTED the trade; `params.errorKey` is the chain `ErrorKey` (or\n * `CHAIN_ERROR`) and `params.serverMessage` its English message.\n *\n * `uniqueKey` is always set and, where known, `requestTransactionId`, `applyTransactionId`,\n * `blockNumber`, `status`, `body`, `url` and the last transport `cause`.\n */\nexport class AppliedTradeError<C extends GSwapErrorCode = GSwapErrorCode> extends GSwapSDKError<C> {\n constructor(code: C, params: GSwapErrorParams<C>, context: GalaErrorContext = {}) {\n super(code, params, context);\n this.name = 'AppliedTradeError';\n }\n}\n\n/** The transport and backend a confirmation reads from. */\nexport interface ApplyResultsClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com` (no trailing path). */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-read timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /** Request headers of the poll (`userAgent`, `headers`); see {@link WireOptions}. */\n wire?: WireOptions | undefined;\n}\n\n/** What identifies the queued trade to confirm. */\nexport interface AppliedTradeInput {\n uniqueKey: string;\n /** The transaction id of the queued request, carried through to the result; `null` if unknown. */\n requestTransactionId: string | null;\n}\n\n/**\n * Polls `GET /v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract` until the\n * queued RequestTrade reaches a terminal state.\n *\n * Pacing: wait `initialDelayMs` (default 3 s), then read; on 404, 429, 500, 502, 503, 504 or a\n * transport error wait with jittered exponential backoff (`pollIntervalMs` doubling to 8 s,\n * `Retry-After` honored as seconds or an HTTP date) until `timeoutMs`. Any other status is\n * terminal. At least one read is always made.\n *\n * @returns The applied trade.\n * @throws AppliedTradeError - see its documentation for every `code`.\n * @example\n * ```ts\n * const applied = await confirmAppliedTrade(\n * { dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' },\n * { uniqueKey, requestTransactionId: null },\n * { initialDelayMs: 0, timeoutMs: 60_000, signal: controller.signal },\n * );\n * ```\n */\nexport async function confirmAppliedTrade(\n client: ApplyResultsClient,\n input: AppliedTradeInput,\n options?: ConfirmOptions,\n): Promise<AppliedTrade> {\n const { uniqueKey } = input;\n if (!isValidUniqueKey(uniqueKey)) {\n throw new AppliedTradeError(\n 'INVALID_UNIQUE_KEY',\n { uniqueKey: String(uniqueKey) },\n { uniqueKey },\n );\n }\n const requestor = client.httpRequestor ?? fetchRequestor;\n const requestTimeoutMs = client.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const signal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new AppliedTradeError('CONFIRMATION_ABORTED', {}, { uniqueKey, cause });\n const url = `${client.dexBackendBaseUrl.replace(/\\/$/u, '')}/v1/chain/apply-results/${encodeURIComponent(uniqueKey)}?channel=asset&contract=dex-contract`;\n\n const schedule = createConfirmationSchedule(options, DEFAULT_INITIAL_DELAY_MS, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n\n while (true) {\n throwIfAborted(signal, abortError);\n let response: HTTPResponse;\n let body: unknown;\n try {\n response = await requestWithTimeout(\n requestor,\n url,\n {\n method: 'GET',\n headers: buildRequestHeaders(client.wire),\n ...(signal === undefined ? {} : { signal }),\n },\n requestTimeoutMs,\n );\n body = await readResponseBody(response);\n } catch (error: unknown) {\n throwIfAborted(signal, abortError);\n lastError = error;\n if (!(await schedule.waitForRead())) break;\n continue;\n }\n throwIfAborted(signal, abortError);\n\n if (response.status === 200) return readAppliedResult(input, response, body, url);\n\n if (response.status === 404 || response.status === 429 || isTransient(response.status)) {\n const retryAfter = response.status === 429 ? readRetryAfter(response) : undefined;\n if (!(await schedule.waitForRead(retryAfter))) break;\n continue;\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_FAILED',\n { status: response.status, serverMessage: serverMessageOfBody(body) },\n { uniqueKey, status: response.status, body, url },\n );\n }\n\n throw new AppliedTradeError(\n 'CONFIRMATION_TIMEOUT',\n {},\n { uniqueKey, requestTransactionId: input.requestTransactionId, url, cause: lastError },\n );\n}\n\nfunction readAppliedResult(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTrade {\n const { uniqueKey } = input;\n const record = asRecord(body);\n const responseKey = record?.['uniqueKey'] ?? record?.['UniqueKey'];\n if (typeof responseKey === 'string' && responseKey !== uniqueKey) {\n throw new AppliedTradeError(\n 'CONFIRMATION_KEY_MISMATCH',\n {},\n { uniqueKey, status: response.status, body, url },\n );\n }\n const status = record?.['Status'];\n const applyTransactionId = readHeader(response, 'x-apply-transaction-id') ?? null;\n const blockNumber = readBlockNumberHeader(response, 'x-apply-block-number') ?? null;\n if (status === 0) {\n const errorKey = getStringProperty(record, 'ErrorKey') ?? 'CHAIN_ERROR';\n const chainMessage = getStringProperty(record, 'Message') ?? '';\n throw new AppliedTradeError(\n 'CHAIN_REJECTED',\n { errorKey, serverMessage: chainMessage },\n {\n uniqueKey,\n requestTransactionId: input.requestTransactionId,\n applyTransactionId,\n blockNumber,\n status: response.status,\n body,\n url,\n },\n );\n }\n if (status !== 1) throw malformed(input, response, body, url);\n const result = parseTradeExecution(record?.['Data']);\n if (result === undefined) throw malformed(input, response, body, url);\n return {\n uniqueKey,\n transactionId: applyTransactionId,\n blockNumber,\n requestTransactionId: input.requestTransactionId,\n result,\n };\n}\n\nfunction malformed(\n input: AppliedTradeInput,\n response: HTTPResponse,\n body: unknown,\n url: string,\n): AppliedTradeError<'CONFIRMATION_MALFORMED'> {\n return new AppliedTradeError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey: input.uniqueKey, status: response.status, body, url },\n );\n}\n\nfunction parseTradeExecution(value: unknown): TradeExecution | undefined {\n const record = asRecord(value);\n if (\n record === undefined ||\n typeof record['token0'] !== 'string' ||\n typeof record['token1'] !== 'string' ||\n typeof record['fee'] !== 'number'\n ) {\n return undefined;\n }\n const optionalFields = [\n 'sell0Qty',\n 'sell1Qty',\n 'buy0Qty',\n 'buy1Qty',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n ] as const;\n for (const field of optionalFields) {\n if (field in record && typeof record[field] !== 'string') return undefined;\n }\n return {\n token0: record['token0'],\n token1: record['token1'],\n fee: record['fee'],\n ...Object.fromEntries(\n optionalFields.flatMap((field) =>\n typeof record[field] === 'string' ? [[field, record[field]]] : [],\n ),\n ),\n };\n}\n\nfunction isTransient(status: number): boolean {\n return status === 500 || status === 502 || status === 503 || status === 504;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n","/**\n * Fee tiers for pools.\n */\nexport enum FEE_TIER {\n /** No trading fee. */\n PERCENT_00_00 = 0,\n /** 0.05% fee tier */\n PERCENT_00_05 = 500,\n /** 0.3% fee tier */\n PERCENT_00_30 = 3000,\n /** 1.0% fee tier */\n PERCENT_01_00 = 10000,\n}\n\n/** Tick spacing required by the current GalaChainDex contract for each fee tier. */\nexport const TICK_SPACING_BY_FEE: Readonly<Record<FEE_TIER, number>> = {\n [FEE_TIER.PERCENT_00_00]: 200,\n [FEE_TIER.PERCENT_00_05]: 10,\n [FEE_TIER.PERCENT_00_30]: 60,\n [FEE_TIER.PERCENT_01_00]: 200,\n};\n\n/** All fee tiers supported by the current GalaChainDex contract. */\nexport const ALL_FEE_TIERS: readonly FEE_TIER[] = [\n FEE_TIER.PERCENT_00_00,\n FEE_TIER.PERCENT_00_05,\n FEE_TIER.PERCENT_00_30,\n FEE_TIER.PERCENT_01_00,\n];\n","/**\n * Whether a pool's current tick lies inside a position's range, by the contract's own rule. This\n * module imports nothing, so an app shell (a position badge, a filter) pays for a few dozen bytes.\n */\n\n/** A tick as the chain and the backends write it: a number, or the decimal string of one. */\nexport type TickInput = number | string;\n\nfunction integerTickOf(tick: TickInput): number {\n if (typeof tick === 'string') return tick.trim() === '' ? Number.NaN : Number(tick);\n return tick;\n}\n\n/**\n * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick\n * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule\n * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a\n * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out\n * of range: the position is entirely token1 there, and a swap through the tick has crossed it.\n *\n * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than\n * the pool's price), not a rounded display value. A tick may be a number or the decimal string a\n * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a\n * fraction) makes the answer `false`: an app that must tell \"not loaded yet\" from \"out of range\"\n * checks for the missing value itself first.\n *\n * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both\n * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is\n * then in range at the upper edge (the contract says it is not), and two representations of the\n * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which\n * derives the tick the way the contract does and then applies this rule.\n *\n * @example\n * ```ts\n * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive\n * isTickInRange(60, -60, 60); // false: the upper tick is exclusive\n * ```\n */\nexport function isTickInRange(\n currentTick: TickInput,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n const current = integerTickOf(currentTick);\n const lower = integerTickOf(tickLower);\n const upper = integerTickOf(tickUpper);\n if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) {\n return false;\n }\n return current >= lower && current < upper;\n}\n","import BigNumber from 'bignumber.js';\nimport { Decimal } from 'decimal.js';\nimport { isTickInRange, type TickInput } from './tick_range.js';\n\n/**\n * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the\n * conversions between ticks and prices, and nothing that validates a range. It imports only the\n * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog\n * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an\n * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of\n * error templates. A value that cannot be computed is `NaN`, never an exception.\n */\n\n/** Minimum tick supported by GalaChainDex. */\nexport const GC_MIN_TICK = -887272;\n/** Maximum tick supported by GalaChainDex. */\nexport const GC_MAX_TICK = 887272;\n\nconst DexMath = BigNumber.clone({\n DECIMAL_PLACES: 60,\n ROUNDING_MODE: BigNumber.ROUND_DOWN,\n});\n/** `decimal.js` at the 60 significant digits the contract's price math is exact to. */\nexport const DexDecimal = Decimal.clone({ precision: 60 });\n\n/** Convert a tick to the corresponding square-root price. */\nexport function tickToSqrtPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick / 2).toString());\n}\n\n/** Return the greatest tick whose square-root price is no greater than the input. */\nexport function sqrtPriceToTick(sqrtPrice: BigNumber.Value): number {\n let value: BigNumber;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this function's contract is to signal an invalid input via NaN, not\n // to throw, so an unparseable value is just another case for the guard below.\n value = new DexMath(sqrtPrice);\n } catch {\n return Number.NaN;\n }\n if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return Number.NaN;\n\n const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);\n if (!Number.isFinite(approximate)) return Number.NaN;\n // Clamp the seed before the correction loops below — an unclamped seed derived from an\n // out-of-range sqrtPrice (extreme but finite, e.g. 1e20) leaves the loops running past\n // GC_MIN_TICK/GC_MAX_TICK for a long time; an infinite (overflowed) seed would never\n // enter the increasing loop and never terminate the decreasing one.\n let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));\n while (tick < GC_MAX_TICK && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;\n while (tick > GC_MIN_TICK && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;\n return tick;\n}\n\n/**\n * The token1/token0 price at `tick`: `1.0001 ** tick`, exact to 60 significant digits (the lower\n * edge of the tick's price range; `tickToSqrtPrice(tick) ** 2`). A tick outside the contract's\n * bounds is still computed; ask `assertTickRange` first when that matters. A non-integer tick is\n * computed as given.\n *\n * Use `.toNumber()` for a display value (it differs from `Math.exp(tick * Math.log(1.0001))` in\n * the last digits of a double: that expression multiplies in floating point first).\n */\nexport function tickToPrice(tick: number): BigNumber {\n return new BigNumber(new DexDecimal(1.0001).pow(tick).toString());\n}\n\n/**\n * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that\n * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as\n * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater\n * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,\n * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly\n * on `tickUpper`'s price is not, and no float rounding can flip either.\n *\n * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing\n * about the position, so an app that must show a neutral state checks for the missing price\n * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.\n *\n * @example\n * ```ts\n * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);\n * ```\n */\nexport function isSqrtPriceInRange(\n sqrtPrice: BigNumber.Value,\n tickLower: TickInput,\n tickUpper: TickInput,\n): boolean {\n return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);\n}\n\n/** How {@link tickFromPrice} turns the exact logarithm into an integer tick. */\nexport interface TickFromPriceOptions {\n /**\n * `'floor'` (default): the greatest tick whose price is no greater than `price`, which is how\n * the contract places a price. `'nearest'`: the closest tick, a half rounding away from zero.\n * That is what a price INPUT wants (a person types a price, the field snaps to the nearest\n * tick), and it differs from `'floor'` for any price in the upper half of a tick's range.\n */\n rounding?: 'floor' | 'nearest' | undefined;\n}\n\n/**\n * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price\n * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that\n * is not positive and finite.\n */\nexport function tickFromPrice(price: BigNumber.Value, options: TickFromPriceOptions = {}): number {\n const priceText =\n typeof price === 'string'\n ? price\n : typeof price === 'number'\n ? price.toString()\n : BigNumber.isBigNumber(price)\n ? price.toString()\n : 'NaN';\n const value = new DexDecimal(priceText);\n if (!value.isFinite() || value.lessThanOrEqualTo(0)) return Number.NaN;\n if (!Number.isFinite(value.toNumber())) return Number.NaN;\n const exact = value.ln().dividedBy(new DexDecimal(1.0001).ln());\n const tick = (options.rounding === 'nearest' ? exact.round() : exact.floor()).toNumber();\n return Number.isFinite(tick) ? tick : Number.NaN;\n}\n","import { galaChainUserRef, isGalaError } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\n/**\n * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.\n *\n * @param amount - The amount to check.\n * @param parameterName - The field name reported in the error's `params.field`.\n * @param allowZero - Accept zero (default `false`).\n * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero\n * when `allowZero` is false) or `AMOUNT_NEGATIVE`.\n */\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\n/**\n * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and\n * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.\n *\n * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.\n */\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\n/**\n * Validates a token's decimals: a non-negative integer.\n *\n * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).\n */\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\n/**\n * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within\n * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see\n * `assertTickRange`).\n *\n * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.\n */\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\n/**\n * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).\n *\n * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).\n */\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\n/**\n * Validates a tick spacing: a positive integer.\n *\n * @throws GSwapSDKError `INVALID_TICK_SPACING`.\n */\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\n/**\n * The GalaChain user reference an owner, user or wallet address names, in the one spelling the\n * gateway and the swap backend accept: `eth|<EIP-55 checksummed digits>` for an Ethereum account\n * (given as `eth|<40 hex>` in any casing, `0x<40 hex>` or bare hex), `client|<id>` as written.\n * `eth|0x<hex>` is not an address form. This is `galaChainUserRef` of\n * `@gala-chain/gala-core-sdk`, the one implementation; only the error for a spelling that is no\n * address at all is this package's. Every place this SDK puts a user identity on the wire goes\n * through it, so what is signed, sent and compared on the backend (`owner === position.owner`,\n * strict) is always the chain's own spelling.\n *\n * @param value - The identity the caller gave.\n * @param field - The field name reported in the error's `params.field`.\n * @throws GalaSDKError core's `INVALID_ETH_USER_REF_PREFIX` (passed through as it is: its message\n * says an `eth|` reference takes the 40 hex digits with no `0x` and names the correct spelling,\n * `params.expected`) for `eth|0x...`; GSwapSDKError `INVALID_WALLET_ADDRESS` for anything else, a\n * mixed-case spelling whose casing is not the EIP-55 checksum included (a typo); nothing is\n * signed or sent.\n */\nexport function userRef(value: unknown, field: string): string {\n try {\n return galaChainUserRef(value, field);\n } catch (cause: unknown) {\n if (isGalaError(cause) && cause.code === 'INVALID_ETH_USER_REF_PREFIX') throw cause;\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', { field, value: String(value) });\n }\n}\n\n/**\n * {@link userRef} of an address that must be there.\n *\n * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS`; core's\n * `INVALID_ETH_USER_REF_PREFIX` for `eth|0x...` (see {@link userRef}).\n */\nexport function requireUserRef(address: string | undefined, field: string): string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n return userRef(address, field);\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n","import type { UserAsset, UserAssetsResult } from '../types/v2_results.js';\nimport { requireUserRef } from '../utils/validation.js';\nimport { getObjectProperty, GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * Service for handling user asset operations.\n * Provides functionality to retrieve user token balances and asset information.\n */\nexport class Assets {\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Gets all token assets owned by a user with their balances.\n * @param ownerAddress - The wallet address to get assets for.\n * @param page - Page number for pagination (default: 1).\n * @param limit - Maximum number of assets to return per page (default: 10).\n * @returns User assets including token information and balances.\n * @example\n * ```typescript\n * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);\n * console.log(`User has ${assets.count} different tokens`);\n * assets.tokens.forEach(token => {\n * console.log(`${token.symbol}: ${token.quantity}`);\n * });\n * ```\n */\n async getUserAssets(\n ownerAddress: string,\n page: number = 1,\n limit: number = 10,\n ): Promise<UserAssetsResult> {\n const address = requireUserRef(ownerAddress, 'walletAddress');\n\n if (!Number.isInteger(page) || page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: page });\n }\n\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n throw new GSwapSDKError('INVALID_LIMIT', { value: limit, min: 1, max: 100 });\n }\n\n const json: unknown = await this.httpClient.sendGetRequest(\n this.dexBackendBaseUrl,\n '/user/assets',\n '',\n { address, page: page.toString(), limit: limit.toString() },\n );\n return parseUserAssets(json);\n }\n}\n\nfunction parseUserAssets(value: unknown): UserAssetsResult {\n const data = getObjectProperty(value, 'data');\n // Not getObjectProperty — that's typed for object properties, and Array.isArray on its\n // Record<string, unknown> return type narrows to any[] instead of a real array type.\n const tokens: unknown = data?.['token'];\n if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'user assets response' },\n { body: value, write: false },\n );\n }\n const count = data?.['count'];\n return {\n tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),\n count: typeof count === 'number' ? count : 0,\n };\n}\n\ntype RawUserAsset = Omit<UserAsset, 'decimals'> & { decimals: string };\n\nfunction isRawUserAsset(value: unknown): value is RawUserAsset {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry['image'] === 'string' &&\n typeof entry['name'] === 'string' &&\n typeof entry['decimals'] === 'string' &&\n /^\\d+$/u.test(entry['decimals']) &&\n typeof entry['verify'] === 'boolean' &&\n typeof entry['symbol'] === 'string' &&\n typeof entry['quantity'] === 'string'\n );\n}\n","import {\n buildRequestHeaders,\n createUniqueKey,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n signPreSend,\n type ChainContractPath,\n type GalaChainSigner,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n contractPath: ChainContractPath = 'asset/dexv3-contract',\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, contractPath, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto,\n // Core's RN-safe mint (`getRandomValues`, never `randomUUID`, which Hermes lacks).\n uniqueKey: createUniqueKey(uniqueKeyPrefix),\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = client.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n undefined,\n `asset/${contract}`,\n );\n const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n if (contract === 'dex-contract' && (status === 403 || status === 404)) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n","import type { ChainContractPath } from '@gala-chain/gala-core-sdk';\n\n/**\n * The contract every v2 write goes to: its route under `/v1/chain/` and (through core's table) the\n * `dtoOperation` each DTO is signed with. One constant for both, so they cannot disagree.\n */\nexport const DEX_CONTRACT_PATH = 'asset/dex-contract' satisfies ChainContractPath;\n","import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError, isGSwapError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Failures of the shadow (dark) path carry that fact, so an app can apply its own policy (no\n * Retry, no public fallback) without tracking which call it made. An SDK error gets `shadow: true`;\n * a non-SDK object that escapes the path (an app requestor's own rejection) is remembered in a\n * WeakSet, which `isShadowError` reads. Nothing here changes what an error means, only where it\n * came from.\n */\nconst shadowRejections = new WeakSet<object>();\n\n/**\n * True when `value` is a failure of the shadow (dark) path: an SDK error with `shadow: true`, a\n * plain-object view of one (`{ code, shadow: true }`, see `FailureView`), or a non-SDK object (a requestor's own rejection) that escaped `swapShadow`, `submitSwapShadow` or\n * `ChainGateway.submitShadow`. A primitive that was thrown (`throw 'x'`) cannot be remembered, so\n * it is never shadow; an app that cares tracks the call it made.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { retryable } = classifyFailure(error);\n * offerRetry(retryable && !isShadowError(error)); // never retry a dark swap in public\n * }\n * ```\n */\nexport function isShadowError(value: unknown): boolean {\n if (isGSwapError(value)) return value.shadow;\n if (toFailureView(value)?.shadow === true) return true;\n return typeof value === 'object' && value !== null && shadowRejections.has(value);\n}\n\n/**\n * The same failure, marked as shadow. An SDK error is COPIED (same code, params, status, body,\n * url, ids, cause, phase, read/write, wallet code and stack), never mutated: one error object can\n * be shared by several callers (a registry read many swaps wait on), and only the shadow caller's\n * copy is shadow. Everything the deciders read is carried over, so the copy classifies exactly as\n * the original (a failed READ stays a read, never a \"maybe queued\" write).\n */\nfunction asShadowError(error: unknown): unknown {\n if (isGSwapError(error)) {\n if (error.shadow) return error;\n const copy = new GSwapSDKError(error.code, error.params, {\n status: error.status,\n body: error.body ?? error.bodyText,\n url: error.url,\n uniqueKey: error.uniqueKey,\n requestTransactionId: error.requestTransactionId,\n applyTransactionId: error.applyTransactionId,\n blockNumber: error.blockNumber,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n phase: error.phase,\n write: error.write,\n walletCode: error.walletCode,\n shadow: true,\n });\n if (error.stack !== undefined) copy.stack = error.stack;\n return copy;\n }\n if (typeof error === 'object' && error !== null) shadowRejections.add(error);\n return error;\n}\n\n/** Runs one shadow operation and marks whatever it throws as shadow (see {@link isShadowError}). */\nexport async function shadowFailures<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error: unknown) {\n throw asShadowError(error);\n }\n}\n","import { armTimeout, type HttpRequestor, type WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\nimport { createConfirmationSchedule, throwIfAborted } from '../utils/confirmation_schedule.js';\nimport type { SubmitStatus } from '../utils/submit_state.js';\nimport { confirmAppliedTrade } from './apply_results.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\n\n/** Result of one position-confirmation poll. */\nexport type PositionConfirmationResult =\n { confirmed: true; position: Position | null } | { confirmed: false; position?: Position | null };\n\n/** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */\nexport class SubmittedTransaction<TConfirmation = AppliedTrade | Position | null> {\n /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */\n public readonly method: string;\n /** The write's durable correlation key: persist it, and confirm from it alone later. */\n public readonly uniqueKey: string;\n /** The request transaction id the gateway reported, or `null` when it gave none. */\n public readonly transactionId: string | null;\n /** The block of the transaction, when the answer carried one; otherwise `null`. */\n public readonly blockNumber: number | null;\n /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */\n public readonly mode: 'sync' | 'queued';\n /**\n * What the gateway's answer established: `'executed'` for `mode: 'sync'`, `'queued'` for\n * `mode: 'queued'` (accepted, NOT executed: `await confirm()` for the outcome). A refused answer\n * never becomes a transaction, so there is no `'rejected'` here; see {@link classifySubmitEnvelope}\n * for classifying a raw envelope.\n */\n public readonly status: SubmitStatus;\n /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */\n public readonly result: unknown;\n /**\n * The gateway's whole JSON answer as it came (`{ status, message, error, data }`), for an app\n * that hands the backend's own envelope to its callers; `undefined` for a transaction built from\n * a uniqueKey alone.\n */\n public readonly envelope: unknown;\n private readonly backendBaseUrl: string;\n private readonly requestor: HttpRequestor;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n private readonly positionConfirmation:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n\n /** Construct a submitted transaction from a successful gateway response.\n *\n * @example\n * ```ts\n * const transaction = new SubmittedTransaction({\n * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',\n * transactionId: 'request-tx', result: undefined,\n * dexBackendBaseUrl: 'https://dex.example', httpRequestor,\n * });\n * ```\n */\n constructor(options: {\n method: string;\n uniqueKey: string;\n transactionId: string | null;\n mode: 'sync' | 'queued';\n result: unknown;\n dexBackendBaseUrl: string;\n httpRequestor: HttpRequestor;\n blockNumber?: number | null | undefined;\n envelope?: unknown;\n requestTimeoutMs?: number | undefined;\n /** Wire options of the apply-results polls `confirm()` makes. */\n wire?: WireOptions | undefined;\n positionConfirmation?:\n ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n }) {\n this.method = options.method;\n this.uniqueKey = options.uniqueKey;\n this.transactionId = options.transactionId;\n this.blockNumber = options.blockNumber ?? null;\n this.mode = options.mode;\n this.status = options.mode === 'queued' ? 'queued' : 'executed';\n this.result = options.result;\n this.envelope = options.envelope;\n this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestor = options.httpRequestor;\n this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;\n this.wire = options.wire;\n this.positionConfirmation = options.positionConfirmation;\n }\n\n /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.\n *\n * For RequestTrade, calling this method is required to learn the outcome: the queued\n * acknowledgement proves acceptance, not execution.\n *\n * Every failure is the write's (it carries `uniqueKey`, so `mayHaveBeenQueued` is true): a\n * re-read that cannot succeed is `CONFIRMATION_FAILED` (a terminal HTTP status) or\n * `CONFIRMATION_MALFORMED` (an unusable answer); one that may (no answer, a 5xx, 404, 408,\n * 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error\n * as `cause`. Confirm the same transaction again; never resubmit the write.\n *\n * @example\n * ```ts\n * const applied = await submitted.confirm({ initialDelayMs: 3_000 });\n * ```\n */\n public async confirm(options?: ConfirmOptions): Promise<TConfirmation> {\n if (this.method === 'RequestTrade') {\n return this.confirmApplied(options) as Promise<TConfirmation>;\n }\n return this.confirmPosition(options) as Promise<TConfirmation>;\n }\n\n private confirmApplied(options?: ConfirmOptions): Promise<AppliedTrade> {\n return confirmAppliedTrade(\n {\n dexBackendBaseUrl: this.backendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.requestTimeoutMs,\n wire: this.wire,\n },\n { uniqueKey: this.uniqueKey, requestTransactionId: this.transactionId },\n options,\n );\n }\n\n /** Confirm a liquidity write against the position's observable effect.\n *\n * @returns The position after the write, or `null` for a confirmed full close.\n * @example\n * ```ts\n * const position = await submitted.confirm({ timeoutMs: 60_000 });\n * ```\n */\n private async confirmPosition(options?: ConfirmOptions): Promise<Position | null> {\n if (this.positionConfirmation === undefined) throw GSwapSDKError.noWalletAddressError();\n // A liquidity write has already executed when the gateway answers, so the first re-read\n // happens immediately unless the caller asks for a delay.\n const callerSignal = options?.signal;\n const abortError = (cause?: unknown): Error =>\n new GSwapSDKError('CONFIRMATION_ABORTED', {}, { uniqueKey: this.uniqueKey, cause });\n const schedule = createConfirmationSchedule(options, 0, abortError);\n await schedule.waitForRead();\n let lastError: unknown;\n while (true) {\n const controller = new AbortController();\n const disarm = armTimeout(controller, this.requestTimeoutMs);\n const forwardAbort = (): void => controller.abort();\n callerSignal?.addEventListener('abort', forwardAbort, { once: true });\n try {\n const result = await this.positionConfirmation(controller.signal);\n if (result.confirmed) return result.position;\n } catch (error: unknown) {\n throwIfAborted(callerSignal, abortError);\n // The write was accepted, so a failed re-read says nothing about it, and the read's own\n // error must never reach the caller: a read failure means \"retry the read\", and a\n // retried WRITE could apply twice. As on the trade path: a terminal answer is\n // CONFIRMATION_FAILED / CONFIRMATION_MALFORMED, anything else is read again until the\n // deadline, then CONFIRMATION_TIMEOUT. Each carries the write's uniqueKey (a write's).\n const terminal = terminalPositionReadFailure(this.uniqueKey, error);\n if (terminal !== undefined) throw terminal;\n lastError = error;\n } finally {\n disarm();\n callerSignal?.removeEventListener('abort', forwardAbort);\n }\n if (!(await schedule.waitForRead())) break;\n }\n throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);\n }\n}\n\n/** HTTP answers a confirmation reads again (as the apply-results poll does), not terminal ones. */\nfunction isRetriedStatus(status: number): boolean {\n return status === 404 || status === 408 || status === 429 || status >= 500;\n}\n\n/**\n * The confirmation error for a position re-read that failed TERMINALLY (an answer that reading\n * again cannot change), or `undefined` when it is worth reading again.\n */\nfunction terminalPositionReadFailure(uniqueKey: string, error: unknown): GSwapSDKError | undefined {\n if (!isGSwapError(error)) return undefined;\n if (error.code === 'INVALID_POSITION_RESPONSE' || error.code === 'INVALID_CHAIN_RESPONSE') {\n return new GSwapSDKError(\n 'CONFIRMATION_MALFORMED',\n {},\n { uniqueKey, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n const status = error.status;\n if (\n (error.code === 'HTTP_ERROR' || error.code === 'UPDATE_REQUIRED') &&\n status !== undefined &&\n !isRetriedStatus(status)\n ) {\n const serverMessage = (error.params as Record<string, unknown>)['serverMessage'];\n return new GSwapSDKError(\n 'CONFIRMATION_FAILED',\n { status, serverMessage: typeof serverMessage === 'string' ? serverMessage : '' },\n { uniqueKey, status, url: error.url, body: error.body ?? error.bodyText, cause: error },\n );\n }\n return undefined;\n}\n","import {\n buildRequestHeaders,\n fetchRequestor,\n readBlockNumberHeader,\n readHeader,\n readResponseBody,\n readRetryAfter,\n requestWithTimeout,\n validateTimeoutMs,\n type GalaErrorContext,\n type HttpRequestor,\n type HTTPResponse,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { DEX_CONTRACT_PATH } from '../utils/chain_contract.js';\nimport {\n getObjectProperty,\n getStringProperty,\n GSwapSDKError,\n isGSwapError,\n UPDATE_REQUIRED_STATUS,\n} from './gswap_sdk_error.js';\nimport { serverMessageOfBody } from '../utils/server_message.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport { userRef } from '../utils/validation.js';\nimport type { SubmissionOutcomeUnknownReason } from './gswap_error_catalog.js';\nimport type { ShadowSubmitResult } from './shadow_submit.js';\nimport { SubmittedTransaction, type PositionConfirmationResult } from './submitted_transaction.js';\nimport type { AppliedTrade, Position } from '../types/v2_results.js';\n\n/** Options for a chain-gateway client. */\nexport interface ChainGatewayOptions {\n dexBackendBaseUrl: string;\n httpRequestor?: HttpRequestor | undefined;\n walletAddress?: string | undefined;\n /**\n * Timeout of every gateway request in milliseconds (default 30 000); also the per-read timeout\n * of the services built on this gateway and of `confirm()`. `Infinity` arms no timer, for an\n * app whose HTTP stack owns request lifetimes.\n */\n chainCallTimeoutMs?: number | undefined;\n /**\n * Wire format of every request of this gateway and of the services built on it: the headers\n * (`userAgent`, `headers`) of reads AND of the POSTs that submit writes, and the query encoding\n * of reads. `X-Wallet-Address` and `X-Shadow` always win over a same-named `wire.headers` entry.\n */\n wire?: WireOptions | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` mean \"no HTTP answer arrived\" (the\n * connection failed, was reset or dropped), as opposed to an answer your requestor turned into\n * an error (an interceptor that rejects on a 4xx, a version wall). Used only when submitting a\n * write: a rejection it accepts becomes `SUBMISSION_OUTCOME_UNKNOWN` with `reason: 'transport'`\n * (the request may have been queued; the original error is `cause`), and any other rejection\n * reaches the caller unchanged. The SDK's own `TRANSPORT_ERROR` (the default `fetch` requestor,\n * `httpRequestorFromAxios`) always counts, so this is only for requestors that reject with\n * their own errors. Never throw from it; a throw is treated as \"not a transport failure\".\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: galaFetch, // a fetch wrapper: its TypeError is the network failing\n * isTransportFailure: (error) => error instanceof TypeError,\n * });\n * ```\n */\n isTransportFailure?: ((error: unknown) => boolean) | undefined;\n /**\n * Tells the gateway which rejections of YOUR `httpRequestor` are an HTTP ANSWER, and what the\n * answer was: a requestor built on an HTTP client that rejects every non-2xx (an interceptor\n * that throws on a 4xx, a version wall that throws on a 426) loses the answer the SDK reads\n * errors from. Return `{ status, body }` (the parsed JSON, or the raw text; `headers` for\n * `Retry-After`) for such a rejection and the write is handled exactly as if the requestor had\n * resolved that answer: the gateway's own code becomes its catalogued error\n * (`DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ...), an uncoded body `HTTP_ERROR`,\n * both carrying the signed `uniqueKey` and classified by `classifyFailure` as a write. Return\n * `undefined` for any other rejection: it reaches the caller unchanged. Used only when\n * submitting a write; `isTransportFailure` is asked first (no answer proves nothing, so\n * \"maybe queued\" wins), and a throw from this hook, or a `status` outside 100-599, means \"not an\n * answer\". Never throw from it.\n *\n * @example\n * ```ts\n * new ChainGateway({\n * dexBackendBaseUrl,\n * httpRequestor: httpRequestorFromAxios(instance, { rejectOnHttpError: true }),\n * answerOfRejection: (error) =>\n * error instanceof GatewayError && error.status !== undefined\n * ? { status: error.status, body: error.data }\n * : undefined,\n * });\n * ```\n */\n answerOfRejection?: ((error: unknown) => RejectedAnswer | undefined) | undefined;\n}\n\n/** The HTTP answer a rejection of the app's requestor stands for (see `ChainGatewayOptions.answerOfRejection`). */\nexport interface RejectedAnswer {\n /** The HTTP status of the answer (100-599). */\n status: number;\n /** The answer's body: parsed JSON when it was JSON, else the raw text. */\n body: unknown;\n /** The answer's headers, for `Retry-After`. */\n headers?: Record<string, string | undefined> | undefined;\n}\n\n/** Optional attribution and operation-specific confirmation hooks for a write. */\nexport interface ChainSubmitOptions {\n walletAddress?: string | undefined;\n positionConfirmation?: ((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined;\n}\n\n/** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */\nexport class ChainGateway {\n private readonly requestor: HttpRequestor;\n private readonly walletAddress: string | undefined;\n private readonly chainCallTimeoutMs: number;\n private readonly isTransportFailure: ((error: unknown) => boolean) | undefined;\n private readonly answerOfRejectionHook:\n ((error: unknown) => RejectedAnswer | undefined) | undefined;\n /** The request timeout in milliseconds (`Infinity` when no timer is armed). */\n public readonly requestTimeoutMs: number;\n /** The swap backend base URL every request is sent to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** Wire format shared by the read services built on this gateway. */\n public readonly wire: WireOptions;\n\n /** Create a chain gateway client. */\n constructor(options: ChainGatewayOptions) {\n this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);\n this.requestor = options.httpRequestor ?? fetchRequestor;\n this.walletAddress =\n options.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n this.chainCallTimeoutMs = validateTimeoutMs(\n options.chainCallTimeoutMs ?? 30_000,\n 'chainCallTimeoutMs',\n );\n this.requestTimeoutMs = this.chainCallTimeoutMs;\n this.wire = options.wire ?? {};\n this.isTransportFailure = options.isTransportFailure;\n this.answerOfRejectionHook = options.answerOfRejection;\n }\n\n /**\n * Submit a signed v2 DTO through the chain gateway.\n *\n * @throws GSwapSDKError `SUBMISSION_OUTCOME_UNKNOWN` when no answer was read: `params.reason` is\n * `'timeout'` (the POST exceeded `chainCallTimeoutMs`) or `'transport'` (the connection failed\n * or broke off). Either way the write MAY have been queued: keep `error.uniqueKey` and confirm\n * it. Whether to offer the user a Retry (a NEW request under a fresh key) is the app's policy;\n * the SDK states only that the outcome is unknown. Reads keep `TRANSPORT_ERROR`.\n */\n public async submit(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction<Position | null>>;\n public async submit(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<SubmittedTransaction> {\n // The synchronous swap was removed from the contract and from this SDK. This is the only\n // place the retired name may appear in the write path; the class guard in\n // tests/foundation.test.ts pins that nothing signs or submits it.\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const url = this.writeUrl(method);\n const walletAddress = this.walletOf(options);\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: walletAddress === undefined ? {} : { 'X-Wallet-Address': walletAddress },\n });\n const { response, body } = await this.post(method, url, headers, signedBody);\n // Every failure after an answer names the write it is about, so an app can confirm it and a\n // failure classifier can tell a write's HTTP failure from a read's.\n const uniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const context = responseContext(response, body, url, uniqueKey);\n\n if (!response.ok) {\n throw gatewayError(response, body, url, uniqueKey);\n }\n\n const envelope = asRecord(body);\n // `error: true` is the gateway refusing the write, even inside a 2xx. It is never a transaction.\n if (envelope?.['error'] === true) {\n throw new GSwapSDKError(\n 'GATEWAY_REPORTED_ERROR',\n { serverMessage: serverMessageOfBody(envelope) },\n context,\n );\n }\n const data = asRecord(envelope?.['data'] ?? envelope?.['Data']);\n if (data === undefined) {\n throw new GSwapSDKError('GATEWAY_DATA_MISSING', {}, context);\n }\n\n const transactionId = getStringProperty(data, 'transactionId');\n const mode = getStringProperty(data, 'mode');\n const rawTransactionId = data['transactionId'];\n const bodyBlockNumber = data['blockNumber'];\n const invalidMode = (): GSwapSDKError<'GATEWAY_MODE_INVALID'> =>\n new GSwapSDKError('GATEWAY_MODE_INVALID', {}, context);\n if (mode !== 'sync' && mode !== 'queued') {\n throw invalidMode();\n }\n if (\n ('transactionId' in data && typeof rawTransactionId !== 'string') ||\n (bodyBlockNumber !== undefined && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber))\n ) {\n throw invalidMode();\n }\n if (method === 'RequestTrade' && mode === 'sync') {\n throw new GSwapSDKError('GATEWAY_SYNC_REQUEST_TRADE', {}, context);\n }\n if (method === 'RequestTrade' && mode === 'queued') {\n assertQueuedUnderSignedKey(response, body, url, data, signedBody);\n } else if (mode === 'queued' || !('result' in data)) {\n throw invalidMode();\n }\n\n // Only synchronous writes carry an executed chain result in the gateway response.\n if (mode === 'sync') {\n const embeddedResult = asRecord(data['result']);\n if (embeddedResult !== undefined) {\n const resultStatus = embeddedResult['Status'];\n if (resultStatus !== undefined && resultStatus !== 1) {\n throw GSwapSDKError.fromChainError(\n getStringProperty(embeddedResult, 'ErrorKey') ?? 'CHAIN_ERROR',\n getStringProperty(embeddedResult, 'Message') ?? '',\n context,\n );\n }\n }\n }\n\n const headerTransactionId = readHeader(response, 'x-transaction-id');\n const resolvedTransactionId =\n transactionId === undefined || transactionId === '' ? headerTransactionId : transactionId;\n const blockNumber: number | undefined =\n bodyBlockNumber === null || bodyBlockNumber === undefined\n ? readBlockNumberHeader(response)\n : isBlockNumber(bodyBlockNumber)\n ? bodyBlockNumber\n : undefined;\n return new SubmittedTransaction({\n method,\n uniqueKey,\n transactionId:\n resolvedTransactionId === undefined || resolvedTransactionId === ''\n ? null\n : resolvedTransactionId,\n blockNumber: blockNumber ?? null,\n mode,\n result: mode === 'queued' ? undefined : data['result'],\n envelope: body,\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n httpRequestor: this.requestor,\n requestTimeoutMs: this.chainCallTimeoutMs,\n wire: this.wire,\n ...(options?.positionConfirmation === undefined\n ? {}\n : { positionConfirmation: options.positionConfirmation }),\n });\n }\n\n /**\n * Submit a signed v2 DTO as a SHADOW (dark) write: the same route and body as {@link submit},\n * plus `X-Wallet-Address` and `X-Shadow: true`, so the swap backend marks the transaction private\n * before it reaches the contract. The wallet address is required (the backend resolves the\n * owner from it).\n *\n * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,\n * because shadow failures are classified from the status together with the body's `code`\n * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);\n * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with\n * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may\n * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object\n * that escapes (your requestor's own rejection) answers `isShadowError(error)`.\n *\n * @example\n * ```ts\n * const result = await gateway.submitShadow('RequestTrade', signedDto, { walletAddress });\n * const outcome = readShadowSubmitOutcome('RequestTrade', signedDto, result);\n * ```\n */\n public async submitShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n return shadowFailures(() => this.sendShadow(method, signedBody, options));\n }\n\n private async sendShadow(\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ): Promise<ShadowSubmitResult> {\n if (method === 'Trade') {\n throw new GSwapSDKError('METHOD_NOT_SUPPORTED', { method });\n }\n const walletAddress = this.walletOf(options);\n if (walletAddress === undefined) {\n throw new GSwapSDKError('SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS', {});\n }\n // Header order is the one the Gala web apps send: X-Wallet-Address, then X-Shadow.\n const headers = buildRequestHeaders(this.wire, {\n json: true,\n fixed: { 'X-Wallet-Address': walletAddress, 'X-Shadow': 'true' },\n });\n const { response, body } = await this.post(method, this.writeUrl(method), headers, signedBody);\n return { httpStatus: response.status, body };\n }\n\n /**\n * The `X-Wallet-Address` of a write: the per-call wallet or the gateway's, in the gateway's\n * spelling (`eth|<EIP-55>`, `client|<id>` as written). A per-call wallet that is no user\n * reference is refused before anything is sent.\n */\n private walletOf(options: ChainSubmitOptions | undefined): string | undefined {\n return options?.walletAddress === undefined\n ? this.walletAddress\n : userRef(options.walletAddress, 'walletAddress');\n }\n\n private writeUrl(method: string): string {\n return `${this.dexBackendBaseUrl}/v1/chain/${DEX_CONTRACT_PATH}/${method}`;\n }\n\n /**\n * POSTs a signed body and reads the answer. Neither a timeout nor a transport failure proves the\n * write was not submitted, so both are `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` says which),\n * never a retryable read failure. A rejection that is an answer (see `isTransportFailure`) is\n * rethrown unchanged.\n */\n private async post(\n method: string,\n url: string,\n headers: Record<string, string>,\n signedBody: Record<string, unknown>,\n ): Promise<{ response: HTTPResponse; body: unknown }> {\n // Serialized BEFORE the request is attempted and outside the try below: a body that cannot be\n // serialized (a cycle, a BigInt) was never sent, so it must not be mistaken for a transport\n // failure the app's `isTransportFailure` might claim, which would call it \"maybe queued\".\n let payload: string;\n try {\n payload = JSON.stringify(signedBody);\n } catch (cause: unknown) {\n throw new GSwapSDKError('SIGNING_FAILED', { method, reason: 'failed' }, { cause });\n }\n const outcomeUnknown = (\n reason: SubmissionOutcomeUnknownReason,\n cause: unknown,\n ): GSwapSDKError<'SUBMISSION_OUTCOME_UNKNOWN'> =>\n new GSwapSDKError(\n 'SUBMISSION_OUTCOME_UNKNOWN',\n { reason },\n { uniqueKey: getStringProperty(signedBody, 'uniqueKey') ?? '', url, cause },\n );\n let response: HTTPResponse;\n try {\n response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers,\n body: payload,\n },\n this.chainCallTimeoutMs,\n );\n } catch (error: unknown) {\n if (isGSwapError(error, 'REQUEST_TIMEOUT')) throw outcomeUnknown('timeout', error);\n if (isGSwapError(error, 'TRANSPORT_ERROR') || this.isTransportRejection(error)) {\n throw outcomeUnknown('transport', error);\n }\n // A rejection that IS an HTTP answer (the app's interceptor rejecting on a non-2xx, a\n // version wall) is handled exactly as the answer would have been, so the app does not\n // rebuild the SDK's error from it. Anything else the app's requestor threw reaches the\n // caller unchanged.\n const answered = this.answerOfRejection(error);\n if (answered !== undefined) return answered;\n throw error;\n }\n try {\n return { response, body: await readResponseBody(response) };\n } catch (error: unknown) {\n // The answer's headers arrived but its body broke off: the status alone does not say what\n // the gateway did with the write.\n throw outcomeUnknown('transport', error);\n }\n }\n\n /**\n * The HTTP answer a rejection of the app's requestor stands for, as the response the gateway\n * would have read. `undefined` when the app named none, when its hook throws, or when what it\n * returned is not an HTTP status; then the rejection is not an answer.\n */\n private answerOfRejection(error: unknown): { response: HTTPResponse; body: unknown } | undefined {\n let answer: RejectedAnswer | undefined;\n try {\n answer = this.answerOfRejectionHook?.(error);\n } catch {\n return undefined;\n }\n if (answer === undefined) return undefined;\n const { status, body, headers } = answer;\n if (!Number.isInteger(status) || status < 100 || status > 599) return undefined;\n const text = typeof body === 'string' ? body : '';\n const response: HTTPResponse = {\n ok: status >= 200 && status < 300,\n status,\n json: async () => body,\n text: async () => text,\n headers: headers ?? {},\n };\n return { response, body };\n }\n\n private isTransportRejection(error: unknown): boolean {\n try {\n return this.isTransportFailure?.(error) === true;\n } catch {\n return false;\n }\n }\n\n /** Expose the requestor for sibling read services that share this gateway transport. */\n public get httpRequestor(): HttpRequestor {\n return this.requestor;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n\nfunction responseContext(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey?: string,\n): GalaErrorContext {\n return {\n status: response.status,\n body,\n url,\n ...(uniqueKey === undefined || uniqueKey === '' ? {} : { uniqueKey }),\n };\n}\n\n/**\n * A queued RequestTrade acknowledgement is a swap only if it names the exact key that was signed:\n * the key is the only handle `confirm()` and every recovery path have on the trade, so an\n * acknowledgement without it (or with another) proves nothing about THIS request. Fails closed:\n * an absent echo is as unacceptable as a wrong one. The code is `MISSING_UNIQUE_KEY` or\n * `UNIQUE_KEY_MISMATCH`, `error.uniqueKey` the signed key.\n *\n * Only RequestTrade is checked: a synchronous write is proven by its own executed chain result,\n * and the apps never required an echo for it.\n */\nfunction assertQueuedUnderSignedKey(\n response: HTTPResponse,\n body: unknown,\n url: string,\n data: Record<string, unknown>,\n signedBody: Record<string, unknown>,\n): void {\n const signedUniqueKey = getStringProperty(signedBody, 'uniqueKey') ?? '';\n const echoed = data['uniqueKey'];\n if (typeof echoed === 'string' && echoed !== '' && echoed === signedUniqueKey) return;\n const missing = echoed === undefined || echoed === null || echoed === '';\n const context: GalaErrorContext = {\n ...responseContext(response, body, url),\n uniqueKey: signedUniqueKey,\n };\n throw missing\n ? new GSwapSDKError('MISSING_UNIQUE_KEY', {}, context)\n : new GSwapSDKError('UNIQUE_KEY_MISMATCH', {}, context);\n}\n\nfunction gatewayError(\n response: HTTPResponse,\n body: unknown,\n url: string,\n uniqueKey: string,\n): GSwapSDKError {\n // The version wall is decided by the status alone, whatever the body names: nothing was queued.\n if (response.status === UPDATE_REQUIRED_STATUS) {\n return new GSwapSDKError(\n 'UPDATE_REQUIRED',\n { status: response.status },\n responseContext(response, body, url, uniqueKey),\n );\n }\n const object = asRecord(body);\n const nested = getObjectProperty(body, 'error');\n const code =\n getStringProperty(object, 'code') ??\n getStringProperty(nested, 'code') ??\n getStringProperty(nested, 'ErrorKey') ??\n 'HTTP_ERROR';\n // Missing server text is an empty param, never SDK-written English standing in for it. A body\n // that is not JSON (an HTML 502 page, a WAF block) is kept as error.bodyText.\n const message = serverMessageOfBody(body);\n const retryAfterMs = response.status === 429 ? readRetryAfter(response) : undefined;\n if (code === 'HTTP_ERROR') {\n return new GSwapSDKError(\n 'HTTP_ERROR',\n { status: response.status, url, serverMessage: message },\n responseContext(response, body, url, uniqueKey),\n );\n }\n return GSwapSDKError.fromGatewayBounce(\n code,\n message,\n response.status,\n body,\n url,\n retryAfterMs,\n uniqueKey === '' ? undefined : uniqueKey,\n );\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction isBlockNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n","/** SDK deployment environment. */\nexport type GSwapEnv = 'prod' | 'stage';\n\n/** Backend URLs used by one SDK deployment environment. */\nexport interface GSwapEnvironmentConfig {\n dexBackendBaseUrl: string;\n /** The realtime stream endpoint (raw WebSocket, JSON-RPC 2.0). */\n dexBackendWsUrl: string;\n}\n\n/** Built-in GalaSwap deployment environments. */\nexport const GSWAP_ENVIRONMENTS: Readonly<Record<GSwapEnv, GSwapEnvironmentConfig>> = {\n prod: {\n dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com',\n dexBackendWsUrl: 'wss://dex-backend-prod1.defi.gala.com/ws',\n },\n stage: {\n dexBackendBaseUrl: 'https://swap-backend.stage.defi.ovh.gala.com',\n dexBackendWsUrl: 'wss://swap-backend.stage.defi.ovh.gala.com/ws',\n },\n};\n","import debug from 'debug';\n\nexport const debugLog = debug('GSWAP_SDK');\n","/** Options for {@link ReconnectionBackoff}. */\nexport interface ReconnectionBackoffOptions {\n /** Attempts allowed before giving up. */\n maxAttempts: number;\n /** Delay before the first attempt, in milliseconds. */\n baseDelayMs: number;\n /** Ceiling the doubling delay never exceeds, in milliseconds. */\n maxDelayMs?: number;\n}\n\n/** Counts reconnect attempts and doubles the delay between them, up to a ceiling. */\nexport class ReconnectionBackoff {\n private attempts = 0;\n private delayMs: number;\n private readonly maxDelayMs: number;\n\n constructor(private readonly options: ReconnectionBackoffOptions) {\n this.delayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs ?? 30_000;\n }\n\n /** Whether another attempt is allowed. */\n shouldRetry(): boolean {\n return this.attempts < this.options.maxAttempts;\n }\n\n /** The delay to wait before the next attempt. */\n nextDelayMs(): number {\n return this.delayMs;\n }\n\n /** Record that an attempt is being made, and double the next delay. */\n recordAttempt(): void {\n this.attempts += 1;\n this.delayMs = Math.min(this.delayMs * 2, this.maxDelayMs);\n }\n\n /** Forget every attempt: the connection is healthy again. */\n reset(): void {\n this.attempts = 0;\n this.delayMs = this.options.baseDelayMs;\n }\n\n get attemptCount(): number {\n return this.attempts;\n }\n\n get maxAttempts(): number {\n return this.options.maxAttempts;\n }\n}\n","import { GSWAP_ENVIRONMENTS } from '../types/env.js';\nimport { debugLog } from '../utils/debug.js';\nimport { userRef } from '../utils/validation.js';\nimport { ReconnectionBackoff } from '../utils/reconnection.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nconst GDEX_SUBPROTOCOL = 'gdex.jsonrpc.v1';\nconst RATE_LIMITED = -32003;\nconst MAX_RESUBSCRIBE_RATE_RETRIES = 5;\nconst WEBSOCKET_OPEN = 1;\n\n/** Options for {@link GdexStreamService}. */\nexport interface GdexStreamConfig {\n /** Stream endpoint. Defaults to production (`wss://dex-backend-prod1.defi.gala.com/ws`). */\n url?: string | undefined;\n /** Reconnect attempts after an unexpected close. Default 5. */\n reconnectAttempts?: number | undefined;\n /** Delay before the first reconnect attempt; doubles each attempt. Default 2000 ms. */\n reconnectDelayMs?: number | undefined;\n /** How long a request waits for its response. Default 15000 ms. */\n requestTimeoutMs?: number | undefined;\n /**\n * A standards-compatible WebSocket constructor. Required on Node.js older than 22, which has no\n * global `WebSocket` (pass the one from the `ws` package).\n */\n webSocketImpl?: unknown;\n /**\n * Presents `x-api-key` on the WebSocket upgrade request, which the swap backend uses to serve the\n * PRIVILEGED view (shadow swaps with the wallet unredacted). Without it, or with a wrong key, the\n * connection is simply public: the server never says whether a privileged mode exists.\n *\n * It must travel as an HTTP header, because the server reads no other credential, and a browser\n * `WebSocket` cannot set headers. So this option needs a constructor that accepts them as its\n * third argument (`{ headers }`): the `ws` package on Node.js, or React Native's built-in\n * `WebSocket`. It therefore REQUIRES `webSocketImpl` (the platform default is never assumed to\n * honor headers, and a key that is silently dropped would look like a working privileged\n * connection); the constructor throws otherwise. Use it from server-side code only: a key\n * shipped inside a browser or app bundle is not a secret. Browser clients stay public.\n */\n apiKey?: string | undefined;\n}\n\n/** The channels of the realtime stream. */\nexport type GdexChannel = 'pool' | 'balance' | 'poolCreated' | 'swap' | 'liquidity' | 'blocks';\n\n/** A pool named by its two token class keys (pipe form) and fee tier. */\nexport interface GdexPoolKey {\n token0ClassKey: string;\n token1ClassKey: string;\n fee: number;\n}\n\n/** A pool named either by its key or by its hash (`v2:<poolRef>` for a v2 pool). */\nexport type GdexPoolSelector = { pool: GdexPoolKey } | { poolHash: string };\n\n/** Options common to every subscription. */\nexport interface GdexSubscribeOptions {\n /** Send the current state right after the subscribe response. */\n snapshot?: boolean | undefined;\n /** Trim each event to these fields; identity and envelope fields always stay. */\n fields?: string[] | undefined;\n}\n\n/** Filters for {@link GdexStreamService.subscribeLiquidity}; all optional. */\nexport interface GdexLiquidityFilter {\n /** Only this pool, named by its key. */\n pool?: GdexPoolKey | undefined;\n /** Only this pool, named by its hash (`v2:<poolRef>` for a v2 pool). */\n poolHash?: string | undefined;\n /** Only events for this LP wallet (the position's owner). */\n owner?: string | undefined;\n /** Only this transaction. */\n transactionId?: string | undefined;\n /** Contract version filter. */\n version?: 'v1' | 'v2' | 'all' | undefined;\n}\n\n/** One committed add, remove or collect, as the `liquidity` channel reports it. */\nexport interface GdexLiquidityEvent {\n version: 'v1' | 'v2';\n pool: GdexPoolKey;\n poolHash: string;\n transactionId: string;\n /** `add`, `remove` or `collect`. */\n action: 'add' | 'remove' | 'collect';\n /** The position's owner (the LP wallet). */\n owner: string;\n /** v1: the position id. v2: the chain position key `<pool>|<tickLow>|<tickHigh>|<owner>`. */\n positionId?: string;\n tickLower?: number;\n tickUpper?: number;\n /** v2 only: the position's liquidity after the operation; `\"0\"` means it is closed. */\n liquidityAfter?: string;\n /** Principal moved: deposited by an add, withdrawn by a remove, `\"0\"` for a collect. */\n amount0: string;\n amount1: string;\n /** Fees paid out. v2: always present (`\"0\"` for an add). v1: present on a collect only. */\n fees0?: string;\n fees1?: string;\n /** v2 only. */\n token0Symbol?: string;\n token1Symbol?: string;\n blockNumber: number;\n timestamp: string;\n}\n\nconst LIQUIDITY_ACTIONS: readonly unknown[] = ['add', 'remove', 'collect'];\n\n/** Whether a stream payload carries every field of a {@link GdexLiquidityEvent}. */\nexport function isGdexLiquidityEvent(\n value: Record<string, unknown>,\n): value is Record<string, unknown> & GdexLiquidityEvent {\n const { pool } = value;\n return (\n (value['version'] === 'v1' || value['version'] === 'v2') &&\n typeof pool === 'object' &&\n pool !== null &&\n typeof value['poolHash'] === 'string' &&\n typeof value['transactionId'] === 'string' &&\n LIQUIDITY_ACTIONS.includes(value['action']) &&\n typeof value['owner'] === 'string' &&\n typeof value['amount0'] === 'string' &&\n typeof value['amount1'] === 'string' &&\n typeof value['blockNumber'] === 'number' &&\n typeof value['timestamp'] === 'string'\n );\n}\n\n/** A live subscription. */\nexport interface GdexSubscription {\n subscriptionId: string;\n unsubscribe(): Promise<void>;\n}\n\n/** A JSON-RPC error answered by the stream. */\nexport class GdexStreamError extends Error {\n /** The JSON-RPC error code. */\n readonly code: number;\n /** The error's optional `data` member, as the server sent it. */\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = 'GdexStreamError';\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\ninterface WebSocketLike {\n readonly readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code?: number; reason?: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n}\n\ninterface WebSocketConstructor {\n new (\n url: string,\n protocols?: string | string[],\n options?: { headers: Record<string, string> },\n ): WebSocketLike;\n}\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: Error): void;\n timeout: ReturnType<typeof setTimeout>;\n /**\n * Runs SYNCHRONOUSLY when the response frame is handled, before any frame that follows it in\n * the same read. Subscriptions register here: the server writes a snapshot right after the\n * subscribe response, and a runtime that delivers both frames without yielding to microtasks\n * (Node's `ws` does, for frames in one chunk) would otherwise drop the snapshot because the\n * awaiting caller has not registered the subscription yet.\n */\n onResult?: ((value: unknown) => void) | undefined;\n}\n\ntype EventCallback = (event: Record<string, unknown>) => void;\n\ninterface ActiveSubscription {\n serverId: string;\n readonly params: Record<string, unknown>;\n readonly callback: EventCallback;\n readonly handle: MutableGdexSubscription;\n active: boolean;\n}\n\ninterface MutableGdexSubscription extends GdexSubscription {\n subscriptionId: string;\n}\n\nfunction readSubscriptionId(value: unknown): string {\n const id =\n typeof value === 'object' && value !== null\n ? (value as { subscriptionId?: unknown }).subscriptionId\n : undefined;\n if (typeof id !== 'string') {\n throw new GdexStreamError(-32603, 'GDEX subscribe response is missing its subscriptionId');\n }\n return id;\n}\n\ninterface JsonRpcResponse {\n id?: unknown;\n method?: unknown;\n result?: unknown;\n error?: { code?: unknown; message?: unknown; data?: unknown };\n params?: unknown;\n}\n\n/**\n * Client for the gSwap realtime stream (gdex WebSocket Protocol v1): JSON-RPC 2.0 over one raw\n * WebSocket, with automatic reconnect and resubscribe.\n *\n * @example\n * ```typescript\n * const stream = new GdexStreamService();\n * await stream.connect();\n * await stream.subscribeLiquidity(event => console.log(event.action, event.owner), {\n * owner: 'client|618ae395c1c653111d3315be',\n * });\n * ```\n */\nexport class GdexStreamService {\n private readonly url: string;\n private readonly requestTimeoutMs: number;\n private readonly apiKey: string | undefined;\n private readonly webSocketConstructor: WebSocketConstructor;\n private readonly backoff: ReconnectionBackoff;\n private socket: WebSocketLike | undefined;\n private connectPromise: Promise<void> | undefined;\n private nextRequestId = 0;\n private readonly pending = new Map<number, PendingRequest>();\n private readonly subscriptionsByServerId = new Map<string, ActiveSubscription>();\n private readonly activeSubscriptions = new Set<ActiveSubscription>();\n private intentionalClose = false;\n private reconnecting = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n private reconnectDelayResolve: (() => void) | undefined;\n\n constructor(config: GdexStreamConfig = {}) {\n this.url = config.url ?? GSWAP_ENVIRONMENTS.prod.dexBackendWsUrl;\n this.requestTimeoutMs = config.requestTimeoutMs ?? 15_000;\n this.backoff = new ReconnectionBackoff({\n maxAttempts: config.reconnectAttempts ?? 5,\n baseDelayMs: config.reconnectDelayMs ?? 2_000,\n });\n\n const implementation =\n config.webSocketImpl ?? (globalThis as { WebSocket?: unknown }).WebSocket;\n if (typeof implementation !== 'function') {\n throw new GSwapSDKError('STREAM_WEBSOCKET_UNAVAILABLE', {});\n }\n this.webSocketConstructor = implementation as WebSocketConstructor;\n if (config.apiKey !== undefined) {\n if (config.apiKey === '' || config.webSocketImpl === undefined) {\n throw new GSwapSDKError('STREAM_API_KEY_UNUSABLE', {});\n }\n this.apiKey = config.apiKey;\n }\n }\n\n /** Open the connection. Resolves at once when already connected. */\n connect(): Promise<void> {\n if (this.isConnected()) return Promise.resolve();\n if (this.connectPromise) return this.connectPromise;\n this.intentionalClose = false;\n this.clearReconnectTimer();\n this.connectPromise = this.openSocket();\n return this.connectPromise;\n }\n\n /** Close the connection and stop reconnecting. */\n disconnect(): void {\n this.intentionalClose = true;\n this.reconnecting = false;\n this.clearReconnectTimer();\n this.rejectPending(new GSwapSDKError('STREAM_DISCONNECTED', {}));\n const socket = this.socket;\n this.socket = undefined;\n this.connectPromise = undefined;\n socket?.close(1000, 'client disconnect');\n }\n\n /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */\n isConnected(): boolean {\n return this.socket?.readyState === WEBSOCKET_OPEN;\n }\n\n /** Raw JSON-RPC escape hatch. */\n request<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {\n return this.send<T>(method, params);\n }\n\n private send<T>(\n method: string,\n params: Record<string, unknown> | undefined,\n onResult?: (value: unknown) => void,\n ): Promise<T> {\n if (!this.isConnected() || !this.socket) {\n return Promise.reject(new GSwapSDKError('STREAM_NOT_CONNECTED', {}));\n }\n\n const id = ++this.nextRequestId;\n const frame: Record<string, unknown> = { jsonrpc: '2.0', id, method };\n if (params !== undefined) frame['params'] = params;\n\n return new Promise<T>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(id);\n reject(\n new GSwapSDKError('STREAM_REQUEST_TIMEOUT', { method, timeoutMs: this.requestTimeoutMs }),\n );\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve: (value) => resolve(value as T), reject, timeout, onResult });\n\n try {\n this.socket?.send(JSON.stringify(frame));\n } catch (error) {\n clearTimeout(timeout);\n this.pending.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */\n serverInfo(): Promise<Record<string, unknown>> {\n return this.request('gdex_serverInfo');\n }\n\n /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */\n ping(): Promise<{ pong: boolean; serverTime: string }> {\n return this.request('gdex_ping');\n }\n\n /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */\n getPool(selector: GdexPoolSelector): Promise<Record<string, unknown>> {\n return this.request('gdex_getPool', selector);\n }\n\n /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */\n async getBalance(owner: string, tokenClassKey?: string): Promise<Record<string, unknown>> {\n const ref = userRef(owner, 'owner');\n return this.request(\n 'gdex_getBalance',\n tokenClassKey === undefined ? { owner: ref } : { owner: ref, tokenClassKey },\n );\n }\n\n /**\n * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the\n * returned `bookmark` back in as `bookmark` for the next page.\n */\n async getPositions(opts: {\n owner: string;\n pool?: GdexPoolKey;\n poolHash?: string;\n limit?: number;\n bookmark?: string;\n }): Promise<{ positions: Record<string, unknown>[]; bookmark: string }> {\n return this.request('gdex_getPositions', { ...opts, owner: userRef(opts.owner, 'owner') });\n }\n\n /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */\n getBlockHeight(): Promise<{ blockNumber: number; timestamp: string }> {\n return this.request('gdex_getBlockHeight');\n }\n\n /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */\n quote(params: {\n tokenIn: string;\n tokenOut: string;\n fee?: number;\n amountIn?: string;\n amountOut?: string;\n }): Promise<Record<string, unknown>> {\n return this.request('gdex_quote', params);\n }\n\n /** `gdex_getToken`: the server's record of one token class, as it sends it. */\n getToken(tokenClassKey: string): Promise<Record<string, unknown>> {\n return this.request('gdex_getToken', { tokenClassKey });\n }\n\n /** One event per committed swap. Omit the pool to receive every pool's swaps. */\n subscribeSwaps(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & {\n pool?: GdexPoolKey;\n poolHash?: string;\n transactionId?: string;\n } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('swap', cb, opts);\n }\n\n /**\n * State changes of one pool (price, tick, reserves, liquidity). These events carry no acting wallet:\n * on v2 `creator` is whoever created the pool, not whoever just traded or added liquidity. For\n * \"who did it\", use {@link subscribeLiquidity} (`owner`) or {@link subscribeSwaps} (`sender`).\n */\n subscribePool(\n selector: GdexPoolSelector,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('pool', cb, { ...selector, ...opts });\n }\n\n /** Balance changes of one wallet. */\n async subscribeBalances(\n owner: string,\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('balance', cb, { owner: userRef(owner, 'owner'), ...opts });\n }\n\n /** Each newly created pool. */\n subscribePoolCreated(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions & { tokenClassKey?: string } = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('poolCreated', cb, opts);\n }\n\n /**\n * One event per committed AddLiquidity, RemoveLiquidity and CollectPositionFees, on both contract\n * versions. Every filter is optional; with none, every liquidity event arrives. These events never\n * appear on {@link subscribeSwaps}. There is no snapshot: read positions with {@link getPositions}.\n * Deduplicate by `transactionId` plus `positionId`: a v1 BatchSubmit can hold several operations\n * under one transaction id.\n */\n async subscribeLiquidity(\n cb: (event: GdexLiquidityEvent) => void,\n opts: GdexSubscribeOptions & GdexLiquidityFilter = {},\n ): Promise<GdexSubscription> {\n const filter =\n opts.owner === undefined ? opts : { ...opts, owner: userRef(opts.owner, 'owner') };\n return this.subscribe(\n 'liquidity',\n (event) => {\n if (isGdexLiquidityEvent(event)) cb(event);\n else debugLog('Ignoring a malformed liquidity event from the GDEX stream');\n },\n filter,\n );\n }\n\n /** Each block-height advance. */\n subscribeBlocks(\n cb: (event: Record<string, unknown>) => void,\n opts: GdexSubscribeOptions = {},\n ): Promise<GdexSubscription> {\n return this.subscribe('blocks', cb, opts);\n }\n\n private openSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let opened = false;\n const socket =\n this.apiKey === undefined\n ? new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL)\n : new this.webSocketConstructor(this.url, GDEX_SUBPROTOCOL, {\n headers: { 'x-api-key': this.apiKey },\n });\n this.socket = socket;\n\n socket.onopen = () => {\n if (this.socket !== socket) return;\n opened = true;\n this.connectPromise = undefined;\n if (!this.reconnecting) this.backoff.reset();\n debugLog('Connected to GDEX stream');\n resolve();\n };\n socket.onmessage = (event) => this.handleMessage(event.data);\n socket.onerror = () => {\n if (!opened) reject(new GSwapSDKError('STREAM_CONNECT_FAILED', { url: this.url }));\n };\n socket.onclose = (event) => {\n if (this.socket !== socket) return;\n this.socket = undefined;\n this.connectPromise = undefined;\n if (!opened) {\n reject(new GSwapSDKError('STREAM_CLOSED_BEFORE_CONNECT', { closeCode: event.code ?? 0 }));\n }\n this.rejectPending(\n new GSwapSDKError('STREAM_CONNECTION_CLOSED', { closeCode: event.code ?? 0 }),\n );\n if (!this.intentionalClose && !this.reconnecting) this.startReconnectLoop();\n };\n });\n }\n\n private handleMessage(data: unknown): void {\n if (typeof data !== 'string') {\n debugLog('Ignoring non-text GDEX WebSocket frame');\n return;\n }\n\n let message: JsonRpcResponse;\n try {\n message = JSON.parse(data) as JsonRpcResponse;\n } catch {\n debugLog('Ignoring invalid JSON from GDEX stream');\n return;\n }\n\n if (typeof message.id === 'number') {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timeout);\n this.pending.delete(message.id);\n if (message.error) {\n const code = typeof message.error.code === 'number' ? message.error.code : -32603;\n const errorMessage =\n typeof message.error.message === 'string' ? message.error.message : 'GDEX request failed';\n pending.reject(new GdexStreamError(code, errorMessage, message.error.data));\n } else {\n try {\n pending.onResult?.(message.result);\n } catch (error) {\n pending.reject(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n pending.resolve(message.result);\n }\n return;\n }\n\n if (message.method !== 'gdex_subscription' || !this.isRecord(message.params)) return;\n const subscriptionId = message.params['subscription'];\n const result = message.params['result'];\n if (typeof subscriptionId !== 'string' || !this.isRecord(result)) return;\n const subscription = this.subscriptionsByServerId.get(subscriptionId);\n if (!subscription?.active) return;\n try {\n subscription.callback(result);\n } catch (error) {\n debugLog('GDEX subscription callback failed', error);\n }\n }\n\n private async subscribe(\n channel: GdexChannel,\n callback: EventCallback,\n options: object,\n ): Promise<GdexSubscription> {\n const params: Record<string, unknown> = { channel, ...options };\n const handle: MutableGdexSubscription = {\n subscriptionId: '',\n unsubscribe: async () => this.unsubscribe(subscription),\n };\n const subscription: ActiveSubscription = {\n serverId: '',\n params,\n callback,\n handle,\n active: true,\n };\n // Registered inside the response handler, not after the await: see PendingRequest.onResult.\n await this.send('gdex_subscribe', params, (value) => {\n const serverId = readSubscriptionId(value);\n subscription.serverId = serverId;\n handle.subscriptionId = serverId;\n this.activeSubscriptions.add(subscription);\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n return handle;\n }\n\n private async unsubscribe(subscription: ActiveSubscription): Promise<void> {\n if (!subscription.active) return;\n subscription.active = false;\n this.activeSubscriptions.delete(subscription);\n this.subscriptionsByServerId.delete(subscription.serverId);\n if (this.isConnected()) {\n await this.request('gdex_unsubscribe', { subscriptionId: subscription.serverId });\n }\n }\n\n private startReconnectLoop(): void {\n if (this.reconnecting || this.intentionalClose) return;\n this.reconnecting = true;\n void this.reconnectLoop();\n }\n\n private async reconnectLoop(): Promise<void> {\n while (!this.intentionalClose && this.backoff.shouldRetry()) {\n const delay = this.backoff.nextDelayMs();\n this.backoff.recordAttempt();\n debugLog(\n `GDEX reconnect attempt ${this.backoff.attemptCount}/${this.backoff.maxAttempts} in ${delay}ms`,\n );\n await this.waitForReconnectDelay(delay);\n // `disconnect()` can run while the asynchronous delay is pending.\n if (this.intentionalClose) break;\n\n try {\n await this.openSocket();\n await this.resubscribeAll();\n this.backoff.reset();\n this.reconnecting = false;\n return;\n } catch (error) {\n debugLog(\n `GDEX reconnect failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n this.reconnecting = false;\n if (!this.intentionalClose) debugLog('GDEX reconnection attempts exhausted');\n }\n\n private async resubscribeAll(): Promise<void> {\n this.subscriptionsByServerId.clear();\n for (const subscription of this.activeSubscriptions) {\n if (!subscription.active) continue;\n const params = { ...subscription.params, snapshot: true };\n const result = await this.resubscribeWithRateLimitRetry(params, (value) => {\n const serverId = readSubscriptionId(value);\n // The consumer can unsubscribe while the asynchronous subscribe request is pending.\n if (!subscription.active) return;\n subscription.serverId = serverId;\n subscription.handle.subscriptionId = serverId;\n this.subscriptionsByServerId.set(serverId, subscription);\n });\n if (!subscription.active) {\n await this.request('gdex_unsubscribe', { subscriptionId: result.subscriptionId });\n }\n }\n }\n\n private async resubscribeWithRateLimitRetry(\n params: Record<string, unknown>,\n onResult: (value: unknown) => void,\n ): Promise<{ subscriptionId: string }> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.send('gdex_subscribe', params, onResult);\n } catch (error) {\n if (\n !(error instanceof GdexStreamError) ||\n error.code !== RATE_LIMITED ||\n attempt >= MAX_RESUBSCRIBE_RATE_RETRIES\n ) {\n throw error;\n }\n const retryAfterMs = this.readRetryAfterMs(error.data);\n debugLog(`GDEX resubscribe rate limited; retrying in ${retryAfterMs}ms`);\n await new Promise<void>((resolve) => setTimeout(resolve, retryAfterMs));\n }\n }\n }\n\n private waitForReconnectDelay(delay: number): Promise<void> {\n return new Promise((resolve) => {\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = undefined;\n this.reconnectDelayResolve = undefined;\n resolve();\n }, delay);\n this.reconnectDelayResolve = resolve;\n });\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer !== undefined) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n const resolve = this.reconnectDelayResolve;\n this.reconnectDelayResolve = undefined;\n resolve?.();\n }\n\n private rejectPending(error: Error): void {\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n private readRetryAfterMs(data: unknown): number {\n if (\n !this.isRecord(data) ||\n typeof data['retryAfterMs'] !== 'number' ||\n data['retryAfterMs'] < 0\n )\n return 1_000;\n return data['retryAfterMs'];\n }\n\n private isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n","import {\n buildQueryString,\n buildRequestHeaders,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { debugLog } from '../utils/debug.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\nexport class HttpClient {\n /**\n * Create an HTTP client around fetch or an injected requestor. `wire` selects the query\n * encoding and the `User-Agent` (see {@link WireOptions}).\n */\n constructor(\n private readonly httpRequestor: HttpRequestor = fetchRequestor,\n private readonly timeoutMs = 30_000,\n private readonly wire: WireOptions = {},\n ) {}\n\n private async sendRequest<TReturnType>(\n method: 'POST' | 'GET',\n baseUrl: string,\n basePath: string,\n endpoint: string,\n body?: unknown,\n options?: Pick<RequestInit, 'signal'>,\n ): Promise<TReturnType> {\n const url = `${baseUrl}${basePath}${endpoint}`;\n debugLog(`Sending request to ${url} with body:`, body);\n\n const hasBody = Boolean(body);\n const response = await requestWithTimeout(\n this.httpRequestor,\n url,\n {\n method,\n // Content-Type describes a body, so a GET carries none: it also keeps a browser's\n // cross-origin GET a simple request instead of forcing a CORS preflight.\n headers: buildRequestHeaders(this.wire, { json: hasBody }),\n ...(hasBody ? { body: JSON.stringify(body) } : {}),\n ...(options?.signal === undefined ? {} : { signal: options.signal }),\n },\n this.timeoutMs,\n // Every request of this client is a read (writes go through ChainGateway): a timeout or a\n // transport failure is a read's, as its HTTP errors are (`fromErrorResponse`).\n { write: false },\n );\n\n if (!response.ok) {\n throw await GSwapSDKError.fromErrorResponse(url, response);\n }\n\n const json = await readResponseBody(response);\n debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);\n\n return json as TReturnType;\n }\n\n /** Send a JSON POST request and decode its response. */\n async sendPostRequest<TReturnType>(\n baseUrl: string,\n basePath: string,\n endpoint: string,\n body: unknown,\n ): Promise<TReturnType> {\n return this.sendRequest('POST', baseUrl, basePath, endpoint, body);\n }\n\n /** Send a GET request with URL-encoded query parameters and decode its response. */\n async sendGetRequest<TReturnType>(\n baseUrl: string,\n basePath: string,\n endpoint: string,\n params?: Record<string, string>,\n options?: Pick<RequestInit, 'signal'>,\n ): Promise<TReturnType> {\n const endpointWithParams = params\n ? `${endpoint}?${buildQueryString(params, this.wire.queryEncoding)}`\n : endpoint;\n\n return this.sendRequest('GET', baseUrl, basePath, endpointWithParams, undefined, options);\n }\n}\n","import { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** One row of a list answer that the SDK skipped because it was not usable. */\nexport interface InvalidEntry {\n /** Which read the row came from. */\n source: 'pools' | 'symbols' | 'positions' | 'prices' | 'priceSeries' | 'seasons' | 'leaderboard';\n /**\n * Position of the row in the answer's array; for `prices` (an answer keyed by token), the\n * position of the token in the list asked for.\n */\n index: number;\n /** The row exactly as the backend sent it. */\n entry: unknown;\n /** Why it was skipped, in words. */\n reason: string;\n}\n\n/**\n * Called once per skipped row, in order, before the read resolves. It is a diagnostics hook: what it\n * does, or throws, never changes the result of the read.\n */\nexport type InvalidEntryHandler = (invalid: InvalidEntry) => void;\n\n/** The outcome of reading one row. */\nexport type EntryParse<T> = { ok: true; value: T } | { ok: false; reason: string };\n\n/** A usable row. */\nexport function entryOk<T>(value: T): EntryParse<T> {\n return { ok: true, value };\n}\n\n/** An unusable row, with the reason it is reported under. */\nexport function entryRejected<T>(reason: string): EntryParse<T> {\n return { ok: false, reason };\n}\n\n/**\n * Reads a list answer row by row: a row that cannot be used is skipped and reported, instead of\n * rejecting the whole list because of one bad row. An answer that is not a list at all is still\n * `INVALID_CHAIN_RESPONSE` (a read's: `write: false`): nothing in it can be trusted.\n */\nexport function readEntries<T>(\n source: InvalidEntry['source'],\n data: unknown,\n parse: (entry: unknown) => EntryParse<T>,\n onInvalidEntry?: InvalidEntryHandler,\n): T[] {\n if (!Array.isArray(data)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: `${source} list` },\n { body: data, write: false },\n );\n }\n const rows: T[] = [];\n (data as unknown[]).forEach((entry, index) => {\n const parsed = parse(entry);\n if (parsed.ok) {\n rows.push(parsed.value);\n return;\n }\n try {\n onInvalidEntry?.({ source, index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n });\n return rows;\n}\n\n/** A plain JSON object (not null, not an array). */\nexport function asEntryRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** A finite number, or a non-empty numeric string, as a number; otherwise `undefined`. */\nexport function finiteNumberOf(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n","import type {\n LeaderboardEntry,\n LeaderboardSeason,\n MasteryTitle,\n SeasonLeaderboard,\n} from '../types/market.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/** Options of every leaderboard read. */\nexport interface LeaderboardReadOptions {\n signal?: AbortSignal | undefined;\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** Options of the reads that pick the season running now. */\nexport interface CurrentSeasonOptions extends LeaderboardReadOptions {\n /** The instant \"now\" is (default: the current time). */\n now?: Date | undefined;\n}\n\n/**\n * The swap backend's trading-competition reads: seasons (`GET /leaderboard/seasons`) and a\n * season's rankings (`GET /leaderboard?seasonId=`). Public reads: no signer, no wallet. A row that\n * is not usable is skipped and reported to `onInvalidEntry`; an answer that is not the expected\n * list is `INVALID_CHAIN_RESPONSE`.\n */\nexport class Leaderboard {\n /**\n * Creates a leaderboard service. `options.onInvalidEntry` is told about every season or entry\n * row that was skipped as unusable.\n *\n * @example\n * ```ts\n * const leaderboard = new Leaderboard('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {}\n\n /**\n * Every active season, in the backend's order (newest first).\n *\n * @example\n * ```ts\n * const seasons = await gSwap.leaderboard.getSeasons();\n * console.log(seasons.map((season) => season.name));\n * ```\n */\n public async getSeasons(options?: LeaderboardReadOptions): Promise<LeaderboardSeason[]> {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/leaderboard',\n '/seasons',\n undefined,\n signalOption(options),\n );\n return readEntries(\n 'seasons',\n response,\n parseSeason,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n }\n\n /**\n * The season running at `options.now` (default: now; `start` and `end` both count as inside),\n * or `null` between seasons. When seasons overlap, the first in the backend's order.\n *\n * @example\n * ```ts\n * const season = await gSwap.leaderboard.getCurrentSeason();\n * console.log(season === null ? 'no season running' : season.name);\n * ```\n */\n public async getCurrentSeason(options?: CurrentSeasonOptions): Promise<LeaderboardSeason | null> {\n const now = (options?.now ?? new Date()).getTime();\n const seasons = await this.getSeasons(options);\n return (\n seasons.find((season) => season.start.getTime() <= now && now <= season.end.getTime()) ?? null\n );\n }\n\n /**\n * A season's rankings (the backend's top 100 wallets). `seasonId` must be an integer of at\n * least 1 (`INVALID_SEASON_ID` before anything is sent); a season with no rankings, or none at\n * all, is an empty list.\n *\n * @example\n * ```ts\n * const { entries } = await gSwap.leaderboard.getLeaderboard(1);\n * console.log(entries[0]?.wallet, entries[0]?.totalXp);\n * ```\n */\n public async getLeaderboard(\n seasonId: number,\n options?: LeaderboardReadOptions,\n ): Promise<SeasonLeaderboard> {\n if (typeof seasonId !== 'number' || !Number.isSafeInteger(seasonId) || seasonId < 1) {\n throw new GSwapSDKError('INVALID_SEASON_ID', { value: String(seasonId) });\n }\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/leaderboard',\n '',\n { seasonId: String(seasonId) },\n signalOption(options),\n );\n const rows = asEntryRecord(response)?.['leaderboard'];\n if (!Array.isArray(rows)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'leaderboard' },\n { body: response, write: false },\n );\n }\n const entries = readEntries(\n 'leaderboard',\n rows,\n parseEntry,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n return { seasonId, entries };\n }\n\n /**\n * The rankings of the season running at `options.now` (see\n * {@link Leaderboard.getCurrentSeason}), or `null` between seasons.\n *\n * @example\n * ```ts\n * const current = await gSwap.leaderboard.getCurrentLeaderboard();\n * if (current !== null) console.log(current.seasonId, current.entries.length);\n * ```\n */\n public async getCurrentLeaderboard(\n options?: CurrentSeasonOptions,\n ): Promise<SeasonLeaderboard | null> {\n const season = await this.getCurrentSeason(options);\n return season === null ? null : this.getLeaderboard(season.id, options);\n }\n}\n\nfunction signalOption(\n options: LeaderboardReadOptions | undefined,\n): { signal: AbortSignal } | undefined {\n return options?.signal === undefined ? undefined : { signal: options.signal };\n}\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1 ? value : undefined;\n}\n\nfunction isoDate(value: unknown): Date | undefined {\n if (typeof value !== 'string') return undefined;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nfunction parseSeason(entry: unknown): EntryParse<LeaderboardSeason> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const id = positiveInteger(record['id']);\n if (id === undefined) return entryRejected('id is not an integer of at least 1');\n const name = record['name'];\n if (typeof name !== 'string') return entryRejected('name is not a string');\n const start = isoDate(record['start']);\n const end = isoDate(record['end']);\n if (start === undefined || end === undefined) return entryRejected('start or end is not a date');\n if (start.getTime() > end.getTime()) return entryRejected('start is after end');\n const rulesId = record['rules_id'];\n if (typeof rulesId !== 'number' || !Number.isSafeInteger(rulesId) || rulesId < 0) {\n return entryRejected('rules_id is not an integer');\n }\n return entryOk({ id, name, start, end, rulesId });\n}\n\n/** A non-negative decimal, as the backend's DECIMAL columns are serialized (or a finite number). */\nconst DECIMAL = /^\\d+(?:\\.\\d+)?$/u;\n\nfunction decimalOf(value: unknown): string | undefined {\n // A number is accepted only when it prints as a plain decimal (never `1e+21`).\n const text = typeof value === 'number' ? String(value) : value;\n return typeof text === 'string' && DECIMAL.test(text) ? text : undefined;\n}\n\nfunction parseTitle(value: unknown): MasteryTitle | undefined {\n const record = asEntryRecord(value);\n if (record === undefined) return undefined;\n const { name, type, order } = record;\n if (typeof name !== 'string' || typeof type !== 'string') return undefined;\n if (typeof order !== 'number' || !Number.isFinite(order)) return undefined;\n return { name, type, order };\n}\n\nfunction parseEntry(entry: unknown): EntryParse<LeaderboardEntry> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const wallet = record['wallet'];\n if (typeof wallet !== 'string' || wallet === '') return entryRejected('wallet is not a string');\n const rank = positiveInteger(record['rank']);\n if (rank === undefined) return entryRejected('rank is not an integer of at least 1');\n // The backend leaves total_xp out for a ranked wallet it has no XP breakdown for.\n const rawTotal = record['total_xp'];\n const totalXp = rawTotal === undefined || rawTotal === null ? null : decimalOf(rawTotal);\n if (totalXp === undefined) return entryRejected('total_xp is not a decimal');\n const distributionPercent = decimalOf(record['distribution_percent']);\n const liquidityXp = decimalOf(record['liquidity_xp']);\n const tradingXp = decimalOf(record['trading_xp']);\n if (distributionPercent === undefined || liquidityXp === undefined || tradingXp === undefined) {\n return entryRejected('distribution_percent, liquidity_xp or trading_xp is not a decimal');\n }\n const rawTitles = record['mastery_titles'];\n if (!Array.isArray(rawTitles)) return entryRejected('mastery_titles is not a list');\n const masteryTitles: MasteryTitle[] = [];\n for (const raw of rawTitles as unknown[]) {\n const title = parseTitle(raw);\n if (title === undefined) return entryRejected('a mastery title is not { name, type, order }');\n masteryTitles.push(title);\n }\n return entryOk({\n wallet,\n rank,\n totalXp,\n distributionPercent,\n liquidityXp,\n tradingXp,\n masteryTitles,\n });\n}\n","/**\n * The swap backend's market data and trading-competition reads: what `GSwap.market` and\n * `GSwap.leaderboard` return. Values are the backend's, unconverted: USD prices as numbers, times\n * as unix seconds or `Date`s, XP as decimal strings.\n */\n\n/** The windows `GET /market/price-series` serves (the backend refuses any other with a 400). */\nexport const PRICE_SERIES_TIMEFRAMES = ['1D', '1W', '1M', '1Y', 'ALL'] as const;\n\n/** One member of {@link PRICE_SERIES_TIMEFRAMES}. */\nexport type PriceSeriesTimeframe = (typeof PRICE_SERIES_TIMEFRAMES)[number];\n\n/** The most tokens one `GET /market/price` request may name (the backend's limit). */\nexport const MARKET_PRICE_BATCH_LIMIT = 500;\n\n/** One token's market price, as `GET /market/price` answered it. */\nexport interface MarketPrice {\n /** The id the price was asked for: the token string as given, or an object key's `$` form. */\n token: string;\n /** USD price; `null` when the backend knows the token but has no price for it. */\n price: number | null;\n /** 24-hour change in percent (`-2.1` is -2.1 %); `null` when unknown. */\n change24h: number | null;\n /** Whether the token is on the backend's CoinGecko list (what the swap app's \"trending\" uses). */\n listed: boolean;\n}\n\n/** One point of a price series. */\nexport interface PriceSeriesPoint {\n /** Unix time in seconds. */\n time: number;\n /** USD price at `time`. */\n price: number;\n}\n\n/** A token's USD price line, as `GET /market/price-series` answered it. */\nexport interface PriceSeries {\n /** The id the series was asked for: the token string as given, or an object key's `$` form. */\n token: string;\n timeframe: PriceSeriesTimeframe;\n /** In the backend's order (oldest first). Empty for a token the backend has no prices for. */\n prices: PriceSeriesPoint[];\n /** USD price now; `null` when unknown. */\n currentPrice: number | null;\n /** 24-hour change in percent; `null` when unknown. */\n change24h: number | null;\n}\n\n/**\n * Totals across every current-contract pool, as `GET /v2/trade/volume` answered them. USD amounts;\n * a delta is a fraction (`-0.11` is 11 % less than the previous period, `0` when that period had\n * no volume), not a percentage.\n */\nexport interface VolumeSummary {\n tvl: number;\n volume1d: number;\n volume7d: number;\n volume30d: number;\n /** Number of trades in the last 24 hours. */\n trades1d: number;\n volume1dDelta: number;\n volume7dDelta: number;\n volume30dDelta: number;\n}\n\n/** A trading-competition season, as `GET /leaderboard/seasons` answered it. */\nexport interface LeaderboardSeason {\n id: number;\n name: string;\n /** First instant of the season. */\n start: Date;\n /** Last instant of the season (inclusive). */\n end: Date;\n /** The scoring rules the season uses. */\n rulesId: number;\n}\n\n/** An achievement shown on a leaderboard entry. */\nexport interface MasteryTitle {\n name: string;\n /** For example `trade` or `liquidity`; the backend's own word, passed on as it is. */\n type: string;\n /** Display order. */\n order: number;\n}\n\n/** One wallet's row on a season's leaderboard. */\nexport interface LeaderboardEntry {\n wallet: string;\n /** 1 for the top wallet. */\n rank: number;\n /** Decimal string; `null` when the backend has no XP breakdown for the wallet yet. */\n totalXp: string | null;\n /** The wallet's share of the season's XP, in percent, as a decimal string (`'12.34'`). */\n distributionPercent: string;\n liquidityXp: string;\n tradingXp: string;\n masteryTitles: MasteryTitle[];\n}\n\n/** A season's leaderboard (the backend returns at most its top 100 wallets). */\nexport interface SeasonLeaderboard {\n seasonId: number;\n entries: LeaderboardEntry[];\n}\n","import { compositeKeyOf, isTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport {\n MARKET_PRICE_BATCH_LIMIT,\n PRICE_SERIES_TIMEFRAMES,\n type MarketPrice,\n type PriceSeries,\n type PriceSeriesPoint,\n type PriceSeriesTimeframe,\n type VolumeSummary,\n} from '../types/market.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { HttpClient } from './http_client.js';\n\n/**\n * The ids `GET /market/price` and `GET /market/price-series` accept (the backend's own allowlist):\n * a symbol, or a class key in the `$` or `|` form. A comma would split the price request.\n */\nconst MARKET_TOKEN_PATTERN = /^[A-Za-z0-9._$+/:|-]{1,120}$/u;\n\n/** Options of every market read. */\nexport interface MarketReadOptions {\n signal?: AbortSignal | undefined;\n}\n\n/** Options of {@link Market.getPrices} and {@link Market.getPriceSeries}. */\nexport interface MarketListOptions extends MarketReadOptions {\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/**\n * Market data from the swap backend: USD prices (`GET /market/price`), price series\n * (`GET /market/price-series`) and the platform volume totals (`GET /v2/trade/volume`). Public\n * reads: no signer, no wallet.\n *\n * A token is named by a symbol (`GALA`) or a class key (`GALA$Unit$none$none`,\n * `GALA|Unit|none|none` or the object). The backend answers each token under the exact id it was\n * asked for, so the answer is read back under that id: a token the backend has no entry for is\n * `undefined`, never another token's price.\n */\nexport class Market {\n /**\n * Creates a market service. `options.onInvalidEntry` is told about every price or price point\n * that was skipped as unusable.\n *\n * @example\n * ```ts\n * const market = new Market('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {}\n\n /**\n * USD prices of 1 to 500 tokens, in the order asked (a token named twice is asked for once).\n * The ids go in as many requests as their length needs (see {@link MARKET_PRICE_QUERY_BYTES}),\n * one after another; any request failing fails the call. A token the backend did not answer\n * for is `undefined`; one it answered for unusably is `undefined` too, and reported to\n * `onInvalidEntry`. An answer that is not an object is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const [gala, gusdc] = await gSwap.market.getPrices(['GALA$Unit$none$none', 'GUSDC$Unit$none$none']);\n * console.log(gala?.price, gusdc?.price);\n * ```\n */\n public async getPrices(\n tokens: readonly TokenRef[],\n options?: MarketListOptions,\n ): Promise<Array<MarketPrice | undefined>> {\n if (!Array.isArray(tokens) || tokens.length < 1 || tokens.length > MARKET_PRICE_BATCH_LIMIT) {\n throw new GSwapSDKError('INVALID_TOKEN_BATCH', {\n method: 'getPrices',\n count: Array.isArray(tokens) ? tokens.length : 0,\n max: MARKET_PRICE_BATCH_LIMIT,\n });\n }\n const ids = tokens.map(marketTokenOf);\n // One request per batch, one after another (the endpoint allows 60 a minute): each batch's\n // answer is read under the ids that batch asked for, never another batch's.\n const answered = new Map<string, unknown>();\n for (const batch of priceBatches([...new Set(ids)])) {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/market',\n '/price',\n { assetIds: batch.join(',') },\n signalOption(options),\n );\n const answer = asEntryRecord(response);\n if (answer === undefined) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'market prices' },\n { body: response, write: false },\n );\n }\n for (const id of batch) {\n if (Object.hasOwn(answer, id)) answered.set(id, answer[id]);\n }\n }\n const onInvalidEntry = options?.onInvalidEntry ?? this.options.onInvalidEntry;\n return ids.map((id, index) => {\n if (!answered.has(id)) return undefined;\n const entry = answered.get(id);\n const parsed = parseMarketPrice(id, entry);\n if (parsed.ok) return parsed.value;\n try {\n onInvalidEntry?.({ source: 'prices', index, entry, reason: parsed.reason });\n } catch {\n // A diagnostics hook must not turn a lenient read into a failed one.\n }\n return undefined;\n });\n }\n\n /**\n * The USD price of one token, or `undefined` when the backend has no entry for it (see\n * {@link Market.getPrices}).\n *\n * @example\n * ```ts\n * const gala = await gSwap.market.getPrice('GALA$Unit$none$none');\n * if (gala?.price != null) console.log(`GALA: $${gala.price}`);\n * ```\n */\n public async getPrice(\n token: TokenRef,\n options?: MarketListOptions,\n ): Promise<MarketPrice | undefined> {\n const [price] = await this.getPrices([token], options);\n return price;\n }\n\n /**\n * A token's USD price line for one window (1D, 1W, 1M, 1Y or ALL; any other is\n * `INVALID_TIMEFRAME` before anything is sent). The whole series in one answer, oldest first; a\n * token the backend has no prices for is an empty series. An unusable point is skipped and\n * reported to `onInvalidEntry`; an answer that is not a series is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W');\n * console.log(series.prices.length, series.currentPrice);\n * ```\n */\n public async getPriceSeries(\n token: TokenRef,\n timeframe: PriceSeriesTimeframe,\n options?: MarketListOptions,\n ): Promise<PriceSeries> {\n if (!(PRICE_SERIES_TIMEFRAMES as readonly unknown[]).includes(timeframe)) {\n throw new GSwapSDKError('INVALID_TIMEFRAME', {\n value: String(timeframe),\n allowed: PRICE_SERIES_TIMEFRAMES.join(', '),\n });\n }\n const id = marketTokenOf(token);\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/market',\n '/price-series',\n { token: id, timeframe },\n signalOption(options),\n );\n const answer = asEntryRecord(response);\n const currentPrice = answer === undefined ? undefined : nullableFinite(answer['currentPrice']);\n const change24h = answer === undefined ? undefined : nullableFinite(answer['change24h']);\n if (\n answer === undefined ||\n !Array.isArray(answer['prices']) ||\n currentPrice === undefined ||\n change24h === undefined\n ) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'price series' },\n { body: response, write: false },\n );\n }\n const prices = readEntries(\n 'priceSeries',\n answer['prices'],\n parsePricePoint,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n return { token: id, timeframe, prices, currentPrice, change24h };\n }\n\n /**\n * TVL, volume and trade totals across every current-contract pool. Every field must be a finite\n * number, or the answer is `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const volume = await gSwap.market.getVolumeSummary();\n * console.log(`24h: $${volume.volume1d.toFixed(0)} (${(volume.volume1dDelta * 100).toFixed(1)} %)`);\n * ```\n */\n public async getVolumeSummary(options?: MarketReadOptions): Promise<VolumeSummary> {\n const response = await this.httpClient.sendGetRequest<unknown>(\n this.dexBackendBaseUrl,\n '/v2/trade',\n '/volume',\n undefined,\n signalOption(options),\n );\n const summary = parseVolumeSummary(asEntryRecord(asEntryRecord(response)?.['data']));\n if (summary === undefined) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'volume summary' },\n { body: response, write: false },\n );\n }\n return summary;\n }\n}\n\n/**\n * The most query bytes one `GET /market/price` carries. The backend refuses a request line over\n * 16 KB (Node's default header limit: 300 launchpad keys, 17.7 KB encoded, answer HTTP 431,\n * recorded on prod 2026-10-13), so a long list is split well under it (about 135 launchpad keys\n * per request, 270 short ones).\n */\nexport const MARKET_PRICE_QUERY_BYTES = 8_000;\n\n/**\n * The ids in request-sized batches: at most {@link MARKET_PRICE_BATCH_LIMIT} ids and\n * {@link MARKET_PRICE_QUERY_BYTES} of encoded `assetIds` each (the standard encoding's size, the\n * larger of the two, with a `%2C` per id).\n */\nexport function priceBatches(ids: readonly string[]): string[][] {\n const batches: string[][] = [];\n let batch: string[] = [];\n let bytes = 0;\n for (const id of ids) {\n const size = encodeURIComponent(id).length + 3;\n if (\n batch.length > 0 &&\n (bytes + size > MARKET_PRICE_QUERY_BYTES || batch.length === MARKET_PRICE_BATCH_LIMIT)\n ) {\n batches.push(batch);\n batch = [];\n bytes = 0;\n }\n batch.push(id);\n bytes += size;\n }\n if (batch.length > 0) batches.push(batch);\n return batches;\n}\n\n/**\n * The id a market read sends for a token: a string as given (a symbol or a class key in either\n * form), an object key in its `$` form. Anything the backend's allowlist refuses is refused here.\n */\nfunction marketTokenOf(token: TokenRef): string {\n if (typeof token !== 'string') {\n if (!isTokenClassKey(token)) {\n throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', {\n tokenClassKey: describeValue(token),\n });\n }\n return checkedMarketToken(compositeKeyOf(token));\n }\n return checkedMarketToken(token);\n}\n\nfunction checkedMarketToken(id: string): string {\n if (!MARKET_TOKEN_PATTERN.test(id)) {\n throw new GSwapSDKError('INVALID_MARKET_TOKEN', { token: id });\n }\n return id;\n}\n\nfunction describeValue(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction signalOption(options: MarketReadOptions | undefined): { signal: AbortSignal } | undefined {\n return options?.signal === undefined ? undefined : { signal: options.signal };\n}\n\n/** A finite number, `null` for `null`, `undefined` for anything else (an unusable value). */\nfunction nullableFinite(value: unknown): number | null | undefined {\n if (value === null) return null;\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction parseMarketPrice(token: string, entry: unknown): EntryParse<MarketPrice> {\n const record = asEntryRecord(entry);\n if (record === undefined) return entryRejected('not an object');\n const price = nullableFinite(record['price']);\n if (price === undefined || (price !== null && price < 0)) {\n return entryRejected('price is not a non-negative number or null');\n }\n const change24h = nullableFinite(record['change24h']);\n if (change24h === undefined) return entryRejected('change24h is not a number or null');\n const listed = record['listed'];\n if (typeof listed !== 'boolean') return entryRejected('listed is not a boolean');\n return entryOk({ token, price, change24h, listed });\n}\n\nfunction parsePricePoint(entry: unknown): EntryParse<PriceSeriesPoint> {\n const record = asEntryRecord(entry);\n const time = finite(record?.['time']);\n const price = finite(record?.['price']);\n if (time === undefined || !Number.isInteger(time) || time < 0) {\n return entryRejected('time is not unix seconds');\n }\n if (price === undefined || price < 0) return entryRejected('price is not a non-negative number');\n return entryOk({ time, price });\n}\n\nconst VOLUME_FIELDS = [\n 'tvl',\n 'volume1d',\n 'volume7d',\n 'volume30d',\n 'trades1d',\n 'volume1dDelta',\n 'volume7dDelta',\n 'volume30dDelta',\n] as const satisfies ReadonlyArray<keyof VolumeSummary>;\n\nfunction parseVolumeSummary(data: Record<string, unknown> | undefined): VolumeSummary | undefined {\n if (data === undefined) return undefined;\n const summary: Partial<Record<keyof VolumeSummary, number>> = {};\n for (const field of VOLUME_FIELDS) {\n const value = finite(data[field]);\n if (value === undefined) return undefined;\n summary[field] = value;\n }\n const trades = summary.trades1d;\n if (trades === undefined || !Number.isInteger(trades) || trades < 0) return undefined;\n return summary as VolumeSummary;\n}\n","import type { HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { asEntryRecord } from '../utils/lenient.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\n\n/** What the Onramper widget does. */\nexport const ONRAMPER_MODES = ['buy', 'sell', 'swap'] as const;\n\n/** One of {@link ONRAMPER_MODES}. */\nexport type OnramperMode = (typeof ONRAMPER_MODES)[number];\n\n/**\n * The request of {@link Onramper.generateWidgetUrl}: the fields of the swap backend's\n * `GenerateWidgetUrlDto`, no others (the backend refuses a field it does not know). A field left\n * out is the backend's default (`mode` `buy`, `defaultFiat` `USD`, `defaultAmount` 100,\n * `sellDefaultAmount` 1, `onlyCryptoNetworks` `gala`, `defaultPaymentMethod` `creditcard`,\n * `networkPrefix` `gala_gala`).\n */\nexport interface OnramperWidgetRequest {\n /** The wallet that receives the crypto, sent as given (the backend accepts `0x…` or `eth|…` Ethereum addresses and `client|…` aliases, and canonicalizes them). */\n walletAddress: string;\n mode?: OnramperMode | undefined;\n defaultFiat?: string | undefined;\n /** The fiat amount the widget opens with (the backend accepts 15 to 15 000, at most 2 decimals). */\n defaultAmount?: number | undefined;\n /** The crypto amount a sell opens with (0.000001 to 1 000 000, at most 18 decimals). */\n sellDefaultAmount?: number | undefined;\n onlyCryptoNetworks?: string | undefined;\n defaultPaymentMethod?: string | undefined;\n defaultCrypto?: string | undefined;\n onlyPaymentMethods?: string | undefined;\n excludePaymentMethods?: string | undefined;\n onlyFiat?: string | undefined;\n excludeFiat?: string | undefined;\n isAddressEditable?: string | undefined;\n networkPrefix?: string | undefined;\n}\n\n/** The request fields that are text, besides `walletAddress` and `mode`. */\nconst TEXT_FIELDS = [\n 'defaultFiat',\n 'onlyCryptoNetworks',\n 'defaultPaymentMethod',\n 'defaultCrypto',\n 'onlyPaymentMethods',\n 'excludePaymentMethods',\n 'onlyFiat',\n 'excludeFiat',\n 'isAddressEditable',\n 'networkPrefix',\n] as const;\n\n/** The request fields that are amounts. */\nconst AMOUNT_FIELDS = ['defaultAmount', 'sellDefaultAmount'] as const;\n\nconst METHOD = 'onramper.generateWidgetUrl';\n\nfunction invalidField(field: string, expected: string): GSwapSDKError {\n return new GSwapSDKError('INVALID_DTO', { method: METHOD, field, expected });\n}\n\n/**\n * The body to send: the fields the caller gave, checked. A field left out (or `undefined`) is not\n * sent, so the backend's default applies. An amount that is not a finite number is refused here:\n * `JSON.stringify` would turn `NaN` into `null`, which the backend reads as \"not given\" and\n * silently replaces with its default amount.\n */\nfunction widgetBody(request: OnramperWidgetRequest): Record<string, string | number> {\n if (typeof request !== 'object' || request === null) {\n throw invalidField('request', 'an object');\n }\n if (typeof request.walletAddress !== 'string' || request.walletAddress.trim() === '') {\n throw invalidField('walletAddress', 'a non-empty string');\n }\n const body: Record<string, string | number> = { walletAddress: request.walletAddress };\n if (request.mode !== undefined) {\n if (!(ONRAMPER_MODES as readonly unknown[]).includes(request.mode)) {\n throw invalidField('mode', ONRAMPER_MODES.join(', '));\n }\n body['mode'] = request.mode;\n }\n for (const field of TEXT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'string') throw invalidField(field, 'a string');\n body[field] = value;\n }\n for (const field of AMOUNT_FIELDS) {\n const value: unknown = request[field];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw invalidField(field, 'a finite number, 0 or more');\n }\n body[field] = value;\n }\n return body;\n}\n\n/** The widget URL of the backend's `{ status, error, message, data: { url } }` answer. */\nfunction widgetUrlOf(response: unknown): string {\n const data = asEntryRecord(asEntryRecord(response)?.['data']);\n const url = data?.['url'];\n if (typeof url === 'string' && url !== '') {\n try {\n // Only to know it is an absolute URL; the backend's text is returned as it is.\n void new URL(url);\n return url;\n } catch {\n // Falls through to the invalid-answer error below.\n }\n }\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'onramper widget url' },\n { body: response, write: false },\n );\n}\n\n/**\n * The swap backend's Onramper (fiat on-ramp) widget URL. The route is PUBLIC: the request carries\n * no `Authorization` header and no signature, whatever session the app has, so no token can leak to\n * it. The backend signs the wallet into the URL; the app adds its own look (theme query parameters)\n * to the returned URL.\n */\nexport class Onramper {\n /**\n * Creates the service. To get one without building a whole {@link GSwap} client, use\n * {@link createOnramper}.\n *\n * @example\n * ```ts\n * const onramper = new Onramper('https://dex-backend-prod1.defi.gala.com', httpClient);\n * ```\n */\n constructor(\n private readonly dexBackendBaseUrl: string,\n private readonly httpClient: HttpClient,\n ) {}\n\n /**\n * Asks the backend for a signed Onramper widget URL for `request.walletAddress`.\n *\n * @returns The widget URL.\n * @throws GSwapSDKError `INVALID_DTO` (before anything is sent: no wallet address, an unknown\n * `mode`, a text field that is not text, an amount that is not a finite number of 0 or more),\n * `HTTP_ERROR` (the backend refused: `serverMessage` is its message, e.g. \"Failed to generate\n * widget URL. Check server configuration.\" for a 500, its validation message for a 400, the\n * throttle for a 429), `REQUEST_FAILED` (no answer), `INVALID_CHAIN_RESPONSE` (an answer without\n * a usable `data.url`).\n *\n * @example\n * ```ts\n * const url = await gSwap.onramper.generateWidgetUrl({\n * walletAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\n * defaultCrypto: 'gala',\n * onlyCryptoNetworks: 'gala',\n * mode: 'buy',\n * });\n * window.open(url);\n * ```\n */\n public async generateWidgetUrl(request: OnramperWidgetRequest): Promise<string> {\n const body = widgetBody(request);\n const response = await this.httpClient.sendPostRequest<unknown>(\n this.dexBackendBaseUrl,\n '/api/v1/onramper',\n '/generate-widget-url',\n body,\n );\n return widgetUrlOf(response);\n }\n}\n\n/** Options of {@link createOnramper}. */\nexport interface OnramperOptions {\n /** The swap backend's base URL (no trailing slash needed). */\n dexBackendBaseUrl: string;\n /** Your own HTTP requestor instead of `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000). */\n timeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the requests. */\n wire?: WireOptions | undefined;\n}\n\n/**\n * An {@link Onramper} for a swap backend, without building a {@link GSwap} client (no signer, no\n * wallet, no pool or stream services): the call for an app that only needs the widget URL.\n *\n * @example\n * ```ts\n * import { createOnramper } from '@gala-chain/gswap-sdk';\n *\n * const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' });\n * const url = await onramper.generateWidgetUrl({ walletAddress, mode: 'buy' });\n * ```\n */\nexport function createOnramper(options: OnramperOptions): Onramper {\n return new Onramper(\n options.dexBackendBaseUrl.replace(/\\/$/u, ''),\n new HttpClient(options.httpRequestor, options.timeoutMs, options.wire),\n );\n}\n","import { splitClassKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** A symbol or a GalaChain token class key accepted by v2 operations. */\nexport type TokenRef = string | GalaChainTokenClassKey;\n\n/** Return two trading symbols in the contract's plain-string order. */\nexport function orderSymbols(a: string, b: string): [string, string] {\n return a < b ? [a, b] : [b, a];\n}\n\n/** Read an ordered symbol pair from a tuple or object returned by a boundary helper.\n *\n * @example\n * ```ts\n * const pair = readOrderedSymbols(['GALA', 'GUSDC']);\n * console.log(pair.token0);\n * ```\n */\nexport function readOrderedSymbols(value: unknown): { token0: string; token1: string } {\n if (Array.isArray(value) && value.length >= 2) {\n const token0 = (value as unknown[])[0];\n const token1 = (value as unknown[])[1];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n if (typeof value === 'object' && value !== null) {\n const record = value as Record<string, unknown>;\n const token0 = record['token0'];\n const token1 = record['token1'];\n if (typeof token0 === 'string' && typeof token1 === 'string') return { token0, token1 };\n }\n throw new GSwapSDKError('UNORDERABLE_SYMBOLS', {\n received: Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value,\n });\n}\n\n/**\n * Parse a pipe- or dollar-separated token class key.\n *\n * The LAST three segments are always `category`, `type` and `additionalKey`; everything before\n * them is the `collection`. Parsing from the right is required because real collections contain\n * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`\n * shifts every field. Nothing here says anything about the token's symbol: a class key carries\n * no symbol, which must come from the token class or trading-symbol registry.\n *\n * @example\n * ```ts\n * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'\n * ```\n */\nexport function parseTokenClassKey(tokenClassKey: TokenRef): GalaChainTokenClassKey {\n if (typeof tokenClassKey === 'object') {\n return {\n collection: tokenClassKey.collection,\n category: tokenClassKey.category,\n type: tokenClassKey.type,\n additionalKey: tokenClassKey.additionalKey,\n };\n }\n\n const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes('|') ? '|' : '$');\n if (parsed === undefined) throw new GSwapSDKError('INVALID_TOKEN_CLASS_KEY', { tokenClassKey });\n return parsed;\n}\n","import { isGalaError } from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry\n * through the app's HTTP stack) on the \"nothing was sent\" boundary, like core's `signPreSend` does\n * for the signer. A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED` (`token` names\n * what was being resolved, the original is `cause`); an SDK error of any product (every one is a\n * `GalaSDKError`, core's transport errors included) passes through.\n *\n * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.\n */\nexport async function resolvePreSend<T>(token: string, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (cause: unknown) {\n throw isGalaError(cause)\n ? cause\n : new GSwapSDKError('TOKEN_RESOLUTION_FAILED', { token }, { cause });\n }\n}\n","import {\n compositeKeyOf,\n type GalaChainTokenClassKey,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { TradingSymbol } from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { orderSymbols, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport { isProposableTradingSymbol } from '../utils/validation.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport type { ChainGateway } from './gateway.js';\nimport { HttpClient } from './http_client.js';\n\nconst SYMBOL_CACHE_TTL_MS = 60_000;\n\n/** Symbol registry client for the current GalaChainDex contract. */\nexport class Symbols {\n private cachedSymbols: TradingSymbol[] | undefined;\n private cachedAt = 0;\n private refreshInFlight: Promise<TradingSymbol[]> | undefined;\n\n private readonly http: HttpClient;\n\n /**\n * Create a symbol service backed by the swap backend. `onInvalidEntry` is told about every\n * registry row that was skipped as unusable (see {@link InvalidEntryHandler}).\n */\n constructor(\n private readonly gateway: Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n },\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs, gateway.wire);\n }\n\n /**\n * List all registered GalaChainDex trading symbols, cached for 60 seconds. A registry row that\n * is not a usable symbol is skipped (and reported to `onInvalidEntry`) instead of failing the\n * whole list.\n */\n public async list(): Promise<TradingSymbol[]> {\n if (this.cachedSymbols !== undefined && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) {\n return this.cachedSymbols;\n }\n if (this.refreshInFlight !== undefined) return this.refreshInFlight;\n this.refreshInFlight = this.http\n .sendGetRequest<{ data: unknown }>(this.gateway.dexBackendBaseUrl, '/v2/trade', '/symbols')\n .then((response) =>\n readEntries('symbols', response.data, parseTradingSymbol, this.options.onInvalidEntry),\n )\n .then((symbols) => {\n this.cachedSymbols = symbols;\n this.cachedAt = Date.now();\n return symbols;\n })\n .finally(() => {\n this.refreshInFlight = undefined;\n });\n return this.refreshInFlight;\n }\n\n /** Invalidate the cached symbol registry after a write changes registration state.\n *\n * @example\n * ```ts\n * gSwap.symbols.invalidate();\n * ```\n */\n public invalidate(): void {\n this.cachedSymbols = undefined;\n this.cachedAt = 0;\n }\n\n /** Force one registry refresh, bypassing the cache.\n *\n * @example\n * ```ts\n * const symbols = await gSwap.symbols.refresh();\n * ```\n */\n public async refresh(): Promise<TradingSymbol[]> {\n this.invalidate();\n // list() would otherwise return an ALREADY in-flight refresh that started before this\n // call (built from pre-invalidation state) — bypassing it too is what makes this\n // actually force a fresh fetch, not just satisfy the cache-freshness check.\n this.refreshInFlight = undefined;\n return this.list();\n }\n\n /** Resolve a symbol or token class key to its registered symbol metadata. */\n public async resolve(ref: TokenRef): Promise<TradingSymbol> {\n let symbols = await this.list();\n const composite =\n typeof ref === 'string'\n ? isCompositeKey(ref)\n ? compositeKeyOf(parseTokenClassKey(ref))\n : undefined\n : compositeKeyOf(ref);\n const resolved = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (resolved === undefined) {\n symbols = await this.refresh();\n const refreshed = symbols.find(\n (entry) =>\n entry.symbol === ref || (composite !== undefined && compositeKeyOf(entry) === composite),\n );\n if (refreshed === undefined) throw GSwapSDKError.unknownTokenError(ref);\n return refreshed;\n }\n return resolved;\n }\n\n /**\n * The trading symbol to put in a token's first CreatePool.\n *\n * 1. The symbol ALREADY registered for exactly this class key, if any: proposing another one\n * fails the gateway's registry-conflict check.\n * 2. Otherwise `displaySymbol` (the token's curated symbol), when it is proposable\n * ({@link isProposableTradingSymbol}).\n * 3. Otherwise a `NO_VALID_TRADING_SYMBOL` error: a symbol is never derived from the key (BNB's collection is\n * `GBNB`, a launchpad token's is the reserved word `Token`).\n *\n * `registryFailure: 'ignore'` treats an unreachable registry as an empty one and falls through\n * to step 2 (the gateway still rejects a conflicting symbol); the default `'throw'` propagates\n * the failure.\n *\n * @example\n * ```ts\n * const symbol = await gSwap.symbols.proposeSymbol(\n * { collection: 'GALA_TEST1', category: 'Unit', type: 'none', additionalKey: 'none' },\n * 'GALATEST',\n * );\n * ```\n */\n public async proposeSymbol(\n classKey: GalaChainTokenClassKey,\n displaySymbol: string,\n options: { registryFailure?: 'throw' | 'ignore' | undefined } = {},\n ): Promise<string> {\n let registry: TradingSymbol[] = [];\n try {\n registry = await this.list();\n } catch (error: unknown) {\n if (options.registryFailure !== 'ignore') throw error;\n }\n const wanted = compositeKeyOf(classKey);\n const registered = registry.find(\n (entry) =>\n entry.collection === classKey.collection &&\n entry.category === classKey.category &&\n entry.type === classKey.type &&\n entry.additionalKey === classKey.additionalKey,\n );\n if (registered !== undefined) return registered.symbol;\n if (isProposableTradingSymbol(displaySymbol)) return displaySymbol;\n throw new GSwapSDKError('NO_VALID_TRADING_SYMBOL', { classKey: wanted, displaySymbol });\n }\n\n /** Resolve and put two token references in canonical trading-symbol order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{\n token0: TradingSymbol;\n token1: TradingSymbol;\n flipped: boolean;\n }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n return {\n token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,\n token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,\n flipped: token0Symbol !== resolvedA.symbol,\n };\n }\n}\n\n/** Reads one registry row: all four class-key parts, a symbol and non-negative integer decimals. */\nfunction parseTradingSymbol(value: unknown): EntryParse<TradingSymbol> {\n const entry = asEntryRecord(value);\n if (entry === undefined) return entryRejected('the row is not an object');\n const { symbol, collection, category, type, additionalKey, decimals } = entry;\n if (typeof symbol !== 'string') return entryRejected('symbol is not a string');\n if (symbol.length === 0) return entryRejected('symbol is empty');\n if (typeof collection !== 'string') return entryRejected('collection is not a string');\n if (typeof category !== 'string') return entryRejected('category is not a string');\n if (typeof type !== 'string') return entryRejected('type is not a string');\n if (typeof additionalKey !== 'string') return entryRejected('additionalKey is not a string');\n if (typeof decimals !== 'number' || !Number.isInteger(decimals) || decimals < 0) {\n return entryRejected('decimals is not a non-negative integer');\n }\n return entryOk({ symbol, collection, category, type, additionalKey, decimals });\n}\n\nfunction isCompositeKey(ref: string): boolean {\n return ref.includes('|') || ref.includes('$');\n}\n\n/**\n * What the services need from a token resolver: how a token reference becomes a trading symbol,\n * and whether requests carry the caller's references untouched. {@link Symbols} is the registry\n * resolver (one `GET /v2/trade/symbols`, cached); {@link CanonicalSymbols} is the offline one.\n */\nexport interface TokenResolver {\n resolve(ref: TokenRef): Promise<TradingSymbol>;\n /**\n * True when reads send the caller's token references verbatim (a symbol, or a composite key as\n * the caller wrote it) and let the backend resolve and orient the pair — no registry request\n * and no client-side ordering or tick flip.\n */\n readonly passthrough?: boolean | undefined;\n}\n\n/** A token reference as the caller wrote it: a string verbatim, a class key as its `$` composite. */\nexport function rawTokenOf(ref: TokenRef): string {\n return typeof ref === 'string' ? ref : compositeKeyOf(ref);\n}\n\n/** The trading symbol of a reference, or `SYMBOL_NOT_FOUND` when the resolver has none. */\nexport async function tradingSymbolOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n const resolved = await resolvePreSend(rawTokenOf(ref), () => resolver.resolve(ref));\n if (resolved.symbol.length > 0) return resolved.symbol;\n throw new GSwapSDKError('SYMBOL_NOT_FOUND', { token: rawTokenOf(ref) });\n}\n\n/** What a read request names a token by: the reference itself in pass-through mode, else its symbol. */\nexport async function queryTokenOf(resolver: TokenResolver, ref: TokenRef): Promise<string> {\n return resolver.passthrough === true ? rawTokenOf(ref) : tradingSymbolOf(resolver, ref);\n}\n\n/**\n * The offline resolver for apps that already hold the backend's canonical trading symbols (from\n * `/quote`, `/add-liq-estimate`, a position row) and must not make a registry request of their own.\n *\n * - `resolve` accepts a bare trading symbol and returns it as is; a class key (object, `$` or `|`\n * form) is not a symbol and is refused as `UNKNOWN_TOKEN`. `createPool` relies on that refusal to\n * fall back to the symbols its caller supplies.\n * - `orderPair` orders two symbols by plain string comparison, as the contract does.\n * - Reads are pass-through (see {@link TokenResolver.passthrough}): the caller's references go on\n * the wire verbatim, composite keys included, and the backend orients the pair.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, new CanonicalSymbols(), signer, walletAddress);\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '10' });\n * ```\n */\nexport class CanonicalSymbols implements TokenResolver {\n public readonly passthrough = true;\n\n /** Resolve a bare trading symbol to itself. */\n public resolve(ref: TokenRef): Promise<TradingSymbol> {\n if (typeof ref === 'string' && !isCompositeKey(ref)) {\n return Promise.resolve({\n symbol: ref,\n collection: '',\n category: '',\n type: '',\n additionalKey: '',\n decimals: 0,\n });\n }\n return Promise.reject(GSwapSDKError.unknownTokenError(ref));\n }\n\n /** Put two symbols in canonical (string) order. */\n public async orderPair(\n a: TokenRef,\n b: TokenRef,\n ): Promise<{ token0: TradingSymbol; token1: TradingSymbol; flipped: boolean }> {\n const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);\n const [first] = orderSymbols(resolvedA.symbol, resolvedB.symbol);\n const flipped = first !== resolvedA.symbol;\n return {\n token0: flipped ? resolvedB : resolvedA,\n token1: flipped ? resolvedA : resolvedB,\n flipped,\n };\n }\n\n /** There is no registry state to drop. */\n public invalidate(): void {\n // Nothing is cached: every answer is derived from the reference itself.\n }\n}\n","import type { FEE_TIER } from '../types/fees.js';\nimport type { CompositePool, PoolInfo, PoolListInfo, Slot0 } from '../types/v2_results.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n finiteNumberOf,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { orderSymbols, readOrderedSymbols, type TokenRef } from '../utils/ordering.js';\nimport type { ChainGateway } from './gateway.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, rawTokenOf, tradingSymbolOf, type TokenResolver } from './symbols.js';\nimport { validateFee } from '../utils/validation.js';\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\ntype PoolGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** The sort keys of `GET /v2/trade/pools`. */\nexport type PoolSortBy = 'tvl' | 'volume1d' | 'volume30d';\n\n/** Options of {@link Pools.getPools}. Omit all of `search`, `sortBy`, `sortOrder`, `page`, `limit` for the full, unsorted list. */\nexport interface PoolListOptions {\n signal?: AbortSignal | undefined;\n /** Case-insensitive match on the pair's symbols; `A/B` or `A B` matches either order. At most 64 characters. */\n search?: string | undefined;\n sortBy?: PoolSortBy | undefined;\n sortOrder?: 'asc' | 'desc' | undefined;\n /** 1-based page number; only meaningful together with `limit`. */\n page?: number | undefined;\n /** Rows per page, 1-1000; omitted returns every row. */\n limit?: number | undefined;\n /** Overrides the service-level handler for this call. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** Options of {@link Pools.watchNewPools}. */\nexport interface WatchNewPoolsOptions {\n /** Milliseconds between polls (default 30 000; a finite number of at least 1). */\n intervalMs?: number | undefined;\n /** Report only a pool whose `tvlUsd` is at least this (a pool without `tvlUsd` counts as 0). */\n minTvl?: number | undefined;\n /** Report only a pool with one of these symbols as `token0` or `token1`. */\n tokens?: readonly string[] | undefined;\n /** Told about a poll that failed and about an `onPool` that threw; polling goes on either way. */\n onError?: ((error: unknown) => void) | undefined;\n}\n\n/** Read-only pool and current-price access for the current GalaChainDex contract. */\nexport class Pools {\n /**\n * Creates a pool service. `options.onInvalidEntry` is told about every pool row that was\n * skipped as unusable (see {@link InvalidEntryHandler}).\n *\n * @example\n * ```ts\n * const pools = new Pools(gateway, symbols);\n * ```\n */\n constructor(\n private readonly gateway: PoolGateway,\n private readonly symbols: TokenResolver,\n private readonly options: { onInvalidEntry?: InvalidEntryHandler | undefined } = {},\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Fetches current-contract pools from the swap backend, optionally searched, sorted and paged\n * by the backend. A row that is not a usable pool is skipped and reported to `onInvalidEntry`\n * instead of failing the whole list; an answer that is not a list at all is\n * `INVALID_CHAIN_RESPONSE`.\n *\n * @example\n * ```ts\n * const top = await service.getPools({ sortBy: 'tvl', sortOrder: 'desc', page: 1, limit: 8 });\n * console.log(top.length);\n * ```\n */\n public async getPools(options?: PoolListOptions): Promise<PoolListInfo[]> {\n const response = await this.http.sendGetRequest<BackendEnvelope<unknown>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/pools',\n poolListParams(options),\n options?.signal === undefined ? undefined : { signal: options.signal },\n );\n return readEntries(\n 'pools',\n response.data,\n parsePoolListInfo,\n options?.onInvalidEntry ?? this.options.onInvalidEntry,\n );\n }\n\n /**\n * Watches for pools created from now on, by polling {@link Pools.getPools} every `intervalMs`\n * (the polling alternative to the realtime stream's `GSwap.stream.subscribePoolCreated`, for a\n * client that cannot hold a WebSocket open). The first answer is the baseline: a pool that\n * existed then is never reported. Each later pool is judged once, when it first appears, against\n * `minTvl` and `tokens`. A poll never overlaps the previous one (a tick that finds one still in\n * flight is skipped), and nothing is reported after the returned function stops the watcher.\n *\n * @example\n * ```ts\n * const stop = gSwap.pools.watchNewPools((pool) => console.log('new pool', pool.poolRef), {\n * intervalMs: 60_000,\n * tokens: ['GALA'],\n * });\n * // later\n * stop();\n * ```\n */\n public watchNewPools(\n onPool: (pool: PoolListInfo) => void,\n options: WatchNewPoolsOptions = {},\n ): () => void {\n const intervalMs = options.intervalMs ?? 30_000;\n if (typeof intervalMs !== 'number' || !Number.isFinite(intervalMs) || intervalMs < 1) {\n throw new GSwapSDKError('INVALID_POLL_INTERVAL', { value: String(intervalMs) });\n }\n let known: Set<string> | undefined;\n let stopped = false;\n let polling = false;\n const report = (error: unknown): void => {\n try {\n options.onError?.(error);\n } catch {\n // A diagnostics hook must not stop the watcher.\n }\n };\n const wanted = (pool: PoolListInfo): boolean =>\n (options.minTvl === undefined || (pool.tvlUsd ?? 0) >= options.minTvl) &&\n (options.tokens === undefined ||\n options.tokens.includes(pool.token0) ||\n options.tokens.includes(pool.token1));\n const poll = async (): Promise<void> => {\n if (stopped || polling) return;\n polling = true;\n try {\n const pools = await this.getPools();\n if (known === undefined) {\n known = new Set(pools.map((pool) => pool.poolRef));\n return;\n }\n for (const pool of pools) {\n if (stopped) return;\n if (known.has(pool.poolRef)) continue;\n known.add(pool.poolRef);\n if (!wanted(pool)) continue;\n try {\n onPool(pool);\n } catch (error: unknown) {\n report(error);\n }\n }\n } catch (error: unknown) {\n if (!stopped) report(error);\n } finally {\n polling = false;\n }\n };\n void poll();\n const timer = setInterval(() => void poll(), intervalMs);\n return () => {\n stopped = true;\n clearInterval(timer);\n };\n }\n\n /**\n * Fetches one pool from the backend, preserving whether the request order was flipped.\n *\n * @example\n * ```ts\n * const pool = await service.getPool('GUSDC', 'GALA', 3000);\n * console.log(pool.flippedFromRequest);\n * ```\n */\n public async getPool(token0: TokenRef, token1: TokenRef, fee: FEE_TIER): Promise<PoolInfo> {\n validateFee(fee);\n return this.getBackend<PoolInfo>('/pool', await this.backendParams(token0, token1, fee));\n }\n\n /**\n * Fetches the current sqrt price, price, and tick for one pool.\n *\n * @example\n * ```ts\n * const slot0 = await service.getSlot0('GALA', 'GUSDC', 3000);\n * console.log(slot0.tick);\n * ```\n */\n public async getSlot0(token0: TokenRef, token1: TokenRef, fee: FEE_TIER): Promise<Slot0> {\n validateFee(fee);\n return this.getBackend<Slot0>('/slot0', await this.backendParams(token0, token1, fee));\n }\n\n /**\n * Fetches the complete chain composite pool snapshot, in canonical symbol order.\n *\n * @example\n * ```ts\n * const composite = await service.getCompositePool('GALA', 'GUSDC', 3000);\n * console.log(composite.positions?.length ?? 0);\n * ```\n */\n public async getCompositePool(\n token0: TokenRef,\n token1: TokenRef,\n fee: FEE_TIER,\n ): Promise<CompositePool> {\n validateFee(fee);\n if (this.symbols.passthrough === true) {\n return this.getBackend<CompositePool>('/composite-pool', {\n token0: rawTokenOf(token0),\n token1: rawTokenOf(token1),\n fee: String(fee),\n });\n }\n const first = await tradingSymbolOf(this.symbols, token0);\n const second = await tradingSymbolOf(this.symbols, token1);\n const ordered = readOrderedSymbols(orderSymbols(first, second));\n return this.getBackend<CompositePool>('/composite-pool', {\n token0: ordered.token0,\n token1: ordered.token1,\n fee: String(fee),\n });\n }\n\n private async backendParams(\n token0: TokenRef,\n token1: TokenRef,\n fee: FEE_TIER,\n ): Promise<Record<string, string>> {\n return {\n token0: await queryTokenOf(this.symbols, token0),\n token1: await queryTokenOf(this.symbols, token1),\n fee: String(fee),\n };\n }\n\n private async getBackend<T>(endpoint: string, params: Record<string, string>): Promise<T> {\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<T>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n );\n return response.data;\n } catch (error: unknown) {\n // Any SDK error passes through, core's transport errors (`REQUEST_TIMEOUT`,\n // `TRANSPORT_ERROR`, a plain `GalaSDKError`) included: only a foreign failure is wrapped.\n if (isGSwapError(error)) throw error;\n throw new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'pool' },\n { cause: error, write: false },\n );\n }\n }\n}\n\nconst SORT_KEYS: readonly string[] = ['tvl', 'volume1d', 'volume30d'];\nconst MAX_SEARCH_LENGTH = 64;\nconst MAX_PAGE_SIZE = 1000;\n\n/** The pool-list query, in the order the apps write it: search, sortBy, sortOrder, page, limit. */\nfunction poolListParams(options: PoolListOptions | undefined): Record<string, string> | undefined {\n if (options === undefined) return undefined;\n const params: Record<string, string> = {};\n if (options.search !== undefined) {\n if (options.search.length > MAX_SEARCH_LENGTH) {\n throw new GSwapSDKError('SEARCH_TOO_LONG', {\n length: options.search.length,\n maxLength: MAX_SEARCH_LENGTH,\n });\n }\n params['search'] = options.search;\n }\n if (options.sortBy !== undefined) {\n if (!SORT_KEYS.includes(options.sortBy)) {\n throw new GSwapSDKError('INVALID_SORT_BY', {\n value: String(options.sortBy),\n allowed: SORT_KEYS.join(','),\n });\n }\n params['sortBy'] = options.sortBy;\n }\n if (options.sortOrder !== undefined) {\n if (options.sortOrder !== 'asc' && options.sortOrder !== 'desc') {\n throw new GSwapSDKError('INVALID_SORT_ORDER', { value: String(options.sortOrder) });\n }\n params['sortOrder'] = options.sortOrder;\n }\n if (options.page !== undefined) {\n if (!Number.isInteger(options.page) || options.page < 1) {\n throw new GSwapSDKError('INVALID_PAGE', { value: options.page });\n }\n params['page'] = String(options.page);\n }\n if (options.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > MAX_PAGE_SIZE) {\n throw new GSwapSDKError('INVALID_LIMIT', {\n value: options.limit,\n min: 1,\n max: MAX_PAGE_SIZE,\n });\n }\n params['limit'] = String(options.limit);\n }\n return Object.keys(params).length === 0 ? undefined : params;\n}\n\nconst OPTIONAL_POOL_STRINGS = [\n 'poolName',\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'creator',\n 'price',\n 'sqrtPrice',\n 'token0Tvl',\n 'token1Tvl',\n] as const;\n\nconst OPTIONAL_POOL_NUMBERS = [\n 'tickSpacing',\n 'protocolFees',\n 'tradingFees',\n 'tick',\n 'volume1d',\n 'volume7d',\n 'volume30d',\n 'trades1d',\n 'fee24h',\n 'token0Price',\n 'token1Price',\n] as const;\n\n/** Fields the apps accept as a number or a numeric string (the wallet does `Number(row.x)`). */\nconst NUMERIC_POOL_FIELDS = ['fee', 'tvlUsd', 'apr1d'] as const;\n\n/**\n * Reads one pool-list row the way the apps do: the identity (`token0`, `token1`, `poolRef`) and\n * `fee` must be usable, every other field is optional but, when present, must have its type.\n * `fee`, `tvlUsd` and `apr1d` may arrive as numeric strings and are returned as numbers. Fields\n * the SDK does not know are kept.\n */\nfunction parsePoolListInfo(entry: unknown): EntryParse<PoolListInfo> {\n const row = asEntryRecord(entry);\n if (row === undefined) return entryRejected('the row is not an object');\n for (const key of ['token0', 'token1', 'poolRef'] as const) {\n if (typeof row[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n if (row['contractVersion'] !== undefined && row['contractVersion'] !== 'v2') {\n return entryRejected('contractVersion is not v2');\n }\n const normalized: Record<string, unknown> = { ...row };\n for (const key of NUMERIC_POOL_FIELDS) {\n const raw = row[key];\n if (raw === undefined && key !== 'fee') continue;\n const value = finiteNumberOf(raw);\n if (value === undefined) return entryRejected(`${key} is not a number`);\n normalized[key] = value;\n }\n for (const key of OPTIONAL_POOL_STRINGS) {\n if (row[key] !== undefined && typeof row[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n for (const key of OPTIONAL_POOL_NUMBERS) {\n const value = row[key];\n if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value))) {\n return entryRejected(`${key} is not a number`);\n }\n }\n return entryOk(normalized as unknown as PoolListInfo);\n}\n","/**\n * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an\n * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error\n * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they\n * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.\n */\n\n/** True for a tick spacing the contract can use: a positive integer. The one definition. */\nexport function hasValidSpacing(spacing: number): boolean {\n return Number.isInteger(spacing) && spacing > 0;\n}\n\n/**\n * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`\n * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose\n * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,\n * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use\n * it) gives the same value and throws for the bad spacing.\n *\n * @example\n * ```ts\n * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero\n * alignTickDownOrNaN(100, 0); // NaN\n * ```\n */\nexport function alignTickDownOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : Number.NaN;\n}\n\n/**\n * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that\n * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See\n * {@link alignTickDownOrNaN}.\n */\nexport function alignTickUpOrNaN(tick: number, spacing: number): number {\n return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : Number.NaN;\n}\n","import { ALLOWED_FEE_TIERS_TEXT } from '../classes/gswap_error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport { alignTickDownOrNaN, alignTickUpOrNaN, hasValidSpacing } from './tick_align.js';\nimport { DexDecimal, GC_MAX_TICK, GC_MIN_TICK, sqrtPriceToTick } from './tick_math.js';\n\n/**\n * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,\n * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,\n * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which\n * does not import the error class or the catalog; import it from the package entry as usual.\n */\n\n/** Align a tick down to the nearest multiple of a positive spacing. */\nexport function alignTickDown(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickDownOrNaN(tick, spacing);\n}\n\n/** Align a tick up to the nearest multiple of a positive spacing. */\nexport function alignTickUp(tick: number, spacing: number): number {\n assertSpacing(spacing);\n return alignTickUpOrNaN(tick, spacing);\n}\n\n/** Validate a position range against the global tick bounds and fee-tier spacing. */\nexport function assertTickRange(lower: number, upper: number, fee: FEE_TIER): void {\n const spacing = TICK_SPACING_BY_FEE[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n if (!Number.isInteger(lower) || !Number.isInteger(upper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower: lower, tickUpper: upper });\n }\n if (lower >= upper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower: lower, tickUpper: upper });\n }\n if (lower < GC_MIN_TICK || upper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower: lower,\n tickUpper: upper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n if (lower % spacing !== 0 || upper % spacing !== 0) {\n throw new GSwapSDKError('TICKS_NOT_ALIGNED', {\n tickLower: lower,\n tickUpper: upper,\n spacing,\n });\n }\n}\n\nfunction assertSpacing(spacing: number): void {\n if (!hasValidSpacing(spacing)) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: spacing });\n }\n}\n\n/** A pool's current price in the frame of the request that asked for it. */\nexport interface FramedSlot0 {\n /** The square-root price, token1 per token0 in the REQUESTED order. */\n sqrtPrice: string;\n /** The greatest tick whose square-root price is no greater than `sqrtPrice`. */\n tick: number;\n}\n\n/**\n * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's\n * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse\n * order the price is inverted here (at 60 significant digits, so a very large or very small\n * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the\n * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks\n * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).\n *\n * @example\n * ```ts\n * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);\n * const { sqrtPrice, tick } = frameSlot0(slot0);\n * ```\n */\nexport function frameSlot0(slot0: {\n sqrtPrice: string;\n tick: number;\n flippedFromRequest?: boolean | undefined;\n}): FramedSlot0 {\n if (slot0.flippedFromRequest !== true) return { sqrtPrice: slot0.sqrtPrice, tick: slot0.tick };\n const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));\n if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_SQRT_PRICE', { sqrtPrice: slot0.sqrtPrice });\n }\n const sqrtPrice = inverted.toString();\n return { sqrtPrice, tick: sqrtPriceToTick(sqrtPrice) };\n}\n","import { assertUniqueKey, type GalaChainTokenClassKey } from '@gala-chain/gala-core-sdk';\nimport BigNumber from 'bignumber.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount, SwapAmount } from '../types/amounts.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n RequestTradeDTO,\n} from '../types/v2_dtos.js';\nimport { assertTickRange } from './ticks.js';\nimport {\n assertCanonicalPair,\n isProposableTradingSymbol,\n validateFee,\n validateNumericAmount,\n} from './validation.js';\n\n// The pure builders of every v2 write DTO. They validate, canonicalize decimals\n// (`BigNumber#toFixed`) and fix the key order, and nothing else: no network, no signer, no\n// clock, no randomness — the `uniqueKey` is an input. The `Swaps` and `Positions` services call\n// exactly these functions, so a DTO an app builds here (to show in an approval popup, to sign on\n// another device, to submit later) is the DTO the services would have built.\n//\n// Inputs are already CANONICAL: `token0 < token1` by plain string comparison, ticks and prices in\n// that orientation. Orienting a caller's pair (and inverting its ticks and price) is the\n// services' job; a reversed pair is refused (`NON_CANONICAL_PAIR`) rather than silently signed.\n\nconst decimalString = (amount: NumericAmount): string => new BigNumber(amount).toFixed();\n\n/** The pool a RequestTrade trades in, its fee tier, the `uniqueKey` and what is traded. */\nexport type RequestTradeInput = {\n /** Canonical pool symbols: `token0 < token1`. Take them from a quote verbatim. */\n token0: string;\n token1: string;\n fee: number;\n /** Which side of the pool is sold: `true` when the input token is `token0`. */\n tokenInIsToken0: boolean;\n uniqueKey: string;\n} & SwapAmount;\n\n/**\n * Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or\n * `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the\n * side's slippage bound and an optional `priceLimit`. Key order is\n * `token0, token1, fee, uniqueKey`, then the one quantity, then the slippage bound, then\n * `priceLimit`.\n *\n * @example\n * ```ts\n * const dto = buildRequestTradeDto({\n * token0: quote.token0Symbol, token1: quote.token1Symbol,\n * tokenInIsToken0: quote.tokenInIsToken0, fee: quote.fee,\n * uniqueKey: createUniqueKey('galaswap-operation-'),\n * exactIn: '100', amountOutMinimum: '14',\n * });\n * ```\n */\nexport function buildRequestTradeDto(input: RequestTradeInput): RequestTradeDTO {\n validateFee(input.fee);\n assertCanonicalPair(input.token0, input.token1);\n assertUniqueKey(input.uniqueKey);\n const dto: Record<string, unknown> = {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n uniqueKey: input.uniqueKey,\n };\n if ('exactIn' in input) {\n const exactIn = input.exactIn;\n if (exactIn === undefined) {\n throw new GSwapSDKError('EXACT_AMOUNT_REQUIRED', { field: 'exactIn' });\n }\n validateNumericAmount(exactIn, 'exactIn');\n dto[input.tokenInIsToken0 ? 'sell0Qty' : 'sell1Qty'] = decimalString(exactIn);\n if (input.amountOutMinimum !== undefined) {\n validateNumericAmount(input.amountOutMinimum, 'amountOutMinimum', true);\n dto['amountOutMinimum'] = decimalString(input.amountOutMinimum);\n }\n } else {\n const exactOut = input.exactOut;\n if (exactOut === undefined) {\n throw new GSwapSDKError('EXACT_AMOUNT_REQUIRED', { field: 'exactOut' });\n }\n validateNumericAmount(exactOut, 'exactOut');\n dto[input.tokenInIsToken0 ? 'buy1Qty' : 'buy0Qty'] = decimalString(exactOut);\n if (input.amountInMaximum !== undefined) {\n validateNumericAmount(input.amountInMaximum, 'amountInMaximum', true);\n dto['amountInMaximum'] = decimalString(input.amountInMaximum);\n }\n }\n if (input.priceLimit !== undefined) {\n validateNumericAmount(input.priceLimit, 'priceLimit');\n dto['priceLimit'] = decimalString(input.priceLimit);\n }\n return dto as unknown as RequestTradeDTO;\n}\n\n/** A canonical pool position: the pair, fee tier, tick range and the attempt's `uniqueKey`. */\nexport interface PoolPositionInput {\n token0: string;\n token1: string;\n fee: number;\n tickLower: number;\n tickUpper: number;\n uniqueKey: string;\n}\n\nfunction assertPoolPosition(input: PoolPositionInput): void {\n validateFee(input.fee);\n assertCanonicalPair(input.token0, input.token1);\n assertTickRange(input.tickLower, input.tickUpper, input.fee);\n assertUniqueKey(input.uniqueKey);\n}\n\n/** Exactly one canonical deposit side. */\nexport type AddLiquidityInput = PoolPositionInput &\n (\n | { depositQuantityToken0: NumericAmount; depositQuantityToken1?: undefined }\n | { depositQuantityToken0?: undefined; depositQuantityToken1: NumericAmount }\n );\n\n/**\n * Builds the AddLiquidity DTO: exactly one of `depositQuantityToken0` / `depositQuantityToken1`\n * (the other side is derived on chain). Key order: `token0, token1, fee, tickLower, tickUpper,\n * uniqueKey, <deposit>`.\n */\nexport function buildAddLiquidityDto(input: AddLiquidityInput): AddLiquidityDTO {\n assertPoolPosition(input);\n const side = onlyOne(\n input.depositQuantityToken0,\n input.depositQuantityToken1,\n 'depositQuantityToken0',\n 'depositQuantityToken1',\n );\n if (side === undefined) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'depositQuantityToken0',\n second: 'depositQuantityToken1',\n });\n }\n validateNumericAmount(side.amount, side.name);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n [side.name]: decimalString(side.amount),\n } as AddLiquidityDTO;\n}\n\n/** At most one canonical withdrawal side; neither closes the position. */\nexport type RemoveLiquidityInput = PoolPositionInput & {\n withdrawalQuantityToken0?: NumericAmount | undefined;\n withdrawalQuantityToken1?: NumericAmount | undefined;\n};\n\n/**\n * Builds the RemoveLiquidity DTO: at most one of `withdrawalQuantityToken0` /\n * `withdrawalQuantityToken1`; omitting both closes the position and sweeps its fees.\n */\nexport function buildRemoveLiquidityDto(input: RemoveLiquidityInput): RemoveLiquidityDTO {\n assertPoolPosition(input);\n const side = onlyOne(\n input.withdrawalQuantityToken0,\n input.withdrawalQuantityToken1,\n 'withdrawalQuantityToken0',\n 'withdrawalQuantityToken1',\n true,\n );\n if (side !== undefined) validateNumericAmount(side.amount, side.name);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n ...(side === undefined ? {} : { [side.name]: decimalString(side.amount) }),\n };\n}\n\n/** Builds the CollectPositionFees DTO (the contract sweeps all of a position's fees). */\nexport function buildCollectPositionFeesDto(input: PoolPositionInput): CollectPositionFeesDTO {\n assertPoolPosition(input);\n return {\n token0: input.token0,\n token1: input.token1,\n fee: input.fee,\n tickLower: input.tickLower,\n tickUpper: input.tickUpper,\n uniqueKey: input.uniqueKey,\n };\n}\n\n/** A CreatePool in canonical orientation, with exactly one starting price. */\nexport type CreatePoolInput = {\n token0Key: GalaChainTokenClassKey;\n token1Key: GalaChainTokenClassKey;\n /** The symbols to register; `token0Symbol < token1Symbol` and both proposable. */\n token0Symbol: string;\n token1Symbol: string;\n fee: number;\n /** Optional display name; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n uniqueKey: string;\n} & (\n | { startingPrice: NumericAmount; startingSqrtPrice?: undefined }\n | { startingPrice?: undefined; startingSqrtPrice: NumericAmount }\n);\n\n/**\n * Builds the CreatePool DTO. Key order: `token0Key, token1Key, fee, startingPrice |\n * startingSqrtPrice, token0Symbol, token1Symbol, uniqueKey, name, isPrivate, privateAccess`.\n * Prices are those of the canonical pair (token1 per token0); a price quoted the other way round\n * is inverted by the caller before it gets here.\n */\nexport function buildCreatePoolDto(input: CreatePoolInput): CreatePoolDTO {\n validateFee(input.fee);\n assertUniqueKey(input.uniqueKey);\n assertCanonicalPair(input.token0Symbol, input.token1Symbol);\n for (const symbol of [input.token0Symbol, input.token1Symbol]) {\n if (!isProposableTradingSymbol(symbol)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol });\n }\n }\n for (const key of [input.token0Key, input.token1Key]) assertClassKey(key);\n const price = onlyOne(\n input.startingPrice,\n input.startingSqrtPrice,\n 'startingPrice',\n 'startingSqrtPrice',\n );\n if (price === undefined) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n if (typeof price.amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: price.name });\n }\n const parsed = new BigNumber(price.amount);\n if (!parsed.isFinite() || parsed.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(price.amount) });\n }\n return {\n token0Key: input.token0Key,\n token1Key: input.token1Key,\n fee: input.fee,\n [price.name]: parsed.toFixed(),\n token0Symbol: input.token0Symbol,\n token1Symbol: input.token1Symbol,\n uniqueKey: input.uniqueKey,\n // An empty name is \"no name\", as the Gala web app's builder treats it (its form yields '').\n ...(input.name === undefined || input.name === '' ? {} : { name: input.name }),\n ...(input.isPrivate === undefined ? {} : { isPrivate: input.isPrivate }),\n ...(input.privateAccess === undefined ? {} : { privateAccess: input.privateAccess }),\n } as CreatePoolDTO;\n}\n\nfunction assertClassKey(key: GalaChainTokenClassKey): void {\n for (const part of ['collection', 'category', 'type', 'additionalKey'] as const) {\n if (typeof key[part] !== 'string' || key[part].length === 0) {\n throw new GSwapSDKError('INCOMPLETE_TOKEN_CLASS_KEY', {\n compositeKey: [key.collection, key.category, key.type, key.additionalKey].join('$'),\n part,\n });\n }\n }\n}\n\n/**\n * Of two mutually exclusive fields, the one that is set (`undefined` when neither is);\n * both set is an error (`AT_MOST_ONE_OF_ALLOWED` or `EXACTLY_ONE_OF_REQUIRED`), and so is\n * neither unless `allowNeither`.\n */\nfunction onlyOne<T>(\n first: T | undefined,\n second: T | undefined,\n firstName: string,\n secondName: string,\n allowNeither = false,\n): { name: string; amount: T } | undefined {\n if (first !== undefined && second !== undefined) {\n throw allowNeither\n ? new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: firstName, second: secondName })\n : new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', { first: firstName, second: secondName });\n }\n if (first !== undefined) return { name: firstName, amount: first };\n if (second !== undefined) return { name: secondName, amount: second };\n return undefined;\n}\n\n/** The methods whose DTOs the builders produce. */\nexport type V2WriteMethod =\n 'RequestTrade' | 'AddLiquidity' | 'RemoveLiquidity' | 'CollectPositionFees' | 'CreatePool';\n\ntype DtoExpectation =\n 'string' | 'number' | 'boolean' | 'class_key' | 'string_array' | 'exactly_once';\n\nfunction invalidDto(\n method: string,\n field: string,\n expected: DtoExpectation,\n): GSwapSDKError<'INVALID_DTO'> {\n return new GSwapSDKError('INVALID_DTO', { method, field, expected });\n}\n\n/**\n * Rebuilds a DTO from its own fields with the builder of its method: the canonical form of the\n * DTO, with the same validation. Key order and decimal text are the builder's.\n */\nfunction rebuildV2Dto(\n method: V2WriteMethod,\n dto: Record<string, unknown>,\n): Record<string, unknown> {\n const text = (field: string): string => {\n const value = dto[field];\n if (typeof value !== 'string') throw invalidDto(method, field, 'string');\n return value;\n };\n const integer = (field: string): number => {\n const value = dto[field];\n if (typeof value !== 'number') throw invalidDto(method, field, 'number');\n return value;\n };\n const optionalText = (field: string): string | undefined =>\n dto[field] === undefined ? undefined : text(field);\n const classKey = (field: string): GalaChainTokenClassKey => {\n const value = dto[field];\n if (typeof value !== 'object' || value === null) throw invalidDto(method, field, 'class_key');\n const key = value as Record<string, unknown>;\n const part = (name: string): string => {\n if (typeof key[name] !== 'string') throw invalidDto(method, `${field}.${name}`, 'string');\n return key[name];\n };\n return {\n collection: part('collection'),\n category: part('category'),\n type: part('type'),\n additionalKey: part('additionalKey'),\n };\n };\n // The pool pair is not a field of CreatePool, so these are read per method, not up front.\n const base = () => ({ token0: text('token0'), token1: text('token1'), fee: integer('fee') });\n const uniqueKey = text('uniqueKey');\n const position = () => ({\n ...base(),\n uniqueKey,\n tickLower: integer('tickLower'),\n tickUpper: integer('tickUpper'),\n });\n switch (method) {\n case 'RequestTrade': {\n const qty = ['sell0Qty', 'sell1Qty', 'buy0Qty', 'buy1Qty'].filter(\n (f) => dto[f] !== undefined,\n );\n const [field] = qty;\n if (qty.length !== 1 || field === undefined) {\n throw invalidDto(method, 'sell0Qty|sell1Qty|buy0Qty|buy1Qty', 'exactly_once');\n }\n const tokenInIsToken0 = field === 'sell0Qty' || field === 'buy1Qty';\n const shared = { ...base(), uniqueKey, tokenInIsToken0 };\n const priceLimit = optionalText('priceLimit');\n return field.startsWith('sell')\n ? buildRequestTradeDto({\n ...shared,\n exactIn: text(field),\n amountOutMinimum: optionalText('amountOutMinimum'),\n priceLimit,\n })\n : buildRequestTradeDto({\n ...shared,\n exactOut: text(field),\n amountInMaximum: optionalText('amountInMaximum'),\n priceLimit,\n });\n }\n case 'AddLiquidity': {\n const token0Side = optionalText('depositQuantityToken0');\n const token1Side = optionalText('depositQuantityToken1');\n return buildAddLiquidityDto({\n ...position(),\n ...(token0Side === undefined\n ? { depositQuantityToken1: token1Side as string }\n : { depositQuantityToken0: token0Side }),\n });\n }\n case 'RemoveLiquidity':\n return buildRemoveLiquidityDto({\n ...position(),\n withdrawalQuantityToken0: optionalText('withdrawalQuantityToken0'),\n withdrawalQuantityToken1: optionalText('withdrawalQuantityToken1'),\n });\n case 'CollectPositionFees':\n return buildCollectPositionFeesDto(position());\n case 'CreatePool': {\n const price = optionalText('startingPrice');\n const sqrtPrice = optionalText('startingSqrtPrice');\n const privateAccess = dto['privateAccess'];\n if (\n privateAccess !== undefined &&\n (!Array.isArray(privateAccess) || privateAccess.some((entry) => typeof entry !== 'string'))\n ) {\n throw invalidDto(method, 'privateAccess', 'string_array');\n }\n if (dto['isPrivate'] !== undefined && typeof dto['isPrivate'] !== 'boolean') {\n throw invalidDto(method, 'isPrivate', 'boolean');\n }\n return buildCreatePoolDto({\n token0Key: classKey('token0Key'),\n token1Key: classKey('token1Key'),\n token0Symbol: text('token0Symbol'),\n token1Symbol: text('token1Symbol'),\n fee: integer('fee'),\n uniqueKey,\n name: optionalText('name'),\n isPrivate: dto['isPrivate'],\n privateAccess: privateAccess as string[] | undefined,\n ...(price === undefined\n ? { startingSqrtPrice: sqrtPrice as string }\n : { startingPrice: price }),\n });\n }\n }\n}\n\n/**\n * Asserts that `dto` is EXACTLY what the builder of `method` produces for its own fields — the\n * same fields, canonical decimal text, builder key order, nothing extra (no `signature`). The\n * `submit*` methods use it so that what an app showed a user (a DTO it built) is byte for byte\n * what gets signed; a DTO edited by hand, or built elsewhere, is refused rather than signed.\n *\n * @throws GSwapSDKError `INVALID_DTO` or `DTO_NOT_CANONICAL`.\n */\nexport function assertCanonicalV2Dto(method: V2WriteMethod, dto: Record<string, unknown>): void {\n const rebuilt = rebuildV2Dto(method, dto);\n if (JSON.stringify(rebuilt) !== JSON.stringify(dto)) {\n throw new GSwapSDKError('DTO_NOT_CANONICAL', { method });\n }\n}\n","import {\n assertUniqueKey,\n compositeKeyOf,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { DEX_CONTRACT_PATH } from '../utils/chain_contract.js';\nimport BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport type { ChainGateway, ChainSubmitOptions } from './gateway.js';\nimport type { PositionConfirmationResult, SubmittedTransaction } from './submitted_transaction.js';\nimport { HttpClient } from './http_client.js';\nimport { rawTokenOf, type Symbols, type TokenResolver } from './symbols.js';\nimport type { NumericAmount, PriceIn } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { TICK_SPACING_BY_FEE } from '../types/fees.js';\nimport type {\n AddLiquidityDTO,\n CollectPositionFeesDTO,\n CreatePoolDTO,\n RemoveLiquidityDTO,\n} from '../types/v2_dtos.js';\nimport type {\n AddLiquidityEstimate,\n Position,\n RemoveLiquidityEstimate,\n} from '../types/v2_results.js';\nimport {\n asEntryRecord,\n entryOk,\n entryRejected,\n readEntries,\n type EntryParse,\n type InvalidEntryHandler,\n} from '../utils/lenient.js';\nimport { type TokenRef, parseTokenClassKey } from '../utils/ordering.js';\nimport { resolvePreSend } from '../utils/resolve_pre_send.js';\nimport {\n isProposableTradingSymbol,\n validateFee,\n userRef,\n validateNumericAmount,\n} from '../utils/validation.js';\nimport { tickFromPrice } from '../utils/tick_math.js';\nimport { alignTickDown, alignTickUp, assertTickRange } from '../utils/ticks.js';\nimport {\n assertCanonicalV2Dto,\n buildAddLiquidityDto,\n buildCollectPositionFeesDto,\n buildCreatePoolDto,\n buildRemoveLiquidityDto,\n} from '../utils/dto_builders.js';\n\ntype PositionGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n submit: (\n method: string,\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<Position | null>>;\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\ntype PositionSymbols = TokenResolver & Pick<Symbols, 'orderPair'> & { invalidate?: () => void };\n\n/** Options of {@link Positions}: the `uniqueKey` prefix and a handler for skipped list rows. */\nexport interface PositionsOptions extends UniqueKeyOptions {\n /** Told about every position row of a list that was skipped as unusable. */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n}\n\n/** A write's optional attempt identity. */\ninterface UniqueKeyArg {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing, or to retry the SAME\n * attempt after a lost response; never reuse it for another write.\n */\n uniqueKey?: string | undefined;\n}\n\n/** Arguments of {@link Positions.addLiquidityByTicks} and {@link Positions.buildAddLiquidity}. */\nexport interface AddLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n /** Whether `amount` is of `token0` as the caller passed it (not of the canonical token0). */\n amountIsToken0: boolean;\n}\n\n/** Arguments of {@link Positions.removeLiquidity} and {@link Positions.buildRemoveLiquidity}. */\nexport interface RemoveLiquidityArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n /** Withdraw this much of the caller's `token0`; give at most one of `amount0` / `amount1`. */\n amount0?: NumericAmount | undefined;\n amount1?: NumericAmount | undefined;\n}\n\n/** Arguments of {@link Positions.collectPositionFees} and {@link Positions.buildCollectPositionFees}. */\nexport interface CollectPositionFeesArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Arguments of {@link Positions.createPool} and {@link Positions.buildCreatePool}. */\nexport interface CreatePoolArgs extends UniqueKeyArg {\n token0: TokenRef;\n token1: TokenRef;\n token0Symbol?: string | undefined;\n token1Symbol?: string | undefined;\n fee: FEE_TIER;\n startingPrice?: NumericAmount | undefined;\n startingSqrtPrice?: NumericAmount | undefined;\n /** Optional pool display name, sent as the DTO's `name`; omitted when undefined or empty. */\n name?: string | undefined;\n isPrivate?: boolean | undefined;\n privateAccess?: string[] | undefined;\n}\n\n/** The pool position a liquidity DTO names, as its confirmation needs it. */\nfunction identityOf(\n dto: Pick<CollectPositionFeesDTO, 'token0' | 'token1' | 'fee' | 'tickLower' | 'tickUpper'>,\n): PositionIdentity {\n return {\n token0: dto.token0,\n token1: dto.token1,\n fee: dto.fee,\n tickLower: dto.tickLower,\n tickUpper: dto.tickUpper,\n };\n}\n\n/**\n * The outcome of {@link Positions.readPosition}. Only `not_found` is chain-confirmed absence (the\n * backend answers HTTP 404 only when the chain itself found no such position); `unknown` is \"no\n * evidence either way\" — a transport failure, a gateway timeout, any other error status or an\n * answer that is not a position — and must never be read as a removal.\n */\nexport type PositionRead =\n | { kind: 'found'; data: Position }\n | { kind: 'not_found' }\n | { kind: 'unknown'; error: GSwapSDKError };\n\ninterface BackendEnvelope<TData> {\n data: TData;\n}\n\ninterface AddLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n liquidity: string;\n token0Symbol: string;\n token1Symbol: string;\n tickLower: number;\n tickUpper: number;\n amountIsCanonicalToken0: boolean;\n}\n\ninterface RemoveLiquidityEstimateWire {\n amount0: string;\n amount1: string;\n}\n\ninterface ResolvedCreateToken {\n symbol: string;\n classKey: ReturnType<typeof parseTokenClassKey>;\n}\n\ninterface PositionIdentity {\n token0: string;\n token1: string;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n}\n\n/** Tells `submit()` how to prove a write's own effect for `SubmittedTransaction.confirm()`. */\ntype PositionSubmitConfirmation =\n | { kind: 'add' | 'removePartial' | 'removeFull' | 'collect'; identity: PositionIdentity }\n | { kind: 'createPool'; token0: string; token1: string; fee: FEE_TIER };\n\n/**\n * Manages current-contract concentrated-liquidity positions.\n *\n * @example\n * ```typescript\n * const positions = gSwap.positions;\n * const mine = await positions.getUserPositions('client|012345678901234567890123');\n * console.log(mine.length);\n * ```\n */\nexport class Positions {\n constructor(\n private readonly gateway: PositionGateway,\n private readonly symbols: PositionSymbols,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: PositionsOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n this.onInvalidEntry = options.onInvalidEntry;\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly http: HttpClient;\n private readonly uniqueKeyPrefix: string;\n private readonly onInvalidEntry: InvalidEntryHandler | undefined;\n\n /**\n * Gets all current-contract positions owned by an address.\n *\n * @param owner - GalaChain owner identity.\n * @returns Enriched positions from the v2 trade backend, token images included. A row that is\n * not a usable position is skipped and reported to `onInvalidEntry`.\n * @example\n * ```typescript\n * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');\n * ```\n */\n async getUserPositions(owner: string): Promise<Position[]> {\n const response = await this.get<unknown>('/positions', { user: userRef(owner, 'owner') });\n return readEntries('positions', response.data, parsePosition, this.onInvalidEntry);\n }\n\n /**\n * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.\n * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.\n *\n * @param args - Pair, owner, fee, and position tick range.\n * @returns The position, or `null` when the backend returns 404.\n * @example\n * ```typescript\n * const position = await gSwap.positions.getPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async getPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<Position | null> {\n const response = await this.getNullable<unknown>(\n '/position',\n await this.positionParams(args),\n signal,\n );\n return response === null ? null : readPositionBody(response.data);\n }\n\n /**\n * Reads one position and classifies the outcome instead of throwing: `found` with the position\n * (fees included), `not_found` (the backend's HTTP 404, which it sends only when the chain\n * itself has no such position) or `unknown` (any other failure, carried as `error`). Use it\n * to confirm a write: `unknown` is \"no evidence either way\", never a confirmed absence.\n *\n * Only the caller's own abort rethrows. With a pass-through resolver ({@link CanonicalSymbols})\n * the pair and ticks go to the backend exactly as given and the backend orients them.\n *\n * @example\n * ```typescript\n * const read = await gSwap.positions.readPosition({\n * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',\n * fee: 3000, tickLower: -19200, tickUpper: 12000,\n * });\n * if (read.kind === 'found') console.log(read.data.fees0);\n * ```\n */\n async readPosition(\n args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n },\n signal?: AbortSignal,\n ): Promise<PositionRead> {\n try {\n const position = await this.getPosition(args, signal);\n return position === null ? { kind: 'not_found' } : { kind: 'found', data: position };\n } catch (error: unknown) {\n if (signal?.aborted === true) throw error;\n return {\n kind: 'unknown',\n error: isGSwapError(error)\n ? error\n : new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'position' },\n { cause: error, write: false },\n ),\n };\n }\n }\n\n /**\n * The `/position` query: canonical symbols and canonical ticks after a client-side flip, or,\n * for a pass-through resolver, the caller's references and ticks untouched.\n */\n private async positionParams(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n owner: string;\n tickLower: number;\n tickUpper: number;\n }): Promise<Record<string, string>> {\n // The backend matches `owner` against the chain's position owner with strict equality, so\n // only the chain's own spelling (`eth|<EIP-55>`) finds a position.\n const owner = userRef(args.owner, 'owner');\n if (this.symbols.passthrough === true) {\n return {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n owner,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n };\n }\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n return {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: `${args.fee}`,\n owner,\n tickLower: `${ticks.tickLower}`,\n tickUpper: `${ticks.tickUpper}`,\n };\n }\n\n /**\n * Estimates the other token amount and resulting liquidity for a deposit.\n *\n * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.\n * @returns Backend liquidity estimate.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async estimateAddLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n amount: NumericAmount;\n amountIsToken0: boolean;\n }): Promise<AddLiquidityEstimate> {\n validateNumericAmount(args.amount, 'amount');\n const response = await this.get<AddLiquidityEstimateWire>('/add-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n amount: new BigNumber(args.amount).toFixed(),\n amountIsToken0: String(args.amountIsToken0),\n });\n return response.data;\n }\n\n /**\n * Estimates token amounts released by burning liquidity.\n *\n * @param args - Pair, tick range, fee tier, and liquidity quantity.\n * @returns Estimated token0 and token1 quantities.\n * @example\n * ```typescript\n * const estimate = await gSwap.positions.estimateRemoveLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, liquidity: '1000',\n * });\n * ```\n */\n async estimateRemoveLiquidity(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n tickLower: number;\n tickUpper: number;\n liquidity: NumericAmount;\n }): Promise<RemoveLiquidityEstimate> {\n validateNumericAmount(args.liquidity, 'liquidity');\n const response = await this.get<RemoveLiquidityEstimateWire>('/remove-liq-estimate', {\n token0: rawTokenOf(args.token0),\n token1: rawTokenOf(args.token1),\n fee: `${args.fee}`,\n tickLower: `${args.tickLower}`,\n tickUpper: `${args.tickUpper}`,\n liquidity: new BigNumber(args.liquidity).toFixed(),\n });\n return response.data;\n }\n\n /**\n * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.\n *\n * @param args - Pair, fee, range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByTicks({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * await tx.confirm();\n * ```\n */\n async addLiquidityByTicks(args: AddLiquidityArgs) {\n return this.submitAddLiquidity(await this.buildAddLiquidity(args));\n }\n\n /**\n * Builds the AddLiquidity DTO that {@link addLiquidityByTicks} would sign, without signing or\n * sending it: to show in an approval popup, or to sign elsewhere. Submit exactly this DTO with\n * {@link submitAddLiquidity}. The pure counterpart, with canonical inputs and no resolution,\n * is `buildAddLiquidityDto`.\n *\n * @example\n * ```typescript\n * const dto = await gSwap.positions.buildAddLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async buildAddLiquidity(args: AddLiquidityArgs): Promise<AddLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n // Caller-facing checks first, so a refusal names the caller's own argument (`amount`).\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n validateNumericAmount(args.amount, 'amount');\n const base = {\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n };\n return pair.flipped !== args.amountIsToken0\n ? buildAddLiquidityDto({ ...base, depositQuantityToken0: args.amount })\n : buildAddLiquidityDto({ ...base, depositQuantityToken1: args.amount });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildAddLiquidity} or `buildAddLiquidityDto`; it must\n * be exactly what the builder produces. The returned transaction confirms by proving the\n * position's liquidity grew.\n */\n async submitAddLiquidity(dto: AddLiquidityDTO) {\n assertCanonicalV2Dto('AddLiquidity', dto);\n return this.submit('AddLiquidity', dto, { kind: 'add', identity: identityOf(dto) });\n }\n\n /**\n * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.\n * The resulting range is therefore no narrower than the requested price interval.\n *\n * @param args - Pair, fee, price range, deposit amount, and caller-side token index.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.addLiquidityByPrice({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,\n * });\n * ```\n */\n async addLiquidityByPrice(args: {\n token0: TokenRef;\n token1: TokenRef;\n fee: FEE_TIER;\n minPrice: PriceIn;\n maxPrice: PriceIn;\n amount: NumericAmount;\n amountIsToken0: boolean;\n /** The attempt's `uniqueKey`; default a fresh one (see {@link AddLiquidityArgs.uniqueKey}). */\n uniqueKey?: string | undefined;\n }) {\n validateFee(args.fee);\n this.rejectNumber(args.minPrice, 'minPrice');\n this.rejectNumber(args.maxPrice, 'maxPrice');\n const minPrice = new BigNumber(args.minPrice);\n const maxPrice = new BigNumber(args.maxPrice);\n if (\n !minPrice.isFinite() ||\n !maxPrice.isFinite() ||\n minPrice.isLessThanOrEqualTo(0) ||\n maxPrice.isLessThanOrEqualTo(0)\n ) {\n throw new GSwapSDKError('INVALID_PRICE_BOUNDS', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n if (minPrice.isGreaterThan(maxPrice)) {\n throw new GSwapSDKError('PRICE_BOUNDS_ORDER', {\n minPrice: String(args.minPrice),\n maxPrice: String(args.maxPrice),\n });\n }\n const spacing = this.tickSpacing(args.fee);\n const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);\n const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);\n return this.addLiquidityByTicks({\n token0: args.token0,\n token1: args.token1,\n fee: args.fee,\n tickLower,\n tickUpper,\n amount: args.amount,\n amountIsToken0: args.amountIsToken0,\n uniqueKey: args.uniqueKey,\n });\n }\n\n /**\n * Removes liquidity by withdrawing at most one canonical token quantity.\n * Omitting both amounts closes the position and sweeps all accrued fees.\n *\n * @param args - Pair, fee, range, and optional caller-side withdrawal amount.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.removeLiquidity({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async removeLiquidity(args: RemoveLiquidityArgs) {\n return this.submitRemoveLiquidity(await this.buildRemoveLiquidity(args));\n }\n\n /**\n * Builds the RemoveLiquidity DTO that {@link removeLiquidity} would sign, without signing or\n * sending it. Submit exactly this DTO with {@link submitRemoveLiquidity}. The pure counterpart\n * is `buildRemoveLiquidityDto`.\n */\n async buildRemoveLiquidity(args: RemoveLiquidityArgs): Promise<RemoveLiquidityDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n if (args.amount0 !== undefined && args.amount1 !== undefined) {\n throw new GSwapSDKError('AT_MOST_ONE_OF_ALLOWED', { first: 'amount0', second: 'amount1' });\n }\n if (args.amount0 !== undefined) validateNumericAmount(args.amount0, 'amount0');\n if (args.amount1 !== undefined) validateNumericAmount(args.amount1, 'amount1');\n // The caller's amount0 / amount1 follow the caller's pair; the DTO's follow the canonical one.\n const [canonical0, canonical1] = pair.flipped\n ? [args.amount1, args.amount0]\n : [args.amount0, args.amount1];\n return buildRemoveLiquidityDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n withdrawalQuantityToken0: canonical0,\n withdrawalQuantityToken1: canonical1,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildRemoveLiquidity} or `buildRemoveLiquidityDto`;\n * it must be exactly what the builder produces. A DTO with no withdrawal quantity closes the\n * position, and the returned transaction then confirms by proving the position is gone.\n */\n async submitRemoveLiquidity(dto: RemoveLiquidityDTO) {\n assertCanonicalV2Dto('RemoveLiquidity', dto);\n const isFullClose =\n dto.withdrawalQuantityToken0 === undefined && dto.withdrawalQuantityToken1 === undefined;\n return this.submit('RemoveLiquidity', dto, {\n kind: isFullClose ? 'removeFull' : 'removePartial',\n identity: identityOf(dto),\n });\n }\n\n /**\n * Collects all accrued fees for a position; the contract does not support partial collection.\n *\n * @param args - Pair, fee, and tick range identifying the position.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.collectPositionFees({\n * token0: 'GALA', token1: 'GUSDC', fee: 3000,\n * tickLower: -19200, tickUpper: 12000,\n * });\n * ```\n */\n async collectPositionFees(args: CollectPositionFeesArgs) {\n return this.submitCollectPositionFees(await this.buildCollectPositionFees(args));\n }\n\n /**\n * Builds the CollectPositionFees DTO that {@link collectPositionFees} would sign, without\n * signing or sending it. Submit exactly this DTO with {@link submitCollectPositionFees}. The\n * pure counterpart is `buildCollectPositionFeesDto`.\n */\n async buildCollectPositionFees(args: CollectPositionFeesArgs): Promise<CollectPositionFeesDTO> {\n validateFee(args.fee);\n const pair = await this.orderPair(args.token0, args.token1);\n const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);\n assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);\n return buildCollectPositionFeesDto({\n token0: pair.token0.symbol,\n token1: pair.token1.symbol,\n fee: args.fee,\n tickLower: ticks.tickLower,\n tickUpper: ticks.tickUpper,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCollectPositionFees} or\n * `buildCollectPositionFeesDto`; it must be exactly what the builder produces.\n */\n async submitCollectPositionFees(dto: CollectPositionFeesDTO) {\n assertCanonicalV2Dto('CollectPositionFees', dto);\n return this.submit('CollectPositionFees', dto, { kind: 'collect', identity: identityOf(dto) });\n }\n\n /**\n * Creates a pool, resolving registered trading symbols.\n * Reversed symbol order inverts the supplied starting price or square-root price.\n *\n * A token class key carries no symbol, so for a token being proposed into the v2\n * trading-symbol registry for the first time (no existing pool has registered it yet) the\n * caller MUST pass `token0Symbol`/`token1Symbol` (the token class's symbol, from the token\n * list or FetchTokenClasses). The SDK never derives a symbol from the key, and throws a\n * TOKEN_SYMBOL_NOT_REGISTERED error when an unregistered token has none. For an already-registered token a\n * supplied symbol must match the registered one.\n *\n * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.\n * @returns The synchronously submitted transaction.\n * @example\n * ```typescript\n * const tx = await gSwap.positions.createPool({\n * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,\n * startingPrice: '0.15',\n * });\n * ```\n */\n async createPool(args: CreatePoolArgs) {\n return this.submitCreatePool(await this.buildCreatePool(args));\n }\n\n /**\n * Builds the CreatePool DTO that {@link createPool} would sign, without signing or sending it:\n * symbols resolved or proposed, the pair put in canonical order and the price inverted when it\n * was reversed. Submit exactly this DTO with {@link submitCreatePool}. The pure counterpart,\n * with canonical inputs, is `buildCreatePoolDto`.\n */\n async buildCreatePool(args: CreatePoolArgs): Promise<CreatePoolDTO> {\n const hasPrice = args.startingPrice !== undefined;\n const hasSqrtPrice = args.startingSqrtPrice !== undefined;\n if (hasPrice === hasSqrtPrice) {\n throw new GSwapSDKError('EXACTLY_ONE_OF_REQUIRED', {\n first: 'startingPrice',\n second: 'startingSqrtPrice',\n });\n }\n validateFee(args.fee);\n const [tokenA, tokenB] = await Promise.all([\n this.resolveCreateToken(args.token0, args.token0Symbol),\n this.resolveCreateToken(args.token1, args.token1Symbol),\n ]);\n const flipped = tokenA.symbol > tokenB.symbol;\n const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];\n const sourcePriceInput = hasPrice\n ? (args.startingPrice as NumericAmount)\n : (args.startingSqrtPrice as NumericAmount);\n this.rejectNumber(sourcePriceInput, hasPrice ? 'startingPrice' : 'startingSqrtPrice');\n const sourcePrice = new BigNumber(sourcePriceInput);\n if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) {\n throw new GSwapSDKError('INVALID_STARTING_PRICE', { value: String(sourcePriceInput) });\n }\n const canonicalPrice = flipped ? new BigNumber(1).dividedBy(sourcePrice) : sourcePrice;\n const shared = {\n token0Key: token0.classKey,\n token1Key: token1.classKey,\n token0Symbol: token0.symbol,\n token1Symbol: token1.symbol,\n fee: args.fee,\n uniqueKey: this.uniqueKeyFor(args.uniqueKey),\n name: args.name,\n isPrivate: args.isPrivate,\n privateAccess: args.privateAccess,\n };\n return hasPrice\n ? buildCreatePoolDto({ ...shared, startingPrice: canonicalPrice })\n : buildCreatePoolDto({ ...shared, startingSqrtPrice: canonicalPrice });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildCreatePool} or `buildCreatePoolDto`; it must be\n * exactly what the builder produces. The returned transaction confirms by the pool existing, and\n * the cached symbol registry is dropped, since the pool may have registered new symbols.\n */\n async submitCreatePool(dto: CreatePoolDTO) {\n assertCanonicalV2Dto('CreatePool', dto);\n const transaction = await this.submit('CreatePool', dto, {\n kind: 'createPool',\n token0: dto.token0Symbol,\n token1: dto.token1Symbol,\n fee: dto.fee,\n });\n this.symbols.invalidate?.();\n return transaction;\n }\n\n private async submit(\n method: string,\n dto: Record<string, unknown>,\n confirmation?: PositionSubmitConfirmation,\n ) {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const signed = await signPreSend(this.signer, DEX_CONTRACT_PATH, method, dto);\n const submitOptions =\n this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n const owner = this.walletAddress;\n const positionConfirmation = await this.buildPositionConfirmation(confirmation, owner);\n const options: ChainSubmitOptions = {\n ...submitOptions,\n ...(positionConfirmation === undefined ? {} : { positionConfirmation }),\n };\n return this.gateway.submit(method, signed, options);\n }\n\n /**\n * Builds a confirmation closure that proves the write's own effect, not just that a\n * position row exists (true before most of these writes run too, for any operation on a\n * pre-existing position — existence alone would false-confirm before the write executes,\n * and would never confirm a full close, whose whole point is that the position stops\n * existing).\n *\n * The \"before\" state is read here, before the write is sent. Liquidity writes execute\n * synchronously, so by the time `confirm()` first polls the effect has already landed: a\n * baseline taken on that first poll would already include it, and an add or partial remove\n * would never be seen to change and would time out. Only a full close needs no baseline\n * (it waits for the position to disappear). If the baseline read fails the write is still\n * sent and the closure falls back to taking the baseline on its first poll.\n */\n private async buildPositionConfirmation(\n confirmation: PositionSubmitConfirmation | undefined,\n owner: string | undefined,\n ): Promise<((signal: AbortSignal) => Promise<PositionConfirmationResult>) | undefined> {\n if (confirmation === undefined) return undefined;\n\n if (confirmation.kind === 'createPool') {\n const { token0, token1, fee } = confirmation;\n return async (signal) => {\n const pool = await this.getNullable<unknown>(\n '/pool',\n { token0, token1, fee: `${fee}` },\n signal,\n );\n return pool === null ? { confirmed: false } : { confirmed: true, position: null };\n };\n }\n\n if (owner === undefined) return undefined;\n const { kind, identity } = confirmation;\n const toBaseline = (current: Position | null) => ({\n liquidity: new BigNumber(current?.liquidity ?? 0),\n fees: new BigNumber(current?.fees0 ?? 0).plus(new BigNumber(current?.fees1 ?? 0)),\n });\n let baseline: { liquidity: BigNumber; fees: BigNumber } | undefined;\n if (kind !== 'removeFull') {\n try {\n baseline = toBaseline(await this.getPosition({ ...identity, owner }));\n } catch {\n baseline = undefined;\n }\n }\n\n return async (signal) => {\n const current = await this.getPosition({ ...identity, owner }, signal);\n\n if (baseline === undefined) {\n // First poll only establishes the baseline to compare future polls against — it can\n // never itself be the confirmed outcome (nothing has been observed to change yet).\n baseline = toBaseline(current);\n // A full close starting from \"already gone\" (e.g. a retried confirm after the position\n // was already swept) is confirmed immediately rather than waiting for a change that\n // already happened.\n return kind === 'removeFull' && current === null\n ? { confirmed: true, position: null }\n : { confirmed: false };\n }\n\n switch (kind) {\n case 'add':\n return current !== null &&\n new BigNumber(current.liquidity).isGreaterThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removePartial':\n return current !== null && new BigNumber(current.liquidity).isLessThan(baseline.liquidity)\n ? { confirmed: true, position: current }\n : { confirmed: false };\n case 'removeFull':\n return current === null ? { confirmed: true, position: null } : { confirmed: false };\n case 'collect': {\n if (current === null) return { confirmed: false };\n const currentFees = new BigNumber(current.fees0 ?? 0).plus(\n new BigNumber(current.fees1 ?? 0),\n );\n if (currentFees.isLessThan(baseline.fees)) return { confirmed: true, position: current };\n // Nothing to sweep in the first place — a legitimate no-op collect never moves\n // fees, so \"still zero\" is the confirmed outcome, not an unconfirmed one.\n if (baseline.fees.isZero() && currentFees.isZero())\n return { confirmed: true, position: current };\n return { confirmed: false };\n }\n }\n };\n }\n\n private async get<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData>> {\n return this.http.sendGetRequest<BackendEnvelope<TData>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n endpoint,\n params,\n signal === undefined ? undefined : { signal },\n );\n }\n\n private async getNullable<TData>(\n endpoint: string,\n params: Record<string, string>,\n signal?: AbortSignal,\n ): Promise<BackendEnvelope<TData> | null> {\n try {\n return await this.get<TData>(endpoint, params, signal);\n } catch (error: unknown) {\n if (this.isNotFound(error)) return null;\n throw error;\n }\n }\n\n private isNotFound(error: unknown): boolean {\n return isGSwapError(error) && error.status === 404;\n }\n\n private canonicalTicks(tickLower: number, tickUpper: number, flipped: boolean) {\n return flipped ? { tickLower: -tickUpper, tickUpper: -tickLower } : { tickLower, tickUpper };\n }\n\n private tickSpacing(fee: number): number {\n const spacing = (TICK_SPACING_BY_FEE as Record<number, number>)[fee];\n if (spacing === undefined) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n return spacing;\n }\n\n private rejectNumber(value: unknown, parameterName: string): void {\n if (typeof value === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n }\n\n /** The caller's `uniqueKey` (validated), else a fresh one. */\n private uniqueKeyFor(supplied: string | undefined): string {\n if (supplied === undefined) return createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(supplied);\n return supplied;\n }\n\n /**\n * The pair in canonical order. A resolver failure that is not an SDK error (an app's own\n * resolver, an app requestor's rejection during the registry read) is `TOKEN_RESOLUTION_FAILED`.\n */\n private orderPair(a: TokenRef, b: TokenRef) {\n return resolvePreSend(`${rawTokenOf(a)}/${rawTokenOf(b)}`, () => this.symbols.orderPair(a, b));\n }\n\n private async resolveCreateToken(\n ref: TokenRef,\n symbolOverride?: string,\n ): Promise<ResolvedCreateToken> {\n try {\n const lookupRef = typeof ref === 'object' ? compositeKeyOf(ref) : ref;\n const resolved = await resolvePreSend(rawTokenOf(ref), () => this.symbols.resolve(lookupRef));\n if (\n symbolOverride !== undefined &&\n symbolOverride !== '' &&\n symbolOverride !== resolved.symbol\n ) {\n throw new GSwapSDKError('SYMBOL_DISAGREES_WITH_REGISTRY', {\n token: rawTokenOf(ref),\n suppliedSymbol: symbolOverride,\n registeredSymbol: resolved.symbol,\n });\n }\n const suppliedClassKey = this.tryParseClassKey(ref);\n if (suppliedClassKey === undefined && resolved.collection === '') {\n // An offline resolver knows a bare symbol but not its class key; a pool needs the key.\n throw new GSwapSDKError('CREATE_POOL_NEEDS_CLASS_KEY', { token: rawTokenOf(ref) });\n }\n return {\n symbol: resolved.symbol,\n classKey:\n suppliedClassKey ??\n parseTokenClassKey({\n collection: resolved.collection,\n category: resolved.category,\n type: resolved.type,\n additionalKey: resolved.additionalKey,\n }),\n };\n } catch (error: unknown) {\n if (!isGSwapError(error, 'UNKNOWN_TOKEN')) {\n throw error;\n }\n let classKey: ReturnType<typeof parseTokenClassKey>;\n try {\n classKey = parseTokenClassKey(ref);\n } catch {\n throw error;\n }\n // First-time registration: a class key carries NO symbol (collection and symbol disagree\n // for many tokens, launchpad tokens all share collection `Token`, and some collections\n // contain `$`), so the symbol to propose must be supplied by the caller from the token\n // class / registry. Never derive it from the key.\n if (symbolOverride === undefined || symbolOverride === '') {\n throw new GSwapSDKError('TOKEN_SYMBOL_NOT_REGISTERED', { token: rawTokenOf(ref) });\n }\n if (!isProposableTradingSymbol(symbolOverride)) {\n throw new GSwapSDKError('INVALID_TRADING_SYMBOL', { symbol: symbolOverride });\n }\n return { symbol: symbolOverride, classKey };\n }\n }\n\n private tryParseClassKey(ref: TokenRef): ReturnType<typeof parseTokenClassKey> | undefined {\n try {\n return parseTokenClassKey(ref);\n } catch {\n return undefined;\n }\n }\n}\n\nconst REQUIRED_POSITION_STRINGS = [\n 'token0Symbol',\n 'token1Symbol',\n 'owner',\n 'liquidity',\n 'amount0',\n 'amount1',\n] as const;\nconst REQUIRED_POSITION_NUMBERS = ['fee', 'tickLower', 'tickUpper'] as const;\nconst OPTIONAL_POSITION_STRINGS = [\n 'token0CompositeKey',\n 'token1CompositeKey',\n 'token0Image',\n 'token1Image',\n 'sqrtPrice',\n 'fees0',\n 'fees1',\n] as const;\n\n/**\n * Reads one position row of `/positions` or `/position`: the pair, owner, range, liquidity and\n * amounts must be usable; the composite keys, token images, current tick and price, and the\n * escrowed fees are carried when present. `pool` is the pool reference (`poolRef` wins over\n * `pool`; `''` when the row names neither).\n */\nfunction parsePosition(value: unknown): EntryParse<Position> {\n const wire = asEntryRecord(value);\n if (wire === undefined) return entryRejected('the row is not an object');\n for (const key of REQUIRED_POSITION_STRINGS) {\n if (typeof wire[key] !== 'string') return entryRejected(`${key} is not a string`);\n }\n for (const key of REQUIRED_POSITION_NUMBERS) {\n const number = wire[key];\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n return entryRejected(`${key} is not a number`);\n }\n }\n if (typeof wire['inRange'] !== 'boolean') return entryRejected('inRange is not a boolean');\n for (const key of OPTIONAL_POSITION_STRINGS) {\n if (wire[key] !== undefined && typeof wire[key] !== 'string') {\n return entryRejected(`${key} is not a string`);\n }\n }\n const currentTick = wire['currentTick'];\n if (\n currentTick !== undefined &&\n (typeof currentTick !== 'number' || !Number.isFinite(currentTick))\n ) {\n return entryRejected('currentTick is not a number');\n }\n const pool = wire['poolRef'] ?? wire['pool'] ?? '';\n if (typeof pool !== 'string') return entryRejected('pool is not a string');\n const optional = Object.fromEntries(\n [...OPTIONAL_POSITION_STRINGS, 'currentTick' as const].flatMap((key) =>\n wire[key] === undefined ? [] : [[key, wire[key]]],\n ),\n );\n return entryOk({\n token0Symbol: wire['token0Symbol'] as string,\n token1Symbol: wire['token1Symbol'] as string,\n fee: wire['fee'] as number,\n tickLower: wire['tickLower'] as number,\n tickUpper: wire['tickUpper'] as number,\n liquidity: wire['liquidity'] as string,\n amount0: wire['amount0'] as string,\n amount1: wire['amount1'] as string,\n inRange: wire['inRange'],\n pool,\n owner: wire['owner'] as string,\n ...optional,\n });\n}\n\n/** The position inside a `/position` answer, or `INVALID_CHAIN_RESPONSE` when it is not one. */\nfunction readPositionBody(data: unknown): Position {\n const parsed = parsePosition(data);\n if (parsed.ok) return parsed.value;\n throw new GSwapSDKError(\n 'INVALID_POSITION_RESPONSE',\n { reason: parsed.reason },\n { body: data, write: false },\n );\n}\n","import BigNumber from 'bignumber.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport type { QuoteResult } from '../types/v2_results.js';\nimport type { TokenRef } from '../utils/ordering.js';\nimport { validateNumericAmount } from '../utils/validation.js';\nimport type { WireOptions } from '@gala-chain/gala-core-sdk';\nimport type { ChainGateway } from './gateway.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from './gswap_error_catalog.js';\nimport { readServerMessage } from '../utils/server_message.js';\nimport { GSwapSDKError, isGSwapError } from './gswap_sdk_error.js';\nimport { HttpClient } from './http_client.js';\nimport { queryTokenOf, type TokenResolver } from './symbols.js';\n\ninterface QuoteWire {\n contractVersion: 'v2';\n fee: number;\n amountIn: string;\n amountOut: string;\n currentSqrtPrice?: string;\n newSqrtPrice?: string;\n currentPrice?: string;\n newPrice?: string;\n newTick: number;\n tradingFees: string;\n protocolFees: string;\n totalFees: string;\n feeTokenSymbol: string;\n token0Symbol: string;\n token1Symbol: string;\n tokenInIsToken0: boolean;\n}\n\ninterface BackendEnvelope<T> {\n data: T;\n}\n\n/** The transport a quote service reads through: the same shape `Pools` and `Symbols` take. */\ntype QuoteGateway = Pick<ChainGateway, 'httpRequestor' | 'dexBackendBaseUrl'> & {\n requestTimeoutMs?: number | undefined;\n wire?: WireOptions | undefined;\n};\n\n/** Read-only quote service backed by the v2 offline quote engine. */\nexport class Quoting {\n /**\n * Creates a quote service.\n *\n * @example\n * ```ts\n * const quoting = new Quoting(gateway, symbols); // a ChainGateway, or any { dexBackendBaseUrl, httpRequestor }\n * ```\n */\n constructor(\n private readonly gateway: QuoteGateway,\n private readonly symbols: TokenResolver,\n ) {\n this.http = new HttpClient(\n gateway.httpRequestor,\n gateway.requestTimeoutMs ?? 30_000,\n gateway.wire,\n );\n }\n\n private readonly http: HttpClient;\n\n /**\n * Quotes the output for a positive exact-input amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');\n * console.log(quote.amountOut);\n * ```\n */\n public async quoteExactInput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountIn: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountIn, 'amountIn');\n return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString(amountIn) }, fee);\n }\n\n /**\n * Quotes the input for a positive exact-output amount.\n *\n * @example\n * ```ts\n * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);\n * console.log(quote.amountIn);\n * ```\n */\n public async quoteExactOutput(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amountOut: NumericAmount,\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateNumericAmount(amountOut, 'amountOut');\n return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString(amountOut) }, fee);\n }\n\n private async quote(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n amount: { amountIn: string } | { amountOut: string },\n fee?: FEE_TIER,\n ): Promise<QuoteResult> {\n validateOptionalFee(fee);\n\n const params: Record<string, string> = {\n tokenIn: await queryTokenOf(this.symbols, tokenIn),\n tokenOut: await queryTokenOf(this.symbols, tokenOut),\n ...amount,\n };\n if (fee !== undefined) params['fee'] = String(fee);\n\n try {\n const response = await this.http.sendGetRequest<BackendEnvelope<QuoteWire>>(\n this.gateway.dexBackendBaseUrl,\n '/v2/trade',\n '/quote',\n params,\n );\n return mapQuote(response.data);\n } catch (error: unknown) {\n throw mapQuoteError(error, tokenIn, tokenOut, fee, {\n tokenIn: params['tokenIn'] ?? '',\n tokenOut: params['tokenOut'] ?? '',\n });\n }\n }\n}\n\nfunction mapQuote(value: unknown): QuoteResult {\n if (!isQuoteWire(value)) {\n throw new GSwapSDKError(\n 'INVALID_CHAIN_RESPONSE',\n { resource: 'quote' },\n { body: value, write: false },\n );\n }\n const wire = value;\n const currentPrice =\n wire.currentPrice !== undefined\n ? new BigNumber(wire.currentPrice)\n : orientPrice(wire.currentSqrtPrice!, wire.tokenInIsToken0);\n const newPrice =\n wire.newPrice !== undefined\n ? new BigNumber(wire.newPrice)\n : orientPrice(wire.newSqrtPrice!, wire.tokenInIsToken0);\n const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);\n\n return {\n contractVersion: wire.contractVersion,\n fee: wire.fee,\n amountIn: wire.amountIn,\n amountOut: wire.amountOut,\n ...(wire.currentSqrtPrice === undefined ? {} : { currentSqrtPrice: wire.currentSqrtPrice }),\n ...(wire.newSqrtPrice === undefined ? {} : { newSqrtPrice: wire.newSqrtPrice }),\n feeTier: wire.fee,\n newTick: wire.newTick,\n tradingFees: wire.tradingFees,\n protocolFees: wire.protocolFees,\n totalFees: wire.totalFees,\n feeTokenSymbol: wire.feeTokenSymbol,\n token0Symbol: wire.token0Symbol,\n token1Symbol: wire.token1Symbol,\n tokenInIsToken0: wire.tokenInIsToken0,\n currentPrice,\n newPrice,\n priceImpact,\n };\n}\n\n// The default BigNumber.DECIMAL_PLACES (20) underflows 1/poolPrice to exactly 0 for a\n// pool price above ~1e20 (a real, in-range price for a low-unit-value token quoted\n// against a high-value one) — 60dp matches the precision ticks.ts's DexMath already\n// uses for this same class of division.\nconst HighPrecision = BigNumber.clone({ DECIMAL_PLACES: 60 });\n\nfunction orientPrice(sqrtPrice: string, tokenInIsToken0: boolean): BigNumber {\n const poolPrice = new HighPrecision(sqrtPrice).pow(2);\n return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);\n}\n\nfunction isQuoteWire(value: unknown): value is QuoteWire {\n if (typeof value !== 'object' || value === null) return false;\n const wire = value as Record<string, unknown>;\n const requiredStrings = [\n 'amountIn',\n 'amountOut',\n 'tradingFees',\n 'protocolFees',\n 'totalFees',\n 'feeTokenSymbol',\n 'token0Symbol',\n 'token1Symbol',\n ];\n return (\n wire['contractVersion'] === 'v2' &&\n typeof wire['fee'] === 'number' &&\n Number.isFinite(wire['fee']) &&\n requiredStrings.every((key) => typeof wire[key] === 'string') &&\n typeof wire['newTick'] === 'number' &&\n Number.isInteger(wire['newTick']) &&\n typeof wire['tokenInIsToken0'] === 'boolean' &&\n optionalPositiveDecimal(wire['currentSqrtPrice']) &&\n optionalPositiveDecimal(wire['newSqrtPrice']) &&\n optionalPositiveDecimal(wire['currentPrice']) &&\n optionalPositiveDecimal(wire['newPrice']) &&\n (wire['currentSqrtPrice'] !== undefined || wire['currentPrice'] !== undefined) &&\n (wire['newSqrtPrice'] !== undefined || wire['newPrice'] !== undefined)\n );\n}\n\nfunction optionalPositiveDecimal(value: unknown): boolean {\n if (value === undefined) return true;\n if (typeof value !== 'string') return false;\n try {\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — this validates an untrusted backend field, so an unparseable value\n // must fail validation cleanly (INVALID_CHAIN_RESPONSE), not throw raw.\n const decimal = new BigNumber(value);\n return decimal.isFinite() && decimal.isGreaterThan(0);\n } catch {\n return false;\n }\n}\n\n/**\n * The ways the backend says a pair has no market at all: no pool at ANY fee tier (\"No pools found\n * with sufficient liquidity\") or a missing pool (\"Pool does not exist on the new DEX contract\").\n * A pool that exists but is too thin says \"Insufficient liquidity: ...\" instead.\n */\nconst NO_MARKET_MESSAGE = /no pool|no pools|pool does not exist/iu;\n\n/**\n * A token the DEX contract never registered: the backend's symbol registry answers\n * `Token <token> has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`\n * with an HTTP 400, naming the token exactly as the quote request sent it. That is a different\n * fact from \"no pool for this pair\" (the token itself is unknown), so it is `UNKNOWN_TOKEN` with\n * the token, not `NO_POOL_AVAILABLE`. Token class keys and symbols contain no whitespace.\n */\nconst NO_SYMBOL_MESSAGE = /Token (\\S+) has no trading symbol on the new DEX contract/u;\n\n/** The token the quote request named in the form the caller gave it, else as the backend echoed it. */\nfunction unknownTokenOf(\n echoed: string,\n queried: { tokenIn: string; tokenOut: string },\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n): TokenRef {\n if (echoed === queried.tokenIn) return tokenIn;\n if (echoed === queried.tokenOut) return tokenOut;\n return echoed;\n}\n\nfunction mapQuoteError(\n error: unknown,\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER | undefined,\n queried: { tokenIn: string; tokenOut: string },\n): GSwapSDKError {\n if (isGSwapError(error)) {\n // The backend's own English is read ONLY to classify its answer; it is never surfaced. The\n // SDK's generated `message` is never matched: its templates are not a contract.\n const message = readServerMessage(error) ?? '';\n const unregistered = NO_SYMBOL_MESSAGE.exec(message)?.[1];\n if (unregistered !== undefined) {\n return GSwapSDKError.unknownTokenError(\n unknownTokenOf(unregistered, queried, tokenIn, tokenOut),\n error,\n );\n }\n if (error.status === 404 || NO_MARKET_MESSAGE.test(message)) {\n return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee, error);\n }\n if (error.status === 400 && /insufficient liquidity/iu.test(message)) {\n return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee, error);\n }\n return error;\n }\n return new GSwapSDKError(\n 'REQUEST_FAILED',\n { operation: 'quote' },\n { cause: error, write: false },\n );\n}\n\nfunction validateOptionalFee(fee: FEE_TIER | undefined): void {\n if (fee !== undefined && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: Number(fee),\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\nfunction toDecimalString(amount: NumericAmount): string {\n return new BigNumber(amount).toFixed();\n}\n","import { getStringProperty, GSwapSDKError } from './gswap_sdk_error.js';\n\n/** The raw answer to a shadow (dark) write: every HTTP status resolves. */\nexport interface ShadowSubmitResult {\n httpStatus: number;\n /** Parsed JSON body, or the raw text when the body was not JSON. */\n body: unknown;\n}\n\n/**\n * Machine-readable codes the swap backend returns in a shadow failure body (`{ code, message }`, with\n * no `statusCode`; the HTTP status carries the number).\n *\n * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back\n * silently to a public swap.\n * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.\n * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;\n * `message` is the gateway's verbatim string.\n */\nexport const SHADOW_SUBMIT_CODES = [\n 'SHADOW_UNAVAILABLE',\n 'SHADOW_UNSUPPORTED_TYPE',\n 'SHADOW_RELAY_REJECTED',\n] as const;\n\n/** One member of {@link SHADOW_SUBMIT_CODES}. */\nexport type ShadowSubmitCode = (typeof SHADOW_SUBMIT_CODES)[number];\n\n/**\n * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text\n * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route\n * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow\n * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)\n * and `unknown`.\n */\nexport const SHADOW_FAILURE_KINDS = ['unavailable', 'disabled', 'rejected', 'unknown'] as const;\n\n/** One member of {@link SHADOW_FAILURE_KINDS}. */\nexport type ShadowFailureKind = (typeof SHADOW_FAILURE_KINDS)[number];\n\n/** A RequestTrade the gateway queued: the handle to confirm it with `confirmAppliedTrade`. */\nexport interface ShadowQueuedRequest {\n uniqueKey: string;\n requestTransactionId: string | null;\n}\n\n/** A shadow write the gateway refused or did not answer: `kind` says why (see {@link SHADOW_FAILURE_KINDS}). */\nexport type ShadowSubmitFailure =\n | { ok: false; kind: 'unavailable'; retryable: true }\n | { ok: false; kind: 'disabled'; retryable: false }\n | { ok: false; kind: 'rejected'; retryable: false; message: string }\n | { ok: false; kind: 'unknown'; retryable: false };\n\n/**\n * The normalized outcome of a shadow RequestTrade (a dark swap). A success (`ok: true`) ALWAYS\n * carries `queued`, the exact key the gateway acknowledged: a RequestTrade answer that does not\n * queue the signed key is not an outcome but a thrown `SHADOW_NOT_QUEUED`. So after `if (outcome.ok)`\n * the app reads `outcome.queued` with no `undefined` branch.\n */\nexport type ShadowSubmitOutcome =\n | {\n ok: true;\n /** The request transaction id (`''` when the gateway gave none). */\n bundleId: string;\n /** Confirm with `confirmAppliedTrade`. */\n queued: ShadowQueuedRequest;\n }\n | ShadowSubmitFailure;\n\n/**\n * The success of a shadow write that is NOT a RequestTrade and executed synchronously\n * (`mode: 'sync'`, a liquidity write): there is nothing queued to confirm, so `queued` is absent.\n */\nexport interface ShadowSyncSuccess {\n ok: true;\n /** The transaction id (`''` when the gateway gave none). */\n bundleId: string;\n queued?: undefined;\n}\n\n/** Maps an HTTP status to a failure kind: 503 retryable, 400 disabled, anything else unknown. */\nexport function classifyShadowSubmitStatus(status: number): ShadowFailureKind {\n if (status === 503) return 'unavailable';\n if (status === 400) return 'disabled';\n return 'unknown';\n}\n\n/**\n * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.\n * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway\n * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to \"disabled\".\n */\nexport function classifyShadowSubmitError(status: number, code?: string): ShadowFailureKind {\n if (code === 'SHADOW_UNAVAILABLE') return 'unavailable';\n if (code === 'SHADOW_RELAY_REJECTED') return 'rejected';\n if (code === 'SHADOW_UNSUPPORTED_TYPE') return 'disabled';\n return classifyShadowSubmitStatus(status);\n}\n\n/**\n * Normalizes a shadow write's raw answer. For `'RequestTrade'` the result is a\n * {@link ShadowSubmitOutcome}, whose success always has `queued`; any other method may also be a\n * {@link ShadowSyncSuccess} (no `queued`).\n *\n * A 2xx envelope with `error === false` is a success when it is a queued RequestTrade that\n * acknowledges the EXACT signed `uniqueKey`, or a synchronous (`mode: 'sync'`) liquidity write.\n * Everything else is classified as a failure from the status and the body's `code`.\n *\n * @throws GSwapSDKError SHADOW_NOT_QUEUED when a RequestTrade success does not queue the\n * signed `uniqueKey` (a synchronous or mismatched answer must never be accepted as a swap).\n */\nexport function readShadowSubmitOutcome(\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess;\nexport function readShadowSubmitOutcome(\n method: string,\n signedBody: Record<string, unknown>,\n result: ShadowSubmitResult,\n): ShadowSubmitOutcome | ShadowSyncSuccess {\n const { httpStatus, body } = result;\n const envelope = asRecord(body);\n if (httpStatus >= 200 && httpStatus < 300 && envelope?.['error'] === false) {\n const data = asRecord(envelope['data']);\n const rawTransactionId =\n typeof data?.['transactionId'] === 'string' ? data['transactionId'] : undefined;\n if (method === 'RequestTrade') {\n const requestedKey = signedBody['uniqueKey'];\n if (\n data?.['mode'] !== 'queued' ||\n typeof requestedKey !== 'string' ||\n data['uniqueKey'] !== requestedKey\n ) {\n throw new GSwapSDKError(\n 'SHADOW_NOT_QUEUED',\n {},\n {\n status: httpStatus,\n body,\n shadow: true,\n ...(typeof requestedKey === 'string' ? { uniqueKey: requestedKey } : {}),\n },\n );\n }\n return {\n ok: true,\n bundleId: rawTransactionId ?? '',\n queued: { uniqueKey: requestedKey, requestTransactionId: rawTransactionId ?? null },\n };\n }\n if (data?.['mode'] === 'sync') return { ok: true, bundleId: rawTransactionId ?? '' };\n }\n\n const kind = classifyShadowSubmitError(httpStatus, getStringProperty(body, 'code'));\n if (kind === 'rejected') {\n return {\n ok: false,\n kind: 'rejected',\n retryable: false,\n message: getStringProperty(body, 'message') ?? '',\n };\n }\n return kind === 'unavailable'\n ? { ok: false, kind, retryable: true }\n : { ok: false, kind, retryable: false };\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n","import {\n assertUniqueKey,\n createUniqueKey,\n resolveUniqueKeyPrefix,\n signPreSend,\n type GalaChainSigner,\n type HttpRequestor,\n type UniqueKeyOptions,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport type { SwapAmount } from '../types/amounts.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { orderSymbols, readOrderedSymbols, type TokenRef } from '../utils/ordering.js';\nimport { assertCanonicalV2Dto, buildRequestTradeDto } from '../utils/dto_builders.js';\nimport { DEX_CONTRACT_PATH } from '../utils/chain_contract.js';\nimport { shadowFailures } from '../utils/shadow_errors.js';\nimport { assertCanonicalPair, userRef, validateFee } from '../utils/validation.js';\nimport type { ChainSubmitOptions } from './gateway.js';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\nimport {\n readShadowSubmitOutcome,\n type ShadowSubmitOutcome,\n type ShadowSubmitResult,\n} from './shadow_submit.js';\nimport { SubmittedTransaction } from './submitted_transaction.js';\nimport type { ConfirmOptions } from '../types/confirm_options.js';\nimport type { RequestTradeDTO } from '../types/v2_dtos.js';\nimport type { AppliedTrade, QuoteResult } from '../types/v2_results.js';\nimport { tradingSymbolOf, type TokenResolver } from './symbols.js';\n\ninterface SwapGateway {\n submit: (\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<SubmittedTransaction<AppliedTrade>>;\n submitShadow: (\n method: 'RequestTrade',\n signedBody: Record<string, unknown>,\n options?: ChainSubmitOptions,\n ) => Promise<ShadowSubmitResult>;\n readonly dexBackendBaseUrl: string;\n readonly httpRequestor: HttpRequestor;\n readonly requestTimeoutMs: number;\n readonly wire?: WireOptions | undefined;\n}\n\n/** The canonical pool a swap trades in, as a quote names it. */\nexport interface SwapPool {\n token0: string;\n token1: string;\n}\n\n/** Options of a swap. */\nexport interface SwapOptions {\n /**\n * The attempt's `uniqueKey` (1-128 characters of `A-Za-z0-9._:-`). Default: a fresh\n * `<uniqueKeyPrefix><uuid>`. Supply one to know the key before signing (to remember it, to\n * show it), or to retry the SAME attempt after a lost response; never reuse it for another trade.\n */\n uniqueKey?: string | undefined;\n /**\n * Pin the pool: take `token0` / `token1` verbatim from the quote the user saw, instead of\n * ordering `tokenIn` / `tokenOut` by string comparison. `tokenIn` and `tokenOut` must be exactly\n * these two symbols, and `token0` must sort before `token1`. See {@link swapRouteFromQuote}.\n */\n pool?: SwapPool | undefined;\n}\n\n/** Everything {@link Swaps.swap} needs to trade in the pool a quote priced. */\nexport interface SwapRoute {\n tokenIn: string;\n tokenOut: string;\n fee: FEE_TIER;\n pool: SwapPool;\n}\n\n/**\n * The route of a quote: its fee tier and pool, with `tokenIn` / `tokenOut` taken from\n * `tokenInIsToken0`, nothing re-derived. Use it to swap in exactly the pool a quote priced:\n *\n * @example\n * ```ts\n * const route = swapRouteFromQuote(quote);\n * await swaps.swap(route.tokenIn, route.tokenOut, route.fee, { exactIn: '100' }, { pool: route.pool });\n * ```\n */\nexport function swapRouteFromQuote(\n quote: Pick<QuoteResult, 'token0Symbol' | 'token1Symbol' | 'tokenInIsToken0' | 'fee'>,\n): SwapRoute {\n validateFee(quote.fee);\n assertCanonicalPair(quote.token0Symbol, quote.token1Symbol);\n const [tokenIn, tokenOut] = quote.tokenInIsToken0\n ? [quote.token0Symbol, quote.token1Symbol]\n : [quote.token1Symbol, quote.token0Symbol];\n return {\n tokenIn,\n tokenOut,\n fee: quote.fee,\n pool: { token0: quote.token0Symbol, token1: quote.token1Symbol },\n };\n}\n\n/** Executes queued current-contract RequestTrade operations through the Chain Gateway. */\nexport class Swaps {\n /**\n * Creates a swap service.\n *\n * @example\n * ```ts\n * const swaps = new Swaps(gateway, symbols, signer, 'client|alice');\n * ```\n */\n constructor(\n private readonly gateway: SwapGateway,\n private readonly symbols: TokenResolver,\n private readonly signer?: GalaChainSigner,\n walletAddress?: string,\n options: UniqueKeyOptions = {},\n ) {\n this.walletAddress =\n walletAddress === undefined ? undefined : userRef(walletAddress, 'walletAddress');\n this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);\n }\n\n /** The signing wallet in the gateway's spelling (`eth|<EIP-55>` or `client|<id>`). */\n private readonly walletAddress: string | undefined;\n private readonly uniqueKeyPrefix: string;\n\n /**\n * Signs and submits an exact-input or exact-output RequestTrade DTO. The returned transaction\n * is QUEUED; call `await tx.confirm()` to obtain the executed trade or chain rejection.\n *\n * @example\n * ```ts\n * const submitted = await swaps.swap('GALA', 'GUSDC', 3000, {\n * exactIn: '100',\n * amountOutMinimum: '14',\n * });\n * ```\n */\n public async swap(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<SubmittedTransaction<AppliedTrade>> {\n return this.submitSwap(await this.buildSwap(tokenIn, tokenOut, fee, amount, options));\n }\n\n /**\n * Signs and submits a SHADOW (dark) swap: the same RequestTrade as {@link swap}, relayed with\n * `X-Shadow: true` so the swap backend marks it private before it reaches the contract. Requires a\n * `walletAddress`. Resolves the normalized outcome instead of throwing on a gateway refusal:\n * `ok: false` carries `unavailable` (retryable), `disabled`, `rejected` (with the gateway's\n * message) or `unknown`. A success carries `queued`, to be confirmed with\n * `confirmSwap(queued.uniqueKey)`; never fall back to a public swap on failure. Whatever this\n * THROWS (a validation error, the signer, a lost connection, `SHADOW_NOT_QUEUED`) has\n * `error.shadow === true` (`isShadowError`), so an app can apply its dark-swap policy to it.\n *\n * @example\n * ```ts\n * const outcome = await swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * if (outcome.ok) await swaps.confirmSwap(outcome.queued.uniqueKey);\n * ```\n */\n public async swapShadow(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<ShadowSubmitOutcome> {\n return shadowFailures(async () =>\n this.submitSwapShadow(await this.buildSwap(tokenIn, tokenOut, fee, amount, options)),\n );\n }\n\n /**\n * Builds the RequestTrade DTO that {@link swap} would sign, without signing or sending it: to\n * show in an approval popup, to remember its `uniqueKey`, or to sign elsewhere. Submit exactly\n * this DTO with {@link submitSwap}. The pure counterpart, with canonical inputs and no\n * resolution, is `buildRequestTradeDto`.\n *\n * @example\n * ```ts\n * const dto = await swaps.buildSwap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * showApproval(dto);\n * const submitted = await swaps.submitSwap(dto);\n * ```\n */\n public async buildSwap(\n tokenIn: TokenRef,\n tokenOut: TokenRef,\n fee: FEE_TIER,\n amount: SwapAmount,\n options?: SwapOptions,\n ): Promise<RequestTradeDTO> {\n validateFee(fee);\n const uniqueKey = options?.uniqueKey ?? createUniqueKey(this.uniqueKeyPrefix);\n assertUniqueKey(uniqueKey);\n const tokenInSymbol = await tradingSymbolOf(this.symbols, tokenIn);\n const tokenOutSymbol = await tradingSymbolOf(this.symbols, tokenOut);\n const ordered = this.orientPool(tokenInSymbol, tokenOutSymbol, options?.pool);\n return buildRequestTradeDto({\n token0: ordered.token0,\n token1: ordered.token1,\n fee,\n tokenInIsToken0: tokenInSymbol === ordered.token0,\n uniqueKey,\n ...amount,\n });\n }\n\n /**\n * Signs and submits a DTO built by {@link buildSwap} or `buildRequestTradeDto`. The DTO must be\n * exactly what the builder produces (no signature, canonical decimals, builder key order), so\n * what an app showed is what gets signed.\n *\n * @example\n * ```ts\n * const submitted = await swaps.submitSwap(dto);\n * const applied = await submitted.confirm();\n * ```\n */\n public async submitSwap(dto: RequestTradeDTO): Promise<SubmittedTransaction<AppliedTrade>> {\n const signed = await this.signRequestTrade(dto);\n return this.gateway.submit('RequestTrade', signed, this.submitOptions());\n }\n\n /** Signs and shadow-submits a DTO built by {@link buildSwap}; see {@link swapShadow}. */\n public async submitSwapShadow(dto: RequestTradeDTO): Promise<ShadowSubmitOutcome> {\n return shadowFailures(async () => {\n const signed = await this.signRequestTrade(dto);\n const result = await this.gateway.submitShadow('RequestTrade', signed, this.submitOptions());\n return readShadowSubmitOutcome('RequestTrade', signed, result);\n });\n }\n\n private submitOptions(): ChainSubmitOptions {\n return this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress };\n }\n\n private async signRequestTrade(dto: RequestTradeDTO): Promise<Record<string, unknown>> {\n assertCanonicalV2Dto('RequestTrade', dto);\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n return signPreSend(this.signer, DEX_CONTRACT_PATH, 'RequestTrade', dto);\n }\n\n /** The pool's two symbols in contract order: the quote's own when pinned, else string order. */\n private orientPool(\n tokenInSymbol: string,\n tokenOutSymbol: string,\n pool: SwapPool | undefined,\n ): SwapPool {\n if (pool === undefined) {\n return readOrderedSymbols(orderSymbols(tokenInSymbol, tokenOutSymbol));\n }\n const sameSet =\n (tokenInSymbol === pool.token0 && tokenOutSymbol === pool.token1) ||\n (tokenInSymbol === pool.token1 && tokenOutSymbol === pool.token0);\n if (!sameSet) {\n throw new GSwapSDKError('POOL_MISMATCH', {\n tokenIn: tokenInSymbol,\n tokenOut: tokenOutSymbol,\n poolToken0: pool.token0,\n poolToken1: pool.token1,\n });\n }\n return { token0: pool.token0, token1: pool.token1 };\n }\n\n /**\n * Confirm a swap by its durable `uniqueKey` without resubmitting it. This is the recovery\n * path after a `CONFIRMATION_TIMEOUT`, a `SUBMISSION_OUTCOME_UNKNOWN`, a `409` replay\n * conflict, or a process restart: it reads the same apply-results record that\n * `SubmittedTransaction.confirm()` reads (retained for 7 days) and resolves the applied trade\n * or throws the chain's rejection. The first read happens immediately unless\n * `initialDelayMs` is given.\n *\n * @example\n * ```ts\n * const applied = await swaps.confirmSwap('galaswap-operation-2f1c…');\n * ```\n */\n public async confirmSwap(uniqueKey: string, options?: ConfirmOptions): Promise<AppliedTrade> {\n assertUniqueKey(uniqueKey);\n const transaction = new SubmittedTransaction<AppliedTrade>({\n method: 'RequestTrade',\n uniqueKey,\n transactionId: null,\n mode: 'queued',\n result: undefined,\n dexBackendBaseUrl: this.gateway.dexBackendBaseUrl,\n httpRequestor: this.gateway.httpRequestor,\n requestTimeoutMs: this.gateway.requestTimeoutMs,\n wire: this.gateway.wire,\n });\n return transaction.confirm({ initialDelayMs: 0, ...options });\n }\n}\n","import { Assets } from './assets.js';\nimport { DexFees } from './dex_fees.js';\nimport { ChainGateway } from './gateway.js';\nimport { GdexStreamService } from './gdex_stream.js';\nimport { HttpClient } from './http_client.js';\nimport { Leaderboard } from './leaderboard.js';\nimport { Market } from './market.js';\nimport { Onramper } from './onramper.js';\nimport { Pools } from './pools.js';\nimport { Positions } from './positions.js';\nimport { Quoting } from './quoting.js';\nimport type { GalaChainSigner, HttpRequestor, WireOptions } from '@gala-chain/gala-core-sdk';\nimport { CanonicalSymbols, Symbols } from './symbols.js';\nimport type { InvalidEntryHandler } from '../utils/lenient.js';\nimport { userRef } from '../utils/validation.js';\nimport { Swaps } from './swaps.js';\nimport type { GSwapEnv } from '../types/env.js';\nimport { GSWAP_ENVIRONMENTS } from '../types/env.js';\n\n/** Options for constructing a backend-routed SDK client. */\nexport interface GSwapOptions {\n /** Signs every write. Without one, reads work and any write throws `NO_SIGNER`. */\n signer?: GalaChainSigner | undefined;\n /**\n * The selected account, sent as `X-Wallet-Address` on writes (attribution only; the chain\n * recovers the signer from the signature). Required for shadow writes. Any spelling of an\n * Ethereum account (`eth|<40 hex>` in any casing, `0x...`, bare hex) is sent as `eth|<EIP-55>`,\n * `client|<id>` as written; a mixed-case spelling that is not the checksum is refused at\n * construction (`INVALID_WALLET_ADDRESS`), and `eth|0x...` (not an address form) is refused as\n * core's `INVALID_ETH_USER_REF_PREFIX`.\n */\n walletAddress?: string | undefined;\n /** `'stage'` or `'prod'` swap backend preset; defaults to `'prod'`. */\n env?: GSwapEnv | undefined;\n /** Overrides the preset's swap backend base URL (a test or private deployment). */\n dexBackendBaseUrl?: string | undefined;\n /** HTTP transport for every request; defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Request timeout in milliseconds (default 30 000); `Infinity` arms no timer. */\n chainCallTimeoutMs?: number | undefined;\n /** Query encoding and `User-Agent` of the read requests (see {@link WireOptions}). */\n wire?: WireOptions | undefined;\n /**\n * How tokens are turned into trading symbols. `'registry'` (default) reads the symbol registry\n * once (`GET /v2/trade/symbols`, cached) and accepts symbols or class keys. `'canonical'` makes\n * no registry request: the caller passes the backend's canonical trading symbols (from a quote,\n * an estimate or a position), reads send tokens and ticks exactly as given (composite keys\n * included) and the backend orients the pair; see {@link CanonicalSymbols}.\n */\n symbolResolution?: 'registry' | 'canonical' | undefined;\n /**\n * Told about every row of a pool, symbol, position, price, price-series, season or leaderboard\n * answer that was skipped as unusable (see {@link InvalidEntryHandler}); without it such rows are\n * skipped silently.\n */\n onInvalidEntry?: InvalidEntryHandler | undefined;\n /** Realtime stream endpoint. Defaults to the environment's, or is derived from `dexBackendBaseUrl`. */\n dexBackendWsUrl?: string | undefined;\n /** WebSocket constructor for the realtime stream; required on Node.js older than 22. */\n webSocketImpl?: unknown;\n /**\n * `x-api-key` for the privileged stream view; server-side only, and it requires `webSocketImpl`\n * (see `GdexStreamConfig.apiKey`).\n */\n streamApiKey?: string | undefined;\n /**\n * Prefix of every write's `uniqueKey` (`<prefix><uuid>`). Defaults to `galaswap-operation-`,\n * what the Gala Wallet and the gSwap web app send; the backend does not depend on it.\n */\n uniqueKeyPrefix?: string | undefined;\n}\n\n/**\n * Main entry point for the current GalaChainDex SDK: one client bundling the services that read\n * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,\n * `market`, `leaderboard`, `onramper`, `symbols`, `fees`, `stream`). See {@link GSwapOptions} for\n * configuration.\n */\nexport class GSwap {\n /** The swap backend base URL every request goes to, without a trailing slash. */\n public readonly dexBackendBaseUrl: string;\n /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */\n public readonly chainCallTimeoutMs: number;\n /** The signer given at construction, if any. */\n public readonly signer: GalaChainSigner | undefined;\n /**\n * The account given at construction, if any, in the gateway's spelling (`eth|<EIP-55>`;\n * `client|<id>` as given).\n */\n public readonly walletAddress: string | undefined;\n /** The chain-gateway client every other service reads and writes through. */\n public readonly gateway: ChainGateway;\n /** The trading-symbol registry. */\n public readonly symbols: Symbols;\n /** Read-only exact-input and exact-output quotes. */\n public readonly quoting: Quoting;\n /** Pool, slot0 and composite-pool reads. */\n public readonly pools: Pools;\n /** Position reads, liquidity estimates and liquidity / pool-creation writes. */\n public readonly positions: Positions;\n /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */\n public readonly swaps: Swaps;\n /** User token balances. */\n public readonly assets: Assets;\n /** USD prices, price series and the platform volume totals. */\n public readonly market: Market;\n /** Trading-competition seasons and rankings. */\n public readonly leaderboard: Leaderboard;\n /** The Onramper (fiat on-ramp) widget URL. */\n public readonly onramper: Onramper;\n /** Network-fee quotes (DryRun) signed with this client's signer. */\n public readonly fees: DexFees;\n /** The realtime stream endpoint {@link GSwap.stream} connects to. */\n public readonly dexBackendWsUrl: string;\n private readonly webSocketImpl: unknown;\n private readonly streamApiKey: string | undefined;\n private streamClient: GdexStreamService | undefined;\n\n /**\n * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * const symbols = await gSwap.symbols.list();\n * ```\n */\n constructor(options?: GSwapOptions) {\n const environment = GSWAP_ENVIRONMENTS[options?.env ?? 'prod'];\n this.dexBackendBaseUrl = trimTrailingSlash(\n options?.dexBackendBaseUrl ?? environment.dexBackendBaseUrl,\n );\n this.chainCallTimeoutMs = options?.chainCallTimeoutMs ?? 30_000;\n this.signer = options?.signer;\n this.walletAddress =\n options?.walletAddress === undefined\n ? undefined\n : userRef(options.walletAddress, 'walletAddress');\n\n const httpClient = new HttpClient(\n options?.httpRequestor,\n this.chainCallTimeoutMs,\n options?.wire,\n );\n this.gateway = new ChainGateway({\n dexBackendBaseUrl: this.dexBackendBaseUrl,\n chainCallTimeoutMs: this.chainCallTimeoutMs,\n ...(options?.wire === undefined ? {} : { wire: options.wire }),\n ...(options?.httpRequestor === undefined ? {} : { httpRequestor: options.httpRequestor }),\n ...(this.walletAddress === undefined ? {} : { walletAddress: this.walletAddress }),\n });\n const lenient = { onInvalidEntry: options?.onInvalidEntry };\n this.symbols = new Symbols(this.gateway, lenient);\n // The services resolve tokens through the registry by default; the offline resolver sends the\n // caller's canonical symbols and keys as they are and never reads the registry.\n const resolver =\n options?.symbolResolution === 'canonical' ? new CanonicalSymbols() : this.symbols;\n this.quoting = new Quoting(this.gateway, resolver);\n this.pools = new Pools(this.gateway, resolver, lenient);\n const keyOptions = { uniqueKeyPrefix: options?.uniqueKeyPrefix, ...lenient };\n this.positions = new Positions(\n this.gateway,\n resolver,\n this.signer,\n this.walletAddress,\n keyOptions,\n );\n this.swaps = new Swaps(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);\n this.assets = new Assets(this.dexBackendBaseUrl, httpClient);\n this.market = new Market(this.dexBackendBaseUrl, httpClient, lenient);\n this.leaderboard = new Leaderboard(this.dexBackendBaseUrl, httpClient, lenient);\n this.onramper = new Onramper(this.dexBackendBaseUrl, httpClient);\n this.fees = new DexFees(this.gateway, this.signer);\n this.dexBackendWsUrl =\n options?.dexBackendWsUrl ??\n (options?.dexBackendBaseUrl === undefined\n ? environment.dexBackendWsUrl\n : `${this.dexBackendBaseUrl.replace(/^http/u, 'ws')}/ws`);\n this.webSocketImpl = options?.webSocketImpl;\n this.streamApiKey = options?.streamApiKey;\n }\n\n /**\n * The realtime stream client for this environment (created on first use, not connected until you\n * call `connect()`).\n *\n * @example\n * ```typescript\n * const gSwap = new GSwap({ env: 'stage' });\n * await gSwap.stream.connect();\n * await gSwap.stream.subscribeLiquidity((event) => console.log(event.action, event.amount0));\n * ```\n */\n get stream(): GdexStreamService {\n this.streamClient ??= new GdexStreamService({\n url: this.dexBackendWsUrl,\n ...(this.webSocketImpl === undefined ? {} : { webSocketImpl: this.webSocketImpl }),\n ...(this.streamApiKey === undefined ? {} : { apiKey: this.streamApiKey }),\n });\n return this.streamClient;\n }\n}\n\nfunction trimTrailingSlash(value: string): string {\n return value.replace(/\\/$/u, '');\n}\n","import type { FailureOutcome } from '@gala-chain/gala-core-sdk';\n\n/**\n * The classification values an app shell may need on their own: what an outcome allows. This module\n * is deliberately tiny and imports nothing at run time (the outcome type is erased), so an app\n * shell that builds `classification('not_sent')` or reads `NOT_QUEUED_FINAL` loads a few hundred\n * bytes, not the table of error codes that lives with `classifyFailure`.\n */\n\n/** The result of `classifyFailure`. */\nexport interface FailureClassification {\n readonly outcome: FailureOutcome;\n /**\n * May the app offer the user Retry: repeat the operation as a NEW request (a fresh key for a\n * write) without any risk of applying it twice? Always `false` for `unknown` (confirm the same\n * key instead) and `invalid_input` (the same call fails again). It says a repeat is SAFE, not\n * that it will succeed, and it is the SDK's floor: an app may still withhold Retry (the\n * Gala Wallet does after a Dark swap: see `isShadowError`).\n */\n readonly retryable: boolean;\n}\n\n/**\n * The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the\n * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.\n */\nconst DEFAULT_RETRYABLE = {\n rejected: true,\n unknown: false,\n not_queued: true,\n not_sent: true,\n invalid_input: false,\n transient: true,\n} as const satisfies Record<FailureOutcome, boolean>;\n\n/**\n * Builds the classification the SDK itself gives an outcome, so an app that classifies a step of\n * its OWN (one that is not an SDK call) uses the SDK's type and its values instead of a\n * hard-coded `{ outcome, retryable }` literal. `retryable` is the SDK's default for that outcome\n * (`false` for `unknown` and `invalid_input`, `true` for the rest). Each call returns a new\n * object, safe to mutate or freeze.\n *\n * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the\n * SDK's own `not_queued` for a refusal the gateway will repeat is\n * `classification('not_queued', { retryable: false })` (also exported, frozen, as\n * {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one\n * that cannot have it, so only `false` is accepted.\n *\n * @example\n * ```ts\n * // The app refreshes a quote before it asks the SDK to sign; the refresh failed.\n * throw new AppSwapError(text, classification('not_sent'));\n * // The app refuses a request for a reason a repeat cannot fix.\n * throw new AppSwapError(text, classification('not_queued', { retryable: false }));\n * ```\n */\nexport function classification(\n outcome: FailureOutcome,\n options: { readonly retryable?: false } = {},\n): FailureClassification {\n return { outcome, retryable: options.retryable === false ? false : DEFAULT_RETRYABLE[outcome] };\n}\n\n/**\n * `classification('not_queued', { retryable: false })`: the gateway refused the write before\n * queueing it AND will refuse a repeat the same way (the version wall, a dark swap that did not\n * queue, an HTTP 4xx). Nothing is pending and Retry is not offered. It is frozen: use it as it is\n * (`classification: NOT_QUEUED_FINAL`) instead of spreading `classification('not_queued')` and\n * overriding `retryable`; `{ ...NOT_QUEUED_FINAL }` is a mutable copy.\n */\nexport const NOT_QUEUED_FINAL: Readonly<FailureClassification> = Object.freeze(\n classification('not_queued', { retryable: false }),\n);\n\n/**\n * `classification('not_sent')`: a step of the app's own failed before anything was signed or\n * sent (a quote refresh, a balance read), so nothing is pending and a repeat is safe.\n */\nexport function notSentClassification(): FailureClassification {\n return classification('not_sent');\n}\n","import {\n isWriteView,\n numberParamOf,\n stringParamOf,\n toFailureView,\n type FailureView,\n type GALA_ERROR_CATALOG,\n} from '@gala-chain/gala-core-sdk';\nimport type { GSWAP_ERROR_CATALOG, GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport { isCatalogCode } from '../classes/gswap_error_phase_table.js';\nimport { classification, NOT_QUEUED_FINAL, type FailureClassification } from './classification.js';\n\n/**\n * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every\n * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing\n * else: the classification values live in `classification.ts`, the yes/no guards in\n * `failure_guards.ts`, and the error class and catalog are only named as types.\n */\n\nconst REJECTED: FailureClassification = classification('rejected');\nconst UNKNOWN: FailureClassification = classification('unknown');\nconst NOT_QUEUED: FailureClassification = classification('not_queued');\nconst NOT_SENT: FailureClassification = classification('not_sent');\nconst INVALID_INPUT: FailureClassification = classification('invalid_input');\nconst TRANSIENT: FailureClassification = classification('transient');\n\n/**\n * The classification of every code whose meaning does not depend on the failing answer. A code\n * missing here is a compile error (unless it is `pre_send`, see {@link CodeTable}), so adding a\n * catalog code forces a decision.\n */\nconst BY_CODE = {\n // ----------------------------------------------------------------------------------- transport\n REQUEST_TIMEOUT: TRANSIENT,\n TRANSPORT_ERROR: TRANSIENT,\n REQUEST_FAILED: TRANSIENT,\n\n // ------------------------------------------------------------------------------- write: unknown\n // No answer was read, or a 2xx answer that does not prove the write was queued under the signed\n // key: it may have been applied.\n SUBMISSION_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_REPORTED_ERROR: UNKNOWN,\n GATEWAY_DATA_MISSING: UNKNOWN,\n GATEWAY_MODE_INVALID: UNKNOWN,\n GATEWAY_SYNC_REQUEST_TRADE: UNKNOWN,\n MISSING_UNIQUE_KEY: UNKNOWN,\n UNIQUE_KEY_MISMATCH: UNKNOWN,\n // Core `GatewayWrites` (token-contract writes): no answer read, or a 2xx that proves nothing.\n GATEWAY_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n GATEWAY_RESPONSE_INVALID: UNKNOWN,\n // Core `./bridge` (GalaConnect bridge writes): a 2xx without the id or hash the next step needs,\n // or no answer read after the request left.\n BRIDGE_RESPONSE_INVALID: UNKNOWN,\n BRIDGE_WRITE_OUTCOME_UNKNOWN: UNKNOWN,\n // Any failure after GalaConnect accepted a bridge-out request: the tokens may be locked, so\n // never a retry under a fresh key, whatever the inner failure (a BridgeTokenOut 429 included).\n BRIDGE_OUT_OUTCOME_UNKNOWN: UNKNOWN,\n // A bridge-in deposit that failed once it was being sent (sending, confirming, registering): the\n // funds may have left the wallet. A status wait that timed out: the bridge may still complete.\n BRIDGE_DEPOSIT_OUTCOME_UNKNOWN: UNKNOWN,\n BRIDGE_STATUS_TIMEOUT: UNKNOWN,\n\n // --------------------------------------------------------------------- write: refused, not queued\n SHADOW_NOT_QUEUED: NOT_QUEUED_FINAL,\n METHOD_NOT_ALLOWED: NOT_QUEUED,\n SIGNATURE_INVALID: NOT_QUEUED,\n SIGNER_MISMATCH: NOT_QUEUED,\n DTO_INVALID: NOT_QUEUED,\n DTO_OPERATION_MISMATCH: NOT_QUEUED,\n BOUNDS_VIOLATION: NOT_QUEUED,\n SYMBOL_CONFLICT: NOT_QUEUED,\n RATE_LIMITED: NOT_QUEUED,\n GATEWAY_REJECTED: NOT_QUEUED,\n\n // ----------------------------------------------------------------------- the chain's own verdict\n CHAIN_REJECTED: REJECTED,\n\n // ----------------------------------------------------------------------- reads of backend data\n INVALID_CHAIN_RESPONSE: TRANSIENT,\n INVALID_POSITION_RESPONSE: TRANSIENT,\n // Core `GatewayReads` (unsigned token-contract reads): nothing is applied, so a refusal or an\n // unusable answer is worth another try; a class that does not exist, or a data set larger than\n // the caller allowed, needs a different request.\n GATEWAY_READ_REJECTED: TRANSIENT,\n GATEWAY_READ_RESPONSE_INVALID: TRANSIENT,\n // Core `./bridge` GalaConnect reads (configurations, fee, status): the same as a gateway read;\n // a symbol GalaConnect has no verified configuration for needs a different request.\n BRIDGE_READ_RESPONSE_INVALID: TRANSIENT,\n BRIDGE_TOKEN_NOT_FOUND: INVALID_INPUT,\n // A token the wrappable list does not have (or its counterpart, or a channel a wrap does not\n // move between): a different request is needed.\n TOKEN_NOT_WRAPPABLE: INVALID_INPUT,\n // A failed or unusable read of the external chain before a bridge-in deposit: nothing was sent.\n BRIDGE_CHAIN_READ_FAILED: TRANSIENT,\n TOKEN_CLASS_NOT_FOUND: INVALID_INPUT,\n PAGINATION_LIMIT_EXCEEDED: INVALID_INPUT,\n\n // -------------------------------------------------------------------------------- confirmation\n CONFIRMATION_TIMEOUT: UNKNOWN,\n CONFIRMATION_ABORTED: UNKNOWN,\n CONFIRMATION_FAILED: UNKNOWN,\n CONFIRMATION_MALFORMED: UNKNOWN,\n CONFIRMATION_KEY_MISMATCH: UNKNOWN,\n\n // ------------------------------------------------------------------------------ the realtime stream\n STREAM_DISCONNECTED: TRANSIENT,\n STREAM_REQUEST_TIMEOUT: TRANSIENT,\n STREAM_CONNECT_FAILED: TRANSIENT,\n STREAM_CLOSED_BEFORE_CONNECT: TRANSIENT,\n STREAM_CONNECTION_CLOSED: TRANSIENT,\n\n // ----------------------------------------------- pre-send: an app-supplied callback failed\n // The signer, the key provider or the token resolver threw before anything was transmitted. The\n // original error is `cause`. A repeat cannot apply anything twice.\n SIGNING_FAILED: NOT_SENT,\n KEY_PROVIDER_FAILED: NOT_SENT,\n TOKEN_RESOLUTION_FAILED: NOT_SENT,\n TOKEN_NAME_RESOLUTION_FAILED: NOT_SENT,\n\n // ------------------------------------------- the call cannot work as written, found AFTER an answer\n // (a pre_send code needs no row: it is `invalid_input` by default, see `CodeTable`)\n NO_WALLET_ADDRESS: INVALID_INPUT,\n NO_POOL_AVAILABLE: INVALID_INPUT,\n INSUFFICIENT_LIQUIDITY: INVALID_INPUT,\n} as const satisfies CodeTable;\n\n/** Both catalogs as one type: every code a `GSwapSDKError` can carry reads its entry here. */\ntype Catalogs = typeof GALA_ERROR_CATALOG & typeof GSWAP_ERROR_CATALOG;\n\n/** A code (core or DEX) whose catalog phase is `pre_send`. */\ntype PreSendCode = {\n [C in GSwapErrorCode]: Catalogs[C]['phase'] extends 'pre_send' ? C : never;\n}[GSwapErrorCode];\n\n/** The codes whose classification depends on the failing answer, not on a table row. */\ntype AnswerDependentCode =\n | 'HTTP_ERROR'\n | 'UPDATE_REQUIRED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'INVALID_PRIVATE_KEY'\n | 'GATEWAY_HTTP_ERROR'\n | 'GALACONNECT_HTTP_ERROR'\n | 'GATEWAY_WRITE_REJECTED'\n | 'BRIDGE_REQUEST_REJECTED';\n\n/**\n * Every code that is NOT `pre_send` needs a row (a new one is a compile error until it has one);\n * a `pre_send` code may have one (`SIGNING_FAILED` is `not_sent`). A `pre_send` code without a row\n * is `invalid_input`: nothing was transmitted, so it cannot be `unknown`, and it is not a\n * condition a repeat clears. That keeps the 90-odd validation codes out of the table, which is\n * what keeps `classifyFailure` small enough for an app shell.\n */\ntype CodeTable = {\n readonly [C in Exclude<GSwapErrorCode, PreSendCode | AnswerDependentCode>]: FailureClassification;\n} & {\n readonly [C in Exclude<PreSendCode, AnswerDependentCode>]?: FailureClassification;\n};\n\n/**\n * A key that is not valid is the input's fault (`invalid_input`), except `no_key_provided`: the\n * provider had nothing to give right now (a locked wallet, an empty slot). That is the same\n * situation as a provider that throws (`KEY_PROVIDER_FAILED`), and it clears once a key exists, so\n * it is `not_sent` and Retry is safe.\n */\nfunction classifyInvalidPrivateKey(view: FailureView): FailureClassification {\n return stringParamOf(view, 'reason') === 'no_key_provided' ? NOT_SENT : INVALID_INPUT;\n}\n\n/** The status of an HTTP failure: the one it carries, else its `status` param. */\nfunction statusOfView(view: FailureView): number | undefined {\n return view.status ?? numberParamOf(view, 'status');\n}\n\n/**\n * An HTTP failure with no gateway or chain code: its meaning depends on the status and on read vs\n * write. A view that states no status at all cannot be judged: `unknown`.\n */\nfunction classifyHttpError(view: FailureView): FailureClassification {\n const status = statusOfView(view);\n if (status === undefined) return UNKNOWN;\n if (isWriteView(view)) {\n // A gateway that answered 5xx or 408 may still have queued the write; 429 and 4xx did not.\n if (status === 429) return NOT_QUEUED;\n if (status === 408 || status >= 500) return UNKNOWN;\n return NOT_QUEUED_FINAL;\n }\n return status === 408 || status === 429 || status >= 500 ? TRANSIENT : INVALID_INPUT;\n}\n\n/**\n * A core `./bridge` GalaConnect HTTP failure: like {@link classifyHttpError}, except that a\n * WRITE answered 409 is `unknown`: GalaChain's \"this uniqueKey was already consumed\", after which\n * an earlier attempt under the key may be applied (a bridge-out that locked the tokens).\n */\nfunction classifyGalaConnectHttpError(view: FailureView): FailureClassification {\n return isWriteView(view) && statusOfView(view) === 409 ? UNKNOWN : classifyHttpError(view);\n}\n\n/**\n * The version wall (HTTP 426). On a write the gateway refused it before queueing anything, and a\n * repeat of the same app version is refused the same way, so it is `not_queued` with no Retry. On a\n * read nothing changed either, and only an update helps: `invalid_input`, no Retry. Both say \"show\n * the update screen\", not \"try again\".\n */\nfunction classifyUpdateRequired(view: FailureView): FailureClassification {\n return isWriteView(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;\n}\n\n/**\n * The chain dispatch failed. The gateway echoes the upstream status: 409 is \"this uniqueKey was\n * already consumed\" (the first attempt may be applied), 422 is the chain evaluating the write and\n * refusing it (definite), another 5xx is an upstream outage after which the write may have landed,\n * and a 4xx is a refusal before anything was queued.\n */\nfunction classifyChainDispatchFailed(view: FailureView): FailureClassification {\n const status = view.status;\n if (status === undefined || status === 409 || status >= 500) return UNKNOWN;\n return status === 422 ? REJECTED : NOT_QUEUED;\n}\n\n/**\n * GalaChain answered a core `GatewayWrites` token-contract write with a `Status` other than 1: the\n * chain's verdict, so the write was not applied (`rejected`), except where the verdict does not\n * prove that: a 409 is \"this uniqueKey was already consumed\" (an earlier attempt under it may be\n * applied), and a 5xx, or no status at all, cannot be judged.\n */\nfunction classifyGatewayWriteRejected(view: FailureView): FailureClassification {\n const status = view.status;\n return status === undefined || status === 409 || status >= 500 ? UNKNOWN : REJECTED;\n}\n\n/**\n * Classifies any thrown value from its code (and, for a few codes, its HTTP status), never from\n * message text, so an app does not have to re-derive \"may I offer Retry?\" and \"is the outcome\n * unknown?\" for every code. The decision for each code is in this module's table; a new catalog\n * code cannot be added without one.\n *\n * A failure BEFORE the request left (`error.phase === 'pre_send'`, `isPreSendError`) can never be\n * `unknown` or `rejected`: it is `invalid_input` (the input has to change) or `not_sent` (nothing\n * was transmitted; a repeat is safe). Every app-supplied callback the SDK calls before it sends\n * (the signer, the key provider, a token resolver) has its failure wrapped into such an error\n * (`SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, the original as `cause`),\n * so an app NEVER needs an error class of its own to say \"nothing was sent\": a locked wallet,\n * a declined signature and a failed lookup all arrive as `not_sent`, retryable.\n *\n * It accepts a `GSwapSDKError` or a plain-object VIEW of one ({@link FailureView}: `{ code,\n * params?, status?, uniqueKey?, ... }`, the shape of the wrapper an app builds from an SDK error;\n * `toFailureView` reads any value), and decides from the same fields, so an app does not need to\n * keep the original error to ask. `{ afterQueued: true }` says the write is already queued (the\n * step being classified is a confirmation): `retryable` is then always `false`.\n *\n * Anything that is not an SDK error or such a view, or a view whose `code` the catalog does not\n * define, is `{ outcome: 'unknown', retryable: false }`: the SDK\n * cannot say what happened, and refusing Retry is the safe answer. That is only what escapes AFTER\n * the request left (an app requestor that rejects with its own error, a callback of yours that\n * throws once bytes were sent). An error your own code raises BEFORE it calls the SDK says so\n * itself: give it a code of its own and `outcome` (`{ code: 'POSITION_STALE', outcome: 'not_sent'\n * }`), and the SDK answers with that outcome's classification and `mayHaveBeenQueued` is `false`.\n * The declared `outcome` is read only for a code the catalog does not define.\n *\n * A failure is a WRITE's unless it states `write: false` (`GSwapSDKError.write`, set for every\n * SDK read): see {@link FailureView}. A view that lost its `uniqueKey` is therefore still judged as\n * a write (a 5xx stays `unknown`), never as a retryable read.\n *\n * To learn that a failure came from the dark (shadow) path, read `error.shadow` (a typed field of\n * every `GSwapSDKError`) or call `isShadowError(error)`, which also covers a non-SDK object that\n * escaped `swapShadow` / `submitSwapShadow` / `ChainGateway.submitShadow`. The classification is\n * the same as on the public path; an app that withholds Retry or a public fallback after a dark\n * swap applies that policy on top of `retryable`.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * const { outcome, retryable } = classifyFailure(error);\n * if (outcome === 'unknown') keepPendingAndConfirm(error); // never a second swap\n * else if (retryable) offerRetry(); // a new request under a fresh key\n * }\n * ```\n */\nexport function classifyFailure(\n error: unknown,\n options: ClassifyFailureOptions = {},\n): FailureClassification {\n const result = classifyView(toFailureView(error));\n // A `rejected` outcome is the chain's definite no: the queued write was evaluated and NOT\n // applied, so a new request under a fresh key cannot double-apply it and Retry stays as it is.\n return options.afterQueued === true && result.outcome !== 'rejected'\n ? { ...result, retryable: false }\n : result;\n}\n\n/** Options of {@link classifyFailure}. */\nexport interface ClassifyFailureOptions {\n /**\n * The write is ALREADY queued (the gateway acknowledged it with this `uniqueKey`), and what is\n * being classified is a later step: confirming it, reading its apply result. Whatever the\n * outcome, `retryable` is then `false`: a NEW request would be a second trade, so the app\n * confirms the same key (or forgets it) and never offers \"Try again\". `outcome` is unchanged.\n *\n * The one exception is `rejected`: the chain evaluated the queued write and refused it (an\n * apply result of `Status: 0`, `CHAIN_REJECTED`; a 422 dispatch). That PROVES it was not\n * applied, so a new request under a fresh key cannot make a second trade, and `retryable`\n * keeps the answer it has without this option (`true`). Every outcome that does not prove\n * \"not applied\" (`unknown`, `transient`, `not_queued`, ...) is `false`.\n */\n afterQueued?: boolean | undefined;\n}\n\n/**\n * The classification of a failure view: the table decision for its code, the status-dependent\n * decision for the codes whose meaning needs it, and for a code the catalog does not define\n * (a wallet error, an ethers `ACTION_REJECTED`, a typo, an app's own error): `unknown` unless the\n * view DECLARES its `outcome` (an app's error, `{ code: 'POSITION_STALE', outcome: 'not_sent' }`),\n * then the SDK's own classification of that outcome. A value with no view is `unknown`.\n */\nfunction classifyView(view: FailureView | undefined): FailureClassification {\n if (view === undefined) return { ...UNKNOWN };\n if (!isCatalogCode(view.code)) {\n if (view.outcome === undefined) return { ...UNKNOWN };\n // Withhold-only: `retryable: false` removes Retry from the declared outcome, never adds it.\n return view.retryable === false\n ? classification(view.outcome, { retryable: false })\n : classification(view.outcome);\n }\n const { code } = view;\n // A core gateway HTTP failure without a chain envelope reads exactly like HTTP_ERROR (by its\n // status, and read vs write); so does a GalaConnect one, except a write's 409.\n if (code === 'HTTP_ERROR' || code === 'GATEWAY_HTTP_ERROR') {\n return { ...classifyHttpError(view) };\n }\n if (code === 'GALACONNECT_HTTP_ERROR') return { ...classifyGalaConnectHttpError(view) };\n // GalaChain's refusal of a core gateway or GalaConnect bridge write: by the chain's code.\n if (code === 'GATEWAY_WRITE_REJECTED' || code === 'BRIDGE_REQUEST_REJECTED') {\n return { ...classifyGatewayWriteRejected(view) };\n }\n if (code === 'UPDATE_REQUIRED') return { ...classifyUpdateRequired(view) };\n if (code === 'CHAIN_DISPATCH_FAILED') return { ...classifyChainDispatchFailed(view) };\n if (code === 'INVALID_PRIVATE_KEY') return { ...classifyInvalidPrivateKey(view) };\n const row: FailureClassification | undefined = (\n BY_CODE as Readonly<Partial<Record<GSwapErrorCode, FailureClassification>>>\n )[code];\n return { ...(row ?? INVALID_INPUT) };\n}\n\n/**\n * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is\n * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after\n * the request left, an acknowledgement that proves nothing, a gateway 409 or 5xx, a failed\n * confirmation). The app must keep `error.uniqueKey` and confirm it, and must NOT submit again\n * under a fresh key. Every other outcome (`rejected`, `not_queued`, `not_sent`, `invalid_input`,\n * `transient`) proves the write is not pending.\n *\n * A value the SDK cannot judge (an app requestor's own rejection after the request left) is\n * `unknown` too, so it is `true`; handle errors your own code raised BEFORE calling the SDK first.\n * Meant for the catch of a write; a read never has a pending key to keep.\n *\n * @example\n * ```ts\n * try {\n * await swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' });\n * } catch (error) {\n * if (mayHaveBeenQueued(error)) keepPendingAndConfirm(error);\n * }\n * ```\n */\nexport function mayHaveBeenQueued(error: unknown): boolean {\n return classifyFailure(error).outcome === 'unknown';\n}\n","import { classifyFailure } from '../utils/failure_classification.js';\nimport type { FailureOutcome } from '@gala-chain/gala-core-sdk';\n\n/**\n * What to do with a pending swap after confirming it failed (the answer of\n * {@link pendingSwapFateFor}).\n *\n * - `forget`: the chain REFUSED the trade, so it did not happen. Drop it AND tell the user.\n * - `forget_quietly`: the confirmation can never succeed (the key is refused: `invalid_input`).\n * Drop it without claiming anything about the trade.\n * - `keep`: the trade may still have been applied (a timeout, a broken connection, a gateway\n * hiccup, anything not proven). Leave it pending and look again later.\n *\n * This module holds the decision and nothing of the store, so an app shell that only needs the\n * fate pays for `classifyFailure` and this table, not for `PendingSwapStore`.\n */\nexport const PENDING_SWAP_FATES = ['forget', 'forget_quietly', 'keep'] as const;\n\n/** One member of {@link PENDING_SWAP_FATES}. */\nexport type PendingSwapFate = (typeof PENDING_SWAP_FATES)[number];\n\n/**\n * The fate of a pending swap for each failure OUTCOME. Only a chain rejection proves the trade did\n * not happen; an input that can never be confirmed is dropped quietly; every other outcome leaves\n * the trade possibly applied. Typed over `FailureOutcome`, so a new outcome does not compile until\n * it is decided here.\n */\nconst FATE_OF_OUTCOME = {\n rejected: 'forget',\n invalid_input: 'forget_quietly',\n unknown: 'keep',\n not_queued: 'keep',\n not_sent: 'keep',\n transient: 'keep',\n} as const satisfies Record<FailureOutcome, PendingSwapFate>;\n\n/**\n * {@link pendingSwapFateFor} from an outcome the app already holds (for example the\n * `classifyFailure(error).outcome` it stored on its own failure wrapper). An outcome this SDK\n * version does not know (a newer SDK at run time) is `keep`: never forget what may have happened.\n */\nexport function pendingSwapFateOfOutcome(outcome: FailureOutcome): PendingSwapFate {\n return Object.hasOwn(FATE_OF_OUTCOME, outcome) ? FATE_OF_OUTCOME[outcome] : 'keep';\n}\n\n/**\n * The fate of a queued swap whose confirmation (`confirmAppliedTrade`) just failed with `error`,\n * from the SDK's classification alone: `forget` for a chain rejection (`rejected`), `forget_quietly`\n * for a key that can never be confirmed (`invalid_input`), `keep` for every other outcome\n * (`unknown`, `not_queued`, `not_sent`, `transient`) and for any value the SDK cannot judge. It\n * accepts an SDK error or a plain-object view of one (see `FailureView`). It replaces the\n * hand-written \"forget it or keep it\" table an app would otherwise keep.\n *\n * @example\n * ```ts\n * try {\n * await confirmAppliedTrade(client, swap);\n * } catch (error) {\n * if ((await store.settle(swap.uniqueKey, error)) === 'forget') tellTheUserItFailed();\n * }\n * ```\n */\nexport function pendingSwapFateFor(error: unknown): PendingSwapFate {\n return pendingSwapFateOfOutcome(classifyFailure(error, { afterQueued: true }).outcome);\n}\n","import { isValidUniqueKey } from '@gala-chain/gala-core-sdk';\nimport { pendingSwapFateFor, type PendingSwapFate } from './pending_swap_fate.js';\nimport type { StorageAdapter } from './storage_adapters.js';\n\n/** Default storage key; the stored value is a plain array of entries. */\nexport const PENDING_SWAPS_STORAGE_KEY = 'pendingSwaps.v1';\n\n/** Entries older than this are dropped the next time a wallet's swaps are listed. */\nexport const PENDING_SWAP_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** A RequestTrade that was accepted by the gateway but whose outcome has not been read yet. */\nexport interface PendingSwap {\n uniqueKey: string;\n requestTransactionId: string | null;\n /** The wallet (account) that submitted the swap; `list` filters by it. */\n wallet: string;\n token0Symbol: string;\n token1Symbol: string;\n /** Whether the swap was a shadow (\"dark\") swap. */\n isDarkSwap: boolean;\n /** Epoch milliseconds when the swap was queued. */\n createdAt: number;\n}\n\n/**\n * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).\n *\n * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.\n * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters\n * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`\n * before reading anything and always will, so keeping the entry would retry it forever. The\n * SDK never signs such a key; an entry like this is corrupt or foreign.\n * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the\n * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.\n * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a\n * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.\n */\nexport const PENDING_SWAP_PRUNE_REASONS = [\n 'expired',\n 'invalid_unique_key',\n 'chain_rejected',\n 'unconfirmable',\n] as const;\n\n/** One member of {@link PENDING_SWAP_PRUNE_REASONS}. */\nexport type PendingSwapPruneReason = (typeof PENDING_SWAP_PRUNE_REASONS)[number];\n\n/** A pending swap the store dropped, and why. */\nexport interface PrunedPendingSwap {\n swap: PendingSwap;\n reason: PendingSwapPruneReason;\n}\n\n/** Options for {@link PendingSwapStore}. */\nexport interface PendingSwapStoreOptions {\n /**\n * Called once per dropped entry (after the drop is persisted, for `list`; at once for a\n * `remember` that refuses an invalid key), so the app can tell the user or log why a swap it\n * was tracking is gone. Diagnostics only: what it does, or throws, never changes the store.\n */\n onPrune?: ((pruned: PrunedPendingSwap) => void) | undefined;\n /** Storage key. Default {@link PENDING_SWAPS_STORAGE_KEY}. */\n storageKey?: string | undefined;\n /**\n * The stored name of the dark-swap flag: `isDarkSwap` (default) or `shadow`, for storage written\n * by an older web app. Entries are always exposed to callers as `isDarkSwap`.\n */\n darkFlagField?: 'isDarkSwap' | 'shadow' | undefined;\n /**\n * Where `remember` puts a new entry in the stored array: `end` (default) or `start`.\n */\n insertAt?: 'end' | 'start' | undefined;\n /**\n * The order of `list`: `stored` (default: oldest first for `insertAt: 'end'`) or\n * `newest-first`.\n */\n listOrder?: 'stored' | 'newest-first' | undefined;\n /** Clock, in epoch milliseconds. Defaults to `Date.now`. */\n now?: (() => number) | undefined;\n}\n\n/**\n * Remembers queued swaps so their outcome can be confirmed after the UI, popup or service worker\n * that submitted them is gone (`confirmAppliedTrade` with the stored `uniqueKey`).\n *\n * Guarantees:\n * - Persistence is best effort and NEVER throws: a failing or missing storage must not turn an\n * accepted request into a client-side resubmission. `list` resolves `[]` when storage fails.\n * - Operations of one store instance are serialized, so concurrent `remember` / `forget` calls\n * cannot lose each other's write (read-modify-write over an async adapter). Two store instances\n * over the same storage (for example popup and service worker) are not coordinated.\n * - Entries that do not match the expected shape are ignored and dropped on the next write.\n * - Entries expire after seven days (an entry exactly seven days old is expired); `list` removes\n * them from storage.\n * - An entry whose `uniqueKey` is not a valid apply-results key is terminal, not pending:\n * `confirmAppliedTrade` fails it with `INVALID_UNIQUE_KEY` every time, so a resume loop would\n * retry it forever. `list` prunes it like an expired one, and `remember` refuses to save it;\n * both tell `onPrune` the reason (`PENDING_SWAP_PRUNE_REASONS`).\n * - New entries go to the end (or `insertAt: 'start'`); `list` returns the wallet's entries in\n * stored order (or `listOrder: 'newest-first'`).\n * - `storageKey`, `darkFlagField`, `insertAt` and `listOrder` adapt the stored layout to an\n * existing storage. JSON key order inside an entry is not preserved.\n *\n * Passing no `storage` yields a store that remembers nothing.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore({\n * get: async (key) => (await chrome.storage.local.get(key))[key],\n * set: (key, value) => chrome.storage.local.set({ [key]: value }),\n * });\n * await store.remember({ uniqueKey, requestTransactionId, wallet, token0Symbol: 'GALA',\n * token1Symbol: 'GUSDC', isDarkSwap: false, createdAt: Date.now() });\n * for (const swap of await store.list(wallet)) await confirmAppliedTrade(client, swap);\n * ```\n */\nexport class PendingSwapStore {\n private readonly storageKey: string;\n private readonly darkFlagField: 'isDarkSwap' | 'shadow';\n private readonly insertAt: 'end' | 'start';\n private readonly listOrder: 'stored' | 'newest-first';\n private readonly now: () => number;\n private readonly onPrune: ((pruned: PrunedPendingSwap) => void) | undefined;\n private queue: Promise<unknown> = Promise.resolve();\n\n constructor(\n private readonly storage: StorageAdapter | undefined,\n options: PendingSwapStoreOptions = {},\n ) {\n this.storageKey = options.storageKey ?? PENDING_SWAPS_STORAGE_KEY;\n this.darkFlagField = options.darkFlagField ?? 'isDarkSwap';\n this.insertAt = options.insertAt ?? 'end';\n this.listOrder = options.listOrder ?? 'stored';\n this.now = options.now ?? Date.now;\n this.onPrune = options.onPrune;\n }\n\n /**\n * Saves (or replaces, by `uniqueKey`) a pending swap. A swap whose `uniqueKey` is not a valid\n * apply-results key is not saved (it could never be confirmed); it is reported to `onPrune` as\n * `invalid_unique_key`.\n */\n public remember(swap: PendingSwap): Promise<void> {\n if (!isValidUniqueKey(swap.uniqueKey)) {\n this.report([{ swap, reason: 'invalid_unique_key' }]);\n return Promise.resolve();\n }\n return this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const others = current\n .filter((entry) => entry.uniqueKey !== swap.uniqueKey)\n .map(this.toStored);\n const stored = this.toStored(swap);\n await storage.set(\n this.storageKey,\n this.insertAt === 'end' ? [...others, stored] : [stored, ...others],\n );\n });\n }\n\n /** Removes a pending swap once its outcome is known. */\n public forget(uniqueKey: string): Promise<void> {\n return this.enqueue(async (storage) => {\n const current = await this.read(storage);\n await storage.set(\n this.storageKey,\n current.filter((entry) => entry.uniqueKey !== uniqueKey).map(this.toStored),\n );\n });\n }\n\n /**\n * Applies {@link pendingSwapFateFor} to a swap whose confirmation failed with `error`, and\n * returns the fate so the app can word it (tell the user on `forget`, say nothing on\n * `forget_quietly`, keep polling on `keep`):\n *\n * - `forget`: the entry is removed and `onPrune` hears `chain_rejected`.\n * - `forget_quietly`: the entry is removed and `onPrune` hears `unconfirmable`.\n * - `keep`: nothing changes and `onPrune` is not called.\n *\n * Like every store operation it is serialized and best effort: if storage fails the entry stays\n * (a later `settle` or `list` handles it) and the fate is still returned. A key that is not\n * stored (already forgotten) is not an error and `onPrune` is not called for it.\n */\n public async settle(uniqueKey: string, error: unknown): Promise<PendingSwapFate> {\n const fate = pendingSwapFateFor(error);\n if (fate === 'keep') return fate;\n const removed = await this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const swap = current.find((entry) => entry.uniqueKey === uniqueKey);\n if (swap === undefined) return undefined;\n await storage.set(\n this.storageKey,\n current.filter((entry) => entry.uniqueKey !== uniqueKey).map(this.toStored),\n );\n return swap;\n });\n if (removed !== undefined) {\n this.report([\n { swap: removed, reason: fate === 'forget' ? 'chain_rejected' : 'unconfirmable' },\n ]);\n }\n return fate;\n }\n\n /**\n * The wallet's pending swaps that can still be confirmed (see `listOrder`). Entries that never\n * can be are pruned from storage, for every wallet, and reported to `onPrune`: expired ones\n * (`expired`) and ones whose `uniqueKey` is not a valid apply-results key\n * (`invalid_unique_key`: `confirmAppliedTrade` would fail `INVALID_UNIQUE_KEY` on it forever).\n */\n public async list(wallet: string): Promise<PendingSwap[]> {\n const result = await this.enqueue(async (storage) => {\n const current = await this.read(storage);\n const now = this.now();\n const pruned: PrunedPendingSwap[] = [];\n const kept: PendingSwap[] = [];\n for (const entry of current) {\n const reason = this.pruneReasonOf(entry, now);\n if (reason === undefined) kept.push(entry);\n else pruned.push({ swap: entry, reason });\n }\n if (pruned.length > 0) {\n await storage.set(this.storageKey, kept.map(this.toStored));\n this.report(pruned);\n }\n const mine = kept.filter((entry) => entry.wallet === wallet);\n return this.listOrder === 'newest-first'\n ? mine.sort((left, right) => right.createdAt - left.createdAt)\n : mine;\n });\n return result ?? [];\n }\n\n private pruneReasonOf(entry: PendingSwap, now: number): PendingSwapPruneReason | undefined {\n if (!isValidUniqueKey(entry.uniqueKey)) return 'invalid_unique_key';\n return now - entry.createdAt < PENDING_SWAP_EXPIRY_MS ? undefined : 'expired';\n }\n\n /** Tells `onPrune` about each dropped entry; the hook is diagnostics and cannot break the store. */\n private report(pruned: readonly PrunedPendingSwap[]): void {\n for (const entry of pruned) {\n try {\n this.onPrune?.(entry);\n } catch {\n // A diagnostics hook must not turn a store operation into a failure.\n }\n }\n }\n\n private enqueue<T>(operation: (storage: StorageAdapter) => Promise<T>): Promise<T | undefined> {\n const storage = this.storage;\n if (storage === undefined) return Promise.resolve(undefined);\n const run = this.queue.then(async () => {\n try {\n return await operation(storage);\n } catch {\n // Storage can be missing, full, or disappear while a context is closing. Persistence is\n // best effort by contract.\n return undefined;\n }\n });\n this.queue = run;\n return run;\n }\n\n private async read(storage: StorageAdapter): Promise<PendingSwap[]> {\n const value = await storage.get(this.storageKey);\n if (!Array.isArray(value)) return [];\n const entries: PendingSwap[] = [];\n for (const item of value as unknown[]) {\n const entry = this.fromStored(item);\n if (entry !== undefined) entries.push(entry);\n }\n return entries;\n }\n\n private readonly toStored = (swap: PendingSwap): Record<string, unknown> => ({\n uniqueKey: swap.uniqueKey,\n requestTransactionId: swap.requestTransactionId,\n wallet: swap.wallet,\n token0Symbol: swap.token0Symbol,\n token1Symbol: swap.token1Symbol,\n [this.darkFlagField]: swap.isDarkSwap,\n createdAt: swap.createdAt,\n });\n\n private fromStored(value: unknown): PendingSwap | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n const entry = value as Record<string, unknown>;\n const flag = entry[this.darkFlagField];\n const { uniqueKey, requestTransactionId, wallet, token0Symbol, token1Symbol, createdAt } =\n entry;\n if (\n typeof uniqueKey !== 'string' ||\n !(typeof requestTransactionId === 'string' || requestTransactionId === null) ||\n typeof wallet !== 'string' ||\n typeof token0Symbol !== 'string' ||\n typeof token1Symbol !== 'string' ||\n typeof flag !== 'boolean' ||\n typeof createdAt !== 'number' ||\n !Number.isFinite(createdAt)\n ) {\n return undefined;\n }\n return {\n uniqueKey,\n requestTransactionId,\n wallet,\n token0Symbol,\n token1Symbol,\n isDarkSwap: flag,\n createdAt,\n };\n }\n}\n","/**\n * Async key/value storage the pending-swap store persists through. It stores STRUCTURED VALUES\n * (the store never serializes), so each platform decides how a value lands on disk:\n *\n * - `chrome.storage.local`: `get: async (k) => (await chrome.storage.local.get(k))[k]`,\n * `set: (k, v) => chrome.storage.local.set({ [k]: v })`. This is the wallet's stored shape.\n * {@link storageAdapterFromChromeStorage} builds it.\n * - `localStorage` (a web app): JSON text under the key. {@link webStorageAdapter} builds it,\n * and returns CORRUPT JSON as a value (the raw string), not as a rejection: a value that is not\n * an array reads as \"no entries\" and the next write repairs it, whereas a `get` that rejects\n * forever makes every `remember` a no-op.\n * - React Native: AsyncStorage with the same JSON wrapping and the same corrupt-JSON rule.\n *\n * `get` resolves `undefined` for a missing key. Either method may reject; the store treats that\n * as \"storage unavailable\" and never lets it surface (see `PendingSwapStore`).\n *\n * This module imports nothing, so an app shell that only builds an adapter pays for the adapter.\n */\nexport interface StorageAdapter {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n}\n\n/**\n * The part of a `chrome.storage` area ({@link storageAdapterFromChromeStorage}) the adapter uses,\n * written structurally so the SDK needs no `chrome` types: `chrome.storage.local`,\n * `chrome.storage.session`, `browser.storage.local` (webextension-polyfill) and any object with\n * these two promise-returning methods satisfy it. It is the Manifest V3 promise form: the methods\n * are called WITHOUT a callback.\n */\nexport interface ChromeStorageAreaLike {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n}\n\n/**\n * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps\n * in: the value lands under the key as the structured value it is (the browser clones it; nothing\n * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the\n * store, which treats it as \"storage unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension\n * context) then fails only when the store touches storage, and that failure (a throw inside the\n * function) is the same \"storage unavailable\" rejection.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));\n * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));\n * ```\n */\nexport function storageAdapterFromChromeStorage(\n area: ChromeStorageAreaLike | (() => ChromeStorageAreaLike),\n): StorageAdapter {\n const areaNow = (): ChromeStorageAreaLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const items = await areaNow().get(key);\n return Object.hasOwn(items, key) ? items[key] : undefined;\n },\n async set(key, value) {\n await areaNow().set({ [key]: value });\n },\n };\n}\n\n/**\n * The part of a Web Storage area ({@link webStorageAdapter}) the adapter uses, written\n * structurally so the SDK needs no DOM types: `localStorage`, `sessionStorage` and any object with\n * these two synchronous methods (a React Native MMKV wrapper, a test double) satisfy it.\n */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\n/**\n * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape\n * a web app stores pending swaps in: the value lands under the key as JSON text. A missing key\n * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store\n * reads a value that is not an array as \"no entries\" and the next write repairs it, whereas a\n * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked\n * by the browser, quota exceeded on `setItem`) rejects, which the store treats as \"storage\n * unavailable\".\n *\n * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is\n * built: where `localStorage` does not exist (server rendering, a test, a blocked context)\n * the access throws inside the function, which is the same \"storage unavailable\" rejection, and\n * the module that builds the adapter still loads.\n *\n * @example\n * ```ts\n * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));\n * ```\n */\nexport function webStorageAdapter(area: WebStorageLike | (() => WebStorageLike)): StorageAdapter {\n const areaNow = (): WebStorageLike => (typeof area === 'function' ? area() : area);\n return {\n async get(key) {\n const raw = areaNow().getItem(key);\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n },\n async set(key, value) {\n areaNow().setItem(key, JSON.stringify(value));\n },\n };\n}\n","import { toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\n\n/**\n * Where a failed CONFIRMATION of a queued write stopped, as a closed set a screen can switch on:\n *\n * - `aborted`: the caller's own `AbortSignal` ended the wait (`CONFIRMATION_ABORTED`). The person\n * or the screen gave up waiting; the write may still land, and its `uniqueKey` is still the handle.\n * - `timeout`: the wait ran out before an apply result arrived (`CONFIRMATION_TIMEOUT`). The write\n * is still pending as far as anyone knows.\n * - `failed`: the apply-results read itself failed or answered something unusable\n * (`CONFIRMATION_FAILED`, `CONFIRMATION_MALFORMED`, `CONFIRMATION_KEY_MISMATCH`).\n *\n * All three are `unknown` to `classifyFailure`: never submit again, confirm the same key.\n */\nexport type ConfirmationState = 'aborted' | 'timeout' | 'failed';\n\n/** The state of every confirmation code (a typo is caught by the all-codes test). */\nconst STATE_OF_CODE = {\n CONFIRMATION_ABORTED: 'aborted',\n CONFIRMATION_TIMEOUT: 'timeout',\n CONFIRMATION_FAILED: 'failed',\n CONFIRMATION_MALFORMED: 'failed',\n CONFIRMATION_KEY_MISMATCH: 'failed',\n} as const satisfies Partial<Record<GSwapErrorCode, ConfirmationState>>;\n\n/**\n * The {@link ConfirmationState} of a failure, or `undefined` when it is not a failed confirmation.\n * Accepts an SDK error or a plain-object view of one (an app's wrapper with a `code`), and decides\n * from the code alone, so a screen never matches `'CONFIRMATION_ABORTED'` itself.\n *\n * @example\n * ```ts\n * switch (confirmationStateOf(error)) {\n * case 'aborted': return; // the person closed the dialog\n * case 'timeout': return showStillPending(error.uniqueKey);\n * case 'failed': return showCouldNotCheck(error.uniqueKey);\n * case undefined: return showFailure(error);\n * }\n * ```\n */\nexport function confirmationStateOf(error: unknown): ConfirmationState | undefined {\n const code = toFailureView(error)?.code;\n if (code === undefined) return undefined;\n return Object.entries(STATE_OF_CODE).find(([known]) => known === code)?.[1];\n}\n\n/** True when the wait for the apply result was ended by the caller's `AbortSignal`. */\nexport function isConfirmationAborted(error: unknown): boolean {\n return confirmationStateOf(error) === 'aborted';\n}\n\n/** True when the wait for the apply result ran out of time (`CONFIRMATION_TIMEOUT`). */\nexport function isConfirmationTimeout(error: unknown): boolean {\n return confirmationStateOf(error) === 'timeout';\n}\n","import { isWriteView, stringParamOf, toFailureView } from '@gala-chain/gala-core-sdk';\nimport type { GSwapErrorCode } from '../classes/gswap_error_catalog.js';\nimport type { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/**\n * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure\n * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in\n * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased\n * at build time). An app shell that imports one of them pays for this module and nothing else.\n */\n\n/**\n * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a\n * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied\n * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting\n * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&\n * error.status === 409` and the regex on \"already saved\". Accepts an SDK error or a plain-object\n * view ({@link FailureView}: `code` and `status`); every other value is `false`.\n *\n * @example\n * ```ts\n * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);\n * ```\n */\nexport function isUniqueKeyConsumed(error: unknown): boolean {\n const view = toFailureView(error);\n return view?.code === 'CHAIN_DISPATCH_FAILED' && view.status === 409;\n}\n\nconst UNPROVEN_ACKNOWLEDGEMENT_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_DATA_MISSING',\n 'GATEWAY_MODE_INVALID',\n 'GATEWAY_SYNC_REQUEST_TRADE',\n 'MISSING_UNIQUE_KEY',\n 'UNIQUE_KEY_MISMATCH',\n];\n\n/**\n * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no\n * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.\n * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an\n * app shows is one line for all five (\"the backend did not confirm it queued the request\"), so\n * the app asks this instead of keeping its own list of the codes. A gateway that says\n * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.\n *\n * @example\n * ```ts\n * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);\n * ```\n */\nexport function isUnprovenAcknowledgement(error: unknown): boolean {\n return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);\n}\n\n/** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */\nfunction isCodeIn(code: string, codes: readonly GSwapErrorCode[]): boolean {\n return codes.some((known) => known === code);\n}\n\n/**\n * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose\n * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet\n * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.\n */\nfunction hasCodeIn(error: unknown, codes: readonly GSwapErrorCode[]): boolean {\n const view = toFailureView(error);\n // `codes` holds catalog codes only, so membership already means \"a catalog code\": no table needed.\n return view !== undefined && isCodeIn(view.code, codes);\n}\n\n/**\n * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app\n * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made\n * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the\n * SDK knows, and `GATEWAY_REJECTED` for one it does not).\n */\nconst RELAYABLE_REFUSAL_CODES: readonly GSwapErrorCode[] = [\n 'GATEWAY_REPORTED_ERROR',\n 'METHOD_NOT_ALLOWED',\n 'SIGNATURE_INVALID',\n 'SIGNER_MISMATCH',\n 'DTO_INVALID',\n 'DTO_OPERATION_MISMATCH',\n 'BOUNDS_VIOLATION',\n 'SYMBOL_CONFLICT',\n 'RATE_LIMITED',\n 'CHAIN_DISPATCH_FAILED',\n 'GATEWAY_REJECTED',\n];\n\n/**\n * True when the error is a gateway refusal whose `params.serverMessage` an app may relay to the\n * person as the gateway sent it: `GATEWAY_REPORTED_ERROR`, the gateway bounces (`METHOD_NOT_ALLOWED`,\n * `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `DTO_OPERATION_MISMATCH`, `BOUNDS_VIOLATION`,\n * `SYMBOL_CONFLICT`, `RATE_LIMITED`, `GATEWAY_REJECTED`) and `CHAIN_DISPATCH_FAILED`. The app shows `serverMessage` when\n * it is not empty and its own line when it is; the SDK's English `message` is never what to show.\n *\n * It accepts a plain-object view of an SDK error too ({@link FailureView}: an app's wrapper with a\n * `code`), and decides from the code in the same way. It narrows to `GSwapSDKError<...>` ONLY when\n * called with an SDK error; with an `unknown` or a view it answers `boolean` (narrow with\n * `isGSwapError` first, or read the view's own `params`).\n *\n * It is a test on the code alone, so it also holds for `CHAIN_DISPATCH_FAILED` with HTTP 409\n * (the `uniqueKey` was already consumed; `classifyFailure` says `unknown`): an app that words that\n * case itself (\"already submitted\", then confirm the key) checks `error.status === 409` BEFORE\n * relaying. It is false for `CHAIN_REJECTED` (the chain's verdict, worded by where it is shown: the\n * submit and confirm screens differ), for `HTTP_ERROR` (a proxy's page, not an answer to this\n * write) and for the five unproven acknowledgements (`isUnprovenAcknowledgement`: they carry no\n * server text).\n *\n * @example\n * ```ts\n * if (isRelayableRefusal(error)) show(error.params.serverMessage || t('swap.requestFailed'));\n * ```\n */\nexport function isRelayableRefusal(error: GSwapSDKError): error is GSwapSDKError<RelayableCode>;\nexport function isRelayableRefusal(error: unknown): boolean;\nexport function isRelayableRefusal(error: unknown): boolean {\n return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);\n}\n\n/** The codes {@link isRelayableRefusal} is true for. */\nexport type RelayableCode =\n | 'GATEWAY_REPORTED_ERROR'\n | 'METHOD_NOT_ALLOWED'\n | 'SIGNATURE_INVALID'\n | 'SIGNER_MISMATCH'\n | 'DTO_INVALID'\n | 'DTO_OPERATION_MISMATCH'\n | 'BOUNDS_VIOLATION'\n | 'SYMBOL_CONFLICT'\n | 'RATE_LIMITED'\n | 'CHAIN_DISPATCH_FAILED'\n | 'GATEWAY_REJECTED';\n\n/**\n * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in\n * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements\n * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).\n * The outcome is `unknown` for all six. It replaces the app's own\n * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.\n */\nexport function isUninterpretedAnswer(error: unknown): boolean {\n return isUnprovenAcknowledgement(error) || hasCodeIn(error, ['GATEWAY_REPORTED_ERROR']);\n}\n\n/**\n * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,\n * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the\n * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's\n * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it\n * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent\n * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.\n *\n * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every\n * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named\n * param, so a stray field cannot pass for a chain verdict.\n *\n * @example\n * ```ts\n * const key = chainErrorKeyOf(error);\n * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);\n * ```\n */\nexport function chainErrorKeyOf(error: unknown): string | undefined {\n const view = toFailureView(error);\n if (view === undefined) return undefined;\n if (view.code !== 'CHAIN_REJECTED' && view.code !== 'CHAIN_DISPATCH_FAILED') return undefined;\n const errorKey = stringParamOf(view, 'errorKey');\n return errorKey === undefined || errorKey === '' ? undefined : errorKey;\n}\n\n/** Codes that mean \"there is no market for this\" however the app reached them. */\nconst NO_MARKET_CODES: readonly GSwapErrorCode[] = [\n 'NO_POOL_AVAILABLE',\n 'INSUFFICIENT_LIQUIDITY',\n 'UNKNOWN_TOKEN',\n];\n\n/**\n * True when a failure means \"there is no market to trade this pair\": `NO_POOL_AVAILABLE` (no pool\n * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX\n * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend\n * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||\n * notFound` list, so the empty-state (\"No market for this pair\") has one definition.\n *\n * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing\n * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every\n * other value is `false`.\n *\n * @example\n * ```ts\n * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);\n * ```\n */\nexport function isNoMarket(error: unknown): boolean {\n const view = toFailureView(error);\n if (view === undefined) return false;\n if (isCodeIn(view.code, NO_MARKET_CODES)) return true;\n return !isWriteView(view) && (view.notFound === true || view.status === 404);\n}\n","/**\n * What a write's gateway answer says about the write, as one vocabulary for every app.\n *\n * The gateway answers `{ status, message, error, data }`. `data.mode` is `'sync'` for a liquidity\n * write (its executed chain result is in `data.result`) and `'queued'` for a RequestTrade\n * acknowledgement (accepted, NOT executed: the outcome is read from apply-results with\n * `confirm()`). `error: true` is the gateway refusing the write.\n *\n * A {@link SubmittedTransaction} only exists for an answer the SDK accepted, so its\n * {@link SubmitStatus} is `'executed'` or `'queued'`; a refused answer is a thrown\n * {@link GSwapSDKError}. The predicates below classify a RAW envelope instead, for an app that\n * holds one (`SubmittedTransaction.envelope`, `GSwapSDKError.body`, a stored answer) and for the\n * answers that never became a transaction, so an app does not need its own copies of the\n * success, queued and rejected checks.\n */\n\n/** The state of an accepted write: executed on chain (`mode: 'sync'`) or queued (`mode: 'queued'`). */\nexport type SubmitStatus = 'executed' | 'queued';\n\n/**\n * How a raw gateway envelope classifies:\n *\n * - `'executed'`: `error === false` and `data.mode === 'sync'` (the executed result came back).\n * - `'queued'`: `error === false`, `data.mode === 'queued'` and `data.uniqueKey` is a string.\n * - `'rejected'`: no envelope at all, or `error === true`: a DEFINITE failure.\n * - `'unconfirmed'`: anything else (`error: false` with another or no `mode`, a queued answer\n * with no `uniqueKey`, an envelope with no boolean `error`): accepted, outcome not known. It is\n * NOT a rejection and must not be shown as one.\n *\n * The four are mutually exclusive and exhaustive.\n */\nexport type SubmitClassification = SubmitStatus | 'rejected' | 'unconfirmed';\n\n/** The `mode` of `envelope.data`, or `undefined` when there is no such field. */\nfunction modeOf(envelope: Record<string, unknown>): unknown {\n const data = envelope['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)['mode']\n : undefined;\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** True when the envelope is a definite failure: absent, or `error === true`. */\nexport function isSubmitRejected(envelope: unknown): boolean {\n if (!envelope) return true;\n return recordOf(envelope)?.['error'] === true;\n}\n\n/**\n * True when the envelope carries an executed result: `error === false` and `data.mode === 'sync'`.\n * A queued RequestTrade acknowledgement is deliberately NOT executed: its outcome is not known\n * until apply-results resolves.\n */\nexport function isSubmitExecuted(envelope: unknown): boolean {\n const record = recordOf(envelope);\n return record?.['error'] === false && modeOf(record) === 'sync';\n}\n\n/** True when the envelope acknowledges a `uniqueKey` as queued (`data.mode === 'queued'`). */\nexport function isSubmitQueued(envelope: unknown): boolean {\n const record = recordOf(envelope);\n if (record?.['error'] !== false || modeOf(record) !== 'queued') return false;\n return typeof recordOf(record['data'])?.['uniqueKey'] === 'string';\n}\n\n/** Classifies a raw gateway envelope; see {@link SubmitClassification}. */\nexport function classifySubmitEnvelope(envelope: unknown): SubmitClassification {\n if (isSubmitRejected(envelope)) return 'rejected';\n if (isSubmitExecuted(envelope)) return 'executed';\n if (isSubmitQueued(envelope)) return 'queued';\n return 'unconfirmed';\n}\n"],"mappings":";;;;;;AAEA,MAAM,qBAAqB;AAC3B,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAC7B,MAAM,iBAAiB;;;;;AAiBvB,SAAgB,2BACd,SACA,uBACA,YACsB;CACtB,MAAM,YAAY,KAAK,IAAI,sDAAG,QAAS,cAAa,kBAAkB;CACtE,MAAM,iBAAiB,KAAK,IAC1B,yEACA,QAAS,mBAAkB,wBAC7B;CACA,MAAM,iBAAiB,KAAK,IAAI,sDAAG,QAAS,mBAAkB,qBAAqB;CACnF,MAAM,2DAAS,QAAS;CACxB,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,OAAO,EACL,MAAM,YAAY,cAAyC;EACzD,eAAe,QAAQ,UAAU;EACjC,IAAI,WAAW;GACb,YAAY;GACZ,MAAM,YAAY,KAAK,IAAI,GAAG,WAAW,KAAK,IAAI,CAAC;GACnD,MAAM,MAAM,KAAK,IAAI,gBAAgB,SAAS,GAAG,QAAQ,UAAU;GACnE,OAAO;EACT;EACA,MAAM,UAAU,KAAK,IAAI,gBAAgB,iBAAiB,KAAK,KAAK,IAAI,SAAS,CAAC,CAAC;EACnF,WAAW;EACX,MAAM,SAAS,iBAAiB,SAAY,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,YAAY;EACtF,IAAI,KAAK,IAAI,IAAI,SAAS,UAAU,OAAO;EAC3C,MAAM,MAAM,QAAQ,QAAQ,UAAU;EACtC,OAAO;CACT,EACF;AACF;;AAGA,SAAgB,eACd,QACA,YACM;CACN,qDAAI,OAAQ,aAAY,MAAM,MAAM,WAAW,OAAO,MAAM;AAC9D;AAEA,SAAS,MACP,cACA,QACA,YACe;CACf,qDAAI,OAAQ,aAAY,MAAM,OAAO,QAAQ,OAAO,WAAW,OAAO,MAAM,CAAC;CAC7E,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,gBAAsB;GAC1B,aAAa,KAAK;GAClB,OAAO,2DAAW,OAAQ,MAAM,CAAC;EACnC;EACA,MAAM,QAAQ,iBAAiB;GAC7B,+CAAQ,oBAAoB,SAAS,OAAO;GAC5C,QAAQ;EACV,GAAG,YAAY;EACf,+CAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC3D,CAAC;AACH;AAEA,SAAS,OAAO,cAA8B;CAC5C,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,gBAAgB,KAAM,KAAK,OAAO,IAAI,GAAI,CAAC;AAC3E;;;;ACnFA,SAAS,eAAe,OAAgB,UAAsC;CAC5E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,QAAS,MAAkC;CACjD,OAAO,OAAO,UAAU,YAAY,UAAU,KAAK,QAAQ;AAC7D;;;;;;;;;;;AAYA,SAAgB,oBAAoB,MAAuB;CACzD,MAAM,SACJ,OAAO,SAAS,YAAY,SAAS,OAChC,KAAiC,WAClC;CACN,OACE,eAAe,MAAM,SAAS,KAC9B,eAAe,MAAM,SAAS,KAC9B,eAAe,QAAQ,SAAS,KAChC,eAAe,QAAQ,SAAS,KAChC;AAEJ;;;;;;;AAQA,SAAgB,kBAAkB,OAA0C;CAE1E,MAAM,aAD8D,MAAM,OAChD;CAC1B,IAAI,OAAO,eAAe,YAAY,eAAe,IAAI,OAAO;CAChE,MAAM,WAAW,oBAAoB,MAAM,IAAI;CAC/C,OAAO,aAAa,KAAK,SAAY;AACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACHA,MAAa,qCAAqC,CAAC,WAAW,WAAW;;AAMzE,MAAa,yBAAyB;;AAGtC,MAAa,sBAAsB;CAEjC,YAAY;EACV,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,QAAQ;GAAU,KAAK;GAAU,eAAe;EAAS;EACnE,YAAY,CAAC,eAAe;CAC9B;CACA,iBAAiB;EACf,OAAO;EACP,UACE;EACF,QAAQ,EAAE,QAAQ,SAAS;CAC7B;CACA,gBAAgB;EACd,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,WAAW,SAAS;CAChC;CAGA,sBAAsB;EACpB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,QAAQ,SAAS;CAC7B;CACA,4BAA4B;EAC1B,OAAO;EACP,UACE;EACF,QAAQ,EAAE,QAAQ,mCAAmC;CACvD;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,sBAAsB;EACpB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,sBAAsB;EACpB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,4BAA4B;EAC1B,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,oBAAoB;EAClB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,oCAAoC;EAClC,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,iBAAiB;EACf,OAAO;EACP,UACE;EACF,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,aAAa;EACX,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,wBAAwB;EACtB,OAAO;EACP,UACE;EACF,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,kBAAkB;EAChB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,iBAAiB;EACf,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,cAAc;EACZ,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,uBAAuB;EACrB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,UAAU;GAAU,eAAe;EAAS;CACxD;CACA,kBAAkB;EAChB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,aAAa;GAAU,eAAe;EAAS;CAC3D;CACA,gBAAgB;EACd,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,UAAU;GAAU,eAAe;EAAS;CACxD;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,UAAU,SAAS;CAC/B;CACA,2BAA2B;EACzB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,QAAQ,SAAS;CAC7B;CAGA,sBAAsB;EACpB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,sBAAsB;EACpB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,QAAQ;GAAU,eAAe;EAAS;EACpD,YAAY,CAAC,eAAe;CAC9B;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,2BAA2B;EACzB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CAGA,WAAW;EACT,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,mBAAmB;EACjB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,SAAS;GAAU,UAAU;GAAU,KAAK;EAAS;CACjE;CACA,wBAAwB;EACtB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,SAAS;GAAU,UAAU;GAAU,KAAK;EAAS;CACjE;CACA,eAAe;EACb,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,kBAAkB;EAChB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,yBAAyB;EACvB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,8BAA8B;EAC5B,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,sBAAsB;EACpB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ,CAAC;CACX;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,QAAQ;GAAU,WAAW;EAAS;CAClD;CACA,uBAAuB;EACrB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,KAAK,SAAS;CAC1B;CACA,8BAA8B;EAC5B,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,WAAW,SAAS;CAChC;CACA,0BAA0B;EACxB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,WAAW,SAAS;CAChC;CAGA,yBAAyB;EACvB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,wBAAwB;EACtB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CAGA,oBAAoB;EAClB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,QAAQ;GAAU,QAAQ;EAAS;CAC/C;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,UAAU,SAAS;CAC/B;CACA,yBAAyB;EACvB,OAAO;EACP,UACE;EACF,QAAQ,EAAE,eAAe,SAAS;CACpC;CACA,4BAA4B;EAC1B,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,cAAc;GAAU,MAAM;EAAS;CACnD;CACA,wBAAwB;EACtB,OAAO;EACP,UACE;EACF,QAAQ,EAAE,QAAQ,SAAS;CAC7B;CACA,yBAAyB;EACvB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,UAAU;GAAU,eAAe;EAAS;CACxD;CACA,6BAA6B;EAC3B,OAAO;EACP,UACE;EACF,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,gCAAgC;EAC9B,OAAO;EACP,UACE;EACF,QAAQ;GAAE,OAAO;GAAU,gBAAgB;GAAU,kBAAkB;EAAS;CAClF;CACA,6BAA6B;EAC3B,OAAO;EACP,UACE;EACF,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,OAAO;EAAS;CAC7C;CACA,qBAAqB;EACnB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,OAAO;EAAS;CAC7C;CACA,iBAAiB;EACf,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,OAAO;EAAS;CAC7C;CACA,2BAA2B;EACzB,OAAO;EACP,UACE;EACF,QAAQ,CAAC;CACX;CACA,sBAAsB;EACpB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,WAAW;GAAU,YAAY;GAAU,YAAY;EAAS;CAC5E;CACA,qBAAqB;EACnB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,YAAY;GAAU,YAAY;EAAS;CACvD;CACA,sBAAsB;EACpB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,UAAU;GAAU,UAAU;EAAS;CACnD;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,UAAU;GAAU,UAAU;EAAS;CACnD;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,WAAW,SAAS;CAChC;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,OAAO;EAAS;CAC7C;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,WAAW;GAAU,WAAW;EAAS;CACrD;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,WAAW;GAAU,WAAW;EAAS;CACrD;CACA,qBAAqB;EACnB,OAAO;EACP,UACE;EACF,QAAQ;GAAE,WAAW;GAAU,WAAW;GAAU,SAAS;GAAU,SAAS;EAAS;CAC3F;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,WAAW;GAAU,WAAW;GAAU,SAAS;EAAS;CACxE;CACA,sBAAsB;EACpB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,aAAa;EACX,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,OAAO;GAAU,SAAS;EAAS;CAChE;CACA,uBAAuB;EACrB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,yBAAyB;EACvB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,QAAQ;EAAS;CAC9C;CACA,wBAAwB;EACtB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,QAAQ;EAAS;CAC9C;CACA,eAAe;EACb,OAAO;EACP,UACE;EACF,QAAQ;GACN,SAAS;GACT,UAAU;GACV,YAAY;GACZ,YAAY;EACd;CACF;CACA,aAAa;EACX,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,QAAQ;GAAU,OAAO;GAAU,UAAU;EAAS;CAClE;CACA,mBAAmB;EACjB,OAAO;EACP,UACE;EACF,QAAQ,EAAE,QAAQ,SAAS;CAC7B;CACA,iBAAiB;EACf,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,QAAQ;GAAU,WAAW;EAAS;CAClD;CACA,iBAAiB;EACf,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,SAAS;EAAS;CAC/C;CACA,oBAAoB;EAClB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,cAAc;EACZ,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,eAAe;EACb,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,KAAK;GAAU,KAAK;EAAS;CAC1D;CACA,sBAAsB;EACpB,OAAO;EACP,UACE;EACF,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ;GAAE,OAAO;GAAU,SAAS;EAAS;CAC/C;CACA,mBAAmB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;CACA,uBAAuB;EACrB,OAAO;EACP,UAAU;EACV,QAAQ,EAAE,OAAO,SAAS;CAC5B;AACF;;;;;AAeA,MAAa,0BAAmF;CAC9F,GAAG;CACH,GAAG;AACL;;;;;;;AAQA,MAAa,sBACX,OAAO,YACL,OAAO,QAAQ,mBAAmB,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,MAAM,MAAM,QAAQ,CAAC,CACnF;;;;;;;;;;;;AC5iBF,MAAa,4BAA4B;CACvC,YAAY;CACZ,iBAAiB;CACjB,gBAAgB;CAChB,sBAAsB;CACtB,4BAA4B;CAC5B,wBAAwB;CACxB,sBAAsB;CACtB,sBAAsB;CACtB,4BAA4B;CAC5B,oBAAoB;CACpB,qBAAqB;CACrB,mBAAmB;CACnB,oCAAoC;CACpC,oBAAoB;CACpB,mBAAmB;CACnB,iBAAiB;CACjB,aAAa;CACb,wBAAwB;CACxB,kBAAkB;CAClB,iBAAiB;CACjB,cAAc;CACd,uBAAuB;CACvB,kBAAkB;CAClB,gBAAgB;CAChB,wBAAwB;CACxB,2BAA2B;CAC3B,sBAAsB;CACtB,sBAAsB;CACtB,qBAAqB;CACrB,wBAAwB;CACxB,2BAA2B;CAC3B,WAAW;CACX,mBAAmB;CACnB,mBAAmB;CACnB,wBAAwB;CACxB,eAAe;CACf,kBAAkB;CAClB,yBAAyB;CACzB,8BAA8B;CAC9B,sBAAsB;CACtB,qBAAqB;CACrB,wBAAwB;CACxB,uBAAuB;CACvB,8BAA8B;CAC9B,0BAA0B;CAC1B,yBAAyB;CACzB,wBAAwB;CACxB,oBAAoB;CACpB,qBAAqB;CACrB,yBAAyB;CACzB,4BAA4B;CAC5B,wBAAwB;CACxB,yBAAyB;CACzB,6BAA6B;CAC7B,gCAAgC;CAChC,6BAA6B;CAC7B,qBAAqB;CACrB,mBAAmB;CACnB,qBAAqB;CACrB,iBAAiB;CACjB,2BAA2B;CAC3B,sBAAsB;CACtB,qBAAqB;CACrB,sBAAsB;CACtB,oBAAoB;CACpB,wBAAwB;CACxB,oBAAoB;CACpB,wBAAwB;CACxB,oBAAoB;CACpB,oBAAoB;CACpB,qBAAqB;CACrB,mBAAmB;CACnB,sBAAsB;CACtB,aAAa;CACb,uBAAuB;CACvB,yBAAyB;CACzB,wBAAwB;CACxB,eAAe;CACf,aAAa;CACb,mBAAmB;CACnB,iBAAiB;CACjB,iBAAiB;CACjB,oBAAoB;CACpB,cAAc;CACd,eAAe;CACf,sBAAsB;CACtB,mBAAmB;CACnB,mBAAmB;CACnB,uBAAuB;AACzB;;AAKA,SAAS,iBAAiB,MAA8D;CACtF,OAAO,OAAO,OAAO,2BAA2B,IAAI;AACtD;;AAGA,SAAgB,cAAc,MAAsC;CAClE,OAAO,kBAAkB,IAAI,KAAK,iBAAiB,IAAI;AACzD;;;;;AAMA,SAAgB,YAAY,MAA+C;CACzE,IAAI,KAAK,UAAU,QAAW,OAAO,KAAK;CAC1C,IAAI,kBAAkB,KAAK,IAAI,GAAG,OAAO,yBAAyB,KAAK;CACvE,OAAO,iBAAiB,KAAK,IAAI,IAAI,0BAA0B,KAAK,QAAQ;AAC9E;;;;;;;;;AC3GA,MAAa,yBAAyB;;;;;;;;;;;;;AA8BtC,IAAa,gBAAb,MAAa,sBAAiE,aAG5E;;CAEA,OAAgC,UAAU;CAE1C,YAAY,MAAS,QAA6B,UAA4B,CAAC,GAAG;EAChF,MAAM,MAAM,QAAQ,OAAO;EAC3B,KAAK,OAAO;CACd;;;;;;;;CASA,IAAoB,WAAoB;EACtC,OAAO,MAAM,YAAY,KAAK,SAAS,uBAAuB,KAAK,SAAS;CAC9E;;CAGA,OAAc,gBAA4C;EACxD,OAAO,IAAI,cAAc,aAAa,CAAC,CAAC;CAC1C;;CAGA,OAAc,uBAA2D;EACvE,OAAO,IAAI,cAAc,qBAAqB,CAAC,CAAC;CAClD;;;;;CAMA,OAAc,qBACZ,SACA,UACA,KACA,QACoC;EACpC,OAAO,IAAI,cACT,qBACA;GAAE,SAAS,UAAU,OAAO;GAAG,UAAU,UAAU,QAAQ;GAAG,KAAK,QAAQ,GAAG;EAAE,GAChF,cAAc,MAAM,CACtB;CACF;;CAGA,OAAc,2BACZ,SACA,UACA,KACA,QACyC;EACzC,OAAO,IAAI,cACT,0BACA;GAAE,SAAS,UAAU,OAAO;GAAG,UAAU,UAAU,QAAQ;GAAG,KAAK,QAAQ,GAAG;EAAE,GAChF,cAAc,MAAM,CACtB;CACF;;;;;;;;CASA,OAAc,kBACZ,aACA,eACA,QACA,MACA,KACA,cACA,WACe;EACf,MAAM,UAA4B;GAAE;GAAQ;GAAM;GAAK;GAAc;EAAU;EAC/E,MAAM,SAAS,EAAE,cAAc;EAC/B,QAAQ,aAAR;GACE,KAAK,sBACH,OAAO,IAAI,cAAc,sBAAsB,QAAQ,OAAO;GAChE,KAAK,qBACH,OAAO,IAAI,cAAc,qBAAqB,QAAQ,OAAO;GAC/D,KAAK,mBACH,OAAO,IAAI,cAAc,mBAAmB,QAAQ,OAAO;GAC7D,KAAK,eACH,OAAO,IAAI,cAAc,eAAe,QAAQ,OAAO;GACzD,KAAK,0BACH,OAAO,IAAI,cAAc,0BAA0B,QAAQ,OAAO;GACpE,KAAK,oBACH,OAAO,IAAI,cAAc,oBAAoB,QAAQ,OAAO;GAC9D,KAAK,mBACH,OAAO,IAAI,cAAc,mBAAmB,QAAQ,OAAO;GAC7D,KAAK,gBACH,OAAO,IAAI,cAAc,gBAAgB,QAAQ,OAAO;GAC1D,KAAK,yBAGH,OAAO,IAAI,cACT,yBACA;IAAE,GAAG;IAAQ,UAAU,kBAAkB,MAAM,UAAU,KAAK;GAAG,GACjE,OACF;GACF,SACE,OAAO,IAAI,cAAc,oBAAoB;IAAE;IAAa;GAAc,GAAG,OAAO;EACxF;CACF;;CAGA,OAAc,eACZ,UACA,eACA,SACiC;EACjC,OAAO,IAAI,cAAc,kBAAkB;GAAE;GAAU;EAAc,GAAG,OAAO;CACjF;;;;;CAMA,OAAc,kBACZ,OACA,QACgC;EAChC,OAAO,IAAI,cAAc,iBAAiB,EAAE,OAAO,UAAU,KAAK,EAAE,GAAG,cAAc,MAAM,CAAC;CAC9F;;CAGA,OAAc,yBACZ,WACA,OACuC;EACvC,OAAO,IAAI,cAAc,wBAAwB,CAAC,GAAG;GAAE;GAAW;EAAM,CAAC;CAC3E;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,OAAc,WACZ,QACA,UAAmC,CAAC,GACa;EACjD,MAAM,EAAE,KAAK,WAAW,OAAO,eAAe,MAAM,iBAAiB;EACrE,MAAM,UAAU,UAAU,cAAc,UAAa,cAAc;EACnE,IAAI,YAAY,cAAc,UAAa,cAAc,KACvD,MAAM,IAAI,cAAc,sBAAsB,EAAE,WAAW,aAAa,GAAG,CAAC;EAE9E,MAAM,UAA4B;GAChC;GACA;GACA;GACA;GACA,WAAW,UAAU,YAAY;GACjC,OAAO;GACP,OAAO;EACT;EACA,OAAO,iBACH,IAAI,cAAc,mBAAmB,EAAE,OAAO,GAAG,OAAO,IACxD,IAAI,cACF,cACA;GAAE;GAAQ,KAAK,OAAO;GAAI,eAAe,iBAAiB;EAAG,GAC7D,OACF;CACN;;CAGA,aAAoB,kBAClB,KACA,UACwB;EACxB,MAAM,WAAW,MAAM,SAAS,KAAK;EACrC,MAAM,WAAoB,UAAU,QAAQ;EAC5C,MAAM,cAAc,kBAAkB,UAAU,OAAO;EACvD,MAAM,WAAW,kBAAkB,aAAa,UAAU;EAC1D,MAAM,UAAU,kBAAkB,aAAa,SAAS;EAGxD,MAAM,UAA4B;GAChC,QAAQ,SAAS;GACjB,MAAM,YAAY;GAClB;GACA,OAAO;EACT;EAEA,IAAI,SAAS,gBACX,OAAO,IAAI,cAAc,mBAAmB,EAAE,QAAQ,SAAS,OAAO,GAAG,OAAO;EAGlF,IAAI,aAAa,UAAa,YAAY,QACxC,OAAO,IAAI,cAAc,kBAAkB;GAAE;GAAU,eAAe;EAAQ,GAAG,OAAO;EAG1F,OAAO,IAAI,cACT,cACA;GAAE,QAAQ,SAAS;GAAQ;GAAK,eAAe,oBAAoB,QAAQ;EAAE,GAC7E,OACF;CACF;AACF;;AAGA,SAAS,UAAU,OAAgD;CACjE,OAAO,OAAO,UAAU,WACpB,QACA;EAAC,MAAM;EAAY,MAAM;EAAU,MAAM;EAAM,MAAM;CAAa,CAAC,CAAC,KAAK,GAAG;AAClF;AAEA,SAAS,QAAQ,KAAiC;CAChD,OAAO,QAAQ,SAAY,QAAQ,OAAO,GAAG;AAC/C;;;;;AAMA,SAAS,cAAc,QAAqD;CAC1E,IAAI,WAAW,QAAW,OAAO,CAAC;CAClC,OAAO;EACL,QAAQ,OAAO;EACf,MAAM,OAAO,QAAQ,OAAO;EAC5B,KAAK,OAAO;EACZ,OAAO;EACP,OAAO,OAAO;CAChB;AACF;AA2BA,SAAgB,aAAa,OAAgB,MAAgC;CAC3E,OAAO,iBAAiB,iBAAiB,SAAS,UAAa,MAAM,SAAS;AAChF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,eAAe,OAAyB;CACtD,MAAM,OAAO,cAAc,KAAK;CAChC,OAAO,SAAS,UAAa,YAAY,IAAI,MAAM;AACrD;;AAGA,SAAgB,kBACd,OACA,UACqC;CACrC,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,QAAQ,OAAO;CAChF,MAAM,gBAAiB,MAAkC;CACzD,OAAO,OAAO,kBAAkB,YAAY,kBAAkB,OACzD,gBACD;AACN;;AAGA,SAAgB,kBAAkB,OAAgB,UAAsC;CACtF,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,QAAQ,OAAO;CAChF,MAAM,gBAAiB,MAAkC;CACzD,OAAO,OAAO,kBAAkB,WAAW,gBAAgB;AAC7D;;;;;;;;AC9VA,MAAM,2BAA2B;AACjC,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;AAuBnC,IAAa,oBAAb,cAAkF,cAAiB;CACjG,YAAY,MAAS,QAA6B,UAA4B,CAAC,GAAG;EAChF,MAAM,MAAM,QAAQ,OAAO;EAC3B,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;;;;;;;;AAyCA,eAAsB,oBACpB,QACA,OACA,SACuB;CACvB,MAAM,EAAE,cAAc;CACtB,IAAI,CAAC,iBAAiB,SAAS,GAC7B,MAAM,IAAI,kBACR,sBACA,EAAE,WAAW,OAAO,SAAS,EAAE,GAC/B,EAAE,UAAU,CACd;CAEF,MAAM,YAAY,OAAO,iBAAiB;CAC1C,MAAM,mBAAmB,OAAO,oBAAoB;CACpD,MAAM,2DAAS,QAAS;CACxB,MAAM,cAAc,UAClB,IAAI,kBAAkB,wBAAwB,CAAC,GAAG;EAAE;EAAW;CAAM,CAAC;CACxE,MAAM,MAAM,GAAG,OAAO,kBAAkB,QAAQ,QAAQ,EAAE,EAAE,0BAA0B,mBAAmB,SAAS,EAAE;CAEpH,MAAM,WAAW,2BAA2B,SAAS,0BAA0B,UAAU;CACzF,MAAM,SAAS,YAAY;CAC3B,IAAI;CAEJ,OAAO,MAAM;EACX,eAAe,QAAQ,UAAU;EACjC,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,mBACf,WACA,KACA;IACE,QAAQ;IACR,SAAS,oBAAoB,OAAO,IAAI;IACxC,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;GAC3C,GACA,gBACF;GACA,OAAO,MAAM,iBAAiB,QAAQ;EACxC,SAAS,OAAgB;GACvB,eAAe,QAAQ,UAAU;GACjC,YAAY;GACZ,IAAI,CAAE,MAAM,SAAS,YAAY,GAAI;GACrC;EACF;EACA,eAAe,QAAQ,UAAU;EAEjC,IAAI,SAAS,WAAW,KAAK,OAAO,kBAAkB,OAAO,UAAU,MAAM,GAAG;EAEhF,IAAI,SAAS,WAAW,OAAO,SAAS,WAAW,OAAO,YAAY,SAAS,MAAM,GAAG;GACtF,MAAM,aAAa,SAAS,WAAW,MAAM,eAAe,QAAQ,IAAI;GACxE,IAAI,CAAE,MAAM,SAAS,YAAY,UAAU,GAAI;GAC/C;EACF;EAEA,MAAM,IAAI,kBACR,uBACA;GAAE,QAAQ,SAAS;GAAQ,eAAe,oBAAoB,IAAI;EAAE,GACpE;GAAE;GAAW,QAAQ,SAAS;GAAQ;GAAM;EAAI,CAClD;CACF;CAEA,MAAM,IAAI,kBACR,wBACA,CAAC,GACD;EAAE;EAAW,sBAAsB,MAAM;EAAsB;EAAK,OAAO;CAAU,CACvF;AACF;AAEA,SAAS,kBACP,OACA,UACA,MACA,KACc;CACd,MAAM,EAAE,cAAc;CACtB,MAAM,SAASA,WAAS,IAAI;CAC5B,MAAM,+DAAc,OAAS,kEAAgB,OAAS;CACtD,IAAI,OAAO,gBAAgB,YAAY,gBAAgB,WACrD,MAAM,IAAI,kBACR,6BACA,CAAC,GACD;EAAE;EAAW,QAAQ,SAAS;EAAQ;EAAM;CAAI,CAClD;CAEF,MAAM,yDAAS,OAAS;CACxB,MAAM,qBAAqB,WAAW,UAAU,wBAAwB,KAAK;CAC7E,MAAM,cAAc,sBAAsB,UAAU,sBAAsB,KAAK;CAC/E,IAAI,WAAW,GAAG;EAChB,MAAM,WAAW,kBAAkB,QAAQ,UAAU,KAAK;EAC1D,MAAM,eAAe,kBAAkB,QAAQ,SAAS,KAAK;EAC7D,MAAM,IAAI,kBACR,kBACA;GAAE;GAAU,eAAe;EAAa,GACxC;GACE;GACA,sBAAsB,MAAM;GAC5B;GACA;GACA,QAAQ,SAAS;GACjB;GACA;EACF,CACF;CACF;CACA,IAAI,WAAW,GAAG,MAAM,UAAU,OAAO,UAAU,MAAM,GAAG;CAC5D,MAAM,SAAS,oEAAoB,OAAS,OAAO;CACnD,IAAI,WAAW,QAAW,MAAM,UAAU,OAAO,UAAU,MAAM,GAAG;CACpE,OAAO;EACL;EACA,eAAe;EACf;EACA,sBAAsB,MAAM;EAC5B;CACF;AACF;AAEA,SAAS,UACP,OACA,UACA,MACA,KAC6C;CAC7C,OAAO,IAAI,kBACT,0BACA,CAAC,GACD;EAAE,WAAW,MAAM;EAAW,QAAQ,SAAS;EAAQ;EAAM;CAAI,CACnE;AACF;AAEA,SAAS,oBAAoB,OAA4C;CACvE,MAAM,SAASA,WAAS,KAAK;CAC7B,IACE,WAAW,UACX,OAAO,OAAO,cAAc,YAC5B,OAAO,OAAO,cAAc,YAC5B,OAAO,OAAO,WAAW,UAEzB;CAEF,MAAM,iBAAiB;EACrB;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,KAAK,MAAM,SAAS,gBAClB,IAAI,SAAS,UAAU,OAAO,OAAO,WAAW,UAAU,OAAO;CAEnE,OAAO;EACL,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,GAAG,OAAO,YACR,eAAe,SAAS,UACtB,OAAO,OAAO,WAAW,WAAW,CAAC,CAAC,OAAO,OAAO,MAAM,CAAC,IAAI,CAAC,CAClE,CACF;CACF;AACF;AAEA,SAAS,YAAY,QAAyB;CAC5C,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW;AAC1E;AAEA,SAASA,WAAS,OAAqD;CACrE,OAAO,OAAO,UAAU,YAAY,UAAU,OACzC,QACD;AACN;;;;;;;ACzQA,IAAY,WAAL;;CAEL;;CAEA;;CAEA;;CAEA;;AACF;;AAGA,MAAa,sBAA0D;MAC3C;QACA;QACA;QACA;AAC5B;;AAGA,MAAa,gBAAqC;;;;;AAKlD;;;;ACpBA,SAAS,cAAc,MAAyB;CAC9C,IAAI,OAAO,SAAS,UAAU,OAAO,KAAK,KAAK,MAAM,KAAK,MAAa,OAAO,IAAI;CAClF,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,cACd,aACA,WACA,WACS;CACT,MAAM,UAAU,cAAc,WAAW;CACzC,MAAM,QAAQ,cAAc,SAAS;CACrC,MAAM,QAAQ,cAAc,SAAS;CACrC,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,CAAC,OAAO,UAAU,KAAK,GACnF,OAAO;CAET,OAAO,WAAW,SAAS,UAAU;AACvC;;;;;;;;;;;;;ACpCA,MAAa,cAAc;;AAE3B,MAAa,cAAc;AAE3B,MAAM,UAAU,UAAU,MAAM;CAC9B,gBAAgB;CAChB,eAAe,UAAU;AAC3B,CAAC;;AAED,MAAa,aAAa,QAAQ,MAAM,EAAE,WAAW,GAAG,CAAC;;AAGzD,SAAgB,gBAAgB,MAAyB;CACvD,OAAO,IAAI,UAAU,IAAI,WAAW,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE;;AAGA,SAAgB,gBAAgB,WAAoC;CAClE,IAAI;CACJ,IAAI;EAIF,QAAQ,IAAI,QAAQ,SAAS;CAC/B,QAAQ;EACN,OAAO;CACT;CACA,IAAI,CAAC,MAAM,SAAS,KAAK,MAAM,oBAAoB,CAAC,GAAG,OAAO;CAE9D,MAAM,cAAc,KAAK,IAAI,MAAM,SAAS,KAAK,CAAC,IAAI,KAAK,IAAI,MAAM;CACrE,IAAI,CAAC,OAAO,SAAS,WAAW,GAAG,OAAO;CAK1C,IAAI,OAAO,KAAK,IAAI,aAAa,KAAK,IAAI,aAAa,KAAK,MAAM,WAAW,CAAC,CAAC;CAC/E,OAAO,iBAAsB,gBAAgB,OAAO,CAAC,CAAC,CAAC,oBAAoB,KAAK,GAAG,QAAQ;CAC3F,OAAO,kBAAsB,gBAAgB,IAAI,CAAC,CAAC,cAAc,KAAK,GAAG,QAAQ;CACjF,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,YAAY,MAAyB;CACnD,OAAO,IAAI,UAAU,IAAI,WAAW,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC;AAClE;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBACd,WACA,WACA,WACS;CACT,OAAO,cAAc,gBAAgB,SAAS,GAAG,WAAW,SAAS;AACvE;;;;;;AAkBA,SAAgB,cAAc,OAAwB,UAAgC,CAAC,GAAW;CAChG,MAAM,YACJ,OAAO,UAAU,WACb,QACA,OAAO,UAAU,WACf,MAAM,SAAS,IACf,UAAU,YAAY,KAAK,IACzB,MAAM,SAAS,IACf;CACV,MAAM,QAAQ,IAAI,WAAW,SAAS;CACtC,IAAI,CAAC,MAAM,SAAS,KAAK,MAAM,kBAAkB,CAAC,GAAG,OAAO;CAC5D,IAAI,CAAC,OAAO,SAAS,MAAM,SAAS,CAAC,GAAG,OAAO;CAC/C,MAAM,QAAQ,MAAM,GAAG,CAAC,CAAC,UAAU,IAAI,WAAW,MAAM,CAAC,CAAC,GAAG,CAAC;CAC9D,MAAM,QAAQ,QAAQ,aAAa,YAAY,MAAM,MAAM,IAAI,MAAM,MAAM,EAAC,CAAE,SAAS;CACvF,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO;AACxC;;;;;;;;;;;;;AC1GA,SAAgB,sBACd,QACA,eACA,YAAY,OACN;CACN,IAAI,OAAO,WAAW,UACpB,MAAM,IAAI,cAAc,uBAAuB,EAAE,OAAO,cAAc,CAAC;CAKzE,IAAI;CACJ,IAAI;EACF,WAAW,UAAU,MAAM;CAC7B,QAAQ;EACN,WAAW,UAAU,GAAG;CAC1B;CAEA,IAAI,CAAC,SAAS,SAAS,GACrB,MAAM,IAAI,cAAc,qBAAqB;EAC3C,OAAO;EACP,OAAO,OAAO,MAAM;CACtB,CAAC;CAGH,IAAI,CAAC,aAAa,SAAS,OAAO,GAChC,MAAM,IAAI,cAAc,uBAAuB;EAC7C,OAAO;EACP,OAAO,OAAO,MAAM;CACtB,CAAC;CAGH,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,cAAc,mBAAmB;EAAE,OAAO;EAAe,OAAO,OAAO,MAAM;CAAE,CAAC;AAE9F;;;;;;;AAQA,SAAgB,oBACd,WACA,YACA,YACM;CACN,IAAI;EAAC;EAAW;EAAY;CAAU,CAAC,CAAC,MAAM,UAAU,OAAO,UAAU,QAAQ,GAC/E,MAAM,IAAI,cAAc,6BAA6B,CAAC,CAAC;CAKzD,MAAM,SAAS,UAAoC;EACjD,IAAI;GACF,OAAO,UAAU,KAAK;EACxB,QAAQ;GACN,OAAO,UAAU,GAAG;EACtB;CACF;CACA,MAAM,cAAc,MAAM,SAAS;CACnC,MAAM,eAAe,MAAM,UAAU;CACrC,IAAI,eAAe,MAAM,UAAU;CAEnC,eAAe,aAAa,SAAS,IAAI,eAAe,UAAU,iBAAI;CAEtE,IACE,CAAC,YAAY,SAAS,KACtB,CAAC,aAAa,SAAS,KACvB,CAAC,aAAa,SAAS,KACvB,CAAC,YAAY,WAAW,KACxB,CAAC,aAAa,WAAW,KACzB,CAAC,aAAa,WAAW,GAEzB,MAAM,IAAI,cAAc,wBAAwB;EAC9C,WAAW,OAAO,SAAS;EAC3B,YAAY,OAAO,UAAU;EAC7B,YAAY,OAAO,UAAU;CAC/B,CAAC;CAGH,IAAI,aAAa,cAAc,YAAY,GACzC,MAAM,IAAI,cAAc,uBAAuB;EAC7C,YAAY,OAAO,UAAU;EAC7B,YAAY,OAAO,UAAU;CAC/B,CAAC;AAEL;;;;;;AAOA,SAAgB,sBAAsB,UAAkB,eAA6B;CACnF,IAAI,WAAW,KAAK,CAAC,OAAO,UAAU,QAAQ,GAC5C,MAAM,IAAI,cAAc,0BAA0B;EAAE,OAAO;EAAe,OAAO;CAAS,CAAC;AAE/F;;;;;;;;AASA,SAAgB,kBAAkB,WAAmB,WAAyB;CAC5E,IAAI,CAAC,OAAO,UAAU,SAAS,KAAK,CAAC,OAAO,UAAU,SAAS,GAC7D,MAAM,IAAI,cAAc,sBAAsB;EAAE;EAAW;CAAU,CAAC;CAGxE,IAAI,aAAa,WACf,MAAM,IAAI,cAAc,sBAAsB;EAAE;EAAW;CAAU,CAAC;CAGxE,IAAI,uBAA2B,oBAC7B,MAAM,IAAI,cAAc,uBAAuB;EAC7C;EACA;EACA,SAAS;EACT,SAAS;CACX,CAAC;AAEL;;;;;;AAOA,SAAgB,YAAY,KAAsC;CAChE,IAAI,CAAC,cAAc,MAAM,SAAS,OAAO,IAAI,MAAM,GAAG,GACpD,MAAM,IAAI,cAAc,eAAe;EACrC,OAAO;EACP,OAAO;EACP,SAAS;CACX,CAAC;AAEL;;;;;;AAOA,SAAgB,oBAAoB,aAA2B;CAC7D,IAAI,CAAC,OAAO,UAAU,WAAW,KAAK,eAAe,GACnD,MAAM,IAAI,cAAc,wBAAwB,EAAE,OAAO,YAAY,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,QAAQ,OAAgB,OAAuB;CAC7D,IAAI;EACF,OAAO,iBAAiB,OAAO,KAAK;CACtC,SAAS,OAAgB;EACvB,IAAI,YAAY,KAAK,KAAK,MAAM,SAAS,+BAA+B,MAAM;EAC9E,MAAM,IAAI,cAAc,0BAA0B;GAAE;GAAO,OAAO,OAAO,KAAK;EAAE,CAAC;CACnF;AACF;;;;;;;AAQA,SAAgB,eAAe,SAA6B,OAAuB;CACjF,IAAI,YAAY,QACd,MAAM,IAAI,cAAc,0BAA0B,CAAC,CAAC;CAEtD,OAAO,QAAQ,SAAS,KAAK;AAC/B;;AAGA,MAAM,2CAA2B,IAAI,IAAI;CAAC;CAAS;CAAQ;AAAM,CAAC;AAClE,MAAM,yBAAyB;AAC/B,MAAM,4BAA4B;;;;;;AAOlC,SAAgB,0BAA0B,QAAyB;CACjE,OACE,uBAAuB,KAAK,MAAM,KAClC,OAAO,UAAU,6BACjB,CAAC,yBAAyB,IAAI,MAAM;AAExC;;;;;;;;AASA,SAAgB,oBAAoB,QAAgB,QAAsB;CACxE,IAAI,EAAE,SAAS,SACb,MAAM,IAAI,cAAc,sBAAsB;EAAE;EAAQ;CAAO,CAAC;AAEpE;;;;;;;;ACvOA,IAAa,SAAb,MAAoB;CAEC;CACA;CAFnB,YACE,AAAiB,mBACjB,AAAiB,YACjB;EAFiB;EACA;CAChB;;;;;;;;;;;;;;;;CAiBH,MAAM,cACJ,cACA,OAAe,GACf,QAAgB,IACW;EAC3B,MAAM,UAAU,eAAe,cAAc,eAAe;EAE5D,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,MAAM,IAAI,cAAc,gBAAgB,EAAE,OAAO,KAAK,CAAC;EAGzD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,KACnD,MAAM,IAAI,cAAc,iBAAiB;GAAE,OAAO;GAAO,KAAK;GAAG,KAAK;EAAI,CAAC;EAS7E,OAAO,gBAAgB,MANK,KAAK,WAAW,eAC1C,KAAK,mBACL,gBACA,IACA;GAAE;GAAS,MAAM,KAAK,SAAS;GAAG,OAAO,MAAM,SAAS;EAAE,CAC5D,CAC2B;CAC7B;AACF;AAEA,SAAS,gBAAgB,OAAkC;CACzD,MAAM,OAAO,kBAAkB,OAAO,MAAM;CAG5C,MAAM,qDAAkB,KAAO;CAC/B,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,CAAC,OAAO,MAAM,cAAc,GACxD,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,uBAAuB,GACnC;EAAE,MAAM;EAAO,OAAO;CAAM,CAC9B;CAEF,MAAM,oDAAQ,KAAO;CACrB,OAAO;EACL,QAAQ,OAAO,KAAK,WAAW;GAAE,GAAG;GAAO,UAAU,SAAS,MAAM,UAAU,EAAE;EAAE,EAAE;EACpF,OAAO,OAAO,UAAU,WAAW,QAAQ;CAC7C;AACF;AAIA,SAAS,eAAe,OAAuC;CAC7D,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,QAAQ;CACd,OACE,OAAO,MAAM,aAAa,YAC1B,OAAO,MAAM,YAAY,YACzB,OAAO,MAAM,gBAAgB,YAC7B,SAAS,KAAK,MAAM,WAAW,KAC/B,OAAO,MAAM,cAAc,aAC3B,OAAO,MAAM,cAAc,YAC3B,OAAO,MAAM,gBAAgB;AAEjC;;;;;ACzEA,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;CACA;AACF;;AAQA,MAAa,iBAAiB;;AAG9B,MAAa,4BAA4B;;AAGzC,SAAgB,eAAe,QAAyC;CACtE,OAAO,OAAO,WAAW,YAAa,gBAAsC,SAAS,MAAM;AAC7F;;AAGA,SAAgB,4BACd,SACA,QACS;CACT,OACE,eAAe,MAAM,KACrB,0DAAO,QAAU,eAAc,YAC/B,OAAO,QAAQ,cAAc;AAEjC;;;;;AAmBA,SAAgB,WAAW,SAA2D;CACpF,MAAM,WAAoC,EAAE,GAAG,QAAQ;CACvD,KAAK,MAAM,SAAS;EAAC;EAAa;EAAU;EAAS;EAAU;CAAO,GACpE,OAAO,SAAS;CAElB,OAAO;AACT;;;;;;;;AASA,SAAgB,mBACd,QACA,iBACA,QACA,KACA,kBAA0B,2BAC1B,eAAkC,wBACA;CAClC,OAAO,YAAY,QAAQ,cAAc,gBAAgB;EACvD;EACA;EACA;EAEA,WAAW,gBAAgB,eAAe;CAC5C,CAAC;AACH;;;;;;;;;;;;;;;;;AA4CA,IAAa,UAAb,MAAqB;CAQA;CAPnB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACE,QACA,AAAiB,QACjB;EADiB;EAEjB,KAAK,YAAY,OAAO,iBAAiB;EACzC,KAAK,UAAU,OAAO,kBAAkB,QAAQ,QAAQ,EAAE;EAC1D,KAAK,mBAAmB,OAAO,oBAAoB;EACnD,KAAK,OAAO,OAAO;CACrB;;;;;;;;;;;;;;;;CAiBA,MAAa,MACX,iBACA,QACA,SACA,UAA8B,CAAC,GACF;EAC7B,IAAI,KAAK,WAAW,QAAW,MAAM,cAAc,cAAc;EACjE,MAAM,UAAU,QAAQ,WAAW;EACnC,MAAM,WAAW,QAAQ,YAAY;EACrC,MAAM,UAAU,MAAM,mBACpB,KAAK,QACL,iBACA,QACA,WAAW,OAAO,GAClB,QACA,SAAS,UACX;EACA,MAAM,MAAM,GAAG,KAAK,QAAQ,gCAAgC,mBAAmB,OAAO,EAAE,GAAG,mBAAmB,QAAQ,EAAE,GAAG,mBAAmB,MAAM,EAAE;EAEtJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,WAAW,MAAM,mBACrB,KAAK,WACL,KACA;IACE,QAAQ;IACR,SAAS,oBAAoB,KAAK,MAAM;KACtC,MAAM;KACN,UAAU,EAAE,QAAQ,mBAAmB;IACzC,CAAC;IACD,MAAM,KAAK,UAAU,OAAO;GAC9B,GACA,KAAK,gBACP;GACA,SAAS,SAAS;GAClB,KAAK,SAAS;GACd,OAAO,KAAK,MAAM,iBAAiB,QAAQ,IAAI;EACjD,QAAQ;GACN,OAAO;EACT;EAEA,IAAI,CAAC,IAAI;GACP,IAAI,aAAa,mBAAmB,WAAW,OAAO,WAAW,MAC/D,OAAO;IAAE,QAAQ;IAAW,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC;GAAE;GAEzD,OAAO;EACT;EAGA,OAAO,UAAU,IAAI;CACvB;AACF;AAEA,SAAS,UAAU,MAAmC;;CACpD,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO;CACtD,MAAM,OAAQ,KAA4B;CAC1C,IACE,CAAC,MAAM,QAAQ,IAAI,KACnB,kBAAQ,KAAK,oDAA4C,eAAc,UAEvE,OAAO;CAET,OAAO;AACT;;;;;;;;ACzOA,MAAa,oBAAoB;;;;;;;;;;;ACIjC,MAAM,mCAAmB,IAAI,QAAgB;;;;;;;;;;;;;;;;;AAkB7C,SAAgB,cAAc,OAAyB;;CACrD,IAAI,aAAa,KAAK,GAAG,OAAO,MAAM;CACtC,uBAAI,cAAc,KAAK,mEAAG,YAAW,MAAM,OAAO;CAClD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,IAAI,KAAK;AAClF;;;;;;;;AASA,SAAS,cAAc,OAAyB;CAC9C,IAAI,aAAa,KAAK,GAAG;EACvB,IAAI,MAAM,QAAQ,OAAO;EACzB,MAAM,OAAO,IAAI,cAAc,MAAM,MAAM,MAAM,QAAQ;GACvD,QAAQ,MAAM;GACd,MAAM,MAAM,QAAQ,MAAM;GAC1B,KAAK,MAAM;GACX,WAAW,MAAM;GACjB,sBAAsB,MAAM;GAC5B,oBAAoB,MAAM;GAC1B,aAAa,MAAM;GACnB,cAAc,MAAM;GACpB,OAAO,MAAM;GACb,OAAO,MAAM;GACb,OAAO,MAAM;GACb,YAAY,MAAM;GAClB,QAAQ;EACV,CAAC;EACD,IAAI,MAAM,UAAU,QAAW,KAAK,QAAQ,MAAM;EAClD,OAAO;CACT;CACA,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,iBAAiB,IAAI,KAAK;CAC3E,OAAO;AACT;;AAGA,eAAsB,eAAkB,KAAmC;CACzE,IAAI;EACF,OAAO,MAAM,IAAI;CACnB,SAAS,OAAgB;EACvB,MAAM,cAAc,KAAK;CAC3B;AACF;;;;;AC5DA,IAAa,uBAAb,MAAkF;;CAEhF,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;;;;;;CAOhB,AAAgB;;CAEhB,AAAgB;;;;;;CAMhB,AAAgB;CAChB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;;;;;;;;;;;CAcjB,YAAY,SAeT;EACD,KAAK,SAAS,QAAQ;EACtB,KAAK,YAAY,QAAQ;EACzB,KAAK,gBAAgB,QAAQ;EAC7B,KAAK,cAAc,QAAQ,eAAe;EAC1C,KAAK,OAAO,QAAQ;EACpB,KAAK,SAAS,QAAQ,SAAS,WAAW,WAAW;EACrD,KAAK,SAAS,QAAQ;EACtB,KAAK,WAAW,QAAQ;EACxB,KAAK,iBAAiB,QAAQ,kBAAkB,QAAQ,QAAQ,EAAE;EAClE,KAAK,YAAY,QAAQ;EACzB,KAAK,mBAAmB,QAAQ,oBAAoB;EACpD,KAAK,OAAO,QAAQ;EACpB,KAAK,uBAAuB,QAAQ;CACtC;;;;;;;;;;;;;;;;;CAkBA,MAAa,QAAQ,SAAkD;EACrE,IAAI,KAAK,WAAW,gBAClB,OAAO,KAAK,eAAe,OAAO;EAEpC,OAAO,KAAK,gBAAgB,OAAO;CACrC;CAEA,AAAQ,eAAe,SAAiD;EACtE,OAAO,oBACL;GACE,mBAAmB,KAAK;GACxB,eAAe,KAAK;GACpB,kBAAkB,KAAK;GACvB,MAAM,KAAK;EACb,GACA;GAAE,WAAW,KAAK;GAAW,sBAAsB,KAAK;EAAc,GACtE,OACF;CACF;;;;;;;;;CAUA,MAAc,gBAAgB,SAAoD;EAChF,IAAI,KAAK,yBAAyB,QAAW,MAAM,cAAc,qBAAqB;EAGtF,MAAM,iEAAe,QAAS;EAC9B,MAAM,cAAc,UAClB,IAAI,cAAc,wBAAwB,CAAC,GAAG;GAAE,WAAW,KAAK;GAAW;EAAM,CAAC;EACpF,MAAM,WAAW,2BAA2B,SAAS,GAAG,UAAU;EAClE,MAAM,SAAS,YAAY;EAC3B,IAAI;EACJ,OAAO,MAAM;GACX,MAAM,aAAa,IAAI,gBAAgB;GACvC,MAAM,SAAS,WAAW,YAAY,KAAK,gBAAgB;GAC3D,MAAM,qBAA2B,WAAW,MAAM;GAClD,iEAAc,iBAAiB,SAAS,cAAc,EAAE,MAAM,KAAK,CAAC;GACpE,IAAI;IACF,MAAM,SAAS,MAAM,KAAK,qBAAqB,WAAW,MAAM;IAChE,IAAI,OAAO,WAAW,OAAO,OAAO;GACtC,SAAS,OAAgB;IACvB,eAAe,cAAc,UAAU;IAMvC,MAAM,WAAW,4BAA4B,KAAK,WAAW,KAAK;IAClE,IAAI,aAAa,QAAW,MAAM;IAClC,YAAY;GACd,UAAU;IACR,OAAO;IACP,iEAAc,oBAAoB,SAAS,YAAY;GACzD;GACA,IAAI,CAAE,MAAM,SAAS,YAAY,GAAI;EACvC;EACA,MAAM,cAAc,yBAAyB,KAAK,WAAW,SAAS;CACxE;AACF;;AAGA,SAAS,gBAAgB,QAAyB;CAChD,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACzE;;;;;AAMA,SAAS,4BAA4B,WAAmB,OAA2C;CACjG,IAAI,CAAC,aAAa,KAAK,GAAG,OAAO;CACjC,IAAI,MAAM,SAAS,+BAA+B,MAAM,SAAS,0BAC/D,OAAO,IAAI,cACT,0BACA,CAAC,GACD;EAAE;EAAW,KAAK,MAAM;EAAK,MAAM,MAAM,QAAQ,MAAM;EAAU,OAAO;CAAM,CAChF;CAEF,MAAM,SAAS,MAAM;CACrB,KACG,MAAM,SAAS,gBAAgB,MAAM,SAAS,sBAC/C,WAAW,UACX,CAAC,gBAAgB,MAAM,GACvB;EACA,MAAM,gBAAiB,MAAM,OAAmC;EAChE,OAAO,IAAI,cACT,uBACA;GAAE;GAAQ,eAAe,OAAO,kBAAkB,WAAW,gBAAgB;EAAG,GAChF;GAAE;GAAW;GAAQ,KAAK,MAAM;GAAK,MAAM,MAAM,QAAQ,MAAM;GAAU,OAAO;EAAM,CACxF;CACF;AAEF;;;;;ACzFA,IAAa,eAAb,MAA0B;CACxB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;CAGjB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAGhB,YAAY,SAA8B;EACxC,KAAK,oBAAoBC,oBAAkB,QAAQ,iBAAiB;EACpE,KAAK,YAAY,QAAQ,iBAAiB;EAC1C,KAAK,gBACH,QAAQ,kBAAkB,SACtB,SACA,QAAQ,QAAQ,eAAe,eAAe;EACpD,KAAK,qBAAqB,kBACxB,QAAQ,sBAAsB,KAC9B,oBACF;EACA,KAAK,mBAAmB,KAAK;EAC7B,KAAK,OAAO,QAAQ,QAAQ,CAAC;EAC7B,KAAK,qBAAqB,QAAQ;EAClC,KAAK,wBAAwB,QAAQ;CACvC;CAqBA,MAAa,OACX,QACA,YACA,SAC+B;EAI/B,IAAI,WAAW,SACb,MAAM,IAAI,cAAc,wBAAwB,EAAE,OAAO,CAAC;EAE5D,MAAM,MAAM,KAAK,SAAS,MAAM;EAChC,MAAM,gBAAgB,KAAK,SAAS,OAAO;EAC3C,MAAM,UAAU,oBAAoB,KAAK,MAAM;GAC7C,MAAM;GACN,OAAO,kBAAkB,SAAY,CAAC,IAAI,EAAE,oBAAoB,cAAc;EAChF,CAAC;EACD,MAAM,EAAE,UAAU,SAAS,MAAM,KAAK,KAAK,QAAQ,KAAK,SAAS,UAAU;EAG3E,MAAM,YAAY,kBAAkB,YAAY,WAAW,KAAK;EAChE,MAAM,UAAU,gBAAgB,UAAU,MAAM,KAAK,SAAS;EAE9D,IAAI,CAAC,SAAS,IACZ,MAAM,aAAa,UAAU,MAAM,KAAK,SAAS;EAGnD,MAAM,WAAWC,WAAS,IAAI;EAE9B,yDAAI,SAAW,cAAa,MAC1B,MAAM,IAAI,cACR,0BACA,EAAE,eAAe,oBAAoB,QAAQ,EAAE,GAC/C,OACF;EAEF,MAAM,OAAOA,gEAAS,SAAW,iEAAW,SAAW,QAAO;EAC9D,IAAI,SAAS,QACX,MAAM,IAAI,cAAc,wBAAwB,CAAC,GAAG,OAAO;EAG7D,MAAM,gBAAgB,kBAAkB,MAAM,eAAe;EAC7D,MAAM,OAAO,kBAAkB,MAAM,MAAM;EAC3C,MAAM,mBAAmB,KAAK;EAC9B,MAAM,kBAAkB,KAAK;EAC7B,MAAM,oBACJ,IAAI,cAAc,wBAAwB,CAAC,GAAG,OAAO;EACvD,IAAI,SAAS,UAAU,SAAS,UAC9B,MAAM,YAAY;EAEpB,IACG,mBAAmB,QAAQ,OAAO,qBAAqB,YACvD,oBAAoB,UAAa,oBAAoB,QAAQ,CAAC,cAAc,eAAe,GAE5F,MAAM,YAAY;EAEpB,IAAI,WAAW,kBAAkB,SAAS,QACxC,MAAM,IAAI,cAAc,8BAA8B,CAAC,GAAG,OAAO;EAEnE,IAAI,WAAW,kBAAkB,SAAS,UACxC,2BAA2B,UAAU,MAAM,KAAK,MAAM,UAAU;OAC3D,IAAI,SAAS,YAAY,EAAE,YAAY,OAC5C,MAAM,YAAY;EAIpB,IAAI,SAAS,QAAQ;GACnB,MAAM,iBAAiBA,WAAS,KAAK,SAAS;GAC9C,IAAI,mBAAmB,QAAW;IAChC,MAAM,eAAe,eAAe;IACpC,IAAI,iBAAiB,UAAa,iBAAiB,GACjD,MAAM,cAAc,eAClB,kBAAkB,gBAAgB,UAAU,KAAK,eACjD,kBAAkB,gBAAgB,SAAS,KAAK,IAChD,OACF;GAEJ;EACF;EAEA,MAAM,sBAAsB,WAAW,UAAU,kBAAkB;EACnE,MAAM,wBACJ,kBAAkB,UAAa,kBAAkB,KAAK,sBAAsB;EAC9E,MAAM,cACJ,oBAAoB,QAAQ,oBAAoB,SAC5C,sBAAsB,QAAQ,IAC9B,cAAc,eAAe,IAC3B,kBACA;EACR,OAAO,IAAI,qBAAqB;GAC9B;GACA;GACA,eACE,0BAA0B,UAAa,0BAA0B,KAC7D,OACA;GACN,aAAa,eAAe;GAC5B;GACA,QAAQ,SAAS,WAAW,SAAY,KAAK;GAC7C,UAAU;GACV,mBAAmB,KAAK;GACxB,eAAe,KAAK;GACpB,kBAAkB,KAAK;GACvB,MAAM,KAAK;GACX,sDAAI,QAAS,0BAAyB,SAClC,CAAC,IACD,EAAE,sBAAsB,QAAQ,qBAAqB;EAC3D,CAAC;CACH;;;;;;;;;;;;;;;;;;;;;CAsBA,MAAa,aACX,QACA,YACA,SAC6B;EAC7B,OAAO,qBAAqB,KAAK,WAAW,QAAQ,YAAY,OAAO,CAAC;CAC1E;CAEA,MAAc,WACZ,QACA,YACA,SAC6B;EAC7B,IAAI,WAAW,SACb,MAAM,IAAI,cAAc,wBAAwB,EAAE,OAAO,CAAC;EAE5D,MAAM,gBAAgB,KAAK,SAAS,OAAO;EAC3C,IAAI,kBAAkB,QACpB,MAAM,IAAI,cAAc,sCAAsC,CAAC,CAAC;EAGlE,MAAM,UAAU,oBAAoB,KAAK,MAAM;GAC7C,MAAM;GACN,OAAO;IAAE,oBAAoB;IAAe,YAAY;GAAO;EACjE,CAAC;EACD,MAAM,EAAE,UAAU,SAAS,MAAM,KAAK,KAAK,QAAQ,KAAK,SAAS,MAAM,GAAG,SAAS,UAAU;EAC7F,OAAO;GAAE,YAAY,SAAS;GAAQ;EAAK;CAC7C;;;;;;CAOA,AAAQ,SAAS,SAA6D;EAC5E,0DAAO,QAAS,mBAAkB,SAC9B,KAAK,gBACL,QAAQ,QAAQ,eAAe,eAAe;CACpD;CAEA,AAAQ,SAAS,QAAwB;EACvC,OAAO,GAAG,KAAK,kBAAkB,YAAY,kBAAkB,GAAG;CACpE;;;;;;;CAQA,MAAc,KACZ,QACA,KACA,SACA,YACoD;EAIpD,IAAI;EACJ,IAAI;GACF,UAAU,KAAK,UAAU,UAAU;EACrC,SAAS,OAAgB;GACvB,MAAM,IAAI,cAAc,kBAAkB;IAAE;IAAQ,QAAQ;GAAS,GAAG,EAAE,MAAM,CAAC;EACnF;EACA,MAAM,kBACJ,QACA,UAEA,IAAI,cACF,8BACA,EAAE,OAAO,GACT;GAAE,WAAW,kBAAkB,YAAY,WAAW,KAAK;GAAI;GAAK;EAAM,CAC5E;EACF,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,mBACf,KAAK,WACL,KACA;IACE,QAAQ;IACR;IACA,MAAM;GACR,GACA,KAAK,kBACP;EACF,SAAS,OAAgB;GACvB,IAAI,aAAa,OAAO,iBAAiB,GAAG,MAAM,eAAe,WAAW,KAAK;GACjF,IAAI,aAAa,OAAO,iBAAiB,KAAK,KAAK,qBAAqB,KAAK,GAC3E,MAAM,eAAe,aAAa,KAAK;GAMzC,MAAM,WAAW,KAAK,kBAAkB,KAAK;GAC7C,IAAI,aAAa,QAAW,OAAO;GACnC,MAAM;EACR;EACA,IAAI;GACF,OAAO;IAAE;IAAU,MAAM,MAAM,iBAAiB,QAAQ;GAAE;EAC5D,SAAS,OAAgB;GAGvB,MAAM,eAAe,aAAa,KAAK;EACzC;CACF;;;;;;CAOA,AAAQ,kBAAkB,OAAuE;EAC/F,IAAI;EACJ,IAAI;;GACF,kCAAS,KAAK,gHAAwB,KAAK;EAC7C,QAAQ;GACN;EACF;EACA,IAAI,WAAW,QAAW,OAAO;EACjC,MAAM,EAAE,QAAQ,MAAM,YAAY;EAClC,IAAI,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,OAAO,SAAS,KAAK,OAAO;EACtE,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO;EAQ/C,OAAO;GAAE;IANP,IAAI,UAAU,OAAO,SAAS;IAC9B;IACA,MAAM,YAAY;IAClB,MAAM,YAAY;IAClB,SAAS,WAAW,CAAC;GAEP;GAAG;EAAK;CAC1B;CAEA,AAAQ,qBAAqB,OAAyB;EACpD,IAAI;;GACF,iCAAO,KAAK,6GAAqB,KAAK,OAAM;EAC9C,QAAQ;GACN,OAAO;EACT;CACF;;CAGA,IAAW,gBAA+B;EACxC,OAAO,KAAK;CACd;AACF;AAEA,SAASD,oBAAkB,OAAuB;CAChD,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;AAEA,SAAS,gBACP,UACA,MACA,KACA,WACkB;CAClB,OAAO;EACL,QAAQ,SAAS;EACjB;EACA;EACA,GAAI,cAAc,UAAa,cAAc,KAAK,CAAC,IAAI,EAAE,UAAU;CACrE;AACF;;;;;;;;;;;AAYA,SAAS,2BACP,UACA,MACA,KACA,MACA,YACM;CACN,MAAM,kBAAkB,kBAAkB,YAAY,WAAW,KAAK;CACtE,MAAM,SAAS,KAAK;CACpB,IAAI,OAAO,WAAW,YAAY,WAAW,MAAM,WAAW,iBAAiB;CAC/E,MAAM,UAAU,WAAW,UAAa,WAAW,QAAQ,WAAW;CACtE,MAAM,UAA4B;EAChC,GAAG,gBAAgB,UAAU,MAAM,GAAG;EACtC,WAAW;CACb;CACA,MAAM,UACF,IAAI,cAAc,sBAAsB,CAAC,GAAG,OAAO,IACnD,IAAI,cAAc,uBAAuB,CAAC,GAAG,OAAO;AAC1D;AAEA,SAAS,aACP,UACA,MACA,KACA,WACe;CAEf,IAAI,SAAS,gBACX,OAAO,IAAI,cACT,mBACA,EAAE,QAAQ,SAAS,OAAO,GAC1B,gBAAgB,UAAU,MAAM,KAAK,SAAS,CAChD;CAEF,MAAM,SAASC,WAAS,IAAI;CAC5B,MAAM,SAAS,kBAAkB,MAAM,OAAO;CAC9C,MAAM,OACJ,kBAAkB,QAAQ,MAAM,KAChC,kBAAkB,QAAQ,MAAM,KAChC,kBAAkB,QAAQ,UAAU,KACpC;CAGF,MAAM,UAAU,oBAAoB,IAAI;CACxC,MAAM,eAAe,SAAS,WAAW,MAAM,eAAe,QAAQ,IAAI;CAC1E,IAAI,SAAS,cACX,OAAO,IAAI,cACT,cACA;EAAE,QAAQ,SAAS;EAAQ;EAAK,eAAe;CAAQ,GACvD,gBAAgB,UAAU,MAAM,KAAK,SAAS,CAChD;CAEF,OAAO,cAAc,kBACnB,MACA,SACA,SAAS,QACT,MACA,KACA,cACA,cAAc,KAAK,SAAY,SACjC;AACF;AAEA,SAASA,WAAS,OAAqD;CACrE,OAAO,OAAO,UAAU,YAAY,UAAU,OACzC,QACD;AACN;AAEA,SAAS,cAAc,OAAiC;CACtD,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS;AAC1E;;;;;AClhBA,MAAa,qBAAyE;CACpF,MAAM;EACJ,mBAAmB;EACnB,iBAAiB;CACnB;CACA,OAAO;EACL,mBAAmB;EACnB,iBAAiB;CACnB;AACF;;;;AClBA,MAAa,WAAW,MAAM,WAAW;;;;;ACSzC,IAAa,sBAAb,MAAiC;CAKF;CAJ7B,AAAQ,WAAW;CACnB,AAAQ;CACR,AAAiB;CAEjB,YAAY,AAAiB,SAAqC;EAArC;EAC3B,KAAK,UAAU,QAAQ;EACvB,KAAK,aAAa,QAAQ,cAAc;CAC1C;;CAGA,cAAuB;EACrB,OAAO,KAAK,WAAW,KAAK,QAAQ;CACtC;;CAGA,cAAsB;EACpB,OAAO,KAAK;CACd;;CAGA,gBAAsB;EACpB,KAAK,YAAY;EACjB,KAAK,UAAU,KAAK,IAAI,KAAK,UAAU,GAAG,KAAK,UAAU;CAC3D;;CAGA,QAAc;EACZ,KAAK,WAAW;EAChB,KAAK,UAAU,KAAK,QAAQ;CAC9B;CAEA,IAAI,eAAuB;EACzB,OAAO,KAAK;CACd;CAEA,IAAI,cAAsB;EACxB,OAAO,KAAK,QAAQ;CACtB;AACF;;;;AC5CA,MAAM,mBAAmB;AACzB,MAAM,eAAe;AACrB,MAAM,+BAA+B;AACrC,MAAM,iBAAiB;AAiGvB,MAAM,oBAAwC;CAAC;CAAO;CAAU;AAAS;;AAGzE,SAAgB,qBACd,OACuD;CACvD,MAAM,EAAE,SAAS;CACjB,QACG,MAAM,eAAe,QAAQ,MAAM,eAAe,SACnD,OAAO,SAAS,YAChB,SAAS,QACT,OAAO,MAAM,gBAAgB,YAC7B,OAAO,MAAM,qBAAqB,YAClC,kBAAkB,SAAS,MAAM,SAAS,KAC1C,OAAO,MAAM,aAAa,YAC1B,OAAO,MAAM,eAAe,YAC5B,OAAO,MAAM,eAAe,YAC5B,OAAO,MAAM,mBAAmB,YAChC,OAAO,MAAM,iBAAiB;AAElC;;AASA,IAAa,kBAAb,cAAqC,MAAM;;CAEzC,AAAS;;CAET,AAAS;CAET,YAAY,MAAc,SAAiB,MAAgB;EACzD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,IAAI,SAAS,QAAW,KAAK,OAAO;CACtC;AACF;AAgDA,SAAS,mBAAmB,OAAwB;CAClD,MAAM,KACJ,OAAO,UAAU,YAAY,UAAU,OAClC,MAAuC,iBACxC;CACN,IAAI,OAAO,OAAO,UAChB,MAAM,IAAI,gBAAgB,QAAQ,uDAAuD;CAE3F,OAAO;AACT;;;;;;;;;;;;;;AAuBA,IAAa,oBAAb,MAA+B;CAC7B,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAQ;CACR,AAAQ;CACR,AAAQ,gBAAgB;CACxB,AAAiB,0BAAU,IAAI,IAA4B;CAC3D,AAAiB,0CAA0B,IAAI,IAAgC;CAC/E,AAAiB,sCAAsB,IAAI,IAAwB;CACnE,AAAQ,mBAAmB;CAC3B,AAAQ,eAAe;CACvB,AAAQ;CACR,AAAQ;CAER,YAAY,SAA2B,CAAC,GAAG;EACzC,KAAK,MAAM,OAAO,OAAO,mBAAmB,KAAK;EACjD,KAAK,mBAAmB,OAAO,oBAAoB;EACnD,KAAK,UAAU,IAAI,oBAAoB;GACrC,aAAa,OAAO,qBAAqB;GACzC,aAAa,OAAO,oBAAoB;EAC1C,CAAC;EAED,MAAM,iBACJ,OAAO,iBAAkB,WAAuC;EAClE,IAAI,OAAO,mBAAmB,YAC5B,MAAM,IAAI,cAAc,gCAAgC,CAAC,CAAC;EAE5D,KAAK,uBAAuB;EAC5B,IAAI,OAAO,WAAW,QAAW;GAC/B,IAAI,OAAO,WAAW,MAAM,OAAO,kBAAkB,QACnD,MAAM,IAAI,cAAc,2BAA2B,CAAC,CAAC;GAEvD,KAAK,SAAS,OAAO;EACvB;CACF;;CAGA,UAAyB;EACvB,IAAI,KAAK,YAAY,GAAG,OAAO,QAAQ,QAAQ;EAC/C,IAAI,KAAK,gBAAgB,OAAO,KAAK;EACrC,KAAK,mBAAmB;EACxB,KAAK,oBAAoB;EACzB,KAAK,iBAAiB,KAAK,WAAW;EACtC,OAAO,KAAK;CACd;;CAGA,aAAmB;EACjB,KAAK,mBAAmB;EACxB,KAAK,eAAe;EACpB,KAAK,oBAAoB;EACzB,KAAK,cAAc,IAAI,cAAc,uBAAuB,CAAC,CAAC,CAAC;EAC/D,MAAM,SAAS,KAAK;EACpB,KAAK,SAAS;EACd,KAAK,iBAAiB;EACtB,+CAAQ,MAAM,KAAM,mBAAmB;CACzC;;CAGA,cAAuB;;EACrB,wBAAO,KAAK,oEAAQ,gBAAe;CACrC;;CAGA,QAAqB,QAAgB,QAA8C;EACjF,OAAO,KAAK,KAAQ,QAAQ,MAAM;CACpC;CAEA,AAAQ,KACN,QACA,QACA,UACY;EACZ,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,KAAK,QAC/B,OAAO,QAAQ,OAAO,IAAI,cAAc,wBAAwB,CAAC,CAAC,CAAC;EAGrE,MAAM,KAAK,EAAE,KAAK;EAClB,MAAM,QAAiC;GAAE,SAAS;GAAO;GAAI;EAAO;EACpE,IAAI,WAAW,QAAW,MAAM,YAAY;EAE5C,OAAO,IAAI,SAAY,SAAS,WAAW;GACzC,MAAM,UAAU,iBAAiB;IAC/B,KAAK,QAAQ,OAAO,EAAE;IACtB,OACE,IAAI,cAAc,0BAA0B;KAAE;KAAQ,WAAW,KAAK;IAAiB,CAAC,CAC1F;GACF,GAAG,KAAK,gBAAgB;GACxB,KAAK,QAAQ,IAAI,IAAI;IAAE,UAAU,UAAU,QAAQ,KAAU;IAAG;IAAQ;IAAS;GAAS,CAAC;GAE3F,IAAI;;IACF,sBAAK,8DAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;GACzC,SAAS,OAAO;IACd,aAAa,OAAO;IACpB,KAAK,QAAQ,OAAO,EAAE;IACtB,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;GAClE;EACF,CAAC;CACH;;CAGA,aAA+C;EAC7C,OAAO,KAAK,QAAQ,iBAAiB;CACvC;;CAGA,OAAuD;EACrD,OAAO,KAAK,QAAQ,WAAW;CACjC;;CAGA,QAAQ,UAA8D;EACpE,OAAO,KAAK,QAAQ,gBAAgB,QAAQ;CAC9C;;CAGA,MAAM,WAAW,OAAe,eAA0D;EACxF,MAAM,MAAM,QAAQ,OAAO,OAAO;EAClC,OAAO,KAAK,QACV,mBACA,kBAAkB,SAAY,EAAE,OAAO,IAAI,IAAI;GAAE,OAAO;GAAK;EAAc,CAC7E;CACF;;;;;CAMA,MAAM,aAAa,MAMqD;EACtE,OAAO,KAAK,QAAQ,qBAAqB;GAAE,GAAG;GAAM,OAAO,QAAQ,KAAK,OAAO,OAAO;EAAE,CAAC;CAC3F;;CAGA,iBAAsE;EACpE,OAAO,KAAK,QAAQ,qBAAqB;CAC3C;;CAGA,MAAM,QAM+B;EACnC,OAAO,KAAK,QAAQ,cAAc,MAAM;CAC1C;;CAGA,SAAS,eAAyD;EAChE,OAAO,KAAK,QAAQ,iBAAiB,EAAE,cAAc,CAAC;CACxD;;CAGA,eACE,IACA,OAII,CAAC,GACsB;EAC3B,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;CACxC;;;;;;CAOA,cACE,UACA,IACA,OAA6B,CAAC,GACH;EAC3B,OAAO,KAAK,UAAU,QAAQ,IAAI;GAAE,GAAG;GAAU,GAAG;EAAK,CAAC;CAC5D;;CAGA,MAAM,kBACJ,OACA,IACA,OAA0D,CAAC,GAChC;EAC3B,OAAO,KAAK,UAAU,WAAW,IAAI;GAAE,OAAO,QAAQ,OAAO,OAAO;GAAG,GAAG;EAAK,CAAC;CAClF;;CAGA,qBACE,IACA,OAA0D,CAAC,GAChC;EAC3B,OAAO,KAAK,UAAU,eAAe,IAAI,IAAI;CAC/C;;;;;;;;CASA,MAAM,mBACJ,IACA,OAAmD,CAAC,GACzB;EAC3B,MAAM,SACJ,KAAK,UAAU,SAAY,OAAO;GAAE,GAAG;GAAM,OAAO,QAAQ,KAAK,OAAO,OAAO;EAAE;EACnF,OAAO,KAAK,UACV,cACC,UAAU;GACT,IAAI,qBAAqB,KAAK,GAAG,GAAG,KAAK;QACpC,SAAS,2DAA2D;EAC3E,GACA,MACF;CACF;;CAGA,gBACE,IACA,OAA6B,CAAC,GACH;EAC3B,OAAO,KAAK,UAAU,UAAU,IAAI,IAAI;CAC1C;CAEA,AAAQ,aAA4B;EAClC,OAAO,IAAI,SAAe,SAAS,WAAW;GAC5C,IAAI,SAAS;GACb,MAAM,SACJ,KAAK,WAAW,SACZ,IAAI,KAAK,qBAAqB,KAAK,KAAK,gBAAgB,IACxD,IAAI,KAAK,qBAAqB,KAAK,KAAK,kBAAkB,EACxD,SAAS,EAAE,aAAa,KAAK,OAAO,EACtC,CAAC;GACP,KAAK,SAAS;GAEd,OAAO,eAAe;IACpB,IAAI,KAAK,WAAW,QAAQ;IAC5B,SAAS;IACT,KAAK,iBAAiB;IACtB,IAAI,CAAC,KAAK,cAAc,KAAK,QAAQ,MAAM;IAC3C,SAAS,0BAA0B;IACnC,QAAQ;GACV;GACA,OAAO,aAAa,UAAU,KAAK,cAAc,MAAM,IAAI;GAC3D,OAAO,gBAAgB;IACrB,IAAI,CAAC,QAAQ,OAAO,IAAI,cAAc,yBAAyB,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;GACnF;GACA,OAAO,WAAW,UAAU;IAC1B,IAAI,KAAK,WAAW,QAAQ;IAC5B,KAAK,SAAS;IACd,KAAK,iBAAiB;IACtB,IAAI,CAAC,QACH,OAAO,IAAI,cAAc,gCAAgC,EAAE,WAAW,MAAM,QAAQ,EAAE,CAAC,CAAC;IAE1F,KAAK,cACH,IAAI,cAAc,4BAA4B,EAAE,WAAW,MAAM,QAAQ,EAAE,CAAC,CAC9E;IACA,IAAI,CAAC,KAAK,oBAAoB,CAAC,KAAK,cAAc,KAAK,mBAAmB;GAC5E;EACF,CAAC;CACH;CAEA,AAAQ,cAAc,MAAqB;EACzC,IAAI,OAAO,SAAS,UAAU;GAC5B,SAAS,wCAAwC;GACjD;EACF;EAEA,IAAI;EACJ,IAAI;GACF,UAAU,KAAK,MAAM,IAAI;EAC3B,QAAQ;GACN,SAAS,wCAAwC;GACjD;EACF;EAEA,IAAI,OAAO,QAAQ,OAAO,UAAU;GAClC,MAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,EAAE;GAC3C,IAAI,CAAC,SAAS;GACd,aAAa,QAAQ,OAAO;GAC5B,KAAK,QAAQ,OAAO,QAAQ,EAAE;GAC9B,IAAI,QAAQ,OAAO;IACjB,MAAM,OAAO,OAAO,QAAQ,MAAM,SAAS,WAAW,QAAQ,MAAM,OAAO;IAC3E,MAAM,eACJ,OAAO,QAAQ,MAAM,YAAY,WAAW,QAAQ,MAAM,UAAU;IACtE,QAAQ,OAAO,IAAI,gBAAgB,MAAM,cAAc,QAAQ,MAAM,IAAI,CAAC;GAC5E,OAAO;IACL,IAAI;;KACF,6BAAQ,sFAAW,QAAQ,MAAM;IACnC,SAAS,OAAO;KACd,QAAQ,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;KACxE;IACF;IACA,QAAQ,QAAQ,QAAQ,MAAM;GAChC;GACA;EACF;EAEA,IAAI,QAAQ,WAAW,uBAAuB,CAAC,KAAK,SAAS,QAAQ,MAAM,GAAG;EAC9E,MAAM,iBAAiB,QAAQ,OAAO;EACtC,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,OAAO,mBAAmB,YAAY,CAAC,KAAK,SAAS,MAAM,GAAG;EAClE,MAAM,eAAe,KAAK,wBAAwB,IAAI,cAAc;EACpE,IAAI,8DAAC,aAAc,SAAQ;EAC3B,IAAI;GACF,aAAa,SAAS,MAAM;EAC9B,SAAS,OAAO;GACd,SAAS,qCAAqC,KAAK;EACrD;CACF;CAEA,MAAc,UACZ,SACA,UACA,SAC2B;EAC3B,MAAM,SAAkC;GAAE;GAAS,GAAG;EAAQ;EAC9D,MAAM,SAAkC;GACtC,gBAAgB;GAChB,aAAa,YAAY,KAAK,YAAY,YAAY;EACxD;EACA,MAAM,eAAmC;GACvC,UAAU;GACV;GACA;GACA;GACA,QAAQ;EACV;EAEA,MAAM,KAAK,KAAK,kBAAkB,SAAS,UAAU;GACnD,MAAM,WAAW,mBAAmB,KAAK;GACzC,aAAa,WAAW;GACxB,OAAO,iBAAiB;GACxB,KAAK,oBAAoB,IAAI,YAAY;GACzC,KAAK,wBAAwB,IAAI,UAAU,YAAY;EACzD,CAAC;EACD,OAAO;CACT;CAEA,MAAc,YAAY,cAAiD;EACzE,IAAI,CAAC,aAAa,QAAQ;EAC1B,aAAa,SAAS;EACtB,KAAK,oBAAoB,OAAO,YAAY;EAC5C,KAAK,wBAAwB,OAAO,aAAa,QAAQ;EACzD,IAAI,KAAK,YAAY,GACnB,MAAM,KAAK,QAAQ,oBAAoB,EAAE,gBAAgB,aAAa,SAAS,CAAC;CAEpF;CAEA,AAAQ,qBAA2B;EACjC,IAAI,KAAK,gBAAgB,KAAK,kBAAkB;EAChD,KAAK,eAAe;EACpB,AAAK,KAAK,cAAc;CAC1B;CAEA,MAAc,gBAA+B;EAC3C,OAAO,CAAC,KAAK,oBAAoB,KAAK,QAAQ,YAAY,GAAG;GAC3D,MAAM,QAAQ,KAAK,QAAQ,YAAY;GACvC,KAAK,QAAQ,cAAc;GAC3B,SACE,0BAA0B,KAAK,QAAQ,aAAa,GAAG,KAAK,QAAQ,YAAY,MAAM,MAAM,GAC9F;GACA,MAAM,KAAK,sBAAsB,KAAK;GAEtC,IAAI,KAAK,kBAAkB;GAE3B,IAAI;IACF,MAAM,KAAK,WAAW;IACtB,MAAM,KAAK,eAAe;IAC1B,KAAK,QAAQ,MAAM;IACnB,KAAK,eAAe;IACpB;GACF,SAAS,OAAO;IACd,SACE,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GACjF;GACF;EACF;EACA,KAAK,eAAe;EACpB,IAAI,CAAC,KAAK,kBAAkB,SAAS,sCAAsC;CAC7E;CAEA,MAAc,iBAAgC;EAC5C,KAAK,wBAAwB,MAAM;EACnC,KAAK,MAAM,gBAAgB,KAAK,qBAAqB;GACnD,IAAI,CAAC,aAAa,QAAQ;GAC1B,MAAM,SAAS;IAAE,GAAG,aAAa;IAAQ,UAAU;GAAK;GACxD,MAAM,SAAS,MAAM,KAAK,8BAA8B,SAAS,UAAU;IACzE,MAAM,WAAW,mBAAmB,KAAK;IAEzC,IAAI,CAAC,aAAa,QAAQ;IAC1B,aAAa,WAAW;IACxB,aAAa,OAAO,iBAAiB;IACrC,KAAK,wBAAwB,IAAI,UAAU,YAAY;GACzD,CAAC;GACD,IAAI,CAAC,aAAa,QAChB,MAAM,KAAK,QAAQ,oBAAoB,EAAE,gBAAgB,OAAO,eAAe,CAAC;EAEpF;CACF;CAEA,MAAc,8BACZ,QACA,UACqC;EACrC,KAAK,IAAI,UAAU,IAAK,WACtB,IAAI;GACF,OAAO,MAAM,KAAK,KAAK,kBAAkB,QAAQ,QAAQ;EAC3D,SAAS,OAAO;GACd,IACE,EAAE,iBAAiB,oBACnB,MAAM,SAAS,gBACf,WAAW,8BAEX,MAAM;GAER,MAAM,eAAe,KAAK,iBAAiB,MAAM,IAAI;GACrD,SAAS,8CAA8C,aAAa,GAAG;GACvE,MAAM,IAAI,SAAe,YAAY,WAAW,SAAS,YAAY,CAAC;EACxE;CAEJ;CAEA,AAAQ,sBAAsB,OAA8B;EAC1D,OAAO,IAAI,SAAS,YAAY;GAC9B,KAAK,iBAAiB,iBAAiB;IACrC,KAAK,iBAAiB;IACtB,KAAK,wBAAwB;IAC7B,QAAQ;GACV,GAAG,KAAK;GACR,KAAK,wBAAwB;EAC/B,CAAC;CACH;CAEA,AAAQ,sBAA4B;EAClC,IAAI,KAAK,mBAAmB,QAAW,aAAa,KAAK,cAAc;EACvE,KAAK,iBAAiB;EACtB,MAAM,UAAU,KAAK;EACrB,KAAK,wBAAwB;EAC7B,kDAAU;CACZ;CAEA,AAAQ,cAAc,OAAoB;EACxC,KAAK,MAAM,WAAW,KAAK,QAAQ,OAAO,GAAG;GAC3C,aAAa,QAAQ,OAAO;GAC5B,QAAQ,OAAO,KAAK;EACtB;EACA,KAAK,QAAQ,MAAM;CACrB;CAEA,AAAQ,iBAAiB,MAAuB;EAC9C,IACE,CAAC,KAAK,SAAS,IAAI,KACnB,OAAO,KAAK,oBAAoB,YAChC,KAAK,kBAAkB,GAEvB,OAAO;EACT,OAAO,KAAK;CACd;CAEA,AAAQ,SAAS,OAAkD;EACjE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;CAC5E;AACF;;;;ACjrBA,IAAa,aAAb,MAAwB;CAMH;CACA;CACA;;;;;CAHnB,YACE,AAAiB,gBAA+B,gBAChD,AAAiB,YAAY,KAC7B,AAAiB,OAAoB,CAAC,GACtC;EAHiB;EACA;EACA;CAChB;CAEH,MAAc,YACZ,QACA,SACA,UACA,UACA,MACA,SACsB;EACtB,MAAM,MAAM,GAAG,UAAU,WAAW;EACpC,SAAS,sBAAsB,IAAI,cAAc,IAAI;EAErD,MAAM,UAAU,QAAQ,IAAI;EAC5B,MAAM,WAAW,MAAM,mBACrB,KAAK,eACL,KACA;GACE;GAGA,SAAS,oBAAoB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;GACzD,GAAI,UAAU,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;GAChD,sDAAI,QAAS,YAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;EACpE,GACA,KAAK,WAGL,EAAE,OAAO,MAAM,CACjB;EAEA,IAAI,CAAC,SAAS,IACZ,MAAM,MAAM,cAAc,kBAAkB,KAAK,QAAQ;EAG3D,MAAM,OAAO,MAAM,iBAAiB,QAAQ;EAC5C,SAAS,iBAAiB,UAAU,WAAW,SAAS,IAAI,IAAI;EAEhE,OAAO;CACT;;CAGA,MAAM,gBACJ,SACA,UACA,UACA,MACsB;EACtB,OAAO,KAAK,YAAY,QAAQ,SAAS,UAAU,UAAU,IAAI;CACnE;;CAGA,MAAM,eACJ,SACA,UACA,UACA,QACA,SACsB;EACtB,MAAM,qBAAqB,SACvB,GAAG,SAAS,GAAG,iBAAiB,QAAQ,KAAK,KAAK,aAAa,MAC/D;EAEJ,OAAO,KAAK,YAAY,OAAO,SAAS,UAAU,oBAAoB,QAAW,OAAO;CAC1F;AACF;;;;;AC3DA,SAAgB,QAAW,OAAyB;CAClD,OAAO;EAAE,IAAI;EAAM;CAAM;AAC3B;;AAGA,SAAgB,cAAiB,QAA+B;CAC9D,OAAO;EAAE,IAAI;EAAO;CAAO;AAC7B;;;;;;AAOA,SAAgB,YACd,QACA,MACA,OACA,gBACK;CACL,IAAI,CAAC,MAAM,QAAQ,IAAI,GACrB,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,GAAG,OAAO,OAAO,GAC7B;EAAE,MAAM;EAAM,OAAO;CAAM,CAC7B;CAEF,MAAM,OAAY,CAAC;CACnB,AAAC,KAAmB,SAAS,OAAO,UAAU;EAC5C,MAAM,SAAS,MAAM,KAAK;EAC1B,IAAI,OAAO,IAAI;GACb,KAAK,KAAK,OAAO,KAAK;GACtB;EACF;EACA,IAAI;GACF,uEAAiB;IAAE;IAAQ;IAAO;IAAO,QAAQ,OAAO;GAAO,CAAC;EAClE,QAAQ,CAER;CACF,CAAC;CACD,OAAO;AACT;;AAGA,SAAgB,cAAc,OAAqD;CACjF,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD;AACN;;AAGA,SAAgB,eAAe,OAAoC;CACjE,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;CACvE,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,IAAI;EACpD,MAAM,SAAS,OAAO,KAAK;EAC3B,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS;CAC5C;AAEF;;;;;;;;;;ACjDA,IAAa,cAAb,MAAyB;CAWJ;CACA;CACA;;;;;;;;;;CAHnB,YACE,AAAiB,mBACjB,AAAiB,YACjB,AAAiB,UAAgE,CAAC,GAClF;EAHiB;EACA;EACA;CAChB;;;;;;;;;;CAWH,MAAa,WAAW,SAAgE;EACtF,MAAM,WAAW,MAAM,KAAK,WAAW,eACrC,KAAK,mBACL,gBACA,YACA,QACAC,eAAa,OAAO,CACtB;EACA,OAAO,YACL,WACA,UACA,gEACA,QAAS,mBAAkB,KAAK,QAAQ,cAC1C;CACF;;;;;;;;;;;CAYA,MAAa,iBAAiB,SAAmE;EAC/F,MAAM,0DAAO,QAAS,wBAAO,IAAI,KAAK,EAAC,CAAE,QAAQ;EAEjD,QACE,MAFoB,KAAK,WAAW,OAAO,EAEpC,CAAC,MAAM,WAAW,OAAO,MAAM,QAAQ,KAAK,OAAO,OAAO,OAAO,IAAI,QAAQ,CAAC,KAAK;CAE9F;;;;;;;;;;;;CAaA,MAAa,eACX,UACA,SAC4B;;EAC5B,IAAI,OAAO,aAAa,YAAY,CAAC,OAAO,cAAc,QAAQ,KAAK,WAAW,GAChF,MAAM,IAAI,cAAc,qBAAqB,EAAE,OAAO,OAAO,QAAQ,EAAE,CAAC;EAE1E,MAAM,WAAW,MAAM,KAAK,WAAW,eACrC,KAAK,mBACL,gBACA,IACA,EAAE,UAAU,OAAO,QAAQ,EAAE,GAC7BA,eAAa,OAAO,CACtB;EACA,MAAM,yBAAO,cAAc,QAAQ,mEAAI;EACvC,IAAI,CAAC,MAAM,QAAQ,IAAI,GACrB,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,cAAc,GAC1B;GAAE,MAAM;GAAU,OAAO;EAAM,CACjC;EAQF,OAAO;GAAE;GAAU,SANH,YACd,eACA,MACA,+DACA,QAAS,mBAAkB,KAAK,QAAQ,cAEjB;EAAE;CAC7B;;;;;;;;;;;CAYA,MAAa,sBACX,SACmC;EACnC,MAAM,SAAS,MAAM,KAAK,iBAAiB,OAAO;EAClD,OAAO,WAAW,OAAO,OAAO,KAAK,eAAe,OAAO,IAAI,OAAO;CACxE;AACF;AAEA,SAASA,eACP,SACqC;CACrC,0DAAO,QAAS,YAAW,SAAY,SAAY,EAAE,QAAQ,QAAQ,OAAO;AAC9E;AAEA,SAAS,gBAAgB,OAAoC;CAC3D,OAAO,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,KAAK,SAAS,IAAI,QAAQ;AAC1F;AAEA,SAAS,QAAQ,OAAkC;CACjD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,OAAO,IAAI,KAAK,KAAK;CAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,SAAY;AACpD;AAEA,SAAS,YAAY,OAA+C;CAClE,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,WAAW,QAAW,OAAO,cAAc,eAAe;CAC9D,MAAM,KAAK,gBAAgB,OAAO,KAAK;CACvC,IAAI,OAAO,QAAW,OAAO,cAAc,oCAAoC;CAC/E,MAAM,OAAO,OAAO;CACpB,IAAI,OAAO,SAAS,UAAU,OAAO,cAAc,sBAAsB;CACzE,MAAM,QAAQ,QAAQ,OAAO,QAAQ;CACrC,MAAM,MAAM,QAAQ,OAAO,MAAM;CACjC,IAAI,UAAU,UAAa,QAAQ,QAAW,OAAO,cAAc,4BAA4B;CAC/F,IAAI,MAAM,QAAQ,IAAI,IAAI,QAAQ,GAAG,OAAO,cAAc,oBAAoB;CAC9E,MAAM,UAAU,OAAO;CACvB,IAAI,OAAO,YAAY,YAAY,CAAC,OAAO,cAAc,OAAO,KAAK,UAAU,GAC7E,OAAO,cAAc,4BAA4B;CAEnD,OAAO,QAAQ;EAAE;EAAI;EAAM;EAAO;EAAK;CAAQ,CAAC;AAClD;;AAGA,MAAM,UAAU;AAEhB,SAAS,UAAU,OAAoC;CAErD,MAAM,OAAO,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;CACzD,OAAO,OAAO,SAAS,YAAY,QAAQ,KAAK,IAAI,IAAI,OAAO;AACjE;AAEA,SAAS,WAAW,OAA0C;CAC5D,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,WAAW,QAAW,OAAO;CACjC,MAAM,EAAE,MAAM,MAAM,UAAU;CAC9B,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CACjE,OAAO;EAAE;EAAM;EAAM;CAAM;AAC7B;AAEA,SAAS,WAAW,OAA8C;CAChE,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,WAAW,QAAW,OAAO,cAAc,eAAe;CAC9D,MAAM,SAAS,OAAO;CACtB,IAAI,OAAO,WAAW,YAAY,WAAW,IAAI,OAAO,cAAc,wBAAwB;CAC9F,MAAM,OAAO,gBAAgB,OAAO,OAAO;CAC3C,IAAI,SAAS,QAAW,OAAO,cAAc,sCAAsC;CAEnF,MAAM,WAAW,OAAO;CACxB,MAAM,UAAU,aAAa,UAAa,aAAa,OAAO,OAAO,UAAU,QAAQ;CACvF,IAAI,YAAY,QAAW,OAAO,cAAc,2BAA2B;CAC3E,MAAM,sBAAsB,UAAU,OAAO,uBAAuB;CACpE,MAAM,cAAc,UAAU,OAAO,eAAe;CACpD,MAAM,YAAY,UAAU,OAAO,aAAa;CAChD,IAAI,wBAAwB,UAAa,gBAAgB,UAAa,cAAc,QAClF,OAAO,cAAc,mEAAmE;CAE1F,MAAM,YAAY,OAAO;CACzB,IAAI,CAAC,MAAM,QAAQ,SAAS,GAAG,OAAO,cAAc,8BAA8B;CAClF,MAAM,gBAAgC,CAAC;CACvC,KAAK,MAAM,OAAO,WAAwB;EACxC,MAAM,QAAQ,WAAW,GAAG;EAC5B,IAAI,UAAU,QAAW,OAAO,cAAc,8CAA8C;EAC5F,cAAc,KAAK,KAAK;CAC1B;CACA,OAAO,QAAQ;EACb;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;;;;;;;;;;AC1OA,MAAa,0BAA0B;CAAC;CAAM;CAAM;CAAM;CAAM;AAAK;;AAMrE,MAAa,2BAA2B;;;;;;;;ACaxC,MAAM,uBAAuB;;;;;;;;;;;AAuB7B,IAAa,SAAb,MAAoB;CAWC;CACA;CACA;;;;;;;;;;CAHnB,YACE,AAAiB,mBACjB,AAAiB,YACjB,AAAiB,UAAgE,CAAC,GAClF;EAHiB;EACA;EACA;CAChB;;;;;;;;;;;;;;CAeH,MAAa,UACX,QACA,SACyC;EACzC,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,cACxD,MAAM,IAAI,cAAc,uBAAuB;GAC7C,QAAQ;GACR,OAAO,MAAM,QAAQ,MAAM,IAAI,OAAO,SAAS;GAC/C;EACF,CAAC;EAEH,MAAM,MAAM,OAAO,IAAI,aAAa;EAGpC,MAAM,2BAAW,IAAI,IAAqB;EAC1C,KAAK,MAAM,SAAS,aAAa,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG;GACnD,MAAM,WAAW,MAAM,KAAK,WAAW,eACrC,KAAK,mBACL,WACA,UACA,EAAE,UAAU,MAAM,KAAK,GAAG,EAAE,GAC5B,aAAa,OAAO,CACtB;GACA,MAAM,SAAS,cAAc,QAAQ;GACrC,IAAI,WAAW,QACb,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,gBAAgB,GAC5B;IAAE,MAAM;IAAU,OAAO;GAAM,CACjC;GAEF,KAAK,MAAM,MAAM,OACf,IAAI,OAAO,OAAO,QAAQ,EAAE,GAAG,SAAS,IAAI,IAAI,OAAO,GAAG;EAE9D;EACA,MAAM,oEAAiB,QAAS,mBAAkB,KAAK,QAAQ;EAC/D,OAAO,IAAI,KAAK,IAAI,UAAU;GAC5B,IAAI,CAAC,SAAS,IAAI,EAAE,GAAG,OAAO;GAC9B,MAAM,QAAQ,SAAS,IAAI,EAAE;GAC7B,MAAM,SAAS,iBAAiB,IAAI,KAAK;GACzC,IAAI,OAAO,IAAI,OAAO,OAAO;GAC7B,IAAI;IACF,uEAAiB;KAAE,QAAQ;KAAU;KAAO;KAAO,QAAQ,OAAO;IAAO,CAAC;GAC5E,QAAQ,CAER;EAEF,CAAC;CACH;;;;;;;;;;;CAYA,MAAa,SACX,OACA,SACkC;EAClC,MAAM,CAAC,SAAS,MAAM,KAAK,UAAU,CAAC,KAAK,GAAG,OAAO;EACrD,OAAO;CACT;;;;;;;;;;;;;CAcA,MAAa,eACX,OACA,WACA,SACsB;EACtB,IAAI,CAAE,wBAA+C,SAAS,SAAS,GACrE,MAAM,IAAI,cAAc,qBAAqB;GAC3C,OAAO,OAAO,SAAS;GACvB,SAAS,wBAAwB,KAAK,IAAI;EAC5C,CAAC;EAEH,MAAM,KAAK,cAAc,KAAK;EAC9B,MAAM,WAAW,MAAM,KAAK,WAAW,eACrC,KAAK,mBACL,WACA,iBACA;GAAE,OAAO;GAAI;EAAU,GACvB,aAAa,OAAO,CACtB;EACA,MAAM,SAAS,cAAc,QAAQ;EACrC,MAAM,eAAe,WAAW,SAAY,SAAY,eAAe,OAAO,eAAe;EAC7F,MAAM,YAAY,WAAW,SAAY,SAAY,eAAe,OAAO,YAAY;EACvF,IACE,WAAW,UACX,CAAC,MAAM,QAAQ,OAAO,SAAS,KAC/B,iBAAiB,UACjB,cAAc,QAEd,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,eAAe,GAC3B;GAAE,MAAM;GAAU,OAAO;EAAM,CACjC;EAQF,OAAO;GAAE,OAAO;GAAI;GAAW,QANhB,YACb,eACA,OAAO,WACP,oEACA,QAAS,mBAAkB,KAAK,QAAQ,cAEN;GAAG;GAAc;EAAU;CACjE;;;;;;;;;;;CAYA,MAAa,iBAAiB,SAAqD;;EACjF,MAAM,WAAW,MAAM,KAAK,WAAW,eACrC,KAAK,mBACL,aACA,WACA,QACA,aAAa,OAAO,CACtB;EACA,MAAM,UAAU,mBAAmB,gCAAc,cAAc,QAAQ,mEAAI,OAAO,CAAC;EACnF,IAAI,YAAY,QACd,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,iBAAiB,GAC7B;GAAE,MAAM;GAAU,OAAO;EAAM,CACjC;EAEF,OAAO;CACT;AACF;;;;;;;AAQA,MAAa,2BAA2B;;;;;;AAOxC,SAAgB,aAAa,KAAoC;CAC/D,MAAM,UAAsB,CAAC;CAC7B,IAAI,QAAkB,CAAC;CACvB,IAAI,QAAQ;CACZ,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,mBAAmB,EAAE,CAAC,CAAC,SAAS;EAC7C,IACE,MAAM,SAAS,MACd,QAAQ,cAAmC,MAAM,iBAClD;GACA,QAAQ,KAAK,KAAK;GAClB,QAAQ,CAAC;GACT,QAAQ;EACV;EACA,MAAM,KAAK,EAAE;EACb,SAAS;CACX;CACA,IAAI,MAAM,SAAS,GAAG,QAAQ,KAAK,KAAK;CACxC,OAAO;AACT;;;;;AAMA,SAAS,cAAc,OAAyB;CAC9C,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,CAAC,gBAAgB,KAAK,GACxB,MAAM,IAAI,cAAc,2BAA2B,EACjD,eAAe,cAAc,KAAK,EACpC,CAAC;EAEH,OAAO,mBAAmB,eAAe,KAAK,CAAC;CACjD;CACA,OAAO,mBAAmB,KAAK;AACjC;AAEA,SAAS,mBAAmB,IAAoB;CAC9C,IAAI,CAAC,qBAAqB,KAAK,EAAE,GAC/B,MAAM,IAAI,cAAc,wBAAwB,EAAE,OAAO,GAAG,CAAC;CAE/D,OAAO;AACT;AAEA,SAAS,cAAc,OAAwB;CAC7C,IAAI;EACF,OAAO,KAAK,UAAU,KAAK,KAAK,OAAO,KAAK;CAC9C,QAAQ;EACN,OAAO,OAAO,UAAU,SAAS,KAAK,KAAK;CAC7C;AACF;AAEA,SAAS,aAAa,SAA6E;CACjG,0DAAO,QAAS,YAAW,SAAY,SAAY,EAAE,QAAQ,QAAQ,OAAO;AAC9E;;AAGA,SAAS,eAAe,OAA2C;CACjE,IAAI,UAAU,MAAM,OAAO;CAC3B,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,OAAO,OAAoC;CAClD,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,iBAAiB,OAAe,OAAyC;CAChF,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,WAAW,QAAW,OAAO,cAAc,eAAe;CAC9D,MAAM,QAAQ,eAAe,OAAO,QAAQ;CAC5C,IAAI,UAAU,UAAc,UAAU,QAAQ,QAAQ,GACpD,OAAO,cAAc,4CAA4C;CAEnE,MAAM,YAAY,eAAe,OAAO,YAAY;CACpD,IAAI,cAAc,QAAW,OAAO,cAAc,mCAAmC;CACrF,MAAM,SAAS,OAAO;CACtB,IAAI,OAAO,WAAW,WAAW,OAAO,cAAc,yBAAyB;CAC/E,OAAO,QAAQ;EAAE;EAAO;EAAO;EAAW;CAAO,CAAC;AACpD;AAEA,SAAS,gBAAgB,OAA8C;CACrE,MAAM,SAAS,cAAc,KAAK;CAClC,MAAM,OAAO,uDAAO,OAAS,OAAO;CACpC,MAAM,QAAQ,uDAAO,OAAS,QAAQ;CACtC,IAAI,SAAS,UAAa,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GAC1D,OAAO,cAAc,0BAA0B;CAEjD,IAAI,UAAU,UAAa,QAAQ,GAAG,OAAO,cAAc,oCAAoC;CAC/F,OAAO,QAAQ;EAAE;EAAM;CAAM,CAAC;AAChC;AAEA,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,mBAAmB,MAAsE;CAChG,IAAI,SAAS,QAAW,OAAO;CAC/B,MAAM,UAAwD,CAAC;CAC/D,KAAK,MAAM,SAAS,eAAe;EACjC,MAAM,QAAQ,OAAO,KAAK,MAAM;EAChC,IAAI,UAAU,QAAW,OAAO;EAChC,QAAQ,SAAS;CACnB;CACA,MAAM,SAAS,QAAQ;CACvB,IAAI,WAAW,UAAa,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,GAAG,OAAO;CAC5E,OAAO;AACT;;;;;AC/VA,MAAa,iBAAiB;CAAC;CAAO;CAAQ;AAAM;;AAiCpD,MAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,gBAAgB,CAAC,iBAAiB,mBAAmB;AAE3D,MAAM,SAAS;AAEf,SAAS,aAAa,OAAe,UAAiC;CACpE,OAAO,IAAI,cAAc,eAAe;EAAE,QAAQ;EAAQ;EAAO;CAAS,CAAC;AAC7E;;;;;;;AAQA,SAAS,WAAW,SAAiE;CACnF,IAAI,OAAO,YAAY,YAAY,YAAY,MAC7C,MAAM,aAAa,WAAW,WAAW;CAE3C,IAAI,OAAO,QAAQ,kBAAkB,YAAY,QAAQ,cAAc,KAAK,MAAM,IAChF,MAAM,aAAa,iBAAiB,oBAAoB;CAE1D,MAAM,OAAwC,EAAE,eAAe,QAAQ,cAAc;CACrF,IAAI,QAAQ,SAAS,QAAW;EAC9B,IAAI,CAAE,eAAsC,SAAS,QAAQ,IAAI,GAC/D,MAAM,aAAa,QAAQ,eAAe,KAAK,IAAI,CAAC;EAEtD,KAAK,UAAU,QAAQ;CACzB;CACA,KAAK,MAAM,SAAS,aAAa;EAC/B,MAAM,QAAiB,QAAQ;EAC/B,IAAI,UAAU,QAAW;EACzB,IAAI,OAAO,UAAU,UAAU,MAAM,aAAa,OAAO,UAAU;EACnE,KAAK,SAAS;CAChB;CACA,KAAK,MAAM,SAAS,eAAe;EACjC,MAAM,QAAiB,QAAQ;EAC/B,IAAI,UAAU,QAAW;EACzB,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAClE,MAAM,aAAa,OAAO,4BAA4B;EAExD,KAAK,SAAS;CAChB;CACA,OAAO;AACT;;AAGA,SAAS,YAAY,UAA2B;;CAC9C,MAAM,OAAO,gCAAc,cAAc,QAAQ,mEAAI,OAAO;CAC5D,MAAM,kDAAM,KAAO;CACnB,IAAI,OAAO,QAAQ,YAAY,QAAQ,IACrC,IAAI;EAEF,AAAK,IAAI,IAAI,GAAG;EAChB,OAAO;CACT,QAAQ,CAER;CAEF,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,sBAAsB,GAClC;EAAE,MAAM;EAAU,OAAO;CAAM,CACjC;AACF;;;;;;;AAQA,IAAa,WAAb,MAAsB;CAWD;CACA;;;;;;;;;;CAFnB,YACE,AAAiB,mBACjB,AAAiB,YACjB;EAFiB;EACA;CAChB;;;;;;;;;;;;;;;;;;;;;;;CAwBH,MAAa,kBAAkB,SAAiD;EAC9E,MAAM,OAAO,WAAW,OAAO;EAO/B,OAAO,YAAY,MANI,KAAK,WAAW,gBACrC,KAAK,mBACL,oBACA,wBACA,IACF,CAC2B;CAC7B;AACF;;;;;;;;;;;;;AA0BA,SAAgB,eAAe,SAAoC;CACjE,OAAO,IAAI,SACT,QAAQ,kBAAkB,QAAQ,QAAQ,EAAE,GAC5C,IAAI,WAAW,QAAQ,eAAe,QAAQ,WAAW,QAAQ,IAAI,CACvE;AACF;;;;;ACnMA,SAAgB,aAAa,GAAW,GAA6B;CACnE,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/B;;;;;;;;;AAUA,SAAgB,mBAAmB,OAAoD;CACrF,IAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,UAAU,GAAG;EAC7C,MAAM,SAAU,MAAoB;EACpC,MAAM,SAAU,MAAoB;EACpC,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,UAAU,OAAO;GAAE;GAAQ;EAAO;CACxF;CACA,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAC/C,MAAM,SAAS;EACf,MAAM,SAAS,OAAO;EACtB,MAAM,SAAS,OAAO;EACtB,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,UAAU,OAAO;GAAE;GAAQ;EAAO;CACxF;CACA,MAAM,IAAI,cAAc,uBAAuB,EAC7C,UAAU,MAAM,QAAQ,KAAK,IAAI,UAAU,UAAU,OAAO,SAAS,OAAO,MAC9E,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,mBAAmB,eAAiD;CAClF,IAAI,OAAO,kBAAkB,UAC3B,OAAO;EACL,YAAY,cAAc;EAC1B,UAAU,cAAc;EACxB,MAAM,cAAc;EACpB,eAAe,cAAc;CAC/B;CAGF,MAAM,SAAS,cAAc,eAAe,cAAc,SAAS,GAAG,IAAI,MAAM,GAAG;CACnF,IAAI,WAAW,QAAW,MAAM,IAAI,cAAc,2BAA2B,EAAE,cAAc,CAAC;CAC9F,OAAO;AACT;;;;;;;;;;;;;ACnDA,eAAsB,eAAkB,OAAe,KAAmC;CACxF,IAAI;EACF,OAAO,MAAM,IAAI;CACnB,SAAS,OAAgB;EACvB,MAAM,YAAY,KAAK,IACnB,QACA,IAAI,cAAc,2BAA2B,EAAE,MAAM,GAAG,EAAE,MAAM,CAAC;CACvE;AACF;;;;ACEA,MAAM,sBAAsB;;AAG5B,IAAa,UAAb,MAAqB;CAYA;CAIA;CAfnB,AAAQ;CACR,AAAQ,WAAW;CACnB,AAAQ;CAER,AAAiB;;;;;CAMjB,YACE,AAAiB,SAIjB,AAAiB,UAAgE,CAAC,GAClF;EALiB;EAIA;EAEjB,KAAK,OAAO,IAAI,WAAW,QAAQ,eAAe,QAAQ,kBAAkB,QAAQ,IAAI;CAC1F;;;;;;CAOA,MAAa,OAAiC;EAC5C,IAAI,KAAK,kBAAkB,UAAa,KAAK,IAAI,IAAI,KAAK,WAAW,qBACnE,OAAO,KAAK;EAEd,IAAI,KAAK,oBAAoB,QAAW,OAAO,KAAK;EACpD,KAAK,kBAAkB,KAAK,KACzB,eAAkC,KAAK,QAAQ,mBAAmB,aAAa,UAAU,CAAC,CAC1F,MAAM,aACL,YAAY,WAAW,SAAS,MAAM,oBAAoB,KAAK,QAAQ,cAAc,CACvF,CAAC,CACA,MAAM,YAAY;GACjB,KAAK,gBAAgB;GACrB,KAAK,WAAW,KAAK,IAAI;GACzB,OAAO;EACT,CAAC,CAAC,CACD,cAAc;GACb,KAAK,kBAAkB;EACzB,CAAC;EACH,OAAO,KAAK;CACd;;;;;;;;CASA,AAAO,aAAmB;EACxB,KAAK,gBAAgB;EACrB,KAAK,WAAW;CAClB;;;;;;;;CASA,MAAa,UAAoC;EAC/C,KAAK,WAAW;EAIhB,KAAK,kBAAkB;EACvB,OAAO,KAAK,KAAK;CACnB;;CAGA,MAAa,QAAQ,KAAuC;EAC1D,IAAI,UAAU,MAAM,KAAK,KAAK;EAC9B,MAAM,YACJ,OAAO,QAAQ,WACX,eAAe,GAAG,IAChB,eAAe,mBAAmB,GAAG,CAAC,IACtC,SACF,eAAe,GAAG;EACxB,MAAM,WAAW,QAAQ,MACtB,UACC,MAAM,WAAW,OAAQ,cAAc,UAAa,eAAe,KAAK,MAAM,SAClF;EACA,IAAI,aAAa,QAAW;GAC1B,UAAU,MAAM,KAAK,QAAQ;GAC7B,MAAM,YAAY,QAAQ,MACvB,UACC,MAAM,WAAW,OAAQ,cAAc,UAAa,eAAe,KAAK,MAAM,SAClF;GACA,IAAI,cAAc,QAAW,MAAM,cAAc,kBAAkB,GAAG;GACtE,OAAO;EACT;EACA,OAAO;CACT;;;;;;;;;;;;;;;;;;;;;;;CAwBA,MAAa,cACX,UACA,eACA,UAAgE,CAAC,GAChD;EACjB,IAAI,WAA4B,CAAC;EACjC,IAAI;GACF,WAAW,MAAM,KAAK,KAAK;EAC7B,SAAS,OAAgB;GACvB,IAAI,QAAQ,oBAAoB,UAAU,MAAM;EAClD;EACA,MAAM,SAAS,eAAe,QAAQ;EACtC,MAAM,aAAa,SAAS,MACzB,UACC,MAAM,eAAe,SAAS,cAC9B,MAAM,aAAa,SAAS,YAC5B,MAAM,SAAS,SAAS,QACxB,MAAM,kBAAkB,SAAS,aACrC;EACA,IAAI,eAAe,QAAW,OAAO,WAAW;EAChD,IAAI,0BAA0B,aAAa,GAAG,OAAO;EACrD,MAAM,IAAI,cAAc,2BAA2B;GAAE,UAAU;GAAQ;EAAc,CAAC;CACxF;;CAGA,MAAa,UACX,GACA,GAKC;EACD,MAAM,CAAC,WAAW,aAAa,MAAM,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC;EACnF,MAAM,CAAC,cAAc,gBAAgB,aAAa,UAAU,QAAQ,UAAU,MAAM;EACpF,OAAO;GACL,QAAQ,iBAAiB,UAAU,SAAS,YAAY;GACxD,QAAQ,iBAAiB,UAAU,SAAS,YAAY;GACxD,SAAS,iBAAiB,UAAU;EACtC;CACF;AACF;;AAGA,SAAS,mBAAmB,OAA2C;CACrE,MAAM,QAAQ,cAAc,KAAK;CACjC,IAAI,UAAU,QAAW,OAAO,cAAc,0BAA0B;CACxE,MAAM,EAAE,QAAQ,YAAY,UAAU,MAAM,eAAe,aAAa;CACxE,IAAI,OAAO,WAAW,UAAU,OAAO,cAAc,wBAAwB;CAC7E,IAAI,OAAO,WAAW,GAAG,OAAO,cAAc,iBAAiB;CAC/D,IAAI,OAAO,eAAe,UAAU,OAAO,cAAc,4BAA4B;CACrF,IAAI,OAAO,aAAa,UAAU,OAAO,cAAc,0BAA0B;CACjF,IAAI,OAAO,SAAS,UAAU,OAAO,cAAc,sBAAsB;CACzE,IAAI,OAAO,kBAAkB,UAAU,OAAO,cAAc,+BAA+B;CAC3F,IAAI,OAAO,aAAa,YAAY,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAC5E,OAAO,cAAc,wCAAwC;CAE/D,OAAO,QAAQ;EAAE;EAAQ;EAAY;EAAU;EAAM;EAAe;CAAS,CAAC;AAChF;AAEA,SAAS,eAAe,KAAsB;CAC5C,OAAO,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,GAAG;AAC9C;;AAkBA,SAAgB,WAAW,KAAuB;CAChD,OAAO,OAAO,QAAQ,WAAW,MAAM,eAAe,GAAG;AAC3D;;AAGA,eAAsB,gBAAgB,UAAyB,KAAgC;CAC7F,MAAM,WAAW,MAAM,eAAe,WAAW,GAAG,SAAS,SAAS,QAAQ,GAAG,CAAC;CAClF,IAAI,SAAS,OAAO,SAAS,GAAG,OAAO,SAAS;CAChD,MAAM,IAAI,cAAc,oBAAoB,EAAE,OAAO,WAAW,GAAG,EAAE,CAAC;AACxE;;AAGA,eAAsB,aAAa,UAAyB,KAAgC;CAC1F,OAAO,SAAS,gBAAgB,OAAO,WAAW,GAAG,IAAI,gBAAgB,UAAU,GAAG;AACxF;;;;;;;;;;;;;;;;;;AAmBA,IAAa,mBAAb,MAAuD;CACrD,AAAgB,cAAc;;CAG9B,AAAO,QAAQ,KAAuC;EACpD,IAAI,OAAO,QAAQ,YAAY,CAAC,eAAe,GAAG,GAChD,OAAO,QAAQ,QAAQ;GACrB,QAAQ;GACR,YAAY;GACZ,UAAU;GACV,MAAM;GACN,eAAe;GACf,UAAU;EACZ,CAAC;EAEH,OAAO,QAAQ,OAAO,cAAc,kBAAkB,GAAG,CAAC;CAC5D;;CAGA,MAAa,UACX,GACA,GAC6E;EAC7E,MAAM,CAAC,WAAW,aAAa,MAAM,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC;EACnF,MAAM,CAAC,SAAS,aAAa,UAAU,QAAQ,UAAU,MAAM;EAC/D,MAAM,UAAU,UAAU,UAAU;EACpC,OAAO;GACL,QAAQ,UAAU,YAAY;GAC9B,QAAQ,UAAU,YAAY;GAC9B;EACF;CACF;;CAGA,AAAO,aAAmB,CAE1B;AACF;;;;;AC9OA,IAAa,QAAb,MAAmB;CAWE;CACA;CACA;;;;;;;;;;CAHnB,YACE,AAAiB,SACjB,AAAiB,SACjB,AAAiB,UAAgE,CAAC,GAClF;EAHiB;EACA;EACA;EAEjB,KAAK,OAAO,IAAI,WACd,QAAQ,eACR,QAAQ,oBAAoB,KAC5B,QAAQ,IACV;CACF;CAEA,AAAiB;;;;;;;;;;;;;CAcjB,MAAa,SAAS,SAAoD;EACxE,MAAM,WAAW,MAAM,KAAK,KAAK,eAC/B,KAAK,QAAQ,mBACb,aACA,UACA,eAAe,OAAO,sDACtB,QAAS,YAAW,SAAY,SAAY,EAAE,QAAQ,QAAQ,OAAO,CACvE;EACA,OAAO,YACL,SACA,SAAS,MACT,sEACA,QAAS,mBAAkB,KAAK,QAAQ,cAC1C;CACF;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,cACL,QACA,UAAgC,CAAC,GACrB;EACZ,MAAM,aAAa,QAAQ,cAAc;EACzC,IAAI,OAAO,eAAe,YAAY,CAAC,OAAO,SAAS,UAAU,KAAK,aAAa,GACjF,MAAM,IAAI,cAAc,yBAAyB,EAAE,OAAO,OAAO,UAAU,EAAE,CAAC;EAEhF,IAAI;EACJ,IAAI,UAAU;EACd,IAAI,UAAU;EACd,MAAM,UAAU,UAAyB;GACvC,IAAI;;IACF,4BAAQ,mFAAU,KAAK;GACzB,QAAQ,CAER;EACF;EACA,MAAM,UAAU,UACb,QAAQ,WAAW,WAAc,KAAK,UAAU,MAAM,QAAQ,YAC9D,QAAQ,WAAW,UAClB,QAAQ,OAAO,SAAS,KAAK,MAAM,KACnC,QAAQ,OAAO,SAAS,KAAK,MAAM;EACvC,MAAM,OAAO,YAA2B;GACtC,IAAI,WAAW,SAAS;GACxB,UAAU;GACV,IAAI;IACF,MAAM,QAAQ,MAAM,KAAK,SAAS;IAClC,IAAI,UAAU,QAAW;KACvB,QAAQ,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC;KACjD;IACF;IACA,KAAK,MAAM,QAAQ,OAAO;KACxB,IAAI,SAAS;KACb,IAAI,MAAM,IAAI,KAAK,OAAO,GAAG;KAC7B,MAAM,IAAI,KAAK,OAAO;KACtB,IAAI,CAAC,OAAO,IAAI,GAAG;KACnB,IAAI;MACF,OAAO,IAAI;KACb,SAAS,OAAgB;MACvB,OAAO,KAAK;KACd;IACF;GACF,SAAS,OAAgB;IACvB,IAAI,CAAC,SAAS,OAAO,KAAK;GAC5B,UAAU;IACR,UAAU;GACZ;EACF;EACA,AAAK,KAAK;EACV,MAAM,QAAQ,kBAAkB,KAAK,KAAK,GAAG,UAAU;EACvD,aAAa;GACX,UAAU;GACV,cAAc,KAAK;EACrB;CACF;;;;;;;;;;CAWA,MAAa,QAAQ,QAAkB,QAAkB,KAAkC;EACzF,YAAY,GAAG;EACf,OAAO,KAAK,WAAqB,SAAS,MAAM,KAAK,cAAc,QAAQ,QAAQ,GAAG,CAAC;CACzF;;;;;;;;;;CAWA,MAAa,SAAS,QAAkB,QAAkB,KAA+B;EACvF,YAAY,GAAG;EACf,OAAO,KAAK,WAAkB,UAAU,MAAM,KAAK,cAAc,QAAQ,QAAQ,GAAG,CAAC;CACvF;;;;;;;;;;CAWA,MAAa,iBACX,QACA,QACA,KACwB;EACxB,YAAY,GAAG;EACf,IAAI,KAAK,QAAQ,gBAAgB,MAC/B,OAAO,KAAK,WAA0B,mBAAmB;GACvD,QAAQ,WAAW,MAAM;GACzB,QAAQ,WAAW,MAAM;GACzB,KAAK,OAAO,GAAG;EACjB,CAAC;EAEH,MAAM,QAAQ,MAAM,gBAAgB,KAAK,SAAS,MAAM;EACxD,MAAM,SAAS,MAAM,gBAAgB,KAAK,SAAS,MAAM;EACzD,MAAM,UAAU,mBAAmB,aAAa,OAAO,MAAM,CAAC;EAC9D,OAAO,KAAK,WAA0B,mBAAmB;GACvD,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,KAAK,OAAO,GAAG;EACjB,CAAC;CACH;CAEA,MAAc,cACZ,QACA,QACA,KACiC;EACjC,OAAO;GACL,QAAQ,MAAM,aAAa,KAAK,SAAS,MAAM;GAC/C,QAAQ,MAAM,aAAa,KAAK,SAAS,MAAM;GAC/C,KAAK,OAAO,GAAG;EACjB;CACF;CAEA,MAAc,WAAc,UAAkB,QAA4C;EACxF,IAAI;GAOF,QAAO,MANgB,KAAK,KAAK,eAC/B,KAAK,QAAQ,mBACb,aACA,UACA,MACF,EACe,CAAC;EAClB,SAAS,OAAgB;GAGvB,IAAI,aAAa,KAAK,GAAG,MAAM;GAC/B,MAAM,IAAI,cACR,kBACA,EAAE,WAAW,OAAO,GACpB;IAAE,OAAO;IAAO,OAAO;GAAM,CAC/B;EACF;CACF;AACF;AAEA,MAAM,YAA+B;CAAC;CAAO;CAAY;AAAW;AACpE,MAAM,oBAAoB;AAC1B,MAAM,gBAAgB;;AAGtB,SAAS,eAAe,SAA0E;CAChG,IAAI,YAAY,QAAW,OAAO;CAClC,MAAM,SAAiC,CAAC;CACxC,IAAI,QAAQ,WAAW,QAAW;EAChC,IAAI,QAAQ,OAAO,SAAS,mBAC1B,MAAM,IAAI,cAAc,mBAAmB;GACzC,QAAQ,QAAQ,OAAO;GACvB,WAAW;EACb,CAAC;EAEH,OAAO,YAAY,QAAQ;CAC7B;CACA,IAAI,QAAQ,WAAW,QAAW;EAChC,IAAI,CAAC,UAAU,SAAS,QAAQ,MAAM,GACpC,MAAM,IAAI,cAAc,mBAAmB;GACzC,OAAO,OAAO,QAAQ,MAAM;GAC5B,SAAS,UAAU,KAAK,GAAG;EAC7B,CAAC;EAEH,OAAO,YAAY,QAAQ;CAC7B;CACA,IAAI,QAAQ,cAAc,QAAW;EACnC,IAAI,QAAQ,cAAc,SAAS,QAAQ,cAAc,QACvD,MAAM,IAAI,cAAc,sBAAsB,EAAE,OAAO,OAAO,QAAQ,SAAS,EAAE,CAAC;EAEpF,OAAO,eAAe,QAAQ;CAChC;CACA,IAAI,QAAQ,SAAS,QAAW;EAC9B,IAAI,CAAC,OAAO,UAAU,QAAQ,IAAI,KAAK,QAAQ,OAAO,GACpD,MAAM,IAAI,cAAc,gBAAgB,EAAE,OAAO,QAAQ,KAAK,CAAC;EAEjE,OAAO,UAAU,OAAO,QAAQ,IAAI;CACtC;CACA,IAAI,QAAQ,UAAU,QAAW;EAC/B,IAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,KAAK,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,eAC3E,MAAM,IAAI,cAAc,iBAAiB;GACvC,OAAO,QAAQ;GACf,KAAK;GACL,KAAK;EACP,CAAC;EAEH,OAAO,WAAW,OAAO,QAAQ,KAAK;CACxC;CACA,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,IAAI,SAAY;AACxD;AAEA,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,sBAAsB;CAAC;CAAO;CAAU;AAAO;;;;;;;AAQrD,SAAS,kBAAkB,OAA0C;CACnE,MAAM,MAAM,cAAc,KAAK;CAC/B,IAAI,QAAQ,QAAW,OAAO,cAAc,0BAA0B;CACtE,KAAK,MAAM,OAAO;EAAC;EAAU;EAAU;CAAS,GAC9C,IAAI,OAAO,IAAI,SAAS,UAAU,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAEjF,IAAI,IAAI,uBAAuB,UAAa,IAAI,uBAAuB,MACrE,OAAO,cAAc,2BAA2B;CAElD,MAAM,aAAsC,EAAE,GAAG,IAAI;CACrD,KAAK,MAAM,OAAO,qBAAqB;EACrC,MAAM,MAAM,IAAI;EAChB,IAAI,QAAQ,UAAa,QAAQ,OAAO;EACxC,MAAM,QAAQ,eAAe,GAAG;EAChC,IAAI,UAAU,QAAW,OAAO,cAAc,GAAG,IAAI,iBAAiB;EACtE,WAAW,OAAO;CACpB;CACA,KAAK,MAAM,OAAO,uBAChB,IAAI,IAAI,SAAS,UAAa,OAAO,IAAI,SAAS,UAChD,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAGjD,KAAK,MAAM,OAAO,uBAAuB;EACvC,MAAM,QAAQ,IAAI;EAClB,IAAI,UAAU,WAAc,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,IAC7E,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAEjD;CACA,OAAO,QAAQ,UAAqC;AACtD;;;;;;;;;;;ACpYA,SAAgB,gBAAgB,SAA0B;CACxD,OAAO,OAAO,UAAU,OAAO,KAAK,UAAU;AAChD;;;;;;;;;;;;;;AAeA,SAAgB,mBAAmB,MAAc,SAAyB;CACxE,OAAO,gBAAgB,OAAO,IAAI,KAAK,MAAM,OAAO,OAAO,IAAI,UAAU;AAC3E;;;;;;AAOA,SAAgB,iBAAiB,MAAc,SAAyB;CACtE,OAAO,gBAAgB,OAAO,IAAI,KAAK,KAAK,OAAO,OAAO,IAAI,UAAU;AAC1E;;;;;;;;;;;ACrBA,SAAgB,cAAc,MAAc,SAAyB;CACnE,cAAc,OAAO;CACrB,OAAO,mBAAmB,MAAM,OAAO;AACzC;;AAGA,SAAgB,YAAY,MAAc,SAAyB;CACjE,cAAc,OAAO;CACrB,OAAO,iBAAiB,MAAM,OAAO;AACvC;;AAGA,SAAgB,gBAAgB,OAAe,OAAe,KAAqB;CACjF,MAAM,UAAU,oBAAoB;CACpC,IAAI,YAAY,QACd,MAAM,IAAI,cAAc,eAAe;EACrC,OAAO;EACP,OAAO;EACP,SAAS;CACX,CAAC;CAEH,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,CAAC,OAAO,UAAU,KAAK,GACrD,MAAM,IAAI,cAAc,sBAAsB;EAAE,WAAW;EAAO,WAAW;CAAM,CAAC;CAEtF,IAAI,SAAS,OACX,MAAM,IAAI,cAAc,sBAAsB;EAAE,WAAW;EAAO,WAAW;CAAM,CAAC;CAEtF,IAAI,mBAAuB,gBACzB,MAAM,IAAI,cAAc,uBAAuB;EAC7C,WAAW;EACX,WAAW;EACX,SAAS;EACT,SAAS;CACX,CAAC;CAEH,IAAI,QAAQ,YAAY,KAAK,QAAQ,YAAY,GAC/C,MAAM,IAAI,cAAc,qBAAqB;EAC3C,WAAW;EACX,WAAW;EACX;CACF,CAAC;AAEL;AAEA,SAAS,cAAc,SAAuB;CAC5C,IAAI,CAAC,gBAAgB,OAAO,GAC1B,MAAM,IAAI,cAAc,wBAAwB,EAAE,OAAO,QAAQ,CAAC;AAEtE;;;;;;;;;;;;;;;AAwBA,SAAgB,WAAW,OAIX;CACd,IAAI,MAAM,uBAAuB,MAAM,OAAO;EAAE,WAAW,MAAM;EAAW,MAAM,MAAM;CAAK;CAC7F,MAAM,WAAW,IAAI,WAAW,CAAC,CAAC,CAAC,UAAU,IAAI,WAAW,MAAM,SAAS,CAAC;CAC5E,IAAI,CAAC,SAAS,SAAS,KAAK,SAAS,kBAAkB,CAAC,GACtD,MAAM,IAAI,cAAc,sBAAsB,EAAE,WAAW,MAAM,UAAU,CAAC;CAE9E,MAAM,YAAY,SAAS,SAAS;CACpC,OAAO;EAAE;EAAW,MAAM,gBAAgB,SAAS;CAAE;AACvD;;;;ACtEA,MAAM,iBAAiB,WAAkC,IAAI,UAAU,MAAM,CAAC,CAAC,QAAQ;;;;;;;;;;;;;;;;;;AA8BvF,SAAgB,qBAAqB,OAA2C;CAC9E,YAAY,MAAM,GAAG;CACrB,oBAAoB,MAAM,QAAQ,MAAM,MAAM;CAC9C,gBAAgB,MAAM,SAAS;CAC/B,MAAM,MAA+B;EACnC,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,KAAK,MAAM;EACX,WAAW,MAAM;CACnB;CACA,IAAI,aAAa,OAAO;EACtB,MAAM,UAAU,MAAM;EACtB,IAAI,YAAY,QACd,MAAM,IAAI,cAAc,yBAAyB,EAAE,OAAO,UAAU,CAAC;EAEvE,sBAAsB,SAAS,SAAS;EACxC,IAAI,MAAM,kBAAkB,aAAa,cAAc,cAAc,OAAO;EAC5E,IAAI,MAAM,qBAAqB,QAAW;GACxC,sBAAsB,MAAM,kBAAkB,oBAAoB,IAAI;GACtE,IAAI,sBAAsB,cAAc,MAAM,gBAAgB;EAChE;CACF,OAAO;EACL,MAAM,WAAW,MAAM;EACvB,IAAI,aAAa,QACf,MAAM,IAAI,cAAc,yBAAyB,EAAE,OAAO,WAAW,CAAC;EAExE,sBAAsB,UAAU,UAAU;EAC1C,IAAI,MAAM,kBAAkB,YAAY,aAAa,cAAc,QAAQ;EAC3E,IAAI,MAAM,oBAAoB,QAAW;GACvC,sBAAsB,MAAM,iBAAiB,mBAAmB,IAAI;GACpE,IAAI,qBAAqB,cAAc,MAAM,eAAe;EAC9D;CACF;CACA,IAAI,MAAM,eAAe,QAAW;EAClC,sBAAsB,MAAM,YAAY,YAAY;EACpD,IAAI,gBAAgB,cAAc,MAAM,UAAU;CACpD;CACA,OAAO;AACT;AAYA,SAAS,mBAAmB,OAAgC;CAC1D,YAAY,MAAM,GAAG;CACrB,oBAAoB,MAAM,QAAQ,MAAM,MAAM;CAC9C,gBAAgB,MAAM,WAAW,MAAM,WAAW,MAAM,GAAG;CAC3D,gBAAgB,MAAM,SAAS;AACjC;;;;;;AAcA,SAAgB,qBAAqB,OAA2C;CAC9E,mBAAmB,KAAK;CACxB,MAAM,OAAO,QACX,MAAM,uBACN,MAAM,uBACN,yBACA,uBACF;CACA,IAAI,SAAS,QACX,MAAM,IAAI,cAAc,2BAA2B;EACjD,OAAO;EACP,QAAQ;CACV,CAAC;CAEH,sBAAsB,KAAK,QAAQ,KAAK,IAAI;CAC5C,OAAO;EACL,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,KAAK,MAAM;EACX,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,WAAW,MAAM;GAChB,KAAK,OAAO,cAAc,KAAK,MAAM;CACxC;AACF;;;;;AAYA,SAAgB,wBAAwB,OAAiD;CACvF,mBAAmB,KAAK;CACxB,MAAM,OAAO,QACX,MAAM,0BACN,MAAM,0BACN,4BACA,4BACA,IACF;CACA,IAAI,SAAS,QAAW,sBAAsB,KAAK,QAAQ,KAAK,IAAI;CACpE,OAAO;EACL,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,KAAK,MAAM;EACX,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,GAAI,SAAS,SAAY,CAAC,IAAI,GAAG,KAAK,OAAO,cAAc,KAAK,MAAM,EAAE;CAC1E;AACF;;AAGA,SAAgB,4BAA4B,OAAkD;CAC5F,mBAAmB,KAAK;CACxB,OAAO;EACL,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,KAAK,MAAM;EACX,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,WAAW,MAAM;CACnB;AACF;;;;;;;AA0BA,SAAgB,mBAAmB,OAAuC;CACxE,YAAY,MAAM,GAAG;CACrB,gBAAgB,MAAM,SAAS;CAC/B,oBAAoB,MAAM,cAAc,MAAM,YAAY;CAC1D,KAAK,MAAM,UAAU,CAAC,MAAM,cAAc,MAAM,YAAY,GAC1D,IAAI,CAAC,0BAA0B,MAAM,GACnC,MAAM,IAAI,cAAc,0BAA0B,EAAE,OAAO,CAAC;CAGhE,KAAK,MAAM,OAAO,CAAC,MAAM,WAAW,MAAM,SAAS,GAAG,eAAe,GAAG;CACxE,MAAM,QAAQ,QACZ,MAAM,eACN,MAAM,mBACN,iBACA,mBACF;CACA,IAAI,UAAU,QACZ,MAAM,IAAI,cAAc,2BAA2B;EACjD,OAAO;EACP,QAAQ;CACV,CAAC;CAEH,IAAI,OAAO,MAAM,WAAW,UAC1B,MAAM,IAAI,cAAc,uBAAuB,EAAE,OAAO,MAAM,KAAK,CAAC;CAEtE,MAAM,SAAS,IAAI,UAAU,MAAM,MAAM;CACzC,IAAI,CAAC,OAAO,SAAS,KAAK,OAAO,oBAAoB,CAAC,GACpD,MAAM,IAAI,cAAc,0BAA0B,EAAE,OAAO,OAAO,MAAM,MAAM,EAAE,CAAC;CAEnF,OAAO;EACL,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,KAAK,MAAM;GACV,MAAM,OAAO,OAAO,QAAQ;EAC7B,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,WAAW,MAAM;EAEjB,GAAI,MAAM,SAAS,UAAa,MAAM,SAAS,KAAK,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK;EAC5E,GAAI,MAAM,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,MAAM,UAAU;EACtE,GAAI,MAAM,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,MAAM,cAAc;CACpF;AACF;AAEA,SAAS,eAAe,KAAmC;CACzD,KAAK,MAAM,QAAQ;EAAC;EAAc;EAAY;EAAQ;CAAe,GACnE,IAAI,OAAO,IAAI,UAAU,YAAY,IAAI,KAAK,CAAC,WAAW,GACxD,MAAM,IAAI,cAAc,8BAA8B;EACpD,cAAc;GAAC,IAAI;GAAY,IAAI;GAAU,IAAI;GAAM,IAAI;EAAa,CAAC,CAAC,KAAK,GAAG;EAClF;CACF,CAAC;AAGP;;;;;;AAOA,SAAS,QACP,OACA,QACA,WACA,YACA,eAAe,OAC0B;CACzC,IAAI,UAAU,UAAa,WAAW,QACpC,MAAM,eACF,IAAI,cAAc,0BAA0B;EAAE,OAAO;EAAW,QAAQ;CAAW,CAAC,IACpF,IAAI,cAAc,2BAA2B;EAAE,OAAO;EAAW,QAAQ;CAAW,CAAC;CAE3F,IAAI,UAAU,QAAW,OAAO;EAAE,MAAM;EAAW,QAAQ;CAAM;CACjE,IAAI,WAAW,QAAW,OAAO;EAAE,MAAM;EAAY,QAAQ;CAAO;AAEtE;AASA,SAAS,WACP,QACA,OACA,UAC8B;CAC9B,OAAO,IAAI,cAAc,eAAe;EAAE;EAAQ;EAAO;CAAS,CAAC;AACrE;;;;;AAMA,SAAS,aACP,QACA,KACyB;CACzB,MAAM,QAAQ,UAA0B;EACtC,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UAAU,MAAM,WAAW,QAAQ,OAAO,QAAQ;EACvE,OAAO;CACT;CACA,MAAM,WAAW,UAA0B;EACzC,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UAAU,MAAM,WAAW,QAAQ,OAAO,QAAQ;EACvE,OAAO;CACT;CACA,MAAM,gBAAgB,UACpB,IAAI,WAAW,SAAY,SAAY,KAAK,KAAK;CACnD,MAAM,YAAY,UAA0C;EAC1D,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,WAAW,QAAQ,OAAO,WAAW;EAC5F,MAAM,MAAM;EACZ,MAAM,QAAQ,SAAyB;GACrC,IAAI,OAAO,IAAI,UAAU,UAAU,MAAM,WAAW,QAAQ,GAAG,MAAM,GAAG,QAAQ,QAAQ;GACxF,OAAO,IAAI;EACb;EACA,OAAO;GACL,YAAY,KAAK,YAAY;GAC7B,UAAU,KAAK,UAAU;GACzB,MAAM,KAAK,MAAM;GACjB,eAAe,KAAK,eAAe;EACrC;CACF;CAEA,MAAM,cAAc;EAAE,QAAQ,KAAK,QAAQ;EAAG,QAAQ,KAAK,QAAQ;EAAG,KAAK,QAAQ,KAAK;CAAE;CAC1F,MAAM,YAAY,KAAK,WAAW;CAClC,MAAM,kBAAkB;EACtB,GAAG,KAAK;EACR;EACA,WAAW,QAAQ,WAAW;EAC9B,WAAW,QAAQ,WAAW;CAChC;CACA,QAAQ,QAAR;EACE,KAAK,gBAAgB;GACnB,MAAM,MAAM;IAAC;IAAY;IAAY;IAAW;GAAS,CAAC,CAAC,QACxD,MAAM,IAAI,OAAO,MACpB;GACA,MAAM,CAAC,SAAS;GAChB,IAAI,IAAI,WAAW,KAAK,UAAU,QAChC,MAAM,WAAW,QAAQ,qCAAqC,cAAc;GAE9E,MAAM,kBAAkB,UAAU,cAAc,UAAU;GAC1D,MAAM,SAAS;IAAE,GAAG,KAAK;IAAG;IAAW;GAAgB;GACvD,MAAM,aAAa,aAAa,YAAY;GAC5C,OAAO,MAAM,WAAW,MAAM,IAC1B,qBAAqB;IACnB,GAAG;IACH,SAAS,KAAK,KAAK;IACnB,kBAAkB,aAAa,kBAAkB;IACjD;GACF,CAAC,IACD,qBAAqB;IACnB,GAAG;IACH,UAAU,KAAK,KAAK;IACpB,iBAAiB,aAAa,iBAAiB;IAC/C;GACF,CAAC;EACP;EACA,KAAK,gBAAgB;GACnB,MAAM,aAAa,aAAa,uBAAuB;GACvD,MAAM,aAAa,aAAa,uBAAuB;GACvD,OAAO,qBAAqB;IAC1B,GAAG,SAAS;IACZ,GAAI,eAAe,SACf,EAAE,uBAAuB,WAAqB,IAC9C,EAAE,uBAAuB,WAAW;GAC1C,CAAC;EACH;EACA,KAAK,mBACH,OAAO,wBAAwB;GAC7B,GAAG,SAAS;GACZ,0BAA0B,aAAa,0BAA0B;GACjE,0BAA0B,aAAa,0BAA0B;EACnE,CAAC;EACH,KAAK,uBACH,OAAO,4BAA4B,SAAS,CAAC;EAC/C,KAAK,cAAc;GACjB,MAAM,QAAQ,aAAa,eAAe;GAC1C,MAAM,YAAY,aAAa,mBAAmB;GAClD,MAAM,gBAAgB,IAAI;GAC1B,IACE,kBAAkB,WACjB,CAAC,MAAM,QAAQ,aAAa,KAAK,cAAc,MAAM,UAAU,OAAO,UAAU,QAAQ,IAEzF,MAAM,WAAW,QAAQ,iBAAiB,cAAc;GAE1D,IAAI,IAAI,iBAAiB,UAAa,OAAO,IAAI,iBAAiB,WAChE,MAAM,WAAW,QAAQ,aAAa,SAAS;GAEjD,OAAO,mBAAmB;IACxB,WAAW,SAAS,WAAW;IAC/B,WAAW,SAAS,WAAW;IAC/B,cAAc,KAAK,cAAc;IACjC,cAAc,KAAK,cAAc;IACjC,KAAK,QAAQ,KAAK;IAClB;IACA,MAAM,aAAa,MAAM;IACzB,WAAW,IAAI;IACA;IACf,GAAI,UAAU,SACV,EAAE,mBAAmB,UAAoB,IACzC,EAAE,eAAe,MAAM;GAC7B,CAAC;EACH;CACF;AACF;;;;;;;;;AAUA,SAAgB,qBAAqB,QAAuB,KAAoC;CAC9F,MAAM,UAAU,aAAa,QAAQ,GAAG;CACxC,IAAI,KAAK,UAAU,OAAO,MAAM,KAAK,UAAU,GAAG,GAChD,MAAM,IAAI,cAAc,qBAAqB,EAAE,OAAO,CAAC;AAE3D;;;;;ACxTA,SAAS,WACP,KACkB;CAClB,OAAO;EACL,QAAQ,IAAI;EACZ,QAAQ,IAAI;EACZ,KAAK,IAAI;EACT,WAAW,IAAI;EACf,WAAW,IAAI;CACjB;AACF;;;;;;;;;;;AA6DA,IAAa,YAAb,MAAuB;CAEF;CACA;CACA;CAHnB,YACE,AAAiB,SACjB,AAAiB,SACjB,AAAiB,QACjB,eACA,UAA4B,CAAC,GAC7B;EALiB;EACA;EACA;EAIjB,KAAK,gBACH,kBAAkB,SAAY,SAAY,QAAQ,eAAe,eAAe;EAClF,KAAK,OAAO,IAAI,WACd,QAAQ,eACR,QAAQ,oBAAoB,KAC5B,QAAQ,IACV;EACA,KAAK,kBAAkB,uBAAuB,QAAQ,eAAe;EACrE,KAAK,iBAAiB,QAAQ;CAChC;;CAGA,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;;;;;;;;;;;CAajB,MAAM,iBAAiB,OAAoC;EACzD,MAAM,WAAW,MAAM,KAAK,IAAa,cAAc,EAAE,MAAM,QAAQ,OAAO,OAAO,EAAE,CAAC;EACxF,OAAO,YAAY,aAAa,SAAS,MAAM,eAAe,KAAK,cAAc;CACnF;;;;;;;;;;;;;;;CAgBA,MAAM,YACJ,MAQA,QAC0B;EAC1B,MAAM,WAAW,MAAM,KAAK,YAC1B,aACA,MAAM,KAAK,eAAe,IAAI,GAC9B,MACF;EACA,OAAO,aAAa,OAAO,OAAO,iBAAiB,SAAS,IAAI;CAClE;;;;;;;;;;;;;;;;;;;CAoBA,MAAM,aACJ,MAQA,QACuB;EACvB,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,YAAY,MAAM,MAAM;GACpD,OAAO,aAAa,OAAO,EAAE,MAAM,YAAY,IAAI;IAAE,MAAM;IAAS,MAAM;GAAS;EACrF,SAAS,OAAgB;GACvB,qDAAI,OAAQ,aAAY,MAAM,MAAM;GACpC,OAAO;IACL,MAAM;IACN,OAAO,aAAa,KAAK,IACrB,QACA,IAAI,cACF,kBACA,EAAE,WAAW,WAAW,GACxB;KAAE,OAAO;KAAO,OAAO;IAAM,CAC/B;GACN;EACF;CACF;;;;;CAMA,MAAc,eAAe,MAOO;EAGlC,MAAM,QAAQ,QAAQ,KAAK,OAAO,OAAO;EACzC,IAAI,KAAK,QAAQ,gBAAgB,MAC/B,OAAO;GACL,QAAQ,WAAW,KAAK,MAAM;GAC9B,QAAQ,WAAW,KAAK,MAAM;GAC9B,KAAK,GAAG,KAAK;GACb;GACA,WAAW,GAAG,KAAK;GACnB,WAAW,GAAG,KAAK;EACrB;EAEF,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,KAAK,MAAM;EAC1D,MAAM,QAAQ,KAAK,eAAe,KAAK,WAAW,KAAK,WAAW,KAAK,OAAO;EAC9E,OAAO;GACL,QAAQ,KAAK,OAAO;GACpB,QAAQ,KAAK,OAAO;GACpB,KAAK,GAAG,KAAK;GACb;GACA,WAAW,GAAG,MAAM;GACpB,WAAW,GAAG,MAAM;EACtB;CACF;;;;;;;;;;;;;;CAeA,MAAM,qBAAqB,MAQO;EAChC,sBAAsB,KAAK,QAAQ,QAAQ;EAU3C,QAAO,MATgB,KAAK,IAA8B,qBAAqB;GAC7E,QAAQ,WAAW,KAAK,MAAM;GAC9B,QAAQ,WAAW,KAAK,MAAM;GAC9B,KAAK,GAAG,KAAK;GACb,WAAW,GAAG,KAAK;GACnB,WAAW,GAAG,KAAK;GACnB,QAAQ,IAAI,UAAU,KAAK,MAAM,CAAC,CAAC,QAAQ;GAC3C,gBAAgB,OAAO,KAAK,cAAc;EAC5C,CAAC,EACc,CAAC;CAClB;;;;;;;;;;;;;;CAeA,MAAM,wBAAwB,MAOO;EACnC,sBAAsB,KAAK,WAAW,WAAW;EASjD,QAAO,MARgB,KAAK,IAAiC,wBAAwB;GACnF,QAAQ,WAAW,KAAK,MAAM;GAC9B,QAAQ,WAAW,KAAK,MAAM;GAC9B,KAAK,GAAG,KAAK;GACb,WAAW,GAAG,KAAK;GACnB,WAAW,GAAG,KAAK;GACnB,WAAW,IAAI,UAAU,KAAK,SAAS,CAAC,CAAC,QAAQ;EACnD,CAAC,EACc,CAAC;CAClB;;;;;;;;;;;;;;;CAgBA,MAAM,oBAAoB,MAAwB;EAChD,OAAO,KAAK,mBAAmB,MAAM,KAAK,kBAAkB,IAAI,CAAC;CACnE;;;;;;;;;;;;;;;CAgBA,MAAM,kBAAkB,MAAkD;EACxE,YAAY,KAAK,GAAG;EACpB,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,KAAK,MAAM;EAC1D,MAAM,QAAQ,KAAK,eAAe,KAAK,WAAW,KAAK,WAAW,KAAK,OAAO;EAE9E,gBAAgB,MAAM,WAAW,MAAM,WAAW,KAAK,GAAG;EAC1D,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,MAAM,OAAO;GACX,QAAQ,KAAK,OAAO;GACpB,QAAQ,KAAK,OAAO;GACpB,KAAK,KAAK;GACV,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW,KAAK,aAAa,KAAK,SAAS;EAC7C;EACA,OAAO,KAAK,YAAY,KAAK,iBACzB,qBAAqB;GAAE,GAAG;GAAM,uBAAuB,KAAK;EAAO,CAAC,IACpE,qBAAqB;GAAE,GAAG;GAAM,uBAAuB,KAAK;EAAO,CAAC;CAC1E;;;;;;CAOA,MAAM,mBAAmB,KAAsB;EAC7C,qBAAqB,gBAAgB,GAAG;EACxC,OAAO,KAAK,OAAO,gBAAgB,KAAK;GAAE,MAAM;GAAO,UAAU,WAAW,GAAG;EAAE,CAAC;CACpF;;;;;;;;;;;;;;;CAgBA,MAAM,oBAAoB,MAUvB;EACD,YAAY,KAAK,GAAG;EACpB,KAAK,aAAa,KAAK,UAAU,UAAU;EAC3C,KAAK,aAAa,KAAK,UAAU,UAAU;EAC3C,MAAM,WAAW,IAAI,UAAU,KAAK,QAAQ;EAC5C,MAAM,WAAW,IAAI,UAAU,KAAK,QAAQ;EAC5C,IACE,CAAC,SAAS,SAAS,KACnB,CAAC,SAAS,SAAS,KACnB,SAAS,oBAAoB,CAAC,KAC9B,SAAS,oBAAoB,CAAC,GAE9B,MAAM,IAAI,cAAc,wBAAwB;GAC9C,UAAU,OAAO,KAAK,QAAQ;GAC9B,UAAU,OAAO,KAAK,QAAQ;EAChC,CAAC;EAEH,IAAI,SAAS,cAAc,QAAQ,GACjC,MAAM,IAAI,cAAc,sBAAsB;GAC5C,UAAU,OAAO,KAAK,QAAQ;GAC9B,UAAU,OAAO,KAAK,QAAQ;EAChC,CAAC;EAEH,MAAM,UAAU,KAAK,YAAY,KAAK,GAAG;EACzC,MAAM,YAAY,cAAc,cAAc,QAAQ,GAAG,OAAO;EAChE,MAAM,YAAY,YAAY,cAAc,QAAQ,GAAG,OAAO;EAC9D,OAAO,KAAK,oBAAoB;GAC9B,QAAQ,KAAK;GACb,QAAQ,KAAK;GACb,KAAK,KAAK;GACV;GACA;GACA,QAAQ,KAAK;GACb,gBAAgB,KAAK;GACrB,WAAW,KAAK;EAClB,CAAC;CACH;;;;;;;;;;;;;;;CAgBA,MAAM,gBAAgB,MAA2B;EAC/C,OAAO,KAAK,sBAAsB,MAAM,KAAK,qBAAqB,IAAI,CAAC;CACzE;;;;;;CAOA,MAAM,qBAAqB,MAAwD;EACjF,YAAY,KAAK,GAAG;EACpB,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,KAAK,MAAM;EAC1D,MAAM,QAAQ,KAAK,eAAe,KAAK,WAAW,KAAK,WAAW,KAAK,OAAO;EAC9E,gBAAgB,MAAM,WAAW,MAAM,WAAW,KAAK,GAAG;EAC1D,IAAI,KAAK,YAAY,UAAa,KAAK,YAAY,QACjD,MAAM,IAAI,cAAc,0BAA0B;GAAE,OAAO;GAAW,QAAQ;EAAU,CAAC;EAE3F,IAAI,KAAK,YAAY,QAAW,sBAAsB,KAAK,SAAS,SAAS;EAC7E,IAAI,KAAK,YAAY,QAAW,sBAAsB,KAAK,SAAS,SAAS;EAE7E,MAAM,CAAC,YAAY,cAAc,KAAK,UAClC,CAAC,KAAK,SAAS,KAAK,OAAO,IAC3B,CAAC,KAAK,SAAS,KAAK,OAAO;EAC/B,OAAO,wBAAwB;GAC7B,QAAQ,KAAK,OAAO;GACpB,QAAQ,KAAK,OAAO;GACpB,KAAK,KAAK;GACV,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW,KAAK,aAAa,KAAK,SAAS;GAC3C,0BAA0B;GAC1B,0BAA0B;EAC5B,CAAC;CACH;;;;;;CAOA,MAAM,sBAAsB,KAAyB;EACnD,qBAAqB,mBAAmB,GAAG;EAC3C,MAAM,cACJ,IAAI,6BAA6B,UAAa,IAAI,6BAA6B;EACjF,OAAO,KAAK,OAAO,mBAAmB,KAAK;GACzC,MAAM,cAAc,eAAe;GACnC,UAAU,WAAW,GAAG;EAC1B,CAAC;CACH;;;;;;;;;;;;;;CAeA,MAAM,oBAAoB,MAA+B;EACvD,OAAO,KAAK,0BAA0B,MAAM,KAAK,yBAAyB,IAAI,CAAC;CACjF;;;;;;CAOA,MAAM,yBAAyB,MAAgE;EAC7F,YAAY,KAAK,GAAG;EACpB,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,KAAK,MAAM;EAC1D,MAAM,QAAQ,KAAK,eAAe,KAAK,WAAW,KAAK,WAAW,KAAK,OAAO;EAC9E,gBAAgB,MAAM,WAAW,MAAM,WAAW,KAAK,GAAG;EAC1D,OAAO,4BAA4B;GACjC,QAAQ,KAAK,OAAO;GACpB,QAAQ,KAAK,OAAO;GACpB,KAAK,KAAK;GACV,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW,KAAK,aAAa,KAAK,SAAS;EAC7C,CAAC;CACH;;;;;CAMA,MAAM,0BAA0B,KAA6B;EAC3D,qBAAqB,uBAAuB,GAAG;EAC/C,OAAO,KAAK,OAAO,uBAAuB,KAAK;GAAE,MAAM;GAAW,UAAU,WAAW,GAAG;EAAE,CAAC;CAC/F;;;;;;;;;;;;;;;;;;;;;;CAuBA,MAAM,WAAW,MAAsB;EACrC,OAAO,KAAK,iBAAiB,MAAM,KAAK,gBAAgB,IAAI,CAAC;CAC/D;;;;;;;CAQA,MAAM,gBAAgB,MAA8C;EAClE,MAAM,WAAW,KAAK,kBAAkB;EAExC,IAAI,cADiB,KAAK,sBAAsB,SAE9C,MAAM,IAAI,cAAc,2BAA2B;GACjD,OAAO;GACP,QAAQ;EACV,CAAC;EAEH,YAAY,KAAK,GAAG;EACpB,MAAM,CAAC,QAAQ,UAAU,MAAM,QAAQ,IAAI,CACzC,KAAK,mBAAmB,KAAK,QAAQ,KAAK,YAAY,GACtD,KAAK,mBAAmB,KAAK,QAAQ,KAAK,YAAY,CACxD,CAAC;EACD,MAAM,UAAU,OAAO,SAAS,OAAO;EACvC,MAAM,CAAC,QAAQ,UAAU,UAAU,CAAC,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM;EACrE,MAAM,mBAAmB,WACpB,KAAK,gBACL,KAAK;EACV,KAAK,aAAa,kBAAkB,WAAW,kBAAkB,mBAAmB;EACpF,MAAM,cAAc,IAAI,UAAU,gBAAgB;EAClD,IAAI,CAAC,YAAY,SAAS,KAAK,YAAY,oBAAoB,CAAC,GAC9D,MAAM,IAAI,cAAc,0BAA0B,EAAE,OAAO,OAAO,gBAAgB,EAAE,CAAC;EAEvF,MAAM,iBAAiB,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,WAAW,IAAI;EAC3E,MAAM,SAAS;GACb,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,cAAc,OAAO;GACrB,cAAc,OAAO;GACrB,KAAK,KAAK;GACV,WAAW,KAAK,aAAa,KAAK,SAAS;GAC3C,MAAM,KAAK;GACX,WAAW,KAAK;GAChB,eAAe,KAAK;EACtB;EACA,OAAO,WACH,mBAAmB;GAAE,GAAG;GAAQ,eAAe;EAAe,CAAC,IAC/D,mBAAmB;GAAE,GAAG;GAAQ,mBAAmB;EAAe,CAAC;CACzE;;;;;;CAOA,MAAM,iBAAiB,KAAoB;;EACzC,qBAAqB,cAAc,GAAG;EACtC,MAAM,cAAc,MAAM,KAAK,OAAO,cAAc,KAAK;GACvD,MAAM;GACN,QAAQ,IAAI;GACZ,QAAQ,IAAI;GACZ,KAAK,IAAI;EACX,CAAC;EACD,+CAAK,SAAQ,oGAAa;EAC1B,OAAO;CACT;CAEA,MAAc,OACZ,QACA,KACA,cACA;EACA,IAAI,KAAK,WAAW,QAAW,MAAM,cAAc,cAAc;EACjE,MAAM,SAAS,MAAM,YAAY,KAAK,QAAQ,mBAAmB,QAAQ,GAAG;EAC5E,MAAM,gBACJ,KAAK,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,KAAK,cAAc;EAC9E,MAAM,QAAQ,KAAK;EACnB,MAAM,uBAAuB,MAAM,KAAK,0BAA0B,cAAc,KAAK;EACrF,MAAM,UAA8B;GAClC,GAAG;GACH,GAAI,yBAAyB,SAAY,CAAC,IAAI,EAAE,qBAAqB;EACvE;EACA,OAAO,KAAK,QAAQ,OAAO,QAAQ,QAAQ,OAAO;CACpD;;;;;;;;;;;;;;;CAgBA,MAAc,0BACZ,cACA,OACqF;EACrF,IAAI,iBAAiB,QAAW,OAAO;EAEvC,IAAI,aAAa,SAAS,cAAc;GACtC,MAAM,EAAE,QAAQ,QAAQ,QAAQ;GAChC,OAAO,OAAO,WAAW;IAMvB,OAAO,MALY,KAAK,YACtB,SACA;KAAE;KAAQ;KAAQ,KAAK,GAAG;IAAM,GAChC,MACF,MACgB,OAAO,EAAE,WAAW,MAAM,IAAI;KAAE,WAAW;KAAM,UAAU;IAAK;GAClF;EACF;EAEA,IAAI,UAAU,QAAW,OAAO;EAChC,MAAM,EAAE,MAAM,aAAa;EAC3B,MAAM,cAAc,aAA8B;GAChD,WAAW,IAAI,6DAAU,QAAS,cAAa,CAAC;GAChD,MAAM,IAAI,6DAAU,QAAS,UAAS,CAAC,CAAC,CAAC,KAAK,IAAI,6DAAU,QAAS,UAAS,CAAC,CAAC;EAClF;EACA,IAAI;EACJ,IAAI,SAAS,cACX,IAAI;GACF,WAAW,WAAW,MAAM,KAAK,YAAY;IAAE,GAAG;IAAU;GAAM,CAAC,CAAC;EACtE,QAAQ;GACN,WAAW;EACb;EAGF,OAAO,OAAO,WAAW;GACvB,MAAM,UAAU,MAAM,KAAK,YAAY;IAAE,GAAG;IAAU;GAAM,GAAG,MAAM;GAErE,IAAI,aAAa,QAAW;IAG1B,WAAW,WAAW,OAAO;IAI7B,OAAO,SAAS,gBAAgB,YAAY,OACxC;KAAE,WAAW;KAAM,UAAU;IAAK,IAClC,EAAE,WAAW,MAAM;GACzB;GAEA,QAAQ,MAAR;IACE,KAAK,OACH,OAAO,YAAY,QACjB,IAAI,UAAU,QAAQ,SAAS,CAAC,CAAC,cAAc,SAAS,SAAS,IAC/D;KAAE,WAAW;KAAM,UAAU;IAAQ,IACrC,EAAE,WAAW,MAAM;IACzB,KAAK,iBACH,OAAO,YAAY,QAAQ,IAAI,UAAU,QAAQ,SAAS,CAAC,CAAC,WAAW,SAAS,SAAS,IACrF;KAAE,WAAW;KAAM,UAAU;IAAQ,IACrC,EAAE,WAAW,MAAM;IACzB,KAAK,cACH,OAAO,YAAY,OAAO;KAAE,WAAW;KAAM,UAAU;IAAK,IAAI,EAAE,WAAW,MAAM;IACrF,KAAK,WAAW;KACd,IAAI,YAAY,MAAM,OAAO,EAAE,WAAW,MAAM;KAChD,MAAM,cAAc,IAAI,UAAU,QAAQ,SAAS,CAAC,CAAC,CAAC,KACpD,IAAI,UAAU,QAAQ,SAAS,CAAC,CAClC;KACA,IAAI,YAAY,WAAW,SAAS,IAAI,GAAG,OAAO;MAAE,WAAW;MAAM,UAAU;KAAQ;KAGvF,IAAI,SAAS,KAAK,OAAO,KAAK,YAAY,OAAO,GAC/C,OAAO;MAAE,WAAW;MAAM,UAAU;KAAQ;KAC9C,OAAO,EAAE,WAAW,MAAM;IAC5B;GACF;EACF;CACF;CAEA,MAAc,IACZ,UACA,QACA,QACiC;EACjC,OAAO,KAAK,KAAK,eACf,KAAK,QAAQ,mBACb,aACA,UACA,QACA,WAAW,SAAY,SAAY,EAAE,OAAO,CAC9C;CACF;CAEA,MAAc,YACZ,UACA,QACA,QACwC;EACxC,IAAI;GACF,OAAO,MAAM,KAAK,IAAW,UAAU,QAAQ,MAAM;EACvD,SAAS,OAAgB;GACvB,IAAI,KAAK,WAAW,KAAK,GAAG,OAAO;GACnC,MAAM;EACR;CACF;CAEA,AAAQ,WAAW,OAAyB;EAC1C,OAAO,aAAa,KAAK,KAAK,MAAM,WAAW;CACjD;CAEA,AAAQ,eAAe,WAAmB,WAAmB,SAAkB;EAC7E,OAAO,UAAU;GAAE,WAAW,CAAC;GAAW,WAAW,CAAC;EAAU,IAAI;GAAE;GAAW;EAAU;CAC7F;CAEA,AAAQ,YAAY,KAAqB;EACvC,MAAM,UAAW,oBAA+C;EAChE,IAAI,YAAY,QACd,MAAM,IAAI,cAAc,eAAe;GACrC,OAAO;GACP,OAAO;GACP,SAAS;EACX,CAAC;EAEH,OAAO;CACT;CAEA,AAAQ,aAAa,OAAgB,eAA6B;EAChE,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,cAAc,uBAAuB,EAAE,OAAO,cAAc,CAAC;CAE3E;;CAGA,AAAQ,aAAa,UAAsC;EACzD,IAAI,aAAa,QAAW,OAAO,gBAAgB,KAAK,eAAe;EACvE,gBAAgB,QAAQ;EACxB,OAAO;CACT;;;;;CAMA,AAAQ,UAAU,GAAa,GAAa;EAC1C,OAAO,eAAe,GAAG,WAAW,CAAC,EAAE,GAAG,WAAW,CAAC,WAAW,KAAK,QAAQ,UAAU,GAAG,CAAC,CAAC;CAC/F;CAEA,MAAc,mBACZ,KACA,gBAC8B;EAC9B,IAAI;GACF,MAAM,YAAY,OAAO,QAAQ,WAAW,eAAe,GAAG,IAAI;GAClE,MAAM,WAAW,MAAM,eAAe,WAAW,GAAG,SAAS,KAAK,QAAQ,QAAQ,SAAS,CAAC;GAC5F,IACE,mBAAmB,UACnB,mBAAmB,MACnB,mBAAmB,SAAS,QAE5B,MAAM,IAAI,cAAc,kCAAkC;IACxD,OAAO,WAAW,GAAG;IACrB,gBAAgB;IAChB,kBAAkB,SAAS;GAC7B,CAAC;GAEH,MAAM,mBAAmB,KAAK,iBAAiB,GAAG;GAClD,IAAI,qBAAqB,UAAa,SAAS,eAAe,IAE5D,MAAM,IAAI,cAAc,+BAA+B,EAAE,OAAO,WAAW,GAAG,EAAE,CAAC;GAEnF,OAAO;IACL,QAAQ,SAAS;IACjB,UACE,oBACA,mBAAmB;KACjB,YAAY,SAAS;KACrB,UAAU,SAAS;KACnB,MAAM,SAAS;KACf,eAAe,SAAS;IAC1B,CAAC;GACL;EACF,SAAS,OAAgB;GACvB,IAAI,CAAC,aAAa,OAAO,eAAe,GACtC,MAAM;GAER,IAAI;GACJ,IAAI;IACF,WAAW,mBAAmB,GAAG;GACnC,QAAQ;IACN,MAAM;GACR;GAKA,IAAI,mBAAmB,UAAa,mBAAmB,IACrD,MAAM,IAAI,cAAc,+BAA+B,EAAE,OAAO,WAAW,GAAG,EAAE,CAAC;GAEnF,IAAI,CAAC,0BAA0B,cAAc,GAC3C,MAAM,IAAI,cAAc,0BAA0B,EAAE,QAAQ,eAAe,CAAC;GAE9E,OAAO;IAAE,QAAQ;IAAgB;GAAS;EAC5C;CACF;CAEA,AAAQ,iBAAiB,KAAkE;EACzF,IAAI;GACF,OAAO,mBAAmB,GAAG;EAC/B,QAAQ;GACN;EACF;CACF;AACF;AAEA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;AACF;AACA,MAAM,4BAA4B;CAAC;CAAO;CAAa;AAAW;AAClE,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;AAQA,SAAS,cAAc,OAAsC;CAC3D,MAAM,OAAO,cAAc,KAAK;CAChC,IAAI,SAAS,QAAW,OAAO,cAAc,0BAA0B;CACvE,KAAK,MAAM,OAAO,2BAChB,IAAI,OAAO,KAAK,SAAS,UAAU,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAElF,KAAK,MAAM,OAAO,2BAA2B;EAC3C,MAAM,SAAS,KAAK;EACpB,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,GACvD,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAEjD;CACA,IAAI,OAAO,KAAK,eAAe,WAAW,OAAO,cAAc,0BAA0B;CACzF,KAAK,MAAM,OAAO,2BAChB,IAAI,KAAK,SAAS,UAAa,OAAO,KAAK,SAAS,UAClD,OAAO,cAAc,GAAG,IAAI,iBAAiB;CAGjD,MAAM,cAAc,KAAK;CACzB,IACE,gBAAgB,WACf,OAAO,gBAAgB,YAAY,CAAC,OAAO,SAAS,WAAW,IAEhE,OAAO,cAAc,6BAA6B;CAEpD,MAAM,OAAO,KAAK,cAAc,KAAK,WAAW;CAChD,IAAI,OAAO,SAAS,UAAU,OAAO,cAAc,sBAAsB;CACzE,MAAM,WAAW,OAAO,YACtB,CAAC,GAAG,2BAA2B,aAAsB,CAAC,CAAC,SAAS,QAC9D,KAAK,SAAS,SAAY,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAClD,CACF;CACA,OAAO,QAAQ;EACb,cAAc,KAAK;EACnB,cAAc,KAAK;EACnB,KAAK,KAAK;EACV,WAAW,KAAK;EAChB,WAAW,KAAK;EAChB,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,SAAS,KAAK;EACd,SAAS,KAAK;EACd;EACA,OAAO,KAAK;EACZ,GAAG;CACL,CAAC;AACH;;AAGA,SAAS,iBAAiB,MAAyB;CACjD,MAAM,SAAS,cAAc,IAAI;CACjC,IAAI,OAAO,IAAI,OAAO,OAAO;CAC7B,MAAM,IAAI,cACR,6BACA,EAAE,QAAQ,OAAO,OAAO,GACxB;EAAE,MAAM;EAAM,OAAO;CAAM,CAC7B;AACF;;;;;AC1gCA,IAAa,UAAb,MAAqB;CAUA;CACA;;;;;;;;;CAFnB,YACE,AAAiB,SACjB,AAAiB,SACjB;EAFiB;EACA;EAEjB,KAAK,OAAO,IAAI,WACd,QAAQ,eACR,QAAQ,oBAAoB,KAC5B,QAAQ,IACV;CACF;CAEA,AAAiB;;;;;;;;;;CAWjB,MAAa,gBACX,SACA,UACA,UACA,KACsB;EACtB,sBAAsB,UAAU,UAAU;EAC1C,OAAO,KAAK,MAAM,SAAS,UAAU,EAAE,UAAU,gBAAgB,QAAQ,EAAE,GAAG,GAAG;CACnF;;;;;;;;;;CAWA,MAAa,iBACX,SACA,UACA,WACA,KACsB;EACtB,sBAAsB,WAAW,WAAW;EAC5C,OAAO,KAAK,MAAM,SAAS,UAAU,EAAE,WAAW,gBAAgB,SAAS,EAAE,GAAG,GAAG;CACrF;CAEA,MAAc,MACZ,SACA,UACA,QACA,KACsB;EACtB,oBAAoB,GAAG;EAEvB,MAAM,SAAiC;GACrC,SAAS,MAAM,aAAa,KAAK,SAAS,OAAO;GACjD,UAAU,MAAM,aAAa,KAAK,SAAS,QAAQ;GACnD,GAAG;EACL;EACA,IAAI,QAAQ,QAAW,OAAO,SAAS,OAAO,GAAG;EAEjD,IAAI;GAOF,OAAO,UAAS,MANO,KAAK,KAAK,eAC/B,KAAK,QAAQ,mBACb,aACA,UACA,MACF,EACwB,CAAC,IAAI;EAC/B,SAAS,OAAgB;GACvB,MAAM,cAAc,OAAO,SAAS,UAAU,KAAK;IACjD,SAAS,OAAO,cAAc;IAC9B,UAAU,OAAO,eAAe;GAClC,CAAC;EACH;CACF;AACF;AAEA,SAAS,SAAS,OAA6B;CAC7C,IAAI,CAAC,YAAY,KAAK,GACpB,MAAM,IAAI,cACR,0BACA,EAAE,UAAU,QAAQ,GACpB;EAAE,MAAM;EAAO,OAAO;CAAM,CAC9B;CAEF,MAAM,OAAO;CACb,MAAM,eACJ,KAAK,iBAAiB,SAClB,IAAI,UAAU,KAAK,YAAY,IAC/B,YAAY,KAAK,kBAAmB,KAAK,eAAe;CAC9D,MAAM,WACJ,KAAK,aAAa,SACd,IAAI,UAAU,KAAK,QAAQ,IAC3B,YAAY,KAAK,cAAe,KAAK,eAAe;CAC1D,MAAM,cAAc,SAAS,MAAM,YAAY,CAAC,CAAC,UAAU,YAAY;CAEvE,OAAO;EACL,iBAAiB,KAAK;EACtB,KAAK,KAAK;EACV,UAAU,KAAK;EACf,WAAW,KAAK;EAChB,GAAI,KAAK,qBAAqB,SAAY,CAAC,IAAI,EAAE,kBAAkB,KAAK,iBAAiB;EACzF,GAAI,KAAK,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,KAAK,aAAa;EAC7E,SAAS,KAAK;EACd,SAAS,KAAK;EACd,aAAa,KAAK;EAClB,cAAc,KAAK;EACnB,WAAW,KAAK;EAChB,gBAAgB,KAAK;EACrB,cAAc,KAAK;EACnB,cAAc,KAAK;EACnB,iBAAiB,KAAK;EACtB;EACA;EACA;CACF;AACF;AAMA,MAAM,gBAAgB,UAAU,MAAM,EAAE,gBAAgB,GAAG,CAAC;AAE5D,SAAS,YAAY,WAAmB,iBAAqC;CAC3E,MAAM,YAAY,IAAI,cAAc,SAAS,CAAC,CAAC,IAAI,CAAC;CACpD,OAAO,kBAAkB,YAAY,IAAI,cAAc,CAAC,CAAC,CAAC,UAAU,SAAS;AAC/E;AAEA,SAAS,YAAY,OAAoC;CACvD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,OAAO;CAWb,OACE,KAAK,uBAAuB,QAC5B,OAAO,KAAK,WAAW,YACvB,OAAO,SAAS,KAAK,MAAM,KAC3B;EAbA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAMc,CAAC,CAAC,OAAO,QAAQ,OAAO,KAAK,SAAS,QAAQ,KAC5D,OAAO,KAAK,eAAe,YAC3B,OAAO,UAAU,KAAK,UAAU,KAChC,OAAO,KAAK,uBAAuB,aACnC,wBAAwB,KAAK,mBAAmB,KAChD,wBAAwB,KAAK,eAAe,KAC5C,wBAAwB,KAAK,eAAe,KAC5C,wBAAwB,KAAK,WAAW,MACvC,KAAK,wBAAwB,UAAa,KAAK,oBAAoB,YACnE,KAAK,oBAAoB,UAAa,KAAK,gBAAgB;AAEhE;AAEA,SAAS,wBAAwB,OAAyB;CACxD,IAAI,UAAU,QAAW,OAAO;CAChC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI;EAIF,MAAM,UAAU,IAAI,UAAU,KAAK;EACnC,OAAO,QAAQ,SAAS,KAAK,QAAQ,cAAc,CAAC;CACtD,QAAQ;EACN,OAAO;CACT;AACF;;;;;;AAOA,MAAM,oBAAoB;;;;;;;;AAS1B,MAAM,oBAAoB;;AAG1B,SAAS,eACP,QACA,SACA,SACA,UACU;CACV,IAAI,WAAW,QAAQ,SAAS,OAAO;CACvC,IAAI,WAAW,QAAQ,UAAU,OAAO;CACxC,OAAO;AACT;AAEA,SAAS,cACP,OACA,SACA,UACA,KACA,SACe;CACf,IAAI,aAAa,KAAK,GAAG;;EAGvB,MAAM,UAAU,kBAAkB,KAAK,KAAK;EAC5C,MAAM,wCAAe,kBAAkB,KAAK,OAAO,iFAAI;EACvD,IAAI,iBAAiB,QACnB,OAAO,cAAc,kBACnB,eAAe,cAAc,SAAS,SAAS,QAAQ,GACvD,KACF;EAEF,IAAI,MAAM,WAAW,OAAO,kBAAkB,KAAK,OAAO,GACxD,OAAO,cAAc,qBAAqB,SAAS,UAAU,KAAK,KAAK;EAEzE,IAAI,MAAM,WAAW,OAAO,2BAA2B,KAAK,OAAO,GACjE,OAAO,cAAc,2BAA2B,SAAS,UAAU,KAAK,KAAK;EAE/E,OAAO;CACT;CACA,OAAO,IAAI,cACT,kBACA,EAAE,WAAW,QAAQ,GACrB;EAAE,OAAO;EAAO,OAAO;CAAM,CAC/B;AACF;AAEA,SAAS,oBAAoB,KAAiC;CAC5D,IAAI,QAAQ,UAAa,CAAC,cAAc,MAAM,SAAS,OAAO,IAAI,MAAM,OAAO,GAAG,CAAC,GACjF,MAAM,IAAI,cAAc,eAAe;EACrC,OAAO;EACP,OAAO,OAAO,GAAG;EACjB,SAAS;CACX,CAAC;AAEL;AAEA,SAAS,gBAAgB,QAA+B;CACtD,OAAO,IAAI,UAAU,MAAM,CAAC,CAAC,QAAQ;AACvC;;;;;;;;;;;;;;AC/RA,MAAa,sBAAsB;CACjC;CACA;CACA;AACF;;;;;;;;AAYA,MAAa,uBAAuB;CAAC;CAAe;CAAY;CAAY;AAAS;;AA8CrF,SAAgB,2BAA2B,QAAmC;CAC5E,IAAI,WAAW,KAAK,OAAO;CAC3B,IAAI,WAAW,KAAK,OAAO;CAC3B,OAAO;AACT;;;;;;AAOA,SAAgB,0BAA0B,QAAgB,MAAkC;CAC1F,IAAI,SAAS,sBAAsB,OAAO;CAC1C,IAAI,SAAS,yBAAyB,OAAO;CAC7C,IAAI,SAAS,2BAA2B,OAAO;CAC/C,OAAO,2BAA2B,MAAM;AAC1C;AAwBA,SAAgB,wBACd,QACA,YACA,QACyC;CACzC,MAAM,EAAE,YAAY,SAAS;CAC7B,MAAM,WAAW,SAAS,IAAI;CAC9B,IAAI,cAAc,OAAO,aAAa,4DAAO,SAAW,cAAa,OAAO;EAC1E,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,MAAM,mBACJ,oDAAO,KAAO,sBAAqB,WAAW,KAAK,mBAAmB;EACxE,IAAI,WAAW,gBAAgB;GAC7B,MAAM,eAAe,WAAW;GAChC,iDACE,KAAO,aAAY,YACnB,OAAO,iBAAiB,YACxB,KAAK,iBAAiB,cAEtB,MAAM,IAAI,cACR,qBACA,CAAC,GACD;IACE,QAAQ;IACR;IACA,QAAQ;IACR,GAAI,OAAO,iBAAiB,WAAW,EAAE,WAAW,aAAa,IAAI,CAAC;GACxE,CACF;GAEF,OAAO;IACL,IAAI;IACJ,UAAU,oBAAoB;IAC9B,QAAQ;KAAE,WAAW;KAAc,sBAAsB,oBAAoB;IAAK;GACpF;EACF;EACA,iDAAI,KAAO,aAAY,QAAQ,OAAO;GAAE,IAAI;GAAM,UAAU,oBAAoB;EAAG;CACrF;CAEA,MAAM,OAAO,0BAA0B,YAAY,kBAAkB,MAAM,MAAM,CAAC;CAClF,IAAI,SAAS,YACX,OAAO;EACL,IAAI;EACJ,MAAM;EACN,WAAW;EACX,SAAS,kBAAkB,MAAM,SAAS,KAAK;CACjD;CAEF,OAAO,SAAS,gBACZ;EAAE,IAAI;EAAO;EAAM,WAAW;CAAK,IACnC;EAAE,IAAI;EAAO;EAAM,WAAW;CAAM;AAC1C;AAEA,SAAS,SAAS,OAAqD;CACrE,OAAO,OAAO,UAAU,YAAY,UAAU,OACzC,QACD;AACN;;;;;;;;;;;;;;AC1FA,SAAgB,mBACd,OACW;CACX,YAAY,MAAM,GAAG;CACrB,oBAAoB,MAAM,cAAc,MAAM,YAAY;CAC1D,MAAM,CAAC,SAAS,YAAY,MAAM,kBAC9B,CAAC,MAAM,cAAc,MAAM,YAAY,IACvC,CAAC,MAAM,cAAc,MAAM,YAAY;CAC3C,OAAO;EACL;EACA;EACA,KAAK,MAAM;EACX,MAAM;GAAE,QAAQ,MAAM;GAAc,QAAQ,MAAM;EAAa;CACjE;AACF;;AAGA,IAAa,QAAb,MAAmB;CAUE;CACA;CACA;;;;;;;;;CAHnB,YACE,AAAiB,SACjB,AAAiB,SACjB,AAAiB,QACjB,eACA,UAA4B,CAAC,GAC7B;EALiB;EACA;EACA;EAIjB,KAAK,gBACH,kBAAkB,SAAY,SAAY,QAAQ,eAAe,eAAe;EAClF,KAAK,kBAAkB,uBAAuB,QAAQ,eAAe;CACvE;;CAGA,AAAiB;CACjB,AAAiB;;;;;;;;;;;;;CAcjB,MAAa,KACX,SACA,UACA,KACA,QACA,SAC6C;EAC7C,OAAO,KAAK,WAAW,MAAM,KAAK,UAAU,SAAS,UAAU,KAAK,QAAQ,OAAO,CAAC;CACtF;;;;;;;;;;;;;;;;;CAkBA,MAAa,WACX,SACA,UACA,KACA,QACA,SAC8B;EAC9B,OAAO,eAAe,YACpB,KAAK,iBAAiB,MAAM,KAAK,UAAU,SAAS,UAAU,KAAK,QAAQ,OAAO,CAAC,CACrF;CACF;;;;;;;;;;;;;;CAeA,MAAa,UACX,SACA,UACA,KACA,QACA,SAC0B;EAC1B,YAAY,GAAG;EACf,MAAM,+DAAY,QAAS,cAAa,gBAAgB,KAAK,eAAe;EAC5E,gBAAgB,SAAS;EACzB,MAAM,gBAAgB,MAAM,gBAAgB,KAAK,SAAS,OAAO;EACjE,MAAM,iBAAiB,MAAM,gBAAgB,KAAK,SAAS,QAAQ;EACnE,MAAM,UAAU,KAAK,WAAW,eAAe,kEAAgB,QAAS,IAAI;EAC5E,OAAO,qBAAqB;GAC1B,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB;GACA,iBAAiB,kBAAkB,QAAQ;GAC3C;GACA,GAAG;EACL,CAAC;CACH;;;;;;;;;;;;CAaA,MAAa,WAAW,KAAmE;EACzF,MAAM,SAAS,MAAM,KAAK,iBAAiB,GAAG;EAC9C,OAAO,KAAK,QAAQ,OAAO,gBAAgB,QAAQ,KAAK,cAAc,CAAC;CACzE;;CAGA,MAAa,iBAAiB,KAAoD;EAChF,OAAO,eAAe,YAAY;GAChC,MAAM,SAAS,MAAM,KAAK,iBAAiB,GAAG;GAC9C,MAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,gBAAgB,QAAQ,KAAK,cAAc,CAAC;GAC3F,OAAO,wBAAwB,gBAAgB,QAAQ,MAAM;EAC/D,CAAC;CACH;CAEA,AAAQ,gBAAoC;EAC1C,OAAO,KAAK,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,KAAK,cAAc;CACrF;CAEA,MAAc,iBAAiB,KAAwD;EACrF,qBAAqB,gBAAgB,GAAG;EACxC,IAAI,KAAK,WAAW,QAAW,MAAM,cAAc,cAAc;EACjE,OAAO,YAAY,KAAK,QAAQ,mBAAmB,gBAAgB,GAAG;CACxE;;CAGA,AAAQ,WACN,eACA,gBACA,MACU;EACV,IAAI,SAAS,QACX,OAAO,mBAAmB,aAAa,eAAe,cAAc,CAAC;EAKvE,IAAI,EAFD,kBAAkB,KAAK,UAAU,mBAAmB,KAAK,UACzD,kBAAkB,KAAK,UAAU,mBAAmB,KAAK,SAE1D,MAAM,IAAI,cAAc,iBAAiB;GACvC,SAAS;GACT,UAAU;GACV,YAAY,KAAK;GACjB,YAAY,KAAK;EACnB,CAAC;EAEH,OAAO;GAAE,QAAQ,KAAK;GAAQ,QAAQ,KAAK;EAAO;CACpD;;;;;;;;;;;;;;CAeA,MAAa,YAAY,WAAmB,SAAiD;EAC3F,gBAAgB,SAAS;EAYzB,OAAO,IAXiB,qBAAmC;GACzD,QAAQ;GACR;GACA,eAAe;GACf,MAAM;GACN,QAAQ;GACR,mBAAmB,KAAK,QAAQ;GAChC,eAAe,KAAK,QAAQ;GAC5B,kBAAkB,KAAK,QAAQ;GAC/B,MAAM,KAAK,QAAQ;EACrB,CACiB,CAAC,CAAC,QAAQ;GAAE,gBAAgB;GAAG,GAAG;EAAQ,CAAC;CAC9D;AACF;;;;;;;;;;AC/NA,IAAa,QAAb,MAAmB;;CAEjB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;;;;CAKhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;CAChB,AAAiB;CACjB,AAAiB;CACjB,AAAQ;;;;;;;;;;CAWR,YAAY,SAAwB;EAClC,MAAM,cAAc,sEAAmB,QAAS,QAAO;EACvD,KAAK,oBAAoB,qEACvB,QAAS,sBAAqB,YAAY,iBAC5C;EACA,KAAK,wEAAqB,QAAS,uBAAsB;EACzD,KAAK,2DAAS,QAAS;EACvB,KAAK,mEACH,QAAS,mBAAkB,SACvB,SACA,QAAQ,QAAQ,eAAe,eAAe;EAEpD,MAAM,aAAa,IAAI,6DACrB,QAAS,eACT,KAAK,sEACL,QAAS,IACX;EACA,KAAK,UAAU,IAAI,aAAa;GAC9B,mBAAmB,KAAK;GACxB,oBAAoB,KAAK;GACzB,sDAAI,QAAS,UAAS,SAAY,CAAC,IAAI,EAAE,MAAM,QAAQ,KAAK;GAC5D,sDAAI,QAAS,mBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,QAAQ,cAAc;GACvF,GAAI,KAAK,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,KAAK,cAAc;EAClF,CAAC;EACD,MAAM,UAAU,EAAE,kEAAgB,QAAS,eAAe;EAC1D,KAAK,UAAU,IAAI,QAAQ,KAAK,SAAS,OAAO;EAGhD,MAAM,8DACJ,QAAS,sBAAqB,cAAc,IAAI,iBAAiB,IAAI,KAAK;EAC5E,KAAK,UAAU,IAAI,QAAQ,KAAK,SAAS,QAAQ;EACjD,KAAK,QAAQ,IAAI,MAAM,KAAK,SAAS,UAAU,OAAO;EACtD,MAAM,aAAa;GAAE,mEAAiB,QAAS;GAAiB,GAAG;EAAQ;EAC3E,KAAK,YAAY,IAAI,UACnB,KAAK,SACL,UACA,KAAK,QACL,KAAK,eACL,UACF;EACA,KAAK,QAAQ,IAAI,MAAM,KAAK,SAAS,UAAU,KAAK,QAAQ,KAAK,eAAe,UAAU;EAC1F,KAAK,SAAS,IAAI,OAAO,KAAK,mBAAmB,UAAU;EAC3D,KAAK,SAAS,IAAI,OAAO,KAAK,mBAAmB,YAAY,OAAO;EACpE,KAAK,cAAc,IAAI,YAAY,KAAK,mBAAmB,YAAY,OAAO;EAC9E,KAAK,WAAW,IAAI,SAAS,KAAK,mBAAmB,UAAU;EAC/D,KAAK,OAAO,IAAI,QAAQ,KAAK,SAAS,KAAK,MAAM;EACjD,KAAK,qEACH,QAAS,wEACR,QAAS,uBAAsB,SAC5B,YAAY,kBACZ,GAAG,KAAK,kBAAkB,QAAQ,UAAU,IAAI,EAAE;EACxD,KAAK,kEAAgB,QAAS;EAC9B,KAAK,iEAAe,QAAS;CAC/B;;;;;;;;;;;;CAaA,IAAI,SAA4B;EAC9B,KAAK,iBAAiB,IAAI,kBAAkB;GAC1C,KAAK,KAAK;GACV,GAAI,KAAK,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,KAAK,cAAc;GAChF,GAAI,KAAK,iBAAiB,SAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,aAAa;EACzE,CAAC;EACD,OAAO,KAAK;CACd;AACF;AAEA,SAAS,kBAAkB,OAAuB;CAChD,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;;;;;;;;ACnLA,MAAM,oBAAoB;CACxB,UAAU;CACV,SAAS;CACT,YAAY;CACZ,UAAU;CACV,eAAe;CACf,WAAW;AACb;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,eACd,SACA,UAA0C,CAAC,GACpB;CACvB,OAAO;EAAE;EAAS,WAAW,QAAQ,cAAc,QAAQ,QAAQ,kBAAkB;CAAS;AAChG;;;;;;;;AASA,MAAa,mBAAoD,OAAO,OACtE,eAAe,cAAc,EAAE,WAAW,MAAM,CAAC,CACnD;;;;;AAMA,SAAgB,wBAA+C;CAC7D,OAAO,eAAe,UAAU;AAClC;;;;;;;;;;AC7DA,MAAM,WAAkC,eAAe,UAAU;AACjE,MAAM,UAAiC,eAAe,SAAS;AAC/D,MAAM,aAAoC,eAAe,YAAY;AACrE,MAAM,WAAkC,eAAe,UAAU;AACjE,MAAM,gBAAuC,eAAe,eAAe;AAC3E,MAAM,YAAmC,eAAe,WAAW;;;;;;AAOnE,MAAM,UAAU;CAEd,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAKhB,4BAA4B;CAC5B,wBAAwB;CACxB,sBAAsB;CACtB,sBAAsB;CACtB,4BAA4B;CAC5B,oBAAoB;CACpB,qBAAqB;CAErB,+BAA+B;CAC/B,0BAA0B;CAG1B,yBAAyB;CACzB,8BAA8B;CAG9B,4BAA4B;CAG5B,gCAAgC;CAChC,uBAAuB;CAGvB,mBAAmB;CACnB,oBAAoB;CACpB,mBAAmB;CACnB,iBAAiB;CACjB,aAAa;CACb,wBAAwB;CACxB,kBAAkB;CAClB,iBAAiB;CACjB,cAAc;CACd,kBAAkB;CAGlB,gBAAgB;CAGhB,wBAAwB;CACxB,2BAA2B;CAI3B,uBAAuB;CACvB,+BAA+B;CAG/B,8BAA8B;CAC9B,wBAAwB;CAGxB,qBAAqB;CAErB,0BAA0B;CAC1B,uBAAuB;CACvB,2BAA2B;CAG3B,sBAAsB;CACtB,sBAAsB;CACtB,qBAAqB;CACrB,wBAAwB;CACxB,2BAA2B;CAG3B,qBAAqB;CACrB,wBAAwB;CACxB,uBAAuB;CACvB,8BAA8B;CAC9B,0BAA0B;CAK1B,gBAAgB;CAChB,qBAAqB;CACrB,yBAAyB;CACzB,8BAA8B;CAI9B,mBAAmB;CACnB,mBAAmB;CACnB,wBAAwB;AAC1B;;;;;;;AAwCA,SAAS,0BAA0B,MAA0C;CAC3E,OAAO,cAAc,MAAM,QAAQ,MAAM,oBAAoB,WAAW;AAC1E;;AAGA,SAAS,aAAa,MAAuC;CAC3D,OAAO,KAAK,UAAU,cAAc,MAAM,QAAQ;AACpD;;;;;AAMA,SAAS,kBAAkB,MAA0C;CACnE,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,WAAW,QAAW,OAAO;CACjC,IAAI,YAAY,IAAI,GAAG;EAErB,IAAI,WAAW,KAAK,OAAO;EAC3B,IAAI,WAAW,OAAO,UAAU,KAAK,OAAO;EAC5C,OAAO;CACT;CACA,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU,MAAM,YAAY;AACzE;;;;;;AAOA,SAAS,6BAA6B,MAA0C;CAC9E,OAAO,YAAY,IAAI,KAAK,aAAa,IAAI,MAAM,MAAM,UAAU,kBAAkB,IAAI;AAC3F;;;;;;;AAQA,SAAS,uBAAuB,MAA0C;CACxE,OAAO,YAAY,IAAI,IAAI,mBAAmB;AAChD;;;;;;;AAQA,SAAS,4BAA4B,MAA0C;CAC7E,MAAM,SAAS,KAAK;CACpB,IAAI,WAAW,UAAa,WAAW,OAAO,UAAU,KAAK,OAAO;CACpE,OAAO,WAAW,MAAM,WAAW;AACrC;;;;;;;AAQA,SAAS,6BAA6B,MAA0C;CAC9E,MAAM,SAAS,KAAK;CACpB,OAAO,WAAW,UAAa,WAAW,OAAO,UAAU,MAAM,UAAU;AAC7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,gBACd,OACA,UAAkC,CAAC,GACZ;CACvB,MAAM,SAAS,aAAa,cAAc,KAAK,CAAC;CAGhD,OAAO,QAAQ,gBAAgB,QAAQ,OAAO,YAAY,aACtD;EAAE,GAAG;EAAQ,WAAW;CAAM,IAC9B;AACN;;;;;;;;AA0BA,SAAS,aAAa,MAAsD;CAC1E,IAAI,SAAS,QAAW,OAAO,EAAE,GAAG,QAAQ;CAC5C,IAAI,CAAC,cAAc,KAAK,IAAI,GAAG;EAC7B,IAAI,KAAK,YAAY,QAAW,OAAO,EAAE,GAAG,QAAQ;EAEpD,OAAO,KAAK,cAAc,QACtB,eAAe,KAAK,SAAS,EAAE,WAAW,MAAM,CAAC,IACjD,eAAe,KAAK,OAAO;CACjC;CACA,MAAM,EAAE,SAAS;CAGjB,IAAI,SAAS,gBAAgB,SAAS,sBACpC,OAAO,EAAE,GAAG,kBAAkB,IAAI,EAAE;CAEtC,IAAI,SAAS,0BAA0B,OAAO,EAAE,GAAG,6BAA6B,IAAI,EAAE;CAEtF,IAAI,SAAS,4BAA4B,SAAS,2BAChD,OAAO,EAAE,GAAG,6BAA6B,IAAI,EAAE;CAEjD,IAAI,SAAS,mBAAmB,OAAO,EAAE,GAAG,uBAAuB,IAAI,EAAE;CACzE,IAAI,SAAS,yBAAyB,OAAO,EAAE,GAAG,4BAA4B,IAAI,EAAE;CACpF,IAAI,SAAS,uBAAuB,OAAO,EAAE,GAAG,0BAA0B,IAAI,EAAE;CAIhF,OAAO,EAAE,GAFP,QACA,SACkB,cAAe;AACrC;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,OAAyB;CACzD,OAAO,gBAAgB,KAAK,CAAC,CAAC,YAAY;AAC5C;;;;;;;;;;;;;;;;;ACjWA,MAAa,qBAAqB;CAAC;CAAU;CAAkB;AAAM;;;;;;;AAWrE,MAAM,kBAAkB;CACtB,UAAU;CACV,eAAe;CACf,SAAS;CACT,YAAY;CACZ,UAAU;CACV,WAAW;AACb;;;;;;AAOA,SAAgB,yBAAyB,SAA0C;CACjF,OAAO,OAAO,OAAO,iBAAiB,OAAO,IAAI,gBAAgB,WAAW;AAC9E;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAmB,OAAiC;CAClE,OAAO,yBAAyB,gBAAgB,OAAO,EAAE,aAAa,KAAK,CAAC,CAAC,CAAC,OAAO;AACvF;;;;;AC3DA,MAAa,4BAA4B;;AAGzC,MAAa,yBAAyB;;;;;;;;;;;;;;AA6BtC,MAAa,6BAA6B;CACxC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA,IAAa,mBAAb,MAA8B;CAUT;CATnB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAQ,QAA0B,QAAQ,QAAQ;CAElD,YACE,AAAiB,SACjB,UAAmC,CAAC,GACpC;EAFiB;EAGjB,KAAK,aAAa,QAAQ;EAC1B,KAAK,gBAAgB,QAAQ,iBAAiB;EAC9C,KAAK,WAAW,QAAQ,YAAY;EACpC,KAAK,YAAY,QAAQ,aAAa;EACtC,KAAK,MAAM,QAAQ,OAAO,KAAK;EAC/B,KAAK,UAAU,QAAQ;CACzB;;;;;;CAOA,AAAO,SAAS,MAAkC;EAChD,IAAI,CAAC,iBAAiB,KAAK,SAAS,GAAG;GACrC,KAAK,OAAO,CAAC;IAAE;IAAM,QAAQ;GAAqB,CAAC,CAAC;GACpD,OAAO,QAAQ,QAAQ;EACzB;EACA,OAAO,KAAK,QAAQ,OAAO,YAAY;GAErC,MAAM,UAAS,MADO,KAAK,KAAK,OAAO,EACjB,CACnB,QAAQ,UAAU,MAAM,cAAc,KAAK,SAAS,CAAC,CACrD,IAAI,KAAK,QAAQ;GACpB,MAAM,SAAS,KAAK,SAAS,IAAI;GACjC,MAAM,QAAQ,IACZ,KAAK,YACL,KAAK,aAAa,QAAQ,CAAC,GAAG,QAAQ,MAAM,IAAI,CAAC,QAAQ,GAAG,MAAM,CACpE;EACF,CAAC;CACH;;CAGA,AAAO,OAAO,WAAkC;EAC9C,OAAO,KAAK,QAAQ,OAAO,YAAY;GACrC,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO;GACvC,MAAM,QAAQ,IACZ,KAAK,YACL,QAAQ,QAAQ,UAAU,MAAM,cAAc,SAAS,CAAC,CAAC,IAAI,KAAK,QAAQ,CAC5E;EACF,CAAC;CACH;;;;;;;;;;;;;;CAeA,MAAa,OAAO,WAAmB,OAA0C;EAC/E,MAAM,OAAO,mBAAmB,KAAK;EACrC,IAAI,SAAS,QAAQ,OAAO;EAC5B,MAAM,UAAU,MAAM,KAAK,QAAQ,OAAO,YAAY;GACpD,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO;GACvC,MAAM,OAAO,QAAQ,MAAM,UAAU,MAAM,cAAc,SAAS;GAClE,IAAI,SAAS,QAAW,OAAO;GAC/B,MAAM,QAAQ,IACZ,KAAK,YACL,QAAQ,QAAQ,UAAU,MAAM,cAAc,SAAS,CAAC,CAAC,IAAI,KAAK,QAAQ,CAC5E;GACA,OAAO;EACT,CAAC;EACD,IAAI,YAAY,QACd,KAAK,OAAO,CACV;GAAE,MAAM;GAAS,QAAQ,SAAS,WAAW,mBAAmB;EAAgB,CAClF,CAAC;EAEH,OAAO;CACT;;;;;;;CAQA,MAAa,KAAK,QAAwC;EAoBxD,OAAO,MAnBc,KAAK,QAAQ,OAAO,YAAY;GACnD,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO;GACvC,MAAM,MAAM,KAAK,IAAI;GACrB,MAAM,SAA8B,CAAC;GACrC,MAAM,OAAsB,CAAC;GAC7B,KAAK,MAAM,SAAS,SAAS;IAC3B,MAAM,SAAS,KAAK,cAAc,OAAO,GAAG;IAC5C,IAAI,WAAW,QAAW,KAAK,KAAK,KAAK;SACpC,OAAO,KAAK;KAAE,MAAM;KAAO;IAAO,CAAC;GAC1C;GACA,IAAI,OAAO,SAAS,GAAG;IACrB,MAAM,QAAQ,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,QAAQ,CAAC;IAC1D,KAAK,OAAO,MAAM;GACpB;GACA,MAAM,OAAO,KAAK,QAAQ,UAAU,MAAM,WAAW,MAAM;GAC3D,OAAO,KAAK,cAAc,iBACtB,KAAK,MAAM,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS,IAC3D;EACN,CAAC,KACgB,CAAC;CACpB;CAEA,AAAQ,cAAc,OAAoB,KAAiD;EACzF,IAAI,CAAC,iBAAiB,MAAM,SAAS,GAAG,OAAO;EAC/C,OAAO,MAAM,MAAM,qBAAqC,SAAY;CACtE;;CAGA,AAAQ,OAAO,QAA4C;EACzD,KAAK,MAAM,SAAS,QAClB,IAAI;;GACF,sBAAK,0EAAU,KAAK;EACtB,QAAQ,CAER;CAEJ;CAEA,AAAQ,QAAW,WAA4E;EAC7F,MAAM,UAAU,KAAK;EACrB,IAAI,YAAY,QAAW,OAAO,QAAQ,QAAQ,MAAS;EAC3D,MAAM,MAAM,KAAK,MAAM,KAAK,YAAY;GACtC,IAAI;IACF,OAAO,MAAM,UAAU,OAAO;GAChC,QAAQ;IAGN;GACF;EACF,CAAC;EACD,KAAK,QAAQ;EACb,OAAO;CACT;CAEA,MAAc,KAAK,SAAiD;EAClE,MAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK,UAAU;EAC/C,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;EACnC,MAAM,UAAyB,CAAC;EAChC,KAAK,MAAM,QAAQ,OAAoB;GACrC,MAAM,QAAQ,KAAK,WAAW,IAAI;GAClC,IAAI,UAAU,QAAW,QAAQ,KAAK,KAAK;EAC7C;EACA,OAAO;CACT;CAEA,AAAiB,YAAY,UAAgD;EAC3E,WAAW,KAAK;EAChB,sBAAsB,KAAK;EAC3B,QAAQ,KAAK;EACb,cAAc,KAAK;EACnB,cAAc,KAAK;GAClB,KAAK,gBAAgB,KAAK;EAC3B,WAAW,KAAK;CAClB;CAEA,AAAQ,WAAW,OAAyC;EAC1D,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;EACxD,MAAM,QAAQ;EACd,MAAM,OAAO,MAAM,KAAK;EACxB,MAAM,EAAE,WAAW,sBAAsB,QAAQ,cAAc,cAAc,cAC3E;EACF,IACE,OAAO,cAAc,YACrB,EAAE,OAAO,yBAAyB,YAAY,yBAAyB,SACvE,OAAO,WAAW,YAClB,OAAO,iBAAiB,YACxB,OAAO,iBAAiB,YACxB,OAAO,SAAS,aAChB,OAAO,cAAc,YACrB,CAAC,OAAO,SAAS,SAAS,GAE1B;EAEF,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,YAAY;GACZ;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;ACvQA,SAAgB,gCACd,MACgB;CAChB,MAAM,gBAAwC,OAAO,SAAS,aAAa,KAAK,IAAI;CACpF,OAAO;EACL,MAAM,IAAI,KAAK;GACb,MAAM,QAAQ,MAAM,QAAQ,CAAC,CAAC,IAAI,GAAG;GACrC,OAAO,OAAO,OAAO,OAAO,GAAG,IAAI,MAAM,OAAO;EAClD;EACA,MAAM,IAAI,KAAK,OAAO;GACpB,MAAM,QAAQ,CAAC,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC;EACtC;CACF;AACF;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,kBAAkB,MAA+D;CAC/F,MAAM,gBAAiC,OAAO,SAAS,aAAa,KAAK,IAAI;CAC7E,OAAO;EACL,MAAM,IAAI,KAAK;GACb,MAAM,MAAM,QAAQ,CAAC,CAAC,QAAQ,GAAG;GACjC,IAAI,QAAQ,MAAM,OAAO;GACzB,IAAI;IACF,OAAO,KAAK,MAAM,GAAG;GACvB,QAAQ;IACN,OAAO;GACT;EACF;EACA,MAAM,IAAI,KAAK,OAAO;GACpB,QAAQ,CAAC,CAAC,QAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;EAC9C;CACF;AACF;;;;;AC9FA,MAAM,gBAAgB;CACpB,sBAAsB;CACtB,sBAAsB;CACtB,qBAAqB;CACrB,wBAAwB;CACxB,2BAA2B;AAC7B;;;;;;;;;;;;;;;;AAiBA,SAAgB,oBAAoB,OAA+C;;CACjF,MAAM,yBAAO,cAAc,KAAK,mEAAG;CACnC,IAAI,SAAS,QAAW,OAAO;CAC/B,+BAAO,OAAO,QAAQ,aAAa,CAAC,CAAC,MAAM,CAAC,WAAW,UAAU,IAAI,+EAAI;AAC3E;;AAGA,SAAgB,sBAAsB,OAAyB;CAC7D,OAAO,oBAAoB,KAAK,MAAM;AACxC;;AAGA,SAAgB,sBAAsB,OAAyB;CAC7D,OAAO,oBAAoB,KAAK,MAAM;AACxC;;;;;;;;;;;;;;;;;;;;;;;AC/BA,SAAgB,oBAAoB,OAAyB;CAC3D,MAAM,OAAO,cAAc,KAAK;CAChC,oDAAO,KAAM,UAAS,2BAA2B,KAAK,WAAW;AACnE;AAEA,MAAM,iCAA4D;CAChE;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;AAeA,SAAgB,0BAA0B,OAAyB;CACjE,OAAO,UAAU,OAAO,8BAA8B;AACxD;;AAGA,SAAS,SAAS,MAAc,OAA2C;CACzE,OAAO,MAAM,MAAM,UAAU,UAAU,IAAI;AAC7C;;;;;;AAOA,SAAS,UAAU,OAAgB,OAA2C;CAC5E,MAAM,OAAO,cAAc,KAAK;CAEhC,OAAO,SAAS,UAAa,SAAS,KAAK,MAAM,KAAK;AACxD;;;;;;;AAQA,MAAM,0BAAqD;CACzD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AA6BA,SAAgB,mBAAmB,OAAyB;CAC1D,OAAO,UAAU,OAAO,uBAAuB;AACjD;;;;;;;;AAuBA,SAAgB,sBAAsB,OAAyB;CAC7D,OAAO,0BAA0B,KAAK,KAAK,UAAU,OAAO,CAAC,wBAAwB,CAAC;AACxF;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,gBAAgB,OAAoC;CAClE,MAAM,OAAO,cAAc,KAAK;CAChC,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,yBAAyB,OAAO;CACpF,MAAM,WAAW,cAAc,MAAM,UAAU;CAC/C,OAAO,aAAa,UAAa,aAAa,KAAK,SAAY;AACjE;;AAGA,MAAM,kBAA6C;CACjD;CACA;CACA;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,WAAW,OAAyB;CAClD,MAAM,OAAO,cAAc,KAAK;CAChC,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,SAAS,KAAK,MAAM,eAAe,GAAG,OAAO;CACjD,OAAO,CAAC,YAAY,IAAI,MAAM,KAAK,aAAa,QAAQ,KAAK,WAAW;AAC1E;;;;;ACtKA,SAAS,OAAO,UAA4C;CAC1D,MAAM,OAAO,SAAS;CACtB,OAAO,OAAO,SAAS,YAAY,SAAS,OACvC,KAAiC,UAClC;AACN;AAEA,SAAS,SAAS,OAAqD;CACrE,OAAO,OAAO,UAAU,YAAY,UAAU,OACzC,QACD;AACN;;AAGA,SAAgB,iBAAiB,UAA4B;;CAC3D,IAAI,CAAC,UAAU,OAAO;CACtB,qBAAO,SAAS,QAAQ,yDAAI,cAAa;AAC3C;;;;;;AAOA,SAAgB,iBAAiB,UAA4B;CAC3D,MAAM,SAAS,SAAS,QAAQ;CAChC,wDAAO,OAAS,cAAa,SAAS,OAAO,MAAM,MAAM;AAC3D;;AAGA,SAAgB,eAAe,UAA4B;;CACzD,MAAM,SAAS,SAAS,QAAQ;CAChC,qDAAI,OAAS,cAAa,SAAS,OAAO,MAAM,MAAM,UAAU,OAAO;CACvE,OAAO,sBAAO,SAAS,OAAO,OAAO,2DAAI,kBAAiB;AAC5D;;AAGA,SAAgB,uBAAuB,UAAyC;CAC9E,IAAI,iBAAiB,QAAQ,GAAG,OAAO;CACvC,IAAI,iBAAiB,QAAQ,GAAG,OAAO;CACvC,IAAI,eAAe,QAAQ,GAAG,OAAO;CACrC,OAAO;AACT"}
|