@gala-chain/gswap-sdk 2.1.0-beta.3 → 2.1.0-beta.5

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.
@@ -1,2 +1,2 @@
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{buildRequestHeaders as n,createUniqueKey as r,fetchRequestor as i,readResponseBody as a,requestWithTimeout as o,signPreSend as s}from"@gala-chain/gala-core-sdk";const c=[`Swap`,`RequestTrade`,`AddLiquidity`,`RemoveLiquidity`,`CollectPositionFees`,`CreatePool`],l=`DryRun`,u=`galaconnect-operation-`;function d(e){return typeof e==`string`&&c.includes(e)}function f(e,t){return d(t)&&typeof e?.token0==`string`&&typeof e.token1==`string`}function p(e){let t={...e};for(let e of[`signature`,`prefix`,`types`,`domain`,`trace`])delete t[e];return t}function m(e,t,n,i,a=u,o=`asset/dexv3-contract`){return s(e,o,l,{callerPublicKey:t,method:n,dto:i,uniqueKey:r(a)})}var h=class{constructor(t,n){this.signer=n,e(this,`requestor`,void 0),e(this,`baseUrl`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`wire`,void 0),this.requestor=t.httpRequestor??i,this.baseUrl=t.dexBackendBaseUrl.replace(/\/$/u,``),this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.wire=t.wire}async quote(e,r,i,s={}){if(this.signer===void 0)throw t.noSignerError();let c=s.channel??`asset`,l=s.contract??`dexv3-contract`,u=await m(this.signer,e,r,p(i),void 0,`asset/${l}`),d=`${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(c)}/${encodeURIComponent(l)}/${encodeURIComponent(r)}/fee`,f,h,_;try{let e=await o(this.requestor,d,{method:`POST`,headers:n(this.wire,{json:!0,defaults:{Accept:`application/json`}}),body:JSON.stringify(u)},this.requestTimeoutMs);f=e.status,h=e.ok,_=h?await a(e):void 0}catch{return null}return h?g(_):l===`dex-contract`&&(f===403||f===404)?{source:`default`,fees:[{feeInGala:`0`}]}:null}};function g(e){if(typeof e!=`object`||!e)return null;let t=e.fees;return!Array.isArray(t)||typeof t[0]?.feeInGala!=`string`?null:e}export{c as DEX_FEE_METHODS,l as DRY_RUN_METHOD,u as DRY_RUN_UNIQUE_KEY_PREFIX,h as DexFees,m as buildDryRunWrapper,f as isCurrentContractDexMessage,d as isDexFeeMethod,p as toChainDto};
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{buildRequestHeaders as n,createUniqueKey as r,fetchRequestor as i,readResponseBody as a,requestWithTimeout as o,signPreSend as s}from"@gala-chain/gala-core-sdk";const c=[`Swap`,`RequestTrade`,`AddLiquidity`,`RemoveLiquidity`,`CollectPositionFees`,`CreatePool`],l=`DryRun`,u=`galaconnect-operation-`;function d(e){return typeof e==`string`&&c.includes(e)}function f(e,t){return d(t)&&typeof e?.token0==`string`&&typeof e.token1==`string`}function p(e){return e.replace(/(?:\/+|\/api\/v1(?=\/|$))+$/u,``)}function m(e){let t={...e};for(let e of[`signature`,`prefix`,`types`,`domain`,`dtoOperation`,`trace`])delete t[e];return t}function h(e,t,n,i,a=u,o=`asset/dexv3-contract`){return s(e,o,l,{callerPublicKey:t,method:n,dto:m(i),uniqueKey:r(a)})}var g=class{constructor(t,n){this.signer=n,e(this,`requestor`,void 0),e(this,`baseUrl`,void 0),e(this,`requestTimeoutMs`,void 0),e(this,`wire`,void 0),this.requestor=t.httpRequestor??i,this.baseUrl=p(t.dexBackendBaseUrl),this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.wire=t.wire}async quote(e,r,i,s={}){if(this.signer===void 0)throw t.noSignerError();let c=s.channel??`asset`,l=s.contract??`dexv3-contract`,u=await h(this.signer,e,r,m(i),void 0,`asset/${l}`),d=`${this.baseUrl}/api/v1/wallet/connect/galachain/api/${encodeURIComponent(c)}/${encodeURIComponent(l)}/${encodeURIComponent(r)}/fee`,f,p,g;try{let e=await o(this.requestor,d,{method:`POST`,headers:n(this.wire,{json:!0,defaults:{Accept:`application/json`}}),body:JSON.stringify(u)},this.requestTimeoutMs);f=e.status,p=e.ok,g=p?await a(e):void 0}catch{return null}return p?_(g):l===`dex-contract`&&f===403?{source:`default`,fees:[{feeInGala:`0`}]}:null}};function _(e){if(typeof e!=`object`||!e)return null;let t=e.fees;return!Array.isArray(t)||typeof t[0]?.feeInGala!=`string`?null:e}export{c as DEX_FEE_METHODS,l as DRY_RUN_METHOD,u as DRY_RUN_UNIQUE_KEY_PREFIX,g as DexFees,h as buildDryRunWrapper,p as dexBackendRoot,f as isCurrentContractDexMessage,d as isDexFeeMethod,m as toChainDto};
2
2
  //# sourceMappingURL=dex_fees.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dex_fees.js","names":["_defineProperty","DEX_FEE_METHODS","DRY_RUN_METHOD","DRY_RUN_UNIQUE_KEY_PREFIX","isDexFeeMethod","method","isCurrentContractDexMessage","message","\"token0\"","\"token1\"","toChainDto","chainDto","field","buildDryRunWrapper","signPreSend","signer","contractPath","createUniqueKey","uniqueKeyPrefix","DexFees","client","fetchRequestor","GSwapSDKError","channel","options","contract","wrapper","callerPublicKey","url","status","ok","body","response","requestWithTimeout","buildRequestHeaders","readResponseBody","readQuote","fees"],"sources":["../../../src/classes/dex_fees.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n createUniqueKey,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n signPreSend,\n type ChainContractPath,\n type GalaChainSigner,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n contractPath: ChainContractPath = 'asset/dexv3-contract',\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, contractPath, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto,\n // Core's RN-safe mint (`getRandomValues`, never `randomUUID`, which Hermes lacks).\n uniqueKey: createUniqueKey(uniqueKeyPrefix),\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /** Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = client.dexBackendBaseUrl.replace(/\\/$/u, '');\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n undefined,\n `asset/${contract}`,\n );\n const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n if (contract === 'dex-contract' && (status === 403 || status === 404)) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n"],"mappings":"A,oTAeA,MAAaC,EAAkB,CAC7B,OACA,eACA,eACA,kBACA,sBACA,YACF,EAQaC,EAAiB,SAGjBC,EAA4B,yBAGzC,SAAgBC,EAAe,EAAyC,CACtE,OAAO,OAAOC,GAAW,UAAaJ,EAAsC,SAASI,CAAM,CAC7F,CAGA,SAAgBC,EACd,EACA,EACS,CACT,OACEF,EAAeC,CAAM,GACrB,OAAOE,GAAUC,QAAc,UAC/B,OAAOD,EAAQE,QAAc,QAEjC,CAmBA,SAAgBC,EAAW,EAA2D,CACpF,IAAMC,EAAoC,CAAE,GAAGJ,CAAQ,EACvD,IAAK,IAAMK,IAAS,CAAC,YAAa,SAAU,QAAS,SAAU,OAAO,EACpE,OAAOD,EAASC,GAElB,OAAOD,CACT,CASA,SAAgBE,EACd,EACA,EACA,EACA,EACA,EAA0BV,EAC1B,EAAkC,uBACA,CAClC,OAAOW,EAAYC,EAAQC,EAAcd,EAAgB,CACvD,kBACA,SACA,MAEA,UAAWe,EAAgBC,CAAe,CAC5C,CAAC,CACH,CA4CA,IAAaC,EAAb,KAAqB,CAMnB,YACE,EACA,EACA,CADiB,KAAA,OAAAJ,EAPFf,EAAA,KAAA,YAAA,IAAA,EAAA,EACAA,EAAA,KAAA,UAAA,IAAA,EAAA,EACAA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAMf,KAAK,UAAYoB,EAAO,eAAiBC,EACzC,KAAK,QAAUD,EAAO,kBAAkB,QAAQ,OAAQ,EAAE,EAC1D,KAAK,iBAAmBA,EAAO,kBAAoB,IACnD,KAAK,KAAOA,EAAO,IACrB,CAiBA,MAAa,MACX,EACA,EACA,EACA,EAA8B,CAAC,EACF,CAC7B,GAAI,KAAK,SAAW,IAAA,GAAW,MAAME,EAAc,cAAc,EACjE,IAAMC,EAAUC,EAAQ,SAAW,QAC7BC,EAAWD,EAAQ,UAAY,iBAC/BE,EAAU,MAAMb,EACpB,KAAK,OACLc,EACAtB,EACAK,EAAWH,CAAO,EAClB,IAAA,GACA,SAASkB,GACX,EACMG,EAAM,GAAG,KAAK,QAAQ,gCAAgC,mBAAmBL,CAAO,EAAE,GAAG,mBAAmBE,CAAQ,EAAE,GAAG,mBAAmBpB,CAAM,EAAE,MAElJwB,EACAC,EACAC,EACJ,GAAI,CACF,IAAMC,EAAW,MAAMC,EACrB,KAAK,UACLL,EACA,CACE,OAAQ,OACR,QAASM,EAAoB,KAAK,KAAM,CACtC,KAAM,GACN,SAAU,CAAE,OAAQ,kBAAmB,CACzC,CAAC,EACD,KAAM,KAAK,UAAUR,CAAO,CAC9B,EACA,KAAK,gBACP,EACA,EAASM,EAAS,OAClB,EAAKA,EAAS,GACd,EAAOF,EAAK,MAAMK,EAAiBH,CAAQ,EAAI,IAAA,EACjD,MAAQ,CACN,OAAO,IACT,CAUA,OARKF,EAQEM,EAAUL,CAAI,EAPfN,IAAa,iBAAmBI,IAAW,KAAOA,IAAW,KACxD,CAAE,OAAQ,UAAW,KAAM,CAAC,CAAE,UAAW,GAAI,CAAC,CAAE,EAElD,IAKX,CACF,EAEA,SAASO,EAAU,EAAmC,CACpD,GAAI,OAAOL,GAAS,WAAYA,EAAe,OAAO,KACtD,IAAMM,EAAQN,EAA4B,KAO1C,MALE,CAAC,MAAM,QAAQM,CAAI,GACnB,OAAQA,EAAK,EAAE,EAA0C,WAAc,SAEhE,KAEFN,CACT,C"}
1
+ {"version":3,"file":"dex_fees.js","names":["_defineProperty","DEX_FEE_METHODS","DRY_RUN_METHOD","DRY_RUN_UNIQUE_KEY_PREFIX","isDexFeeMethod","method","isCurrentContractDexMessage","message","\"token0\"","\"token1\"","dexBackendRoot","base","toChainDto","chainDto","field","buildDryRunWrapper","signPreSend","signer","contractPath","dto","createUniqueKey","uniqueKeyPrefix","DexFees","client","fetchRequestor","GSwapSDKError","channel","options","contract","wrapper","callerPublicKey","url","status","ok","body","response","requestWithTimeout","buildRequestHeaders","readResponseBody","readQuote","fees"],"sources":["../../../src/classes/dex_fees.ts"],"sourcesContent":["import {\n buildRequestHeaders,\n createUniqueKey,\n fetchRequestor,\n readResponseBody,\n requestWithTimeout,\n signPreSend,\n type ChainContractPath,\n type GalaChainSigner,\n type HttpRequestor,\n type WireOptions,\n} from '@gala-chain/gala-core-sdk';\nimport { GSwapSDKError } from './gswap_sdk_error.js';\n\n/** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */\nexport const DEX_FEE_METHODS = [\n 'Swap',\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n 'CreatePool',\n] as const;\n/** A chain method whose network fee `DexFees.quote` can price (see `isDexFeeMethod`). */\nexport type DexFeeMethod = (typeof DEX_FEE_METHODS)[number];\n\n/** Which pool contract the DTO being quoted targets: legacy (V3) or current (GalaChainDex). */\nexport type DexFeeContract = 'dexv3-contract' | 'dex-contract';\n\n/** The chain method name the signed DryRun wrapper is signed under. */\nexport const DRY_RUN_METHOD = 'DryRun';\n\n/** `uniqueKey` prefix of the DryRun WRAPPER (distinct from the inner DTO's key). */\nexport const DRY_RUN_UNIQUE_KEY_PREFIX = 'galaconnect-operation-';\n\n/** True when `method` is a DEX method a fee can be quoted for. */\nexport function isDexFeeMethod(method: unknown): method is DexFeeMethod {\n return typeof method === 'string' && (DEX_FEE_METHODS as readonly string[]).includes(method);\n}\n\n/** Current-contract typed DEX messages use trading symbols instead of TokenClassKey objects. */\nexport function isCurrentContractDexMessage(\n message: Record<string, unknown> | null | undefined,\n method: unknown,\n): boolean {\n return (\n isDexFeeMethod(method) &&\n typeof message?.['token0'] === 'string' &&\n typeof message['token1'] === 'string'\n );\n}\n\n/**\n * The backend's response. It ALWAYS carries a usable `fees[0].feeInGala`: the backend decides what\n * to serve when the chain cannot price the operation, so the client never invents a fee.\n *\n * `source` is informational: `'dry-run'` is simulated on chain and authoritative (possibly a\n * legitimate `'0'`), `'default'` means the chain could not price it and the platform default was\n * served.\n */\nexport interface DexFeeQuote {\n fees: Array<{ feeInGala: string }>;\n source: 'dry-run' | 'default';\n}\n\n/** The wallet-connect proxy's fee route, below the backend root (stage, 2026-11-02: only this prefix exists). */\nconst FEE_ROUTE_PREFIX = '/api/v1/wallet/connect/galachain/api';\n\n/**\n * The backend root a fee quote is built on: `base` without trailing slashes and without a trailing\n * `/api/v1` (the wallet passes the versioned base, the SDK presets the host root). Idempotent.\n *\n * @example\n * ```typescript\n * dexBackendRoot('https://swap-backend.stage.defi.ovh.gala.com/api/v1/'); // 'https://swap-backend.stage.defi.ovh.gala.com'\n * ```\n */\nexport function dexBackendRoot(base: string): string {\n return base.replace(/(?:\\/+|\\/api\\/v1(?=\\/|$))+$/u, '');\n}\n\n/**\n * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing\n * envelope (`signature`, `prefix`, `types`, `domain`), the `dtoOperation` it was signed to call (a\n * DryRun runs the DTO inside a wrapper signed for `DryRun`; left inside, the chain refuses it:\n * \"signed to call ...:RequestTrade, but the current operation is ...:DryRun\") and transport\n * metadata (`trace`).\n */\nexport function toChainDto(message: Record<string, unknown>): Record<string, unknown> {\n const chainDto: Record<string, unknown> = { ...message };\n for (const field of ['signature', 'prefix', 'types', 'domain', 'dtoOperation', 'trace']) {\n delete chainDto[field];\n }\n return chainDto;\n}\n\n/**\n * Signs the DryRun WRAPPER the gateway accepts for every contract:\n * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO\n * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already\n * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own\n * `uniqueKey`, distinct from the DTO's, and its own `dtoOperation` (`<Contract>:DryRun`); the inner DTO\n * carries none of the signing envelope or the `dtoOperation` of the call it simulates (see\n * {@link toChainDto}), whatever the caller passes, so a signed DTO can be handed in as is.\n */\nexport function buildDryRunWrapper(\n signer: GalaChainSigner,\n callerPublicKey: string,\n method: string,\n dto: Record<string, unknown>,\n uniqueKeyPrefix: string = DRY_RUN_UNIQUE_KEY_PREFIX,\n contractPath: ChainContractPath = 'asset/dexv3-contract',\n): Promise<Record<string, unknown>> {\n return signPreSend(signer, contractPath, DRY_RUN_METHOD, {\n callerPublicKey,\n method,\n dto: toChainDto(dto),\n // Core's RN-safe mint (`getRandomValues`, never `randomUUID`, which Hermes lacks).\n uniqueKey: createUniqueKey(uniqueKeyPrefix),\n });\n}\n\n/** The transport and backend a fee quote reads from. */\nexport interface DexFeesClient {\n /**\n * Swap backend origin, e.g. `https://dex-backend-prod1.defi.gala.com`. A base that already ends in\n * `/api/v1` (what the wallet passes) and trailing slashes are accepted: the request goes to the\n * same URL either way (see {@link dexBackendRoot}).\n */\n dexBackendBaseUrl: string;\n /** Defaults to the global `fetch`. */\n httpRequestor?: HttpRequestor | undefined;\n /** Per-request timeout in milliseconds (default 30 000). */\n requestTimeoutMs?: number | undefined;\n /**\n * Request headers of the fee POST (`userAgent`, `headers`); see {@link WireOptions}. The SDK's\n * `Accept: application/json` is a default that `wire.headers` may replace.\n */\n wire?: WireOptions | undefined;\n}\n\n/** Options for a single quote. */\nexport interface DexFeeQuoteOptions {\n /** GalaChain channel. Default `asset`. */\n channel?: string | undefined;\n /**\n * Contract the DTO targets. Default `dexv3-contract` (what every legacy caller quotes against);\n * a current-contract operation must pass `dex-contract` explicitly.\n */\n contract?: DexFeeContract | undefined;\n}\n\n/**\n * Network-fee quote for GalaChain DEX methods, derived from a server-side DryRun.\n *\n * The client only SIGNS the DryRun wrapper (with whatever {@link GalaChainSigner} it is given) and\n * the backend forwards it to the gateway, where the simulated writes carry the fee; the backend\n * never holds a key. Intended for wallets: the DTO quoted is the typed message a dApp handed over.\n *\n * @example\n * ```ts\n * const fees = new DexFees({ dexBackendBaseUrl }, new PrivateKeySigner(sessionKey));\n * const quote = await fees.quote(publicKey, 'RequestTrade', toChainDto(message), {\n * contract: 'dex-contract',\n * });\n * const feeInGala = quote?.fees[0]?.feeInGala;\n * ```\n */\nexport class DexFees {\n private readonly requestor: HttpRequestor;\n private readonly baseUrl: string;\n private readonly requestTimeoutMs: number;\n private readonly wire: WireOptions | undefined;\n\n constructor(\n client: DexFeesClient,\n private readonly signer: GalaChainSigner | undefined,\n ) {\n this.requestor = client.httpRequestor ?? fetchRequestor;\n this.baseUrl = dexBackendRoot(client.dexBackendBaseUrl);\n this.requestTimeoutMs = client.requestTimeoutMs ?? 30_000;\n this.wire = client.wire;\n }\n\n /**\n * Quotes the network fee for `method` applied to `message`. The message is reduced with\n * {@link toChainDto} first, so an EIP-712 approval message can be passed as is.\n *\n * Resolves `null` when the BACKEND could not be reached or answered unusably (offline, 4xx/5xx,\n * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is\n * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes\n * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered\n * 403 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`. A 404 is\n * a wrong path, not \"no fee route\": it resolves `null`, never a default. The request always goes\n * to `<root>/api/v1/wallet/connect/galachain/api/{channel}/{contract}/{method}/fee`, whether the\n * client's base URL is the host root or already ends in `/api/v1`.\n * Never throws on transport, so a fee lookup cannot block or break a signing screen.\n *\n * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or\n * `KEY_PROVIDER_FAILED` (a pre-send error, the original as `cause`) when the signer fails, for\n * example a locked wallet.\n */\n public async quote(\n callerPublicKey: string,\n method: DexFeeMethod,\n message: Record<string, unknown>,\n options: DexFeeQuoteOptions = {},\n ): Promise<DexFeeQuote | null> {\n if (this.signer === undefined) throw GSwapSDKError.noSignerError();\n const channel = options.channel ?? 'asset';\n const contract = options.contract ?? 'dexv3-contract';\n const wrapper = await buildDryRunWrapper(\n this.signer,\n callerPublicKey,\n method,\n toChainDto(message),\n undefined,\n `asset/${contract}`,\n );\n const url = `${this.baseUrl}${FEE_ROUTE_PREFIX}/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;\n\n let status: number;\n let ok: boolean;\n let body: unknown;\n try {\n const response = await requestWithTimeout(\n this.requestor,\n url,\n {\n method: 'POST',\n headers: buildRequestHeaders(this.wire, {\n json: true,\n defaults: { Accept: 'application/json' },\n }),\n body: JSON.stringify(wrapper),\n },\n this.requestTimeoutMs,\n );\n status = response.status;\n ok = response.ok;\n body = ok ? await readResponseBody(response) : undefined;\n } catch {\n return null;\n }\n\n if (!ok) {\n // 403: the contract has no fee route yet (the route exists, the backend refuses the path). A 404 is\n // NOT that: it is a wrong path (stage, 2026-11-02: the host root answered 404 and every quote became a\n // silent 0), so it resolves null like any other backend failure.\n if (contract === 'dex-contract' && status === 403) {\n return { source: 'default', fees: [{ feeInGala: '0' }] };\n }\n return null;\n }\n // Accept whatever fee the backend served: 'default' is as usable as 'dry-run'. Only a body\n // missing the fee outright is unusable.\n return readQuote(body);\n }\n}\n\nfunction readQuote(body: unknown): DexFeeQuote | null {\n if (typeof body !== 'object' || body === null) return null;\n const fees = (body as { fees?: unknown }).fees;\n if (\n !Array.isArray(fees) ||\n typeof (fees[0] as { feeInGala?: unknown } | undefined)?.feeInGala !== 'string'\n ) {\n return null;\n }\n return body as DexFeeQuote;\n}\n"],"mappings":"A,oTAeA,MAAaC,EAAkB,CAC7B,OACA,eACA,eACA,kBACA,sBACA,YACF,EAQaC,EAAiB,SAGjBC,EAA4B,yBAGzC,SAAgBC,EAAe,EAAyC,CACtE,OAAO,OAAOC,GAAW,UAAaJ,EAAsC,SAASI,CAAM,CAC7F,CAGA,SAAgBC,EACd,EACA,EACS,CACT,OACEF,EAAeC,CAAM,GACrB,OAAOE,GAAUC,QAAc,UAC/B,OAAOD,EAAQE,QAAc,QAEjC,CA2BA,SAAgBC,EAAe,EAAsB,CACnD,OAAOC,EAAK,QAAQ,+BAAgC,EAAE,CACxD,CASA,SAAgBC,EAAW,EAA2D,CACpF,IAAMC,EAAoC,CAAE,GAAGN,CAAQ,EACvD,IAAK,IAAMO,IAAS,CAAC,YAAa,SAAU,QAAS,SAAU,eAAgB,OAAO,EACpF,OAAOD,EAASC,GAElB,OAAOD,CACT,CAWA,SAAgBE,EACd,EACA,EACA,EACA,EACA,EAA0BZ,EAC1B,EAAkC,uBACA,CAClC,OAAOa,EAAYC,EAAQC,EAAchB,EAAgB,CACvD,kBACA,SACA,IAAKU,EAAWO,CAAG,EAEnB,UAAWC,EAAgBC,CAAe,CAC5C,CAAC,CACH,CAgDA,IAAaC,EAAb,KAAqB,CAMnB,YACE,EACA,EACA,CADiB,KAAA,OAAAL,EAPFjB,EAAA,KAAA,YAAA,IAAA,EAAA,EACAA,EAAA,KAAA,UAAA,IAAA,EAAA,EACAA,EAAA,KAAA,mBAAA,IAAA,EAAA,EACAA,EAAA,KAAA,OAAA,IAAA,EAAA,EAMf,KAAK,UAAYuB,EAAO,eAAiBC,EACzC,KAAK,QAAUd,EAAea,EAAO,iBAAiB,EACtD,KAAK,iBAAmBA,EAAO,kBAAoB,IACnD,KAAK,KAAOA,EAAO,IACrB,CAoBA,MAAa,MACX,EACA,EACA,EACA,EAA8B,CAAC,EACF,CAC7B,GAAI,KAAK,SAAW,IAAA,GAAW,MAAME,EAAc,cAAc,EACjE,IAAMC,EAAUC,EAAQ,SAAW,QAC7BC,EAAWD,EAAQ,UAAY,iBAC/BE,EAAU,MAAMd,EACpB,KAAK,OACLe,EACAzB,EACAO,EAAWL,CAAO,EAClB,IAAA,GACA,SAASqB,GACX,EACMG,EAAM,GAAG,KAAK,+CAA8B,mBAAmBL,CAAO,EAAE,GAAG,mBAAmBE,CAAQ,EAAE,GAAG,mBAAmBvB,CAAM,EAAE,MAExI2B,EACAC,EACAC,EACJ,GAAI,CACF,IAAMC,EAAW,MAAMC,EACrB,KAAK,UACLL,EACA,CACE,OAAQ,OACR,QAASM,EAAoB,KAAK,KAAM,CACtC,KAAM,GACN,SAAU,CAAE,OAAQ,kBAAmB,CACzC,CAAC,EACD,KAAM,KAAK,UAAUR,CAAO,CAC9B,EACA,KAAK,gBACP,EACA,EAASM,EAAS,OAClB,EAAKA,EAAS,GACd,EAAOF,EAAK,MAAMK,EAAiBH,CAAQ,EAAI,IAAA,EACjD,MAAQ,CACN,OAAO,IACT,CAaA,OAXKF,EAWEM,EAAUL,CAAI,EAPfN,IAAa,gBAAkBI,IAAW,IACrC,CAAE,OAAQ,UAAW,KAAM,CAAC,CAAE,UAAW,GAAI,CAAC,CAAE,EAElD,IAKX,CACF,EAEA,SAASO,EAAU,EAAmC,CACpD,GAAI,OAAOL,GAAS,WAAYA,EAAe,OAAO,KACtD,IAAMM,EAAQN,EAA4B,KAO1C,MALE,CAAC,MAAM,QAAQM,CAAI,GACnB,OAAQA,EAAK,EAAE,EAA0C,WAAc,SAEhE,KAEFN,CACT,C"}
@@ -1 +1 @@
1
- import{GSWAP_ERROR_CATALOG as e,SUBMISSION_OUTCOME_UNKNOWN_REASONS as t,gswapErrorTemplates as n}from"./classes/gswap_error_catalog.js";import{GSWAP_ERROR_PHASE_BY_CODE as r}from"./classes/gswap_error_phase_table.js";import{GSwapSDKError as i,UPDATE_REQUIRED_STATUS as a,getObjectProperty as o,getStringProperty as s,isGSwapError as c,isPreSendError as l}from"./classes/gswap_sdk_error.js";import{AppliedTradeError as u,confirmAppliedTrade as d}from"./classes/apply_results.js";import{ALL_FEE_TIERS as f,FEE_TIER as p,TICK_SPACING_BY_FEE as m}from"./types/fees.js";import{isTickInRange as h}from"./utils/tick_range.js";import{GC_MAX_TICK as g,GC_MIN_TICK as _,isSqrtPriceInRange as v,sqrtPriceToTick as y,tickFromPrice as b,tickToPrice as x,tickToSqrtPrice as S}from"./utils/tick_math.js";import{assertCanonicalPair as C,isProposableTradingSymbol as w,requireUserRef as T,userRef as E,validateFee as D,validateNumericAmount as O,validatePriceValues as k,validateTickRange as A,validateTickSpacing as j,validateTokenDecimals as M}from"./utils/validation.js";import{Assets as N}from"./classes/assets.js";import{DEX_FEE_METHODS as P,DRY_RUN_METHOD as F,DRY_RUN_UNIQUE_KEY_PREFIX as I,DexFees as L,buildDryRunWrapper as R,isCurrentContractDexMessage as z,isDexFeeMethod as B,toChainDto as V}from"./classes/dex_fees.js";import{isShadowError as H}from"./utils/shadow_errors.js";import{SubmittedTransaction as U}from"./classes/submitted_transaction.js";import{ChainGateway as W}from"./classes/gateway.js";import{GSWAP_ENVIRONMENTS as G}from"./types/env.js";import{GdexStreamError as K,GdexStreamService as q,isGdexLiquidityEvent as J}from"./classes/gdex_stream.js";import{Leaderboard as Y}from"./classes/leaderboard.js";import{MARKET_PRICE_BATCH_LIMIT as X,PRICE_SERIES_TIMEFRAMES as Z}from"./types/market.js";import{MARKET_PRICE_QUERY_BYTES as Q,Market as $,priceBatches as ee}from"./classes/market.js";import{ONRAMPER_MODES as te,Onramper as ne,createOnramper as re}from"./classes/onramper.js";import{orderSymbols as ie,parseTokenClassKey as ae,readOrderedSymbols as oe}from"./utils/ordering.js";import{CanonicalSymbols as se,Symbols as ce,queryTokenOf as le,rawTokenOf as ue,tradingSymbolOf as de}from"./classes/symbols.js";import{Pools as fe}from"./classes/pools.js";import{alignTickDownOrNaN as pe,alignTickUpOrNaN as me}from"./utils/tick_align.js";import{alignTickDown as he,alignTickUp as ge,assertTickRange as _e,frameSlot0 as ve}from"./utils/ticks.js";import{assertCanonicalV2Dto as ye,buildAddLiquidityDto as be,buildCollectPositionFeesDto as xe,buildCreatePoolDto as Se,buildRemoveLiquidityDto as Ce,buildRequestTradeDto as we}from"./utils/dto_builders.js";import{Positions as Te}from"./classes/positions.js";import{Quoting as Ee}from"./classes/quoting.js";import{SHADOW_FAILURE_KINDS as De,SHADOW_SUBMIT_CODES as Oe,classifyShadowSubmitError as ke,classifyShadowSubmitStatus as Ae,readShadowSubmitOutcome as je}from"./classes/shadow_submit.js";import{Swaps as Me,swapRouteFromQuote as Ne}from"./classes/swaps.js";import{GSwap as Pe}from"./classes/gswap.js";import{NOT_QUEUED_FINAL as Fe,classification as Ie,notSentClassification as Le}from"./utils/classification.js";import{classifyFailure as Re,mayHaveBeenQueued as ze}from"./utils/failure_classification.js";import{PENDING_SWAP_FATES as Be,pendingSwapFateFor as Ve,pendingSwapFateOfOutcome as He}from"./classes/pending_swap_fate.js";import{PENDING_SWAPS_STORAGE_KEY as Ue,PENDING_SWAP_EXPIRY_MS as We,PENDING_SWAP_PRUNE_REASONS as Ge,PendingSwapStore as Ke}from"./classes/pending_swaps.js";import{storageAdapterFromChromeStorage as qe,webStorageAdapter as Je}from"./classes/storage_adapters.js";import{confirmationStateOf as Ye,isConfirmationAborted as Xe,isConfirmationTimeout as Ze}from"./utils/confirmation_state.js";import{chainErrorKeyOf as Qe,isNoMarket as $e,isRelayableRefusal as et,isUninterpretedAnswer as tt,isUniqueKeyConsumed as nt,isUnprovenAcknowledgement as rt}from"./utils/failure_guards.js";import{classifySubmitEnvelope as it,isSubmitExecuted as at,isSubmitQueued as ot,isSubmitRejected as st}from"./utils/submit_state.js";export{f as ALL_FEE_TIERS,u as AppliedTradeError,N as Assets,se as CanonicalSymbols,W as ChainGateway,P as DEX_FEE_METHODS,F as DRY_RUN_METHOD,I as DRY_RUN_UNIQUE_KEY_PREFIX,L as DexFees,p as FEE_TIER,g as GC_MAX_TICK,_ as GC_MIN_TICK,G as GSWAP_ENVIRONMENTS,e as GSWAP_ERROR_CATALOG,r as GSWAP_ERROR_PHASE_BY_CODE,Pe as GSwap,i as GSwapSDKError,K as GdexStreamError,q as GdexStreamService,Y as Leaderboard,X as MARKET_PRICE_BATCH_LIMIT,Q as MARKET_PRICE_QUERY_BYTES,$ as Market,Fe as NOT_QUEUED_FINAL,te as ONRAMPER_MODES,ne as Onramper,Ue as PENDING_SWAPS_STORAGE_KEY,We as PENDING_SWAP_EXPIRY_MS,Be as PENDING_SWAP_FATES,Ge as PENDING_SWAP_PRUNE_REASONS,Z as PRICE_SERIES_TIMEFRAMES,Ke as PendingSwapStore,fe as Pools,Te as Positions,Ee as Quoting,De as SHADOW_FAILURE_KINDS,Oe as SHADOW_SUBMIT_CODES,t as SUBMISSION_OUTCOME_UNKNOWN_REASONS,U as SubmittedTransaction,Me as Swaps,ce as Symbols,m as TICK_SPACING_BY_FEE,a as UPDATE_REQUIRED_STATUS,he as alignTickDown,pe as alignTickDownOrNaN,ge as alignTickUp,me as alignTickUpOrNaN,C as assertCanonicalPair,ye as assertCanonicalV2Dto,_e as assertTickRange,be as buildAddLiquidityDto,xe as buildCollectPositionFeesDto,Se as buildCreatePoolDto,R as buildDryRunWrapper,Ce as buildRemoveLiquidityDto,we as buildRequestTradeDto,Qe as chainErrorKeyOf,Ie as classification,Re as classifyFailure,ke as classifyShadowSubmitError,Ae as classifyShadowSubmitStatus,it as classifySubmitEnvelope,d as confirmAppliedTrade,Ye as confirmationStateOf,re as createOnramper,ve as frameSlot0,o as getObjectProperty,s as getStringProperty,n as gswapErrorTemplates,Xe as isConfirmationAborted,Ze as isConfirmationTimeout,z as isCurrentContractDexMessage,B as isDexFeeMethod,c as isGSwapError,J as isGdexLiquidityEvent,$e as isNoMarket,l as isPreSendError,w as isProposableTradingSymbol,et as isRelayableRefusal,H as isShadowError,v as isSqrtPriceInRange,at as isSubmitExecuted,ot as isSubmitQueued,st as isSubmitRejected,h as isTickInRange,tt as isUninterpretedAnswer,nt as isUniqueKeyConsumed,rt as isUnprovenAcknowledgement,ze as mayHaveBeenQueued,Le as notSentClassification,ie as orderSymbols,ae as parseTokenClassKey,Ve as pendingSwapFateFor,He as pendingSwapFateOfOutcome,ee as priceBatches,le as queryTokenOf,ue as rawTokenOf,oe as readOrderedSymbols,je as readShadowSubmitOutcome,T as requireUserRef,y as sqrtPriceToTick,qe as storageAdapterFromChromeStorage,Ne as swapRouteFromQuote,b as tickFromPrice,x as tickToPrice,S as tickToSqrtPrice,V as toChainDto,de as tradingSymbolOf,E as userRef,D as validateFee,O as validateNumericAmount,k as validatePriceValues,A as validateTickRange,j as validateTickSpacing,M as validateTokenDecimals,Je as webStorageAdapter};
1
+ import{GSWAP_ERROR_CATALOG as e,SUBMISSION_OUTCOME_UNKNOWN_REASONS as t,gswapErrorTemplates as n}from"./classes/gswap_error_catalog.js";import{GSWAP_ERROR_PHASE_BY_CODE as r}from"./classes/gswap_error_phase_table.js";import{GSwapSDKError as i,UPDATE_REQUIRED_STATUS as a,getObjectProperty as o,getStringProperty as s,isGSwapError as c,isPreSendError as l}from"./classes/gswap_sdk_error.js";import{AppliedTradeError as u,confirmAppliedTrade as d}from"./classes/apply_results.js";import{ALL_FEE_TIERS as f,FEE_TIER as p,TICK_SPACING_BY_FEE as m}from"./types/fees.js";import{isTickInRange as h}from"./utils/tick_range.js";import{GC_MAX_TICK as g,GC_MIN_TICK as _,isSqrtPriceInRange as v,sqrtPriceToTick as y,tickFromPrice as b,tickToPrice as x,tickToSqrtPrice as S}from"./utils/tick_math.js";import{assertCanonicalPair as C,isProposableTradingSymbol as w,requireUserRef as T,userRef as E,validateFee as D,validateNumericAmount as O,validatePriceValues as k,validateTickRange as A,validateTickSpacing as j,validateTokenDecimals as M}from"./utils/validation.js";import{Assets as N}from"./classes/assets.js";import{DEX_FEE_METHODS as P,DRY_RUN_METHOD as F,DRY_RUN_UNIQUE_KEY_PREFIX as I,DexFees as L,buildDryRunWrapper as R,dexBackendRoot as z,isCurrentContractDexMessage as B,isDexFeeMethod as V,toChainDto as H}from"./classes/dex_fees.js";import{isShadowError as U}from"./utils/shadow_errors.js";import{SubmittedTransaction as W}from"./classes/submitted_transaction.js";import{ChainGateway as G}from"./classes/gateway.js";import{GSWAP_ENVIRONMENTS as K}from"./types/env.js";import{GdexStreamError as q,GdexStreamService as J,isGdexLiquidityEvent as Y}from"./classes/gdex_stream.js";import{Leaderboard as X}from"./classes/leaderboard.js";import{MARKET_PRICE_BATCH_LIMIT as Z,PRICE_SERIES_TIMEFRAMES as Q}from"./types/market.js";import{MARKET_PRICE_QUERY_BYTES as $,Market as ee,priceBatches as te}from"./classes/market.js";import{ONRAMPER_MODES as ne,Onramper as re,createOnramper as ie}from"./classes/onramper.js";import{orderSymbols as ae,parseTokenClassKey as oe,readOrderedSymbols as se}from"./utils/ordering.js";import{CanonicalSymbols as ce,Symbols as le,queryTokenOf as ue,rawTokenOf as de,tradingSymbolOf as fe}from"./classes/symbols.js";import{Pools as pe}from"./classes/pools.js";import{alignTickDownOrNaN as me,alignTickUpOrNaN as he}from"./utils/tick_align.js";import{alignTickDown as ge,alignTickUp as _e,assertTickRange as ve,frameSlot0 as ye}from"./utils/ticks.js";import{assertCanonicalV2Dto as be,buildAddLiquidityDto as xe,buildCollectPositionFeesDto as Se,buildCreatePoolDto as Ce,buildRemoveLiquidityDto as we,buildRequestTradeDto as Te}from"./utils/dto_builders.js";import{Positions as Ee}from"./classes/positions.js";import{Quoting as De}from"./classes/quoting.js";import{SHADOW_FAILURE_KINDS as Oe,SHADOW_SUBMIT_CODES as ke,classifyShadowSubmitError as Ae,classifyShadowSubmitStatus as je,readShadowSubmitOutcome as Me}from"./classes/shadow_submit.js";import{Swaps as Ne,swapRouteFromQuote as Pe}from"./classes/swaps.js";import{GSwap as Fe}from"./classes/gswap.js";import{NOT_QUEUED_FINAL as Ie,classification as Le,notSentClassification as Re}from"./utils/classification.js";import{classifyFailure as ze,mayHaveBeenQueued as Be}from"./utils/failure_classification.js";import{PENDING_SWAP_FATES as Ve,pendingSwapFateFor as He,pendingSwapFateOfOutcome as Ue}from"./classes/pending_swap_fate.js";import{PENDING_SWAPS_STORAGE_KEY as We,PENDING_SWAP_EXPIRY_MS as Ge,PENDING_SWAP_PRUNE_REASONS as Ke,PendingSwapStore as qe}from"./classes/pending_swaps.js";import{storageAdapterFromChromeStorage as Je,webStorageAdapter as Ye}from"./classes/storage_adapters.js";import{confirmationStateOf as Xe,isConfirmationAborted as Ze,isConfirmationTimeout as Qe}from"./utils/confirmation_state.js";import{chainErrorKeyOf as $e,isNoMarket as et,isRelayableRefusal as tt,isUninterpretedAnswer as nt,isUniqueKeyConsumed as rt,isUnprovenAcknowledgement as it}from"./utils/failure_guards.js";import{classifySubmitEnvelope as at,isSubmitExecuted as ot,isSubmitQueued as st,isSubmitRejected as ct}from"./utils/submit_state.js";export{f as ALL_FEE_TIERS,u as AppliedTradeError,N as Assets,ce as CanonicalSymbols,G as ChainGateway,P as DEX_FEE_METHODS,F as DRY_RUN_METHOD,I as DRY_RUN_UNIQUE_KEY_PREFIX,L as DexFees,p as FEE_TIER,g as GC_MAX_TICK,_ as GC_MIN_TICK,K as GSWAP_ENVIRONMENTS,e as GSWAP_ERROR_CATALOG,r as GSWAP_ERROR_PHASE_BY_CODE,Fe as GSwap,i as GSwapSDKError,q as GdexStreamError,J as GdexStreamService,X as Leaderboard,Z as MARKET_PRICE_BATCH_LIMIT,$ as MARKET_PRICE_QUERY_BYTES,ee as Market,Ie as NOT_QUEUED_FINAL,ne as ONRAMPER_MODES,re as Onramper,We as PENDING_SWAPS_STORAGE_KEY,Ge as PENDING_SWAP_EXPIRY_MS,Ve as PENDING_SWAP_FATES,Ke as PENDING_SWAP_PRUNE_REASONS,Q as PRICE_SERIES_TIMEFRAMES,qe as PendingSwapStore,pe as Pools,Ee as Positions,De as Quoting,Oe as SHADOW_FAILURE_KINDS,ke as SHADOW_SUBMIT_CODES,t as SUBMISSION_OUTCOME_UNKNOWN_REASONS,W as SubmittedTransaction,Ne as Swaps,le as Symbols,m as TICK_SPACING_BY_FEE,a as UPDATE_REQUIRED_STATUS,ge as alignTickDown,me as alignTickDownOrNaN,_e as alignTickUp,he as alignTickUpOrNaN,C as assertCanonicalPair,be as assertCanonicalV2Dto,ve as assertTickRange,xe as buildAddLiquidityDto,Se as buildCollectPositionFeesDto,Ce as buildCreatePoolDto,R as buildDryRunWrapper,we as buildRemoveLiquidityDto,Te as buildRequestTradeDto,$e as chainErrorKeyOf,Le as classification,ze as classifyFailure,Ae as classifyShadowSubmitError,je as classifyShadowSubmitStatus,at as classifySubmitEnvelope,d as confirmAppliedTrade,Xe as confirmationStateOf,ie as createOnramper,z as dexBackendRoot,ye as frameSlot0,o as getObjectProperty,s as getStringProperty,n as gswapErrorTemplates,Ze as isConfirmationAborted,Qe as isConfirmationTimeout,B as isCurrentContractDexMessage,V as isDexFeeMethod,c as isGSwapError,Y as isGdexLiquidityEvent,et as isNoMarket,l as isPreSendError,w as isProposableTradingSymbol,tt as isRelayableRefusal,U as isShadowError,v as isSqrtPriceInRange,ot as isSubmitExecuted,st as isSubmitQueued,ct as isSubmitRejected,h as isTickInRange,nt as isUninterpretedAnswer,rt as isUniqueKeyConsumed,it as isUnprovenAcknowledgement,Be as mayHaveBeenQueued,Re as notSentClassification,ae as orderSymbols,oe as parseTokenClassKey,He as pendingSwapFateFor,Ue as pendingSwapFateOfOutcome,te as priceBatches,ue as queryTokenOf,de as rawTokenOf,se as readOrderedSymbols,Me as readShadowSubmitOutcome,T as requireUserRef,y as sqrtPriceToTick,Je as storageAdapterFromChromeStorage,Pe as swapRouteFromQuote,b as tickFromPrice,x as tickToPrice,S as tickToSqrtPrice,H as toChainDto,fe as tradingSymbolOf,E as userRef,D as validateFee,O as validateNumericAmount,k as validatePriceValues,A as validateTickRange,j as validateTickSpacing,M as validateTokenDecimals,Ye as webStorageAdapter};
package/dist/index.cjs CHANGED
@@ -1730,9 +1730,26 @@ function isDexFeeMethod(method) {
1730
1730
  function isCurrentContractDexMessage(message, method) {
1731
1731
  return isDexFeeMethod(method) && typeof (message === null || message === void 0 ? void 0 : message["token0"]) === "string" && typeof message["token1"] === "string";
1732
1732
  }
1733
+ /** The wallet-connect proxy's fee route, below the backend root (stage, 2026-11-02: only this prefix exists). */
1734
+ const FEE_ROUTE_PREFIX = "/api/v1/wallet/connect/galachain/api";
1735
+ /**
1736
+ * The backend root a fee quote is built on: `base` without trailing slashes and without a trailing
1737
+ * `/api/v1` (the wallet passes the versioned base, the SDK presets the host root). Idempotent.
1738
+ *
1739
+ * @example
1740
+ * ```typescript
1741
+ * dexBackendRoot('https://swap-backend.stage.defi.ovh.gala.com/api/v1/'); // 'https://swap-backend.stage.defi.ovh.gala.com'
1742
+ * ```
1743
+ */
1744
+ function dexBackendRoot(base) {
1745
+ return base.replace(/(?:\/+|\/api\/v1(?=\/|$))+$/u, "");
1746
+ }
1733
1747
  /**
1734
1748
  * Reduces an EIP-712 approval `message` to the DTO the chain actually receives: drops the signing
1735
- * envelope (`signature`, `prefix`, `types`, `domain`) and transport metadata (`trace`).
1749
+ * envelope (`signature`, `prefix`, `types`, `domain`), the `dtoOperation` it was signed to call (a
1750
+ * DryRun runs the DTO inside a wrapper signed for `DryRun`; left inside, the chain refuses it:
1751
+ * "signed to call ...:RequestTrade, but the current operation is ...:DryRun") and transport
1752
+ * metadata (`trace`).
1736
1753
  */
1737
1754
  function toChainDto(message) {
1738
1755
  const chainDto = { ...message };
@@ -1741,6 +1758,7 @@ function toChainDto(message) {
1741
1758
  "prefix",
1742
1759
  "types",
1743
1760
  "domain",
1761
+ "dtoOperation",
1744
1762
  "trace"
1745
1763
  ]) delete chainDto[field];
1746
1764
  return chainDto;
@@ -1750,13 +1768,15 @@ function toChainDto(message) {
1750
1768
  * `{ callerPublicKey, method, dto: <inner DTO object>, uniqueKey, signature }`. The inner DTO
1751
1769
  * travels unsigned and as an object; no `signerPublicKey` is sent because the signature already
1752
1770
  * recovers it (the gateway rejects it as REDUNDANT_SIGNER_PUBLIC_KEY). The wrapper carries its own
1753
- * `uniqueKey`, distinct from the DTO's.
1771
+ * `uniqueKey`, distinct from the DTO's, and its own `dtoOperation` (`<Contract>:DryRun`); the inner DTO
1772
+ * carries none of the signing envelope or the `dtoOperation` of the call it simulates (see
1773
+ * {@link toChainDto}), whatever the caller passes, so a signed DTO can be handed in as is.
1754
1774
  */
1755
1775
  function buildDryRunWrapper(signer, callerPublicKey, method, dto, uniqueKeyPrefix = DRY_RUN_UNIQUE_KEY_PREFIX, contractPath = "asset/dexv3-contract") {
1756
1776
  return (0, _gala_chain_gala_core_sdk.signPreSend)(signer, contractPath, DRY_RUN_METHOD, {
1757
1777
  callerPublicKey,
1758
1778
  method,
1759
- dto,
1779
+ dto: toChainDto(dto),
1760
1780
  uniqueKey: (0, _gala_chain_gala_core_sdk.createUniqueKey)(uniqueKeyPrefix)
1761
1781
  });
1762
1782
  }
@@ -1785,7 +1805,7 @@ var DexFees = class {
1785
1805
  constructor(client, signer) {
1786
1806
  this.signer = signer;
1787
1807
  this.requestor = client.httpRequestor ?? _gala_chain_gala_core_sdk.fetchRequestor;
1788
- this.baseUrl = client.dexBackendBaseUrl.replace(/\/$/u, "");
1808
+ this.baseUrl = dexBackendRoot(client.dexBackendBaseUrl);
1789
1809
  this.requestTimeoutMs = client.requestTimeoutMs ?? 3e4;
1790
1810
  this.wire = client.wire;
1791
1811
  }
@@ -1797,7 +1817,10 @@ var DexFees = class {
1797
1817
  * malformed body): a transport outcome, not a fee. Deciding what to charge when the chain is
1798
1818
  * silent is the backend's job (it serves `source: 'default'`), so the client never substitutes
1799
1819
  * a fee of its own, with ONE exception that mirrors the wallet: a `dex-contract` quote answered
1800
- * 403 or 404 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`.
1820
+ * 403 means the contract has no fee route yet and resolves `{ source: 'default', '0' }`. A 404 is
1821
+ * a wrong path, not "no fee route": it resolves `null`, never a default. The request always goes
1822
+ * to `<root>/api/v1/wallet/connect/galachain/api/{channel}/{contract}/{method}/fee`, whether the
1823
+ * client's base URL is the host root or already ends in `/api/v1`.
1801
1824
  * Never throws on transport, so a fee lookup cannot block or break a signing screen.
1802
1825
  *
1803
1826
  * @throws GSwapSDKError NO_SIGNER when constructed without a signer; `SIGNING_FAILED` or
@@ -1809,7 +1832,7 @@ var DexFees = class {
1809
1832
  const channel = options.channel ?? "asset";
1810
1833
  const contract = options.contract ?? "dexv3-contract";
1811
1834
  const wrapper = await buildDryRunWrapper(this.signer, callerPublicKey, method, toChainDto(message), void 0, `asset/${contract}`);
1812
- const url = `${this.baseUrl}/wallet/connect/galachain/api/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;
1835
+ const url = `${this.baseUrl}${FEE_ROUTE_PREFIX}/${encodeURIComponent(channel)}/${encodeURIComponent(contract)}/${encodeURIComponent(method)}/fee`;
1813
1836
  let status;
1814
1837
  let ok;
1815
1838
  let body;
@@ -1829,7 +1852,7 @@ var DexFees = class {
1829
1852
  return null;
1830
1853
  }
1831
1854
  if (!ok) {
1832
- if (contract === "dex-contract" && (status === 403 || status === 404)) return {
1855
+ if (contract === "dex-contract" && status === 403) return {
1833
1856
  source: "default",
1834
1857
  fees: [{ feeInGala: "0" }]
1835
1858
  };
@@ -6763,6 +6786,7 @@ exports.classifySubmitEnvelope = classifySubmitEnvelope;
6763
6786
  exports.confirmAppliedTrade = confirmAppliedTrade;
6764
6787
  exports.confirmationStateOf = confirmationStateOf;
6765
6788
  exports.createOnramper = createOnramper;
6789
+ exports.dexBackendRoot = dexBackendRoot;
6766
6790
  exports.frameSlot0 = frameSlot0;
6767
6791
  exports.getObjectProperty = getObjectProperty;
6768
6792
  exports.getStringProperty = getStringProperty;