@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_adapters.js","names":["storageAdapterFromChromeStorage","areaNow","area","items","key","value","webStorageAdapter","raw"],"sources":["../../../src/classes/storage_adapters.ts"],"sourcesContent":["/**\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"],"mappings":"AAoDA,SAAgBA,EACd,EACgB,CAChB,IAAMC,MAAwC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EACpF,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMC,EAAQ,MAAMF,EAAQ,CAAC,CAAC,IAAIG,CAAG,EACrC,OAAO,OAAO,OAAOD,EAAOC,CAAG,EAAID,EAAMC,GAAO,IAAA,EAClD,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,MAAMH,EAAQ,CAAC,CAAC,IAAI,EAAGG,GAAMC,CAAM,CAAC,CACtC,CACF,CACF,CA+BA,SAAgBC,EAAkB,EAA+D,CAC/F,IAAML,MAAiC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EAC7E,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMK,EAAMN,EAAQ,CAAC,CAAC,QAAQG,CAAG,EACjC,GAAIG,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAMA,CAAG,CACvB,MAAQ,CACN,OAAOA,CACT,CACF,EACA,MAAM,IAAI,EAAK,EAAO,CACpBN,EAAQ,CAAC,CAAC,QAAQG,EAAK,KAAK,UAAUC,CAAK,CAAC,CAC9C,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"storage_adapters.js","names":["storageAdapterFromChromeStorage","areaNow","area","items","key","value","webStorageAdapter","raw"],"sources":["../../../src/classes/storage_adapters.ts"],"sourcesContent":["/**\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"],"mappings":"AAoDA,SAAgBA,EACd,EACgB,CAChB,IAAMC,MAAwC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EACpF,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMC,EAAQ,MAAMF,EAAQ,CAAC,CAAC,IAAIG,CAAG,EACrC,OAAO,OAAO,OAAOD,EAAOC,CAAG,EAAID,EAAMC,GAAO,IAAA,EAClD,EACA,MAAM,IAAI,EAAK,EAAO,CACpB,MAAMH,EAAQ,CAAC,CAAC,IAAI,EAAGG,GAAMC,CAAM,CAAC,CACtC,CACF,CACF,CA+BA,SAAgBC,EAAkB,EAA+D,CAC/F,IAAML,MAAiC,OAAOC,GAAS,WAAaA,EAAK,EAAIA,EAC7E,MAAO,CACL,MAAM,IAAI,EAAK,CACb,IAAMK,EAAMN,EAAQ,CAAC,CAAC,QAAQG,CAAG,EACjC,GAAIG,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAMA,CAAG,CACvB,MAAQ,CACN,OAAOA,CACT,CACF,EACA,MAAM,IAAI,EAAK,EAAO,CACpBN,EAAQ,CAAC,CAAC,QAAQG,EAAK,KAAK,UAAUC,CAAK,CAAC,CAC9C,CACF,CACF,C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import n from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import{createConfirmationSchedule as e,throwIfAborted as t}from"../utils/confirmation_schedule.js";import n from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as r,isGSwapError as i}from"./gswap_sdk_error.js";import{confirmAppliedTrade as a}from"./apply_results.js";import{armTimeout as o}from"@gala-chain/gala-core-sdk";var s=class{constructor(e){n(this,`method`,void 0),n(this,`uniqueKey`,void 0),n(this,`transactionId`,void 0),n(this,`blockNumber`,void 0),n(this,`mode`,void 0),n(this,`status`,void 0),n(this,`result`,void 0),n(this,`envelope`,void 0),n(this,`backendBaseUrl`,void 0),n(this,`requestor`,void 0),n(this,`requestTimeoutMs`,void 0),n(this,`wire`,void 0),n(this,`positionConfirmation`,void 0),this.method=e.method,this.uniqueKey=e.uniqueKey,this.transactionId=e.transactionId,this.blockNumber=e.blockNumber??null,this.mode=e.mode,this.status=e.mode===`queued`?`queued`:`executed`,this.result=e.result,this.envelope=e.envelope,this.backendBaseUrl=e.dexBackendBaseUrl.replace(/\/$/u,``),this.requestor=e.httpRequestor,this.requestTimeoutMs=e.requestTimeoutMs??3e4,this.wire=e.wire,this.positionConfirmation=e.positionConfirmation}async confirm(e){return this.method===`RequestTrade`?this.confirmApplied(e):this.confirmPosition(e)}confirmApplied(e){return a({dexBackendBaseUrl:this.backendBaseUrl,httpRequestor:this.requestor,requestTimeoutMs:this.requestTimeoutMs,wire:this.wire},{uniqueKey:this.uniqueKey,requestTransactionId:this.transactionId},e)}async confirmPosition(n){if(this.positionConfirmation===void 0)throw r.noWalletAddressError();let i=n?.signal,a=e=>new r(`CONFIRMATION_ABORTED`,{},{uniqueKey:this.uniqueKey,cause:e}),s=e(n,0,a);await s.waitForRead();let c;for(;;){let e=new AbortController,n=o(e,this.requestTimeoutMs),r=()=>e.abort();i?.addEventListener(`abort`,r,{once:!0});try{let t=await this.positionConfirmation(e.signal);if(t.confirmed)return t.position}catch(e){t(i,a);let n=l(this.uniqueKey,e);if(n!==void 0)throw n;c=e}finally{n(),i?.removeEventListener(`abort`,r)}if(!await s.waitForRead())break}throw r.confirmationTimeoutError(this.uniqueKey,c)}};function c(e){return e===404||e===408||e===429||e>=500}function l(e,t){if(!i(t))return;if(t.code===`INVALID_POSITION_RESPONSE`||t.code===`INVALID_CHAIN_RESPONSE`)return new r(`CONFIRMATION_MALFORMED`,{},{uniqueKey:e,url:t.url,body:t.body??t.bodyText,cause:t});let n=t.status;if((t.code===`HTTP_ERROR`||t.code===`UPDATE_REQUIRED`)&&n!==void 0&&!c(n)){let i=t.params.serverMessage;return new r(`CONFIRMATION_FAILED`,{status:n,serverMessage:typeof i==`string`?i:``},{uniqueKey:e,status:n,url:t.url,body:t.body??t.bodyText,cause:t})}}export{s as SubmittedTransaction};
|
|
2
2
|
//# sourceMappingURL=submitted_transaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submitted_transaction.js","names":["_defineProperty","SubmittedTransaction","options","confirmAppliedTrade","GSwapSDKError","callerSignal","abortError","schedule","createConfirmationSchedule","lastError","controller","disarm","armTimeout","forwardAbort","result","error","throwIfAborted","terminal","terminalPositionReadFailure","isRetriedStatus","status","isGSwapError","serverMessage","\"serverMessage\""],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"submitted_transaction.js","names":["_defineProperty","SubmittedTransaction","options","confirmAppliedTrade","GSwapSDKError","callerSignal","abortError","schedule","createConfirmationSchedule","lastError","controller","disarm","armTimeout","forwardAbort","result","error","throwIfAborted","terminal","terminalPositionReadFailure","isRetriedStatus","status","isGSwapError","serverMessage","\"serverMessage\""],"sources":["../../../src/classes/submitted_transaction.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{assertCanonicalPair as n,userRef as r,validateFee as i}from"../utils/validation.js";import{DEX_CONTRACT_PATH as a}from"../utils/chain_contract.js";import{shadowFailures as o}from"../utils/shadow_errors.js";import{SubmittedTransaction as s}from"./submitted_transaction.js";import{orderSymbols as c,readOrderedSymbols as l}from"../utils/ordering.js";import{tradingSymbolOf as u}from"./symbols.js";import{assertCanonicalV2Dto as d,buildRequestTradeDto as f}from"../utils/dto_builders.js";import{readShadowSubmitOutcome as p}from"./shadow_submit.js";import{assertUniqueKey as m,createUniqueKey as h,resolveUniqueKeyPrefix as g,signPreSend as _}from"@gala-chain/gala-core-sdk";function v(e){i(e.fee),n(e.token0Symbol,e.token1Symbol);let[t,r]=e.tokenInIsToken0?[e.token0Symbol,e.token1Symbol]:[e.token1Symbol,e.token0Symbol];return{tokenIn:t,tokenOut:r,fee:e.fee,pool:{token0:e.token0Symbol,token1:e.token1Symbol}}}var y=class{constructor(t,n,i,a,o={}){this.gateway=t,this.symbols=n,this.signer=i,e(this,`walletAddress`,void 0),e(this,`uniqueKeyPrefix`,void 0),this.walletAddress=a===void 0?void 0:r(a,`walletAddress`),this.uniqueKeyPrefix=g(o.uniqueKeyPrefix)}async swap(e,t,n,r,i){return this.submitSwap(await this.buildSwap(e,t,n,r,i))}async swapShadow(e,t,n,r,i){return o(async()=>this.submitSwapShadow(await this.buildSwap(e,t,n,r,i)))}async buildSwap(e,t,n,r,a){i(n);let o=a?.uniqueKey??h(this.uniqueKeyPrefix);m(o);let s=await u(this.symbols,e),c=await u(this.symbols,t),l=this.orientPool(s,c,a?.pool);return f({token0:l.token0,token1:l.token1,fee:n,tokenInIsToken0:s===l.token0,uniqueKey:o,...r})}async submitSwap(e){let t=await this.signRequestTrade(e);return this.gateway.submit(`RequestTrade`,t,this.submitOptions())}async submitSwapShadow(e){return o(async()=>{let t=await this.signRequestTrade(e),n=await this.gateway.submitShadow(`RequestTrade`,t,this.submitOptions());return p(`RequestTrade`,t,n)})}submitOptions(){return this.walletAddress===void 0?{}:{walletAddress:this.walletAddress}}async signRequestTrade(e){if(d(`RequestTrade`,e),this.signer===void 0)throw t.noSignerError();return _(this.signer,a,`RequestTrade`,e)}orientPool(e,n,r){if(r===void 0)return l(c(e,n));if(!(e===r.token0&&n===r.token1||e===r.token1&&n===r.token0))throw new t(`POOL_MISMATCH`,{tokenIn:e,tokenOut:n,poolToken0:r.token0,poolToken1:r.token1});return{token0:r.token0,token1:r.token1}}async confirmSwap(e,t){return m(e),new s({method:`RequestTrade`,uniqueKey:e,transactionId:null,mode:`queued`,result:void 0,dexBackendBaseUrl:this.gateway.dexBackendBaseUrl,httpRequestor:this.gateway.httpRequestor,requestTimeoutMs:this.gateway.requestTimeoutMs,wire:this.gateway.wire}).confirm({initialDelayMs:0,...t})}};export{y as Swaps,v as swapRouteFromQuote};
|
|
2
2
|
//# sourceMappingURL=swaps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swaps.js","names":["_defineProperty","swapRouteFromQuote","validateFee","quote","assertCanonicalPair","tokenIn","tokenOut","Swaps","gateway","symbols","signer","walletAddress","userRef","resolveUniqueKeyPrefix","options","fee","amount","shadowFailures","uniqueKey","createUniqueKey","assertUniqueKey","tokenInSymbol","tradingSymbolOf","tokenOutSymbol","ordered","buildRequestTradeDto","signed","dto","result","readShadowSubmitOutcome","assertCanonicalV2Dto","GSwapSDKError","signPreSend","pool","readOrderedSymbols","orderSymbols","SubmittedTransaction"],"sources":["../../../src/classes/swaps.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"swaps.js","names":["_defineProperty","swapRouteFromQuote","validateFee","quote","assertCanonicalPair","tokenIn","tokenOut","Swaps","gateway","symbols","signer","walletAddress","userRef","resolveUniqueKeyPrefix","options","fee","amount","shadowFailures","uniqueKey","createUniqueKey","assertUniqueKey","tokenInSymbol","tradingSymbolOf","tokenOutSymbol","ordered","buildRequestTradeDto","signed","dto","result","readShadowSubmitOutcome","assertCanonicalV2Dto","GSwapSDKError","signPreSend","DEX_CONTRACT_PATH","pool","readOrderedSymbols","orderSymbols","SubmittedTransaction"],"sources":["../../../src/classes/swaps.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from"../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/defineProperty.js";import{GSwapSDKError as t}from"./gswap_sdk_error.js";import{isProposableTradingSymbol as n}from"../utils/validation.js";import{HttpClient as r}from"./http_client.js";import{asEntryRecord as i,entryOk as a,entryRejected as o,readEntries as s}from"../utils/lenient.js";import{orderSymbols as c,parseTokenClassKey as l}from"../utils/ordering.js";import{resolvePreSend as u}from"../utils/resolve_pre_send.js";import{compositeKeyOf as d}from"@gala-chain/gala-core-sdk";var f=class{constructor(t,n={}){this.gateway=t,this.options=n,e(this,`cachedSymbols`,void 0),e(this,`cachedAt`,0),e(this,`refreshInFlight`,void 0),e(this,`http`,void 0),this.http=new r(t.httpRequestor,t.requestTimeoutMs,t.wire)}async list(){return this.cachedSymbols!==void 0&&Date.now()-this.cachedAt<6e4?this.cachedSymbols:(this.refreshInFlight===void 0&&(this.refreshInFlight=this.http.sendGetRequest(this.gateway.dexBackendBaseUrl,`/v2/trade`,`/symbols`).then(e=>s(`symbols`,e.data,p,this.options.onInvalidEntry)).then(e=>(this.cachedSymbols=e,this.cachedAt=Date.now(),e)).finally(()=>{this.refreshInFlight=void 0})),this.refreshInFlight)}invalidate(){this.cachedSymbols=void 0,this.cachedAt=0}async refresh(){return this.invalidate(),this.refreshInFlight=void 0,this.list()}async resolve(e){let n=await this.list(),r=typeof e==`string`?m(e)?d(l(e)):void 0:d(e),i=n.find(t=>t.symbol===e||r!==void 0&&d(t)===r);if(i===void 0){n=await this.refresh();let i=n.find(t=>t.symbol===e||r!==void 0&&d(t)===r);if(i===void 0)throw t.unknownTokenError(e);return i}return i}async proposeSymbol(e,r,i={}){let a=[];try{a=await this.list()}catch(e){if(i.registryFailure!==`ignore`)throw e}let o=d(e),s=a.find(t=>t.collection===e.collection&&t.category===e.category&&t.type===e.type&&t.additionalKey===e.additionalKey);if(s!==void 0)return s.symbol;if(n(r))return r;throw new t(`NO_VALID_TRADING_SYMBOL`,{classKey:o,displaySymbol:r})}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i,a]=c(n.symbol,r.symbol);return{token0:i===n.symbol?n:r,token1:a===r.symbol?r:n,flipped:i!==n.symbol}}};function p(e){let t=i(e);if(t===void 0)return o(`the row is not an object`);let{symbol:n,collection:r,category:s,type:c,additionalKey:l,decimals:u}=t;return typeof n==`string`?n.length===0?o(`symbol is empty`):typeof r==`string`?typeof s==`string`?typeof c==`string`?typeof l==`string`?typeof u!=`number`||!Number.isInteger(u)||u<0?o(`decimals is not a non-negative integer`):a({symbol:n,collection:r,category:s,type:c,additionalKey:l,decimals:u}):o(`additionalKey is not a string`):o(`type is not a string`):o(`category is not a string`):o(`collection is not a string`):o(`symbol is not a string`)}function m(e){return e.includes(`|`)||e.includes(`$`)}function h(e){return typeof e==`string`?e:d(e)}async function g(e,n){let r=await u(h(n),()=>e.resolve(n));if(r.symbol.length>0)return r.symbol;throw new t(`SYMBOL_NOT_FOUND`,{token:h(n)})}async function _(e,t){return e.passthrough===!0?h(t):g(e,t)}var v=class{constructor(){e(this,`passthrough`,!0)}resolve(e){return typeof e==`string`&&!m(e)?Promise.resolve({symbol:e,collection:``,category:``,type:``,additionalKey:``,decimals:0}):Promise.reject(t.unknownTokenError(e))}async orderPair(e,t){let[n,r]=await Promise.all([this.resolve(e),this.resolve(t)]),[i]=c(n.symbol,r.symbol),a=i!==n.symbol;return{token0:a?r:n,token1:a?n:r,flipped:a}}invalidate(){}};export{v as CanonicalSymbols,f as Symbols,_ as queryTokenOf,h as rawTokenOf,g as tradingSymbolOf};
|
|
2
2
|
//# sourceMappingURL=symbols.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols.js","names":["_defineProperty","Symbols","gateway","options","HttpClient","readEntries","response","parseTradingSymbol","symbols","composite","ref","isCompositeKey","compositeKeyOf","parseTokenClassKey","resolved","entry","refreshed","GSwapSDKError","registry","error","wanted","classKey","registered","isProposableTradingSymbol","displaySymbol","resolvedA","resolvedB","a","b","token0Symbol","token1Symbol","orderSymbols","asEntryRecord","value","entryRejected","symbol","collection","category","type","additionalKey","decimals","entryOk","rawTokenOf","tradingSymbolOf","resolvePreSend","resolver","queryTokenOf","CanonicalSymbols","first","flipped"],"sources":["../../../src/classes/symbols.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"symbols.js","names":["_defineProperty","Symbols","gateway","options","HttpClient","readEntries","response","parseTradingSymbol","symbols","composite","ref","isCompositeKey","compositeKeyOf","parseTokenClassKey","resolved","entry","refreshed","GSwapSDKError","registry","error","wanted","classKey","registered","isProposableTradingSymbol","displaySymbol","resolvedA","resolvedB","a","b","token0Symbol","token1Symbol","orderSymbols","asEntryRecord","value","entryRejected","symbol","collection","category","type","additionalKey","decimals","entryOk","rawTokenOf","tradingSymbolOf","resolvePreSend","resolver","queryTokenOf","CanonicalSymbols","first","flipped"],"sources":["../../../src/classes/symbols.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","names":["GSWAP_ENVIRONMENTS"],"sources":["../../../src/types/env.ts"],"sourcesContent":["/** 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"],"mappings":"AAWA,MAAaA,EAAyE,CACpF,KAAM,CACJ,kBAAmB,0CACnB,gBAAiB,0CACnB,EACA,MAAO,CACL,kBAAmB,+CACnB,gBAAiB,+CACnB,CACF"}
|
|
1
|
+
{"version":3,"file":"env.js","names":["GSWAP_ENVIRONMENTS"],"sources":["../../../src/types/env.ts"],"sourcesContent":["/** 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"],"mappings":"AAWA,MAAaA,EAAyE,CACpF,KAAM,CACJ,kBAAmB,0CACnB,gBAAiB,0CACnB,EACA,MAAO,CACL,kBAAmB,+CACnB,gBAAiB,+CACnB,CACF,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fees.js","names":["FEE_TIER","\"PERCENT_00_00\"","\"PERCENT_00_05\"","\"PERCENT_00_30\"","\"PERCENT_01_00\"","TICK_SPACING_BY_FEE","ALL_FEE_TIERS"],"sources":["../../../src/types/fees.ts"],"sourcesContent":["/**\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"],"mappings":"AAGA,IAAYA,EAAL,yBAAA,EAAA,
|
|
1
|
+
{"version":3,"file":"fees.js","names":["FEE_TIER","\"PERCENT_00_00\"","\"PERCENT_00_05\"","\"PERCENT_00_30\"","\"PERCENT_01_00\"","TICK_SPACING_BY_FEE","ALL_FEE_TIERS"],"sources":["../../../src/types/fees.ts"],"sourcesContent":["/**\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"],"mappings":"AAGA,IAAYA,EAAL,yBAAA,EAAA,C,MAEL,GAAA,EAAAC,cAAA,GAAA,gBAEA,EAAA,EAAAC,cAAA,KAAA,gBAEA,EAAA,EAAAC,cAAA,KAAA,gBAEA,EAAA,EAAAC,cAAA,KAAA,gB,CACF,EAAA,CAAA,CAAA,EAGA,MAAaC,EAA0D,CAC3C,EAAA,IACA,IAAA,GACA,IAAA,GACA,IAAA,GAC5B,EAGaC,EAAqC,C,aAKlD,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market.js","names":["PRICE_SERIES_TIMEFRAMES","MARKET_PRICE_BATCH_LIMIT"],"sources":["../../../src/types/market.ts"],"sourcesContent":["/**\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"],"mappings":"AAOA,MAAaA,EAA0B,CAAC,KAAM,KAAM,KAAM,KAAM,KAAK,EAMxDC,EAA2B"}
|
|
1
|
+
{"version":3,"file":"market.js","names":["PRICE_SERIES_TIMEFRAMES","MARKET_PRICE_BATCH_LIMIT"],"sources":["../../../src/types/market.ts"],"sourcesContent":["/**\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"],"mappings":"AAOA,MAAaA,EAA0B,CAAC,KAAM,KAAM,KAAM,KAAM,KAAK,EAMxDC,EAA2B,I"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain_contract.js","names":["DEX_CONTRACT_PATH"],"sources":["../../../src/utils/chain_contract.ts"],"sourcesContent":["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"],"mappings":"AAMA,MAAaA,EAAoB,qB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classification.js","names":["DEFAULT_RETRYABLE","classification","options","outcome","NOT_QUEUED_FINAL","notSentClassification"],"sources":["../../../src/utils/classification.ts"],"sourcesContent":["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"],"mappings":"AA0BA,MAAMA,EAAoB,CACxB,SAAU,GACV,QAAS,GACT,WAAY,GACZ,SAAU,GACV,cAAe,GACf,UAAW,EACb,EAuBA,SAAgBC,EACd,EACA,EAA0C,CAAC,EACpB,CACvB,MAAO,CAAE,UAAS,UAAWC,EAAQ,YAAc,IAAgBF,EAAkBG,EAAS,CAChG,CASA,MAAaC,EAAoD,OAAO,OACtEH,EAAe,aAAc,CAAE,UAAW,EAAM,CAAC,CACnD,EAMA,SAAgBI,GAA+C,CAC7D,OAAOJ,EAAe,UAAU,CAClC"}
|
|
1
|
+
{"version":3,"file":"classification.js","names":["DEFAULT_RETRYABLE","classification","options","outcome","NOT_QUEUED_FINAL","notSentClassification"],"sources":["../../../src/utils/classification.ts"],"sourcesContent":["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"],"mappings":"AA0BA,MAAMA,EAAoB,CACxB,SAAU,GACV,QAAS,GACT,WAAY,GACZ,SAAU,GACV,cAAe,GACf,UAAW,EACb,EAuBA,SAAgBC,EACd,EACA,EAA0C,CAAC,EACpB,CACvB,MAAO,CAAE,UAAS,UAAWC,EAAQ,YAAc,IAAgBF,EAAkBG,EAAS,CAChG,CASA,MAAaC,EAAoD,OAAO,OACtEH,EAAe,aAAc,CAAE,UAAW,EAAM,CAAC,CACnD,EAMA,SAAgBI,GAA+C,CAC7D,OAAOJ,EAAe,UAAU,CAClC,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirmation_schedule.js","names":["createConfirmationSchedule","timeoutMs","options","pollIntervalMs","initialDelayMs","defaultInitialDelayMs","signal","deadline","firstRead","attempt","throwIfAborted","abortError","remaining","delay","backoff","waitMs","retryAfterMs","jitter","onAbort","timer","reject","resolve","milliseconds"],"sources":["../../../src/utils/confirmation_schedule.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"],"mappings":"AAsBA,SAAgBA,EACd,EACA,EACA,EACsB,CACtB,IAAMC,EAAY,KAAK,IAAI,EAAGC,GAAS,WAAa,GAAkB,EAChEC,EAAiB,KAAK,IAC1B,IACAD,GAAS,gBAAkB,GAC7B,EACME,EAAiB,KAAK,IAAI,EAAGF,GAAS,gBAAkBG,CAAqB,EAC7EC,EAASJ,GAAS,OAClBK,EAAW,KAAK,IAAI,EAAIN,EAC1BO,EAAY,GACZC,EAAU,EACd,MAAO,CACL,MAAM,YAAY,EAAyC,CAEzD,GADAC,EAAeJ,EAAQK,CAAU,EAC7BH,EAAW,CACb,EAAY,GACZ,IAAMI,EAAY,KAAK,IAAI,EAAGL,EAAW,KAAK,IAAI,CAAC,EAEnD,OADA,MAAMM,EAAM,KAAK,IAAIT,EAAgBQ,CAAS,EAAGN,EAAQK,CAAU,EAC5D,EACT,CACA,IAAMG,EAAU,KAAK,IAAI,IAAgBX,EAAiB,GAAK,KAAK,IAAIM,EAAS,CAAC,CAAC,EACnF,GAAW,EACX,IAAMM,EAASC,IAAiB,IAAA,GAAYC,EAAOH,CAAO,EAAI,KAAK,IAAI,EAAGE,CAAY,EAGtF,OAFI,KAAK,IAAI,EAAID,EAASR,EAAiB,IAC3C,MAAMM,EAAME,EAAQT,EAAQK,CAAU,EAC/B,GACT,CACF,CACF,CAGA,SAAgBD,EACd,EACA,EACM,CACN,GAAIJ,GAAQ,UAAY,GAAM,MAAMK,EAAWL,EAAO,MAAM,CAC9D,CAEA,SAASO,EACP,EACA,EACA,EACe,CAEf,OADIP,GAAQ,UAAY,GAAa,QAAQ,OAAOK,EAAWL,EAAO,MAAM,CAAC,EACtE,IAAI,SAAS,EAAS,IAAW,CACtC,IAAMY,MAAsB,CAC1B,aAAaC,CAAK,EAClBC,EAAOT,EAAWL,GAAQ,MAAM,CAAC,CACnC,EACMa,EAAQ,eAAiB,CAC7Bb,GAAQ,oBAAoB,QAASY,CAAO,EAC5CG,EAAQ,CACV,EAAGC,CAAY,EACfhB,GAAQ,iBAAiB,QAASY,EAAS,CAAE,KAAM,EAAK,CAAC,CAC3D,CAAC,CACH,CAEA,SAASD,EAAO,EAA8B,CAC5C,OAAO,KAAK,IAAI,EAAG,KAAK,MAAMK,GAAgB,GAAM,KAAK,OAAO,EAAI,GAAI,CAAC,CAC3E"}
|
|
1
|
+
{"version":3,"file":"confirmation_schedule.js","names":["createConfirmationSchedule","timeoutMs","options","pollIntervalMs","initialDelayMs","defaultInitialDelayMs","signal","deadline","firstRead","attempt","throwIfAborted","abortError","remaining","delay","backoff","waitMs","retryAfterMs","jitter","onAbort","timer","reject","resolve","milliseconds"],"sources":["../../../src/utils/confirmation_schedule.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"],"mappings":"AAsBA,SAAgBA,EACd,EACA,EACA,EACsB,CACtB,IAAMC,EAAY,KAAK,IAAI,EAAGC,GAAS,WAAa,GAAkB,EAChEC,EAAiB,KAAK,IAC1B,IACAD,GAAS,gBAAkB,GAC7B,EACME,EAAiB,KAAK,IAAI,EAAGF,GAAS,gBAAkBG,CAAqB,EAC7EC,EAASJ,GAAS,OAClBK,EAAW,KAAK,IAAI,EAAIN,EAC1BO,EAAY,GACZC,EAAU,EACd,MAAO,CACL,MAAM,YAAY,EAAyC,CAEzD,GADAC,EAAeJ,EAAQK,CAAU,EAC7BH,EAAW,CACb,EAAY,GACZ,IAAMI,EAAY,KAAK,IAAI,EAAGL,EAAW,KAAK,IAAI,CAAC,EAEnD,OADA,MAAMM,EAAM,KAAK,IAAIT,EAAgBQ,CAAS,EAAGN,EAAQK,CAAU,EAC5D,EACT,CACA,IAAMG,EAAU,KAAK,IAAI,IAAgBX,EAAiB,GAAK,KAAK,IAAIM,EAAS,CAAC,CAAC,EACnF,GAAW,EACX,IAAMM,EAASC,IAAiB,IAAA,GAAYC,EAAOH,CAAO,EAAI,KAAK,IAAI,EAAGE,CAAY,EAGtF,OAFI,KAAK,IAAI,EAAID,EAASR,EAAiB,IAC3C,MAAMM,EAAME,EAAQT,EAAQK,CAAU,EAC/B,GACT,CACF,CACF,CAGA,SAAgBD,EACd,EACA,EACM,CACN,GAAIJ,GAAQ,UAAY,GAAM,MAAMK,EAAWL,EAAO,MAAM,CAC9D,CAEA,SAASO,EACP,EACA,EACA,EACe,CAEf,OADIP,GAAQ,UAAY,GAAa,QAAQ,OAAOK,EAAWL,EAAO,MAAM,CAAC,EACtE,IAAI,SAAS,EAAS,IAAW,CACtC,IAAMY,MAAsB,CAC1B,aAAaC,CAAK,EAClBC,EAAOT,EAAWL,GAAQ,MAAM,CAAC,CACnC,EACMa,EAAQ,eAAiB,CAC7Bb,GAAQ,oBAAoB,QAASY,CAAO,EAC5CG,EAAQ,CACV,EAAGC,CAAY,EACfhB,GAAQ,iBAAiB,QAASY,EAAS,CAAE,KAAM,EAAK,CAAC,CAC3D,CAAC,CACH,CAEA,SAASD,EAAO,EAA8B,CAC5C,OAAO,KAAK,IAAI,EAAG,KAAK,MAAMK,GAAgB,GAAM,KAAK,OAAO,EAAI,GAAI,CAAC,CAC3E,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirmation_state.js","names":["STATE_OF_CODE","confirmationStateOf","code","toFailureView","error","known","isConfirmationAborted","isConfirmationTimeout"],"sources":["../../../src/utils/confirmation_state.ts"],"sourcesContent":["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"],"mappings":"0DAkBA,MAAMA,EAAgB,CACpB,qBAAsB,UACtB,qBAAsB,UACtB,oBAAqB,SACrB,uBAAwB,SACxB,0BAA2B,QAC7B,EAiBA,SAAgBC,EAAoB,EAA+C,CACjF,IAAMC,EAAOC,EAAcC,CAAK,CAAC,EAAE,KACnC,GAAIF,IAAS,IAAA,GACb,OAAO,OAAO,QAAQF,CAAa,CAAC,CAAC,MAAM,CAACK,KAAWA,IAAUH,CAAI,CAAC,GAAG,EAC3E,CAGA,SAAgBI,EAAsB,EAAyB,CAC7D,OAAOL,EAAoBG,CAAK,IAAM,SACxC,CAGA,SAAgBG,EAAsB,EAAyB,CAC7D,OAAON,EAAoBG,CAAK,IAAM,SACxC"}
|
|
1
|
+
{"version":3,"file":"confirmation_state.js","names":["STATE_OF_CODE","confirmationStateOf","code","toFailureView","error","known","isConfirmationAborted","isConfirmationTimeout"],"sources":["../../../src/utils/confirmation_state.ts"],"sourcesContent":["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"],"mappings":"A,0DAkBA,MAAMA,EAAgB,CACpB,qBAAsB,UACtB,qBAAsB,UACtB,oBAAqB,SACrB,uBAAwB,SACxB,0BAA2B,QAC7B,EAiBA,SAAgBC,EAAoB,EAA+C,CACjF,IAAMC,EAAOC,EAAcC,CAAK,CAAC,EAAE,KACnC,GAAIF,IAAS,IAAA,GACb,OAAO,OAAO,QAAQF,CAAa,CAAC,CAAC,MAAM,CAACK,KAAWA,IAAUH,CAAI,CAAC,GAAG,EAC3E,CAGA,SAAgBI,EAAsB,EAAyB,CAC7D,OAAOL,EAAoBG,CAAK,IAAM,SACxC,CAGA,SAAgBG,EAAsB,EAAyB,CAC7D,OAAON,EAAoBG,CAAK,IAAM,SACxC,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.js","names":["debug","debugLog"],"sources":["../../../src/utils/debug.ts"],"sourcesContent":["import debug from 'debug';\n\nexport const debugLog = debug('GSWAP_SDK');\n"],"mappings":"qBAEA,MAAaC,EAAWD,EAAM,WAAW"}
|
|
1
|
+
{"version":3,"file":"debug.js","names":["debug","debugLog"],"sources":["../../../src/utils/debug.ts"],"sourcesContent":["import debug from 'debug';\n\nexport const debugLog = debug('GSWAP_SDK');\n"],"mappings":"A,qBAEA,MAAaC,EAAWD,EAAM,WAAW,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dto_builders.js","names":["BigNumber","decimalString","amount","buildRequestTradeDto","validateFee","input","assertCanonicalPair","assertUniqueKey","dto","exactIn","GSwapSDKError","validateNumericAmount","\"amountOutMinimum\"","exactOut","\"amountInMaximum\"","\"priceLimit\"","assertPoolPosition","assertTickRange","buildAddLiquidityDto","side","onlyOne","buildRemoveLiquidityDto","buildCollectPositionFeesDto","buildCreatePoolDto","symbol","isProposableTradingSymbol","key","assertClassKey","price","parsed","part","first","second","allowNeither","firstName","secondName","invalidDto","rebuildV2Dto","text","value","field","method","integer","optionalText","classKey","name","base","uniqueKey","position","qty","f","tokenInIsToken0","shared","priceLimit","token0Side","token1Side","sqrtPrice","privateAccess","\"privateAccess\"","entry","\"isPrivate\"","assertCanonicalV2Dto","rebuilt"],"sources":["../../../src/utils/dto_builders.ts"],"sourcesContent":["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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dto_builders.js","names":["BigNumber","decimalString","amount","buildRequestTradeDto","validateFee","input","assertCanonicalPair","assertUniqueKey","dto","exactIn","GSwapSDKError","validateNumericAmount","\"amountOutMinimum\"","exactOut","\"amountInMaximum\"","\"priceLimit\"","assertPoolPosition","assertTickRange","buildAddLiquidityDto","side","onlyOne","buildRemoveLiquidityDto","buildCollectPositionFeesDto","buildCreatePoolDto","symbol","isProposableTradingSymbol","key","assertClassKey","price","parsed","part","first","second","allowNeither","firstName","secondName","invalidDto","rebuildV2Dto","text","value","field","method","integer","optionalText","classKey","name","base","uniqueKey","position","qty","f","tokenInIsToken0","shared","priceLimit","token0Side","token1Side","sqrtPrice","privateAccess","\"privateAccess\"","entry","\"isPrivate\"","assertCanonicalV2Dto","rebuilt"],"sources":["../../../src/utils/dto_builders.ts"],"sourcesContent":["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"],"mappings":"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"}
|