@gala-chain/gswap-sdk 1.2.0-rc.9 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"eip712.js","names":[],"sources":["../../../src/utils/eip712.ts"],"sourcesContent":["/**\n * Genuine EIP-712 typed-data signing for the four v2 dex-contract operations proven (2026-09-16,\n * live bisection against stage — see defi-backend's `chain-findings-artifact` memory /\n * https://claude.ai/artifact/3N9MevSjoQdU7gqnVB3dfU) to recover the `client|` identity correctly\n * via `eth_signTypedData_v4`, unlike `personal_sign` (which only ever resolves the bare `eth|`\n * form — see `BrowserWalletSigner`'s own doc comment). Mirrors frontend_v2's\n * `src/Services/eip712Types.ts` + `readWriteUtilsV2.ts`'s `EIP712_FIELD_COMPLETERS` exactly —\n * ported here rather than shared as a package because gswap-sdk has no frontend_v2 dependency\n * and should not gain one for four small functions.\n */\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\nexport type EIP712Types = Record<string, Array<{ name: string; type: string }>>;\n\n/**\n * Derives the EIP-712 `types` for a DTO from its runtime shape.\n *\n * The generated `types` travel with the signed payload and are what BOTH sides hash, so they\n * must enumerate EVERY field the chain-side DTO will carry. GalaChain refuses any signature\n * whose `types` leave a DTO field uncovered (`assertNoUnsignedFields`, the fix for the\n * 2026-08-18 unsigned-field-injection drain); when that happens signature recovery fails\n * outright and the chain reports \"Missing signerPublicKey or signerAddress field in dto\".\n */\nexport function generateEIP712Types(\n typeName: string,\n params: Record<string, unknown>,\n): EIP712Types {\n const types: EIP712Types = {};\n types[typeName] = [];\n\n // Every `name` this is ever called with (the top-level `typeName`, or a nested struct's own\n // name) is unconditionally assigned `types[name] = []` on the line immediately before any\n // recursive call that could reach here; TypeScript still types `types[name]` as\n // possibly-undefined (index-signature access), so the guard below stays for real type safety\n // even though no current call path can actually trigger it.\n function fieldsFor(name: string): Array<{ name: string; type: string }> {\n const fields = types[name];\n /* c8 ignore next */\n if (!fields) throw new Error(`Missing EIP-712 type definition for ${name}`);\n return fields;\n }\n\n function addField(\n name: string,\n fieldValue: unknown,\n parentTypeName: string,\n onlyGetType = false,\n ): string | undefined {\n if (Array.isArray(fieldValue)) {\n const type =\n fieldValue.length > 0 ? addField(name, fieldValue[0], parentTypeName, true) : 'string';\n if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: (type ?? name) + '[]' });\n } else if (typeof fieldValue === 'object' && fieldValue !== null) {\n if (types[name]) {\n throw new GSwapSDKError('EIP712_NAME_COLLISION', { name });\n }\n types[name] = [];\n Object.entries(fieldValue).forEach(([key, value]) => {\n addField(key, value, name);\n });\n if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: name });\n } else {\n let eipType: string;\n switch (typeof fieldValue) {\n case 'string':\n eipType = 'string';\n break;\n case 'number':\n eipType = 'int256';\n break;\n case 'boolean':\n eipType = 'bool';\n break;\n case 'bigint':\n case 'symbol':\n case 'undefined':\n case 'function':\n case 'object':\n throw new GSwapSDKError('EIP712_UNSUPPORTED_VALUE', { valueType: typeof fieldValue });\n }\n if (onlyGetType) {\n return eipType;\n }\n fieldsFor(parentTypeName).push({ name, type: eipType });\n }\n return undefined;\n }\n\n Object.entries(params).forEach(([key, value]) => {\n addField(key, value, typeName);\n });\n\n return types;\n}\n\n/** The EIP-712 domain carried by a signed payload: GalaChain only uses `name` and `chainId`. */\nexport interface EIP712DomainValue {\n name: string;\n chainId: number;\n}\n\n/**\n * Builds the EIP-712 domain from the wallet's LIVE `eth_chainId` result, exactly like frontend_v2\n * (DEFI-1895): a wallet hashes whatever domain it is handed, and MetaMask refuses a `chainId` that\n * differs from its active network, so a hardcoded `1` breaks every wallet that is not on Mainnet.\n * defi-backend recovers the signer from the `domain` the payload carries (live-proven for chain\n * ids 1, 56 and 11155111), so following the wallet is correct on every network.\n *\n * @param chainId - The raw `eth_chainId` result: a `0x` hex string (the JSON-RPC form) or an integer.\n * @throws GSwapSDKError (`INVALID_CHAIN_ID`) when the wallet answers with anything else.\n */\nexport function eip712DomainFor(chainId: unknown): EIP712DomainValue {\n const parsed =\n typeof chainId === 'string' && /^0x[0-9a-fA-F]+$/u.test(chainId)\n ? Number(chainId)\n : typeof chainId === 'number'\n ? chainId\n : Number.NaN;\n if (!Number.isSafeInteger(parsed) || parsed <= 0) {\n throw new GSwapSDKError('INVALID_CHAIN_ID', {\n chainId:\n typeof chainId === 'string' || typeof chainId === 'number'\n ? String(chainId)\n : typeof chainId,\n });\n }\n return { name: 'ethereum', chainId: parsed };\n}\n\n/**\n * The four v2 operations proven to recover the signer correctly via genuine EIP-712: `RequestTrade`\n * never had the problem (one numeric field). `AddLiquidity`/`RemoveLiquidity`/\n * `CollectPositionFees` each need their `types` completed with a handful of fields their real\n * server-side DTO always carries — see the `complete*Fields` functions below. `CreatePool` is a\n * genuinely different, unsolved problem (nested `TokenClassKey` structs, not a flat\n * missing-field gap) and is NOT in this set — callers must keep using `personal-sign` for it.\n */\nexport const EIP712_CAPABLE_METHODS: ReadonlySet<string> = new Set([\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n]);\n\n/**\n * Every `complete*Fields` function below shares the same two live-proven rules:\n * 1. Numeric completeness fields MUST be JS `number`, never numeric strings —\n * `generateEIP712Types` infers a field's Solidity type from `typeof`, and declaring one as\n * EIP-712 `string` instead of `int256` breaks recovery identically to omitting the field\n * entirely (verified live on AddLiquidity: `amount0Min: '0'` fails with the exact same\n * \"Missing signerPublicKey\" error as `amount0Min` being absent; `amount0Min: 0` succeeds).\n * 2. `positionId` has no such constraint — an empty string works, and does not target an\n * existing position (`positionId: ''` created a fresh position on AddLiquidity, not an add\n * to position id `''`; on RemoveLiquidity/CollectPositionFees the real position is still\n * resolved from `token0`/`token1`/`fee`/`tickLower`/`tickUpper`, not from this field).\n */\nfunction numericOr0(dto: Record<string, unknown>, field: string): number {\n return typeof dto[field] === 'number' ? dto[field] : 0;\n}\n\n/**\n * `AddLiquidity`'s real server-side DTO always carries `amount0Desired`/`amount0Min`/\n * `amount1Desired`/`amount1Min`/`positionId` once reconstructed, regardless of which deposit\n * convention the caller used (`Positions.addLiquidityByTicks` only ever sends\n * `depositQuantityToken0`/`depositQuantityToken1`). Proven empirically by bisection: none of the\n * five alone fixes recovery, all five together does (live 201, tx `407d9b24...`, block\n * `2429022`).\n */\nfunction completeAddLiquidityFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount0Desired: numericOr0(dto, 'amount0Desired'),\n amount0Min: numericOr0(dto, 'amount0Min'),\n amount1Desired: numericOr0(dto, 'amount1Desired'),\n amount1Min: numericOr0(dto, 'amount1Min'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\n/**\n * `RemoveLiquidity`'s real server-side DTO always carries `amount`/`amount0Min`/`amount1Min`/\n * `positionId` — `Positions.removeLiquidity` only ever sends a `withdrawalQuantityTokenX` (or\n * neither, for a full close). Proven empirically: every subset of these four fails, all four\n * together succeeds (live, random-signer probe — recovery confirmed by the response moving from\n * \"Missing signerPublicKey\" to a genuine position-not-found 404).\n */\nfunction completeRemoveLiquidityFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount: numericOr0(dto, 'amount'),\n amount0Min: numericOr0(dto, 'amount0Min'),\n amount1Min: numericOr0(dto, 'amount1Min'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\n/**\n * `CollectPositionFees`'s real server-side DTO always carries `amount0Requested`/\n * `amount1Requested`/`positionId` — `Positions.collectPositionFees` sends only the five identity\n * fields. Proven empirically the same way as `completeRemoveLiquidityFields`.\n */\nfunction completeCollectPositionFeesFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount0Requested: numericOr0(dto, 'amount0Requested'),\n amount1Requested: numericOr0(dto, 'amount1Requested'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\nexport const EIP712_FIELD_COMPLETERS: Readonly<\n Record<string, (dto: Record<string, unknown>) => Record<string, unknown>>\n> = {\n AddLiquidity: completeAddLiquidityFields,\n RemoveLiquidity: completeRemoveLiquidityFields,\n CollectPositionFees: completeCollectPositionFeesFields,\n};\n\n/**\n * Completes a DTO's fields for EIP-712 signing (a no-op for methods with no known gap, e.g.\n * `RequestTrade`) and derives its `types`. Exported separately from the signing call itself so tests\n * can assert on the exact payload without needing a live provider.\n */\nexport function buildEIP712Payload(\n methodName: string,\n dto: Record<string, unknown>,\n): { completedDto: Record<string, unknown>; types: EIP712Types } {\n const completer = EIP712_FIELD_COMPLETERS[methodName];\n const completedDto = completer ? completer(dto) : dto;\n const types = generateEIP712Types(methodName, completedDto);\n return { completedDto, types };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"eip712.js","names":[],"sources":["../../../src/utils/eip712.ts"],"sourcesContent":["/**\n * Genuine EIP-712 typed-data signing for the four v2 dex-contract operations proven (2026-09-16,\n * live bisection against stage — see defi-backend's `chain-findings-artifact` memory /\n * https://claude.ai/artifact/3N9MevSjoQdU7gqnVB3dfU) to recover the `client|` identity correctly\n * via `eth_signTypedData_v4`, unlike `personal_sign` (which only ever resolves the bare `eth|`\n * form — see `BrowserWalletSigner`'s own doc comment). Mirrors frontend_v2's\n * `src/Services/eip712Types.ts` + `readWriteUtilsV2.ts`'s `EIP712_FIELD_COMPLETERS` exactly —\n * ported here rather than shared as a package because gswap-sdk has no frontend_v2 dependency\n * and should not gain one for four small functions.\n */\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\n\n/** EIP-712 `types`: each struct name mapped to its ordered `{ name, type }` fields. */\nexport type EIP712Types = Record<string, Array<{ name: string; type: string }>>;\n\n/**\n * Derives the EIP-712 `types` for a DTO from its runtime shape.\n *\n * The generated `types` travel with the signed payload and are what BOTH sides hash, so they\n * must enumerate EVERY field the chain-side DTO will carry. GalaChain refuses any signature\n * whose `types` leave a DTO field uncovered (`assertNoUnsignedFields`, the fix for the\n * 2026-08-18 unsigned-field-injection drain); when that happens signature recovery fails\n * outright and the chain reports \"Missing signerPublicKey or signerAddress field in dto\".\n */\nexport function generateEIP712Types(\n typeName: string,\n params: Record<string, unknown>,\n): EIP712Types {\n const types: EIP712Types = {};\n types[typeName] = [];\n\n // Every `name` this is ever called with (the top-level `typeName`, or a nested struct's own\n // name) is unconditionally assigned `types[name] = []` on the line immediately before any\n // recursive call that could reach here; TypeScript still types `types[name]` as\n // possibly-undefined (index-signature access), so the guard below stays for real type safety\n // even though no current call path can actually trigger it.\n function fieldsFor(name: string): Array<{ name: string; type: string }> {\n const fields = types[name];\n /* c8 ignore next */\n if (!fields) throw new Error(`Missing EIP-712 type definition for ${name}`);\n return fields;\n }\n\n function addField(\n name: string,\n fieldValue: unknown,\n parentTypeName: string,\n onlyGetType = false,\n ): string | undefined {\n if (Array.isArray(fieldValue)) {\n const type =\n fieldValue.length > 0 ? addField(name, fieldValue[0], parentTypeName, true) : 'string';\n if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: (type ?? name) + '[]' });\n } else if (typeof fieldValue === 'object' && fieldValue !== null) {\n if (types[name]) {\n throw new GSwapSDKError('EIP712_NAME_COLLISION', { name });\n }\n types[name] = [];\n Object.entries(fieldValue).forEach(([key, value]) => {\n addField(key, value, name);\n });\n if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: name });\n } else {\n let eipType: string;\n switch (typeof fieldValue) {\n case 'string':\n eipType = 'string';\n break;\n case 'number':\n eipType = 'int256';\n break;\n case 'boolean':\n eipType = 'bool';\n break;\n case 'bigint':\n case 'symbol':\n case 'undefined':\n case 'function':\n case 'object':\n throw new GSwapSDKError('EIP712_UNSUPPORTED_VALUE', { valueType: typeof fieldValue });\n }\n if (onlyGetType) {\n return eipType;\n }\n fieldsFor(parentTypeName).push({ name, type: eipType });\n }\n return undefined;\n }\n\n Object.entries(params).forEach(([key, value]) => {\n addField(key, value, typeName);\n });\n\n return types;\n}\n\n/** The EIP-712 domain carried by a signed payload: GalaChain only uses `name` and `chainId`. */\nexport interface EIP712DomainValue {\n name: string;\n chainId: number;\n}\n\n/**\n * Builds the EIP-712 domain from the wallet's LIVE `eth_chainId` result, exactly like frontend_v2\n * (DEFI-1895): a wallet hashes whatever domain it is handed, and MetaMask refuses a `chainId` that\n * differs from its active network, so a hardcoded `1` breaks every wallet that is not on Mainnet.\n * defi-backend recovers the signer from the `domain` the payload carries (live-proven for chain\n * ids 1, 56 and 11155111), so following the wallet is correct on every network.\n *\n * @param chainId - The raw `eth_chainId` result: a `0x` hex string (the JSON-RPC form) or an integer.\n * @throws GSwapSDKError (`INVALID_CHAIN_ID`) when the wallet answers with anything else.\n */\nexport function eip712DomainFor(chainId: unknown): EIP712DomainValue {\n const parsed =\n typeof chainId === 'string' && /^0x[0-9a-fA-F]+$/u.test(chainId)\n ? Number(chainId)\n : typeof chainId === 'number'\n ? chainId\n : Number.NaN;\n if (!Number.isSafeInteger(parsed) || parsed <= 0) {\n throw new GSwapSDKError('INVALID_CHAIN_ID', {\n chainId:\n typeof chainId === 'string' || typeof chainId === 'number'\n ? String(chainId)\n : typeof chainId,\n });\n }\n return { name: 'ethereum', chainId: parsed };\n}\n\n/**\n * The four v2 operations proven to recover the signer correctly via genuine EIP-712: `RequestTrade`\n * never had the problem (one numeric field). `AddLiquidity`/`RemoveLiquidity`/\n * `CollectPositionFees` each need their `types` completed with a handful of fields their real\n * server-side DTO always carries — see the `complete*Fields` functions below. `CreatePool` is a\n * genuinely different, unsolved problem (nested `TokenClassKey` structs, not a flat\n * missing-field gap) and is NOT in this set — callers must keep using `personal-sign` for it.\n */\nexport const EIP712_CAPABLE_METHODS: ReadonlySet<string> = new Set([\n 'RequestTrade',\n 'AddLiquidity',\n 'RemoveLiquidity',\n 'CollectPositionFees',\n]);\n\n/**\n * Every `complete*Fields` function below shares the same two live-proven rules:\n * 1. Numeric completeness fields MUST be JS `number`, never numeric strings —\n * `generateEIP712Types` infers a field's Solidity type from `typeof`, and declaring one as\n * EIP-712 `string` instead of `int256` breaks recovery identically to omitting the field\n * entirely (verified live on AddLiquidity: `amount0Min: '0'` fails with the exact same\n * \"Missing signerPublicKey\" error as `amount0Min` being absent; `amount0Min: 0` succeeds).\n * 2. `positionId` has no such constraint — an empty string works, and does not target an\n * existing position (`positionId: ''` created a fresh position on AddLiquidity, not an add\n * to position id `''`; on RemoveLiquidity/CollectPositionFees the real position is still\n * resolved from `token0`/`token1`/`fee`/`tickLower`/`tickUpper`, not from this field).\n */\nfunction numericOr0(dto: Record<string, unknown>, field: string): number {\n return typeof dto[field] === 'number' ? dto[field] : 0;\n}\n\n/**\n * `AddLiquidity`'s real server-side DTO always carries `amount0Desired`/`amount0Min`/\n * `amount1Desired`/`amount1Min`/`positionId` once reconstructed, regardless of which deposit\n * convention the caller used (`Positions.addLiquidityByTicks` only ever sends\n * `depositQuantityToken0`/`depositQuantityToken1`). Proven empirically by bisection: none of the\n * five alone fixes recovery, all five together does (live 201, tx `407d9b24...`, block\n * `2429022`).\n */\nfunction completeAddLiquidityFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount0Desired: numericOr0(dto, 'amount0Desired'),\n amount0Min: numericOr0(dto, 'amount0Min'),\n amount1Desired: numericOr0(dto, 'amount1Desired'),\n amount1Min: numericOr0(dto, 'amount1Min'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\n/**\n * `RemoveLiquidity`'s real server-side DTO always carries `amount`/`amount0Min`/`amount1Min`/\n * `positionId` — `Positions.removeLiquidity` only ever sends a `withdrawalQuantityTokenX` (or\n * neither, for a full close). Proven empirically: every subset of these four fails, all four\n * together succeeds (live, random-signer probe — recovery confirmed by the response moving from\n * \"Missing signerPublicKey\" to a genuine position-not-found 404).\n */\nfunction completeRemoveLiquidityFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount: numericOr0(dto, 'amount'),\n amount0Min: numericOr0(dto, 'amount0Min'),\n amount1Min: numericOr0(dto, 'amount1Min'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\n/**\n * `CollectPositionFees`'s real server-side DTO always carries `amount0Requested`/\n * `amount1Requested`/`positionId` — `Positions.collectPositionFees` sends only the five identity\n * fields. Proven empirically the same way as `completeRemoveLiquidityFields`.\n */\nfunction completeCollectPositionFeesFields(dto: Record<string, unknown>): Record<string, unknown> {\n return {\n ...dto,\n amount0Requested: numericOr0(dto, 'amount0Requested'),\n amount1Requested: numericOr0(dto, 'amount1Requested'),\n positionId: dto['positionId'] ?? '',\n };\n}\n\nexport const EIP712_FIELD_COMPLETERS: Readonly<\n Record<string, (dto: Record<string, unknown>) => Record<string, unknown>>\n> = {\n AddLiquidity: completeAddLiquidityFields,\n RemoveLiquidity: completeRemoveLiquidityFields,\n CollectPositionFees: completeCollectPositionFeesFields,\n};\n\n/**\n * Completes a DTO's fields for EIP-712 signing (a no-op for methods with no known gap, e.g.\n * `RequestTrade`) and derives its `types`. Exported separately from the signing call itself so tests\n * can assert on the exact payload without needing a live provider.\n */\nexport function buildEIP712Payload(\n methodName: string,\n dto: Record<string, unknown>,\n): { completedDto: Record<string, unknown>; types: EIP712Types } {\n const completer = EIP712_FIELD_COMPLETERS[methodName];\n const completedDto = completer ? completer(dto) : dto;\n const types = generateEIP712Types(methodName, completedDto);\n return { completedDto, types };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{GSwapSDKError as e,parseJson as t}from"../classes/gswap_sdk_error.js";import"../version.js";function n(e,t){if(t===1/0)return()=>void 0;let n=setTimeout(()=>e.abort(),t);return()=>clearTimeout(n)}function r(t,n){if(t===1/0||Number.isFinite(t)&&t>0)return t;throw new e(`INVALID_TIMEOUT`,{field:n,value:t})}const i=/[A-Za-z0-9\-._~!'()*$|:,]/u;function a(e){let t=``;for(let n of e)n===` `?t+=`+`:i.test(n)?t+=n:t+=o(n);return t}function o(e){try{return encodeURIComponent(e)}catch{return`%EF%BF%BD`}}function s(e,t=`standard`){return t===`readable`?Object.entries(e).map(([e,t])=>`${a(e)}=${a(t)}`).join(`&`):new URLSearchParams(e).toString()}function c(e,t={}){let n=/* @__PURE__ */ new Map,r=(e,t=!1)=>{for(let[r,i]of Object.entries(e??{}))t&&n.delete(r.toLowerCase()),n.set(r.toLowerCase(),[r,i])};return e?.userAgent!==!1&&r({"User-Agent":e?.userAgent??`GalaChain-SDK/1.2.0-rc.9`}),r(t.defaults),r(e?.headers),t.json===!0&&!n.has(`content-type`)&&r({"Content-Type":`application/json`}),r(t.fixed,!0),Object.fromEntries(n.values())}const l=async(t,n)=>{try{return await fetch(t,n)}catch(r){throw n?.signal?.aborted===!0?r:new e(`TRANSPORT_ERROR`,{url:t},{url:t,cause:r})}};async function u(t,r,i,a){let o=new AbortController,s=n(o,a),c=i.signal,l=()=>o.abort();c?.addEventListener(`abort`,l,{once:!0});try{return await t(r,{...i,signal:o.signal})}catch(t){throw c?.aborted===!0?t:o.signal.aborted?new e(`REQUEST_TIMEOUT`,{url:r,timeoutMs:a},{url:r,cause:t}):t}finally{s(),c?.removeEventListener(`abort`,l)}}async function d(e){let n=await e.text();return t(n)??n}function f(e,t){let n=e.headers;if(n===void 0)return;if(h(n)){let e=n.get(t);return e===null||e===``?void 0:e}let r=Object.entries(n).find(([e])=>e.toLowerCase()===t.toLowerCase())?.[1];return r===void 0||r===``?void 0:r}function p(e){let t=f(e,`retry-after`);if(t===void 0)return;let n=Number(t);if(Number.isFinite(n)&&n>=0)return n*1e3;let r=Date.parse(t);return Number.isNaN(r)?void 0:Math.max(0,r-Date.now())}function m(e,t=`x-block-number`){let n=f(e,t);if(n===void 0)return;let r=Number(n);return Number.isInteger(r)&&r>=0?r:void 0}function h(e){return`get`in e&&typeof e.get==`function`}export{n as armTimeout,s as buildQueryString,c as buildRequestHeaders,l as fetchRequestor,m as readBlockNumberHeader,f as readHeader,d as readResponseBody,p as readRetryAfter,u as requestWithTimeout,r as validateTimeoutMs};
1
+ import{GSwapSDKError as e,parseJson as t}from"../classes/gswap_sdk_error.js";import"../version.js";function n(e,t){if(t===1/0)return()=>void 0;let n=setTimeout(()=>e.abort(),t);return()=>clearTimeout(n)}function r(t,n){if(t===1/0||Number.isFinite(t)&&t>0)return t;throw new e(`INVALID_TIMEOUT`,{field:n,value:t})}const i=/[A-Za-z0-9\-._~!'()*$|:,]/u;function a(e){let t=``;for(let n of e)n===` `?t+=`+`:i.test(n)?t+=n:t+=o(n);return t}function o(e){try{return encodeURIComponent(e)}catch{return`%EF%BF%BD`}}function s(e,t=`standard`){return t===`readable`?Object.entries(e).map(([e,t])=>`${a(e)}=${a(t)}`).join(`&`):new URLSearchParams(e).toString()}function c(e,t={}){let n=/* @__PURE__ */ new Map,r=(e,t=!1)=>{for(let[r,i]of Object.entries(e??{}))t&&n.delete(r.toLowerCase()),n.set(r.toLowerCase(),[r,i])};return e?.userAgent!==!1&&r({"User-Agent":e?.userAgent??`GalaChain-SDK/1.2.0`}),r(t.defaults),r(e?.headers),t.json===!0&&!n.has(`content-type`)&&r({"Content-Type":`application/json`}),r(t.fixed,!0),Object.fromEntries(n.values())}const l=async(t,n)=>{try{return await fetch(t,n)}catch(r){throw n?.signal?.aborted===!0?r:new e(`TRANSPORT_ERROR`,{url:t},{url:t,cause:r})}};async function u(t,r,i,a){let o=new AbortController,s=n(o,a),c=i.signal,l=()=>o.abort();c?.addEventListener(`abort`,l,{once:!0});try{return await t(r,{...i,signal:o.signal})}catch(t){throw c?.aborted===!0?t:o.signal.aborted?new e(`REQUEST_TIMEOUT`,{url:r,timeoutMs:a},{url:r,cause:t}):t}finally{s(),c?.removeEventListener(`abort`,l)}}async function d(e){let n=await e.text();return t(n)??n}function f(e,t){let n=e.headers;if(n===void 0)return;if(h(n)){let e=n.get(t);return e===null||e===``?void 0:e}let r=Object.entries(n).find(([e])=>e.toLowerCase()===t.toLowerCase())?.[1];return r===void 0||r===``?void 0:r}function p(e){let t=f(e,`retry-after`);if(t===void 0)return;let n=Number(t);if(Number.isFinite(n)&&n>=0)return n*1e3;let r=Date.parse(t);return Number.isNaN(r)?void 0:Math.max(0,r-Date.now())}function m(e,t=`x-block-number`){let n=f(e,t);if(n===void 0)return;let r=Number(n);return Number.isInteger(r)&&r>=0?r:void 0}function h(e){return`get`in e&&typeof e.get==`function`}export{n as armTimeout,s as buildQueryString,c as buildRequestHeaders,l as fetchRequestor,m as readBlockNumberHeader,f as readHeader,d as readResponseBody,p as readRetryAfter,u as requestWithTimeout,r as validateTimeoutMs};
2
2
  //# sourceMappingURL=transport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","names":[],"sources":["../../../src/utils/transport.ts"],"sourcesContent":["import type { HTTPResponse, HttpRequestor } from '../types/http_requestor.js';\nimport type { WireOptions } from '../types/wire.js';\nimport { GSwapSDKError, parseJson } from '../classes/gswap_sdk_error.js';\nimport { SDK_VERSION } from '../version.js';\n\n/**\n * Arms the abort timer for a request. `Infinity` means \"never time out\": `setTimeout` would turn\n * it into 1 ms, so no timer is armed at all. Returns a function that disarms it.\n */\nexport function armTimeout(controller: AbortController, timeoutMs: number): () => void {\n if (timeoutMs === Infinity) return () => undefined;\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n return () => clearTimeout(timer);\n}\n\n/**\n * Validates a request timeout in milliseconds: a positive finite number, or `Infinity` for none.\n *\n * @throws GSwapSDKError `INVALID_TIMEOUT` (`params.field` = `name`) otherwise.\n */\nexport function validateTimeoutMs(timeoutMs: number, name: string): number {\n if (timeoutMs === Infinity || (Number.isFinite(timeoutMs) && timeoutMs > 0)) return timeoutMs;\n throw new GSwapSDKError('INVALID_TIMEOUT', { field: name, value: timeoutMs });\n}\n\nconst READABLE_QUERY_SAFE = /[A-Za-z0-9\\-._~!'()*$|:,]/u;\n\nfunction encodeReadable(text: string): string {\n let out = '';\n for (const char of text) {\n if (char === ' ') out += '+';\n else if (READABLE_QUERY_SAFE.test(char)) out += char;\n else out += encodeScalar(char);\n }\n return out;\n}\n\n/** Percent-encodes one code point; a lone surrogate becomes U+FFFD, as `URLSearchParams` does. */\nfunction encodeScalar(char: string): string {\n try {\n return encodeURIComponent(char);\n } catch {\n return '%EF%BF%BD';\n }\n}\n\n/** Serializes GET parameters, in insertion order, in the encoding the wire options select. */\nexport function buildQueryString(\n params: Record<string, string>,\n encoding: WireOptions['queryEncoding'] = 'standard',\n): string {\n if (encoding === 'readable') {\n return Object.entries(params)\n .map(([key, value]) => `${encodeReadable(key)}=${encodeReadable(value)}`)\n .join('&');\n }\n return new URLSearchParams(params).toString();\n}\n\n/** What an SDK request adds to the headers the wire options describe. */\nexport interface RequestHeaderParts {\n /** The request carries a JSON body: `Content-Type: application/json` unless `wire.headers` sets one. */\n json?: boolean | undefined;\n /** Headers the SDK sends unless `wire.headers` replaces them (for example `Accept`). */\n defaults?: Record<string, string> | undefined;\n /**\n * Headers that carry the request's meaning (`X-Wallet-Address`, `X-Shadow`). They come last and\n * replace a same-named `wire.headers` entry, so an app's static headers can never re-attribute\n * or un-shadow a write.\n */\n fixed?: Record<string, string> | undefined;\n}\n\n/**\n * The request headers for ANY SDK request, GET or POST, from one place so the wire options reach\n * every request alike. Order, which is the order the requestor sees them in: `User-Agent`\n * (`wire.userAgent`, default `GalaChain-SDK/<version>`, `false` omits it), `parts.defaults`,\n * `wire.headers`, `Content-Type` (JSON bodies only), `parts.fixed`. A later entry replaces an\n * earlier one of the same name regardless of case, so a header is never sent twice.\n */\nexport function buildRequestHeaders(\n wire: WireOptions | undefined,\n parts: RequestHeaderParts = {},\n): Record<string, string> {\n const entries = new Map<string, [name: string, value: string]>();\n const put = (headers: Record<string, string> | undefined, last = false): void => {\n for (const [name, value] of Object.entries(headers ?? {})) {\n // A fixed header leaves any earlier same-named entry behind, so it also keeps its place at the end.\n if (last) entries.delete(name.toLowerCase());\n entries.set(name.toLowerCase(), [name, value]);\n }\n };\n if (wire?.userAgent !== false) {\n put({ 'User-Agent': wire?.userAgent ?? `GalaChain-SDK/${SDK_VERSION}` });\n }\n put(parts.defaults);\n put(wire?.headers);\n if (parts.json === true && !entries.has('content-type')) {\n put({ 'Content-Type': 'application/json' });\n }\n put(parts.fixed, true);\n return Object.fromEntries(entries.values());\n}\n\n/**\n * The default requestor: the global `fetch`, with a failure before any answer (offline, DNS,\n * CORS) coded as `TRANSPORT_ERROR` and the original error kept as `cause`. An aborted request is\n * left to {@link requestWithTimeout}, which knows whether the timeout or the caller aborted it.\n * A requestor the app supplies is not wrapped: its rejection reaches the caller unchanged.\n */\nexport const fetchRequestor: HttpRequestor = async (url, init) => {\n try {\n return await fetch(url, init);\n } catch (error: unknown) {\n if (init?.signal?.aborted === true) throw error;\n throw new GSwapSDKError('TRANSPORT_ERROR', { url }, { url, cause: error });\n }\n};\n\nexport async function requestWithTimeout(\n requestor: HttpRequestor,\n url: string,\n options: RequestInit,\n timeoutMs: number,\n): Promise<HTTPResponse> {\n const controller = new AbortController();\n const disarm = armTimeout(controller, timeoutMs);\n const externalSignal = options.signal;\n const abortFromCaller = (): void => controller.abort();\n externalSignal?.addEventListener('abort', abortFromCaller, { once: true });\n try {\n return await requestor(url, { ...options, signal: controller.signal });\n } catch (error: unknown) {\n // The caller's own abort is theirs: it passes through as the abort it is, never as a timeout.\n if (externalSignal?.aborted === true) throw error;\n if (controller.signal.aborted) {\n throw new GSwapSDKError('REQUEST_TIMEOUT', { url, timeoutMs }, { url, cause: error });\n }\n // Anything else is the requestor's own rejection (an app's axios interceptor error, say):\n // rethrown as it is, because the app's error handling produced it.\n throw error;\n } finally {\n disarm();\n externalSignal?.removeEventListener('abort', abortFromCaller);\n }\n}\n\nexport async function readResponseBody(response: HTTPResponse): Promise<unknown> {\n const text = await response.text();\n return parseJson(text) ?? text;\n}\n\n/** Read a case-insensitive response header from either supported header shape. */\nexport function readHeader(response: HTTPResponse, name: string): string | undefined {\n const headers = response.headers;\n if (headers === undefined) return undefined;\n if (hasHeaderGetter(headers)) {\n const value = headers.get(name);\n return value === null || value === '' ? undefined : value;\n }\n const value = Object.entries(headers).find(\n ([key]) => key.toLowerCase() === name.toLowerCase(),\n )?.[1];\n return value === undefined || value === '' ? undefined : value;\n}\n\n/** Read a Retry-After header (delta-seconds or an HTTP date) as non-negative milliseconds. */\nexport function readRetryAfter(response: HTTPResponse): number | undefined {\n const raw = readHeader(response, 'retry-after');\n if (raw === undefined) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;\n const timestamp = Date.parse(raw);\n return Number.isNaN(timestamp) ? undefined : Math.max(0, timestamp - Date.now());\n}\n\n/** Read a non-negative integer block number header. */\nexport function readBlockNumberHeader(\n response: HTTPResponse,\n headerName = 'x-block-number',\n): number | undefined {\n const raw = readHeader(response, headerName);\n if (raw === undefined) return undefined;\n const blockNumber = Number(raw);\n return Number.isInteger(blockNumber) && blockNumber >= 0 ? blockNumber : undefined;\n}\n\nfunction hasHeaderGetter(\n headers: NonNullable<HTTPResponse['headers']>,\n): headers is { get(name: string): string | null } {\n return 'get' in headers && typeof headers.get === 'function';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transport.js","names":[],"sources":["../../../src/utils/transport.ts"],"sourcesContent":["import type { HTTPResponse, HttpRequestor } from '../types/http_requestor.js';\nimport type { WireOptions } from '../types/wire.js';\nimport { GSwapSDKError, parseJson } from '../classes/gswap_sdk_error.js';\nimport { SDK_VERSION } from '../version.js';\n\n/**\n * Arms the abort timer for a request. `Infinity` means \"never time out\": `setTimeout` would turn\n * it into 1 ms, so no timer is armed at all. Returns a function that disarms it.\n */\nexport function armTimeout(controller: AbortController, timeoutMs: number): () => void {\n if (timeoutMs === Infinity) return () => undefined;\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n return () => clearTimeout(timer);\n}\n\n/**\n * Validates a request timeout in milliseconds: a positive finite number, or `Infinity` for none.\n *\n * @throws GSwapSDKError `INVALID_TIMEOUT` (`params.field` = `name`) otherwise.\n */\nexport function validateTimeoutMs(timeoutMs: number, name: string): number {\n if (timeoutMs === Infinity || (Number.isFinite(timeoutMs) && timeoutMs > 0)) return timeoutMs;\n throw new GSwapSDKError('INVALID_TIMEOUT', { field: name, value: timeoutMs });\n}\n\nconst READABLE_QUERY_SAFE = /[A-Za-z0-9\\-._~!'()*$|:,]/u;\n\nfunction encodeReadable(text: string): string {\n let out = '';\n for (const char of text) {\n if (char === ' ') out += '+';\n else if (READABLE_QUERY_SAFE.test(char)) out += char;\n else out += encodeScalar(char);\n }\n return out;\n}\n\n/** Percent-encodes one code point; a lone surrogate becomes U+FFFD, as `URLSearchParams` does. */\nfunction encodeScalar(char: string): string {\n try {\n return encodeURIComponent(char);\n } catch {\n return '%EF%BF%BD';\n }\n}\n\n/** Serializes GET parameters, in insertion order, in the encoding the wire options select. */\nexport function buildQueryString(\n params: Record<string, string>,\n encoding: WireOptions['queryEncoding'] = 'standard',\n): string {\n if (encoding === 'readable') {\n return Object.entries(params)\n .map(([key, value]) => `${encodeReadable(key)}=${encodeReadable(value)}`)\n .join('&');\n }\n return new URLSearchParams(params).toString();\n}\n\n/** What an SDK request adds to the headers the wire options describe. */\nexport interface RequestHeaderParts {\n /** The request carries a JSON body: `Content-Type: application/json` unless `wire.headers` sets one. */\n json?: boolean | undefined;\n /** Headers the SDK sends unless `wire.headers` replaces them (for example `Accept`). */\n defaults?: Record<string, string> | undefined;\n /**\n * Headers that carry the request's meaning (`X-Wallet-Address`, `X-Shadow`). They come last and\n * replace a same-named `wire.headers` entry, so an app's static headers can never re-attribute\n * or un-shadow a write.\n */\n fixed?: Record<string, string> | undefined;\n}\n\n/**\n * The request headers for ANY SDK request, GET or POST, from one place so the wire options reach\n * every request alike. Order, which is the order the requestor sees them in: `User-Agent`\n * (`wire.userAgent`, default `GalaChain-SDK/<version>`, `false` omits it), `parts.defaults`,\n * `wire.headers`, `Content-Type` (JSON bodies only), `parts.fixed`. A later entry replaces an\n * earlier one of the same name regardless of case, so a header is never sent twice.\n */\nexport function buildRequestHeaders(\n wire: WireOptions | undefined,\n parts: RequestHeaderParts = {},\n): Record<string, string> {\n const entries = new Map<string, [name: string, value: string]>();\n const put = (headers: Record<string, string> | undefined, last = false): void => {\n for (const [name, value] of Object.entries(headers ?? {})) {\n // A fixed header leaves any earlier same-named entry behind, so it also keeps its place at the end.\n if (last) entries.delete(name.toLowerCase());\n entries.set(name.toLowerCase(), [name, value]);\n }\n };\n if (wire?.userAgent !== false) {\n put({ 'User-Agent': wire?.userAgent ?? `GalaChain-SDK/${SDK_VERSION}` });\n }\n put(parts.defaults);\n put(wire?.headers);\n if (parts.json === true && !entries.has('content-type')) {\n put({ 'Content-Type': 'application/json' });\n }\n put(parts.fixed, true);\n return Object.fromEntries(entries.values());\n}\n\n/**\n * The default requestor: the global `fetch`, with a failure before any answer (offline, DNS,\n * CORS) coded as `TRANSPORT_ERROR` and the original error kept as `cause`. An aborted request is\n * left to {@link requestWithTimeout}, which knows whether the timeout or the caller aborted it.\n * A requestor the app supplies is not wrapped: its rejection reaches the caller unchanged.\n */\nexport const fetchRequestor: HttpRequestor = async (url, init) => {\n try {\n return await fetch(url, init);\n } catch (error: unknown) {\n if (init?.signal?.aborted === true) throw error;\n throw new GSwapSDKError('TRANSPORT_ERROR', { url }, { url, cause: error });\n }\n};\n\nexport async function requestWithTimeout(\n requestor: HttpRequestor,\n url: string,\n options: RequestInit,\n timeoutMs: number,\n): Promise<HTTPResponse> {\n const controller = new AbortController();\n const disarm = armTimeout(controller, timeoutMs);\n const externalSignal = options.signal;\n const abortFromCaller = (): void => controller.abort();\n externalSignal?.addEventListener('abort', abortFromCaller, { once: true });\n try {\n return await requestor(url, { ...options, signal: controller.signal });\n } catch (error: unknown) {\n // The caller's own abort is theirs: it passes through as the abort it is, never as a timeout.\n if (externalSignal?.aborted === true) throw error;\n if (controller.signal.aborted) {\n throw new GSwapSDKError('REQUEST_TIMEOUT', { url, timeoutMs }, { url, cause: error });\n }\n // Anything else is the requestor's own rejection (an app's axios interceptor error, say):\n // rethrown as it is, because the app's error handling produced it.\n throw error;\n } finally {\n disarm();\n externalSignal?.removeEventListener('abort', abortFromCaller);\n }\n}\n\nexport async function readResponseBody(response: HTTPResponse): Promise<unknown> {\n const text = await response.text();\n return parseJson(text) ?? text;\n}\n\n/** Read a case-insensitive response header from either supported header shape. */\nexport function readHeader(response: HTTPResponse, name: string): string | undefined {\n const headers = response.headers;\n if (headers === undefined) return undefined;\n if (hasHeaderGetter(headers)) {\n const value = headers.get(name);\n return value === null || value === '' ? undefined : value;\n }\n const value = Object.entries(headers).find(\n ([key]) => key.toLowerCase() === name.toLowerCase(),\n )?.[1];\n return value === undefined || value === '' ? undefined : value;\n}\n\n/** Read a Retry-After header (delta-seconds or an HTTP date) as non-negative milliseconds. */\nexport function readRetryAfter(response: HTTPResponse): number | undefined {\n const raw = readHeader(response, 'retry-after');\n if (raw === undefined) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;\n const timestamp = Date.parse(raw);\n return Number.isNaN(timestamp) ? undefined : Math.max(0, timestamp - Date.now());\n}\n\n/** Read a non-negative integer block number header. */\nexport function readBlockNumberHeader(\n response: HTTPResponse,\n headerName = 'x-block-number',\n): number | undefined {\n const raw = readHeader(response, headerName);\n if (raw === undefined) return undefined;\n const blockNumber = Number(raw);\n return Number.isInteger(blockNumber) && blockNumber >= 0 ? blockNumber : undefined;\n}\n\nfunction hasHeaderGetter(\n headers: NonNullable<HTTPResponse['headers']>,\n): headers is { get(name: string): string | null } {\n return 'get' in headers && typeof headers.get === 'function';\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":[],"sources":["../../../src/utils/validation.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\nexport function validateWalletAddress(address?: string): asserts address is string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n\n if (!address || typeof address !== 'string' || address.trim().length === 0) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', {\n field: 'walletAddress',\n value: String(address),\n });\n }\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../../src/utils/validation.ts"],"sourcesContent":["import BigNumber from 'bignumber.js';\nimport { ALLOWED_FEE_TIERS_TEXT } from '../classes/error_catalog.js';\nimport { GSwapSDKError } from '../classes/gswap_sdk_error.js';\nimport type { NumericAmount } from '../types/amounts.js';\nimport { ALL_FEE_TIERS } from '../types/fees.js';\nimport type { FEE_TIER } from '../types/fees.js';\nimport { GC_MAX_TICK, GC_MIN_TICK } from './tick_math.js';\n\n/**\n * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.\n *\n * @param amount - The amount to check.\n * @param parameterName - The field name reported in the error's `params.field`.\n * @param allowZero - Accept zero (default `false`).\n * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero\n * when `allowZero` is false) or `AMOUNT_NEGATIVE`.\n */\nexport function validateNumericAmount(\n amount: NumericAmount,\n parameterName: string,\n allowZero = false,\n): void {\n if (typeof amount === 'number') {\n throw new GSwapSDKError('AMOUNT_IS_JS_NUMBER', { field: parameterName });\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite() check below still catches\n // it and raises the same typed error, instead of a raw exception escaping.\n let bnAmount: BigNumber;\n try {\n bnAmount = BigNumber(amount);\n } catch {\n bnAmount = BigNumber(NaN);\n }\n\n if (!bnAmount.isFinite()) {\n throw new GSwapSDKError('AMOUNT_NOT_FINITE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (!allowZero && bnAmount.isZero()) {\n throw new GSwapSDKError('AMOUNT_NOT_POSITIVE', {\n field: parameterName,\n value: String(amount),\n });\n }\n\n if (bnAmount.isNegative()) {\n throw new GSwapSDKError('AMOUNT_NEGATIVE', { field: parameterName, value: String(amount) });\n }\n}\n\n/**\n * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and\n * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.\n *\n * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.\n */\nexport function validatePriceValues(\n spotPrice: NumericAmount,\n lowerPrice: NumericAmount,\n upperPrice: NumericAmount,\n): void {\n if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === 'number')) {\n throw new GSwapSDKError('PRICE_VALUES_IS_JS_NUMBER', {});\n }\n // bignumber.js 11+ throws on an unparseable value instead of constructing a NaN\n // instance — substitute an explicit NaN so the isFinite()/isPositive() checks below\n // still catch it and raise the same typed error, instead of a raw exception escaping.\n const parse = (value: NumericAmount): BigNumber => {\n try {\n return BigNumber(value);\n } catch {\n return BigNumber(NaN);\n }\n };\n const bnSpotPrice = parse(spotPrice);\n const bnLowerPrice = parse(lowerPrice);\n let bnUpperPrice = parse(upperPrice);\n\n bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);\n\n if (\n !bnSpotPrice.isFinite() ||\n !bnLowerPrice.isFinite() ||\n !bnUpperPrice.isFinite() ||\n !bnSpotPrice.isPositive() ||\n !bnLowerPrice.isPositive() ||\n !bnUpperPrice.isPositive()\n ) {\n throw new GSwapSDKError('INVALID_PRICE_VALUES', {\n spotPrice: String(spotPrice),\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n\n if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {\n throw new GSwapSDKError('INVALID_PRICE_RANGE', {\n lowerPrice: String(lowerPrice),\n upperPrice: String(upperPrice),\n });\n }\n}\n\n/**\n * Validates a token's decimals: a non-negative integer.\n *\n * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).\n */\nexport function validateTokenDecimals(decimals: number, parameterName: string): void {\n if (decimals < 0 || !Number.isInteger(decimals)) {\n throw new GSwapSDKError('INVALID_TOKEN_DECIMALS', { field: parameterName, value: decimals });\n }\n}\n\n/**\n * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within\n * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see\n * `assertTickRange`).\n *\n * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.\n */\nexport function validateTickRange(tickLower: number, tickUpper: number): void {\n if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {\n throw new GSwapSDKError('TICKS_NOT_INTEGERS', { tickLower, tickUpper });\n }\n\n if (tickLower >= tickUpper) {\n throw new GSwapSDKError('INVALID_TICK_RANGE', { tickLower, tickUpper });\n }\n\n if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {\n throw new GSwapSDKError('TICKS_OUT_OF_BOUNDS', {\n tickLower,\n tickUpper,\n minTick: GC_MIN_TICK,\n maxTick: GC_MAX_TICK,\n });\n }\n}\n\n/**\n * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).\n *\n * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).\n */\nexport function validateFee(fee: number): asserts fee is FEE_TIER {\n if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {\n throw new GSwapSDKError('INVALID_FEE', {\n field: 'fee',\n value: fee,\n allowed: ALLOWED_FEE_TIERS_TEXT,\n });\n }\n}\n\n/**\n * Validates a tick spacing: a positive integer.\n *\n * @throws GSwapSDKError `INVALID_TICK_SPACING`.\n */\nexport function validateTickSpacing(tickSpacing: number): void {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new GSwapSDKError('INVALID_TICK_SPACING', { value: tickSpacing });\n }\n}\n\n/**\n * Asserts that a wallet address was given and is a non-blank string. It does not check the address\n * format.\n *\n * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS` (blank).\n */\nexport function validateWalletAddress(address?: string): asserts address is string {\n if (address === undefined) {\n throw new GSwapSDKError('MISSING_WALLET_ADDRESS', {});\n }\n\n if (!address || typeof address !== 'string' || address.trim().length === 0) {\n throw new GSwapSDKError('INVALID_WALLET_ADDRESS', {\n field: 'walletAddress',\n value: String(address),\n });\n }\n}\n\n/** Words the chain gateway refuses as a trading symbol. */\nconst RESERVED_TRADING_SYMBOLS = new Set(['Token', 'Unit', 'none']);\nconst TRADING_SYMBOL_PATTERN = /^[A-Za-z0-9]+$/u;\nconst MAX_TRADING_SYMBOL_LENGTH = 32;\n\n/**\n * True when `symbol` is acceptable to propose into the trading-symbol registry: ASCII letters and\n * digits only, 1 to 32 characters, and not a reserved word (`Token`, `Unit`, `none`) — the rules\n * the chain gateway enforces on a CreatePool symbol.\n */\nexport function isProposableTradingSymbol(symbol: string): boolean {\n return (\n TRADING_SYMBOL_PATTERN.test(symbol) &&\n symbol.length <= MAX_TRADING_SYMBOL_LENGTH &&\n !RESERVED_TRADING_SYMBOLS.has(symbol)\n );\n}\n\n/**\n * Asserts that a pair is in the contract's canonical order (`token0 < token1` by plain string\n * comparison), which every write DTO requires. A pair a caller took from a stale quote or\n * position can be reversed; signing it would sign something other than what was priced.\n *\n * @throws GSwapSDKError `NON_CANONICAL_PAIR` (`params.token0`, `params.token1`) otherwise.\n */\nexport function assertCanonicalPair(token0: string, token1: string): void {\n if (!(token0 < token1)) {\n throw new GSwapSDKError('NON_CANONICAL_PAIR', { token0, token1 });\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=`1.2.0-rc.9`;export{e as SDK_VERSION};
1
+ const e=`1.2.0`;export{e as SDK_VERSION};
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":[],"sources":["../../src/version.ts"],"sourcesContent":["declare const __GSWAP_SDK_VERSION__: string | undefined;\n\n/** Package version embedded by the bundler, with a source-test fallback. */\nexport const SDK_VERSION =\n typeof __GSWAP_SDK_VERSION__ === 'string' ? __GSWAP_SDK_VERSION__ : '1.2.0-rc.9';\n"],"mappings":"AAGA,MAAa,EAAA"}
1
+ {"version":3,"file":"version.js","names":[],"sources":["../../src/version.ts"],"sourcesContent":["declare const __GSWAP_SDK_VERSION__: string | undefined;\n\n/** Package version embedded by the bundler, with a source-test fallback. */\nexport const SDK_VERSION =\n typeof __GSWAP_SDK_VERSION__ === 'string' ? __GSWAP_SDK_VERSION__ : '1.2.0';\n"],"mappings":"AAGA,MAAa,EAAA"}
package/dist/index.cjs CHANGED
@@ -1345,6 +1345,7 @@ var GSwapSDKError = class GSwapSDKError extends Error {
1345
1345
  code;
1346
1346
  /** The named placeholders of the error: a flat object of primitives, safe to localize with. */
1347
1347
  params;
1348
+ /** The server's `Retry-After` in milliseconds (a `RATE_LIMITED` answer), when it sent one. */
1348
1349
  retryAfterMs;
1349
1350
  /** The HTTP status of the response that caused this error, when there was one. */
1350
1351
  status;
@@ -1670,7 +1671,7 @@ function parseJson(text) {
1670
1671
  //#endregion
1671
1672
  //#region src/version.ts
1672
1673
  /** Package version embedded by the bundler, with a source-test fallback. */
1673
- const SDK_VERSION = "1.2.0-rc.9";
1674
+ const SDK_VERSION = "1.2.0";
1674
1675
 
1675
1676
  //#endregion
1676
1677
  //#region src/utils/transport.ts
@@ -1731,7 +1732,7 @@ function buildRequestHeaders(wire, parts = {}) {
1731
1732
  entries.set(name.toLowerCase(), [name, value]);
1732
1733
  }
1733
1734
  };
1734
- if ((wire === null || wire === void 0 ? void 0 : wire.userAgent) !== false) put({ "User-Agent": (wire === null || wire === void 0 ? void 0 : wire.userAgent) ?? `GalaChain-SDK/${"1.2.0-rc.9"}` });
1735
+ if ((wire === null || wire === void 0 ? void 0 : wire.userAgent) !== false) put({ "User-Agent": (wire === null || wire === void 0 ? void 0 : wire.userAgent) ?? `GalaChain-SDK/${"1.2.0"}` });
1735
1736
  put(parts.defaults);
1736
1737
  put(wire === null || wire === void 0 ? void 0 : wire.headers);
1737
1738
  if (parts.json === true && !entries.has("content-type")) put({ "Content-Type": "application/json" });
@@ -2162,6 +2163,15 @@ function tickFromPrice(price, options = {}) {
2162
2163
 
2163
2164
  //#endregion
2164
2165
  //#region src/utils/validation.ts
2166
+ /**
2167
+ * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.
2168
+ *
2169
+ * @param amount - The amount to check.
2170
+ * @param parameterName - The field name reported in the error's `params.field`.
2171
+ * @param allowZero - Accept zero (default `false`).
2172
+ * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero
2173
+ * when `allowZero` is false) or `AMOUNT_NEGATIVE`.
2174
+ */
2165
2175
  function validateNumericAmount(amount, parameterName, allowZero = false) {
2166
2176
  if (typeof amount === "number") throw new GSwapSDKError("AMOUNT_IS_JS_NUMBER", { field: parameterName });
2167
2177
  let bnAmount;
@@ -2183,6 +2193,12 @@ function validateNumericAmount(amount, parameterName, allowZero = false) {
2183
2193
  value: String(amount)
2184
2194
  });
2185
2195
  }
2196
+ /**
2197
+ * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and
2198
+ * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.
2199
+ *
2200
+ * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.
2201
+ */
2186
2202
  function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
2187
2203
  if ([
2188
2204
  spotPrice,
@@ -2210,12 +2226,24 @@ function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
2210
2226
  upperPrice: String(upperPrice)
2211
2227
  });
2212
2228
  }
2229
+ /**
2230
+ * Validates a token's decimals: a non-negative integer.
2231
+ *
2232
+ * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).
2233
+ */
2213
2234
  function validateTokenDecimals(decimals, parameterName) {
2214
2235
  if (decimals < 0 || !Number.isInteger(decimals)) throw new GSwapSDKError("INVALID_TOKEN_DECIMALS", {
2215
2236
  field: parameterName,
2216
2237
  value: decimals
2217
2238
  });
2218
2239
  }
2240
+ /**
2241
+ * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within
2242
+ * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see
2243
+ * `assertTickRange`).
2244
+ *
2245
+ * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.
2246
+ */
2219
2247
  function validateTickRange(tickLower, tickUpper) {
2220
2248
  if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
2221
2249
  tickLower,
@@ -2232,6 +2260,11 @@ function validateTickRange(tickLower, tickUpper) {
2232
2260
  maxTick: GC_MAX_TICK
2233
2261
  });
2234
2262
  }
2263
+ /**
2264
+ * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).
2265
+ *
2266
+ * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).
2267
+ */
2235
2268
  function validateFee(fee) {
2236
2269
  if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) throw new GSwapSDKError("INVALID_FEE", {
2237
2270
  field: "fee",
@@ -2239,9 +2272,20 @@ function validateFee(fee) {
2239
2272
  allowed: ALLOWED_FEE_TIERS_TEXT
2240
2273
  });
2241
2274
  }
2275
+ /**
2276
+ * Validates a tick spacing: a positive integer.
2277
+ *
2278
+ * @throws GSwapSDKError `INVALID_TICK_SPACING`.
2279
+ */
2242
2280
  function validateTickSpacing(tickSpacing) {
2243
2281
  if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: tickSpacing });
2244
2282
  }
2283
+ /**
2284
+ * Asserts that a wallet address was given and is a non-blank string. It does not check the address
2285
+ * format.
2286
+ *
2287
+ * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS` (blank).
2288
+ */
2245
2289
  function validateWalletAddress(address) {
2246
2290
  if (address === void 0) throw new GSwapSDKError("MISSING_WALLET_ADDRESS", {});
2247
2291
  if (!address || typeof address !== "string" || address.trim().length === 0) throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
@@ -2724,9 +2768,13 @@ async function shadowFailures(run) {
2724
2768
  //#region src/classes/submitted_transaction.ts
2725
2769
  /** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */
2726
2770
  var SubmittedTransaction = class {
2771
+ /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */
2727
2772
  method;
2773
+ /** The write's durable correlation key: persist it, and confirm from it alone later. */
2728
2774
  uniqueKey;
2775
+ /** The request transaction id the gateway reported, or `null` when it gave none. */
2729
2776
  transactionId;
2777
+ /** The block of the transaction, when the answer carried one; otherwise `null`. */
2730
2778
  blockNumber;
2731
2779
  /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */
2732
2780
  mode;
@@ -2848,7 +2896,9 @@ var ChainGateway = class {
2848
2896
  chainCallTimeoutMs;
2849
2897
  isTransportFailure;
2850
2898
  answerOfRejectionHook;
2899
+ /** The request timeout in milliseconds (`Infinity` when no timer is armed). */
2851
2900
  requestTimeoutMs;
2901
+ /** The swap backend base URL every request is sent to, without a trailing slash. */
2852
2902
  dexBackendBaseUrl;
2853
2903
  /** Wire format shared by the read services built on this gateway. */
2854
2904
  wire;
@@ -2922,7 +2972,7 @@ var ChainGateway = class {
2922
2972
  *
2923
2973
  * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,
2924
2974
  * because shadow failures are classified from the status together with the body's `code`
2925
- * (`SHADOW_UNAVAILABLE`, `SHADOW_DISABLED`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);
2975
+ * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);
2926
2976
  * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with
2927
2977
  * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may
2928
2978
  * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object
@@ -3170,7 +3220,9 @@ function isGdexLiquidityEvent(value) {
3170
3220
  }
3171
3221
  /** A JSON-RPC error answered by the stream. */
3172
3222
  var GdexStreamError = class extends Error {
3223
+ /** The JSON-RPC error code. */
3173
3224
  code;
3225
+ /** The error's optional `data` member, as the server sent it. */
3174
3226
  data;
3175
3227
  constructor(code, message, data) {
3176
3228
  super(message);
@@ -3248,6 +3300,7 @@ var GdexStreamService = class {
3248
3300
  this.connectPromise = void 0;
3249
3301
  socket === null || socket === void 0 || socket.close(1e3, "client disconnect");
3250
3302
  }
3303
+ /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */
3251
3304
  isConnected() {
3252
3305
  var _this$socket;
3253
3306
  return ((_this$socket = this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.readyState) === WEBSOCKET_OPEN;
@@ -3289,30 +3342,41 @@ var GdexStreamService = class {
3289
3342
  }
3290
3343
  });
3291
3344
  }
3345
+ /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */
3292
3346
  serverInfo() {
3293
3347
  return this.request("gdex_serverInfo");
3294
3348
  }
3349
+ /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */
3295
3350
  ping() {
3296
3351
  return this.request("gdex_ping");
3297
3352
  }
3353
+ /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */
3298
3354
  getPool(selector) {
3299
3355
  return this.request("gdex_getPool", selector);
3300
3356
  }
3357
+ /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */
3301
3358
  getBalance(owner, tokenClassKey) {
3302
3359
  return this.request("gdex_getBalance", tokenClassKey === void 0 ? { owner } : {
3303
3360
  owner,
3304
3361
  tokenClassKey
3305
3362
  });
3306
3363
  }
3364
+ /**
3365
+ * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the
3366
+ * returned `bookmark` back in as `bookmark` for the next page.
3367
+ */
3307
3368
  getPositions(opts) {
3308
3369
  return this.request("gdex_getPositions", opts);
3309
3370
  }
3371
+ /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */
3310
3372
  getBlockHeight() {
3311
3373
  return this.request("gdex_getBlockHeight");
3312
3374
  }
3375
+ /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */
3313
3376
  quote(params) {
3314
3377
  return this.request("gdex_quote", params);
3315
3378
  }
3379
+ /** `gdex_getToken`: the server's record of one token class, as it sends it. */
3316
3380
  getToken(tokenClassKey) {
3317
3381
  return this.request("gdex_getToken", { tokenClassKey });
3318
3382
  }
@@ -4378,8 +4442,9 @@ const decimalString = (amount) => new bignumber_js.default(amount).toFixed();
4378
4442
  /**
4379
4443
  * Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or
4380
4444
  * `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the
4381
- * side's slippage bound and an optional `priceLimit`. Key order: `token0, token1, fee, uniqueKey,
4382
- * <quantity>, amountOutMinimum | amountInMaximum, priceLimit`.
4445
+ * side's slippage bound and an optional `priceLimit`. Key order is
4446
+ * `token0, token1, fee, uniqueKey`, then the one quantity, then the slippage bound, then
4447
+ * `priceLimit`.
4383
4448
  *
4384
4449
  * @example
4385
4450
  * ```ts
@@ -5567,21 +5632,21 @@ function toDecimalString(amount) {
5567
5632
  *
5568
5633
  * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back
5569
5634
  * silently to a public swap.
5570
- * - `SHADOW_DISABLED` (400): the feature is off for this environment.
5571
5635
  * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.
5572
5636
  * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;
5573
5637
  * `message` is the gateway's verbatim string.
5574
5638
  */
5575
5639
  const SHADOW_SUBMIT_CODES = [
5576
5640
  "SHADOW_UNAVAILABLE",
5577
- "SHADOW_DISABLED",
5578
5641
  "SHADOW_UNSUPPORTED_TYPE",
5579
5642
  "SHADOW_RELAY_REJECTED"
5580
5643
  ];
5581
5644
  /**
5582
5645
  * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text
5583
- * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled`, `rejected` (carries
5584
- * the gateway's `message`) and `unknown`.
5646
+ * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route
5647
+ * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow
5648
+ * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)
5649
+ * and `unknown`.
5585
5650
  */
5586
5651
  const SHADOW_FAILURE_KINDS = [
5587
5652
  "unavailable",
@@ -5598,12 +5663,12 @@ function classifyShadowSubmitStatus(status) {
5598
5663
  /**
5599
5664
  * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.
5600
5665
  * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway
5601
- * rejection; the two other 400 codes and any unknown 400 map to "disabled".
5666
+ * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to "disabled".
5602
5667
  */
5603
5668
  function classifyShadowSubmitError(status, code) {
5604
5669
  if (code === "SHADOW_UNAVAILABLE") return "unavailable";
5605
5670
  if (code === "SHADOW_RELAY_REJECTED") return "rejected";
5606
- if (code === "SHADOW_DISABLED" || code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5671
+ if (code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5607
5672
  return classifyShadowSubmitStatus(status);
5608
5673
  }
5609
5674
  function readShadowSubmitOutcome(method, signedBody, result) {
@@ -5845,27 +5910,43 @@ var Swaps = class {
5845
5910
 
5846
5911
  //#endregion
5847
5912
  //#region src/classes/gswap.ts
5848
- /** Main entry point for the current GalaChainDex SDK. */
5913
+ /**
5914
+ * Main entry point for the current GalaChainDex SDK: one client bundling the services that read
5915
+ * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,
5916
+ * `symbols`, `fees`, `stream`). See {@link GSwapOptions} for configuration.
5917
+ */
5849
5918
  var GSwap = class {
5919
+ /** The swap backend base URL every request goes to, without a trailing slash. */
5850
5920
  dexBackendBaseUrl;
5921
+ /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */
5851
5922
  chainCallTimeoutMs;
5923
+ /** The signer given at construction, if any. */
5852
5924
  signer;
5925
+ /** The account given at construction, if any. */
5853
5926
  walletAddress;
5927
+ /** The chain-gateway client every other service reads and writes through. */
5854
5928
  gateway;
5929
+ /** The trading-symbol registry. */
5855
5930
  symbols;
5931
+ /** Read-only exact-input and exact-output quotes. */
5856
5932
  quoting;
5933
+ /** Pool, slot0 and composite-pool reads. */
5857
5934
  pools;
5935
+ /** Position reads, liquidity estimates and liquidity / pool-creation writes. */
5858
5936
  positions;
5937
+ /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */
5859
5938
  swaps;
5939
+ /** User token balances. */
5860
5940
  assets;
5861
5941
  /** Network-fee quotes (DryRun) signed with this client's signer. */
5862
5942
  fees;
5943
+ /** The realtime stream endpoint {@link GSwap.stream} connects to. */
5863
5944
  dexBackendWsUrl;
5864
5945
  webSocketImpl;
5865
5946
  streamApiKey;
5866
5947
  streamClient;
5867
5948
  /**
5868
- * Create an SDK client for prod or stage.
5949
+ * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.
5869
5950
  *
5870
5951
  * @example
5871
5952
  * ```typescript
@@ -5950,10 +6031,10 @@ const DEFAULT_RETRYABLE = {
5950
6031
  * object, safe to mutate or freeze.
5951
6032
  *
5952
6033
  * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the
5953
- * SDK's own `not_queued` for a refusal the gateway will repeat is `classification('not_queued',
5954
- * { retryable: false })` (also exported, frozen, as {@link NOT_QUEUED_FINAL}). An app may take
5955
- * Retry away from an outcome but never grant it to one that cannot have it, so only `false` is
5956
- * accepted.
6034
+ * SDK's own `not_queued` for a refusal the gateway will repeat is
6035
+ * `classification('not_queued', { retryable: false })` (also exported, frozen, as
6036
+ * {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one
6037
+ * that cannot have it, so only `false` is accepted.
5957
6038
  *
5958
6039
  * @example
5959
6040
  * ```ts
@@ -7134,7 +7215,7 @@ function createLazyPrivateKeySigner(getPrivateKey, options = {}) {
7134
7215
  *
7135
7216
  * `scheme: 'personal-sign'` calls
7136
7217
  * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES
7137
- * a wallet build that contains wallet_extension commit 3ad7ae6 (strips the embedded `prefix`
7218
+ * a wallet build that contains wallet_extension commit 34ca4e4 (strips the embedded `prefix`
7138
7219
  * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets
7139
7220
  * released before that fix hash the string with the `prefix` field still inside it and the
7140
7221
  * signature recovers to an address nobody holds, so only opt in once the fixed wallet is
@@ -7159,7 +7240,7 @@ var GalaWalletSigner = class {
7159
7240
  * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits
7160
7241
  * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.
7161
7242
  * @param options - Select native signing (default) or personal-sign explicitly.
7162
- * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 3ad7ae6.
7243
+ * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 34ca4e4.
7163
7244
  * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with
7164
7245
  * `window.gala.setAddress` before every signature, when the wallet offers it.
7165
7246
  */
@@ -7240,6 +7321,7 @@ var BrowserWalletSigner = class {
7240
7321
  this.walletAddress = normalizeEthereumAccount(walletAddress, false);
7241
7322
  this.scheme = options.scheme ?? "personal-sign";
7242
7323
  }
7324
+ /** The selected `0x` Ethereum account every signature is requested for. */
7243
7325
  walletAddress;
7244
7326
  scheme;
7245
7327
  /**
@@ -7338,7 +7420,7 @@ function webStorageAdapter(area) {
7338
7420
  *
7339
7421
  * These are thin, byte-exact ports of the functions the wallet shipped in
7340
7422
  * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign
7341
- * payload resolver from its commit 3ad7ae6), re-expressed over the SDK's own primitives. Every
7423
+ * payload resolver from its commit 34ca4e4), re-expressed over the SDK's own primitives. Every
7342
7424
  * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per
7343
7425
  * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.
7344
7426
  * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.