@gala-chain/gswap-sdk 1.2.0-rc.8 → 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.
Files changed (56) hide show
  1. package/README.md +25 -10
  2. package/dist/browser/classes/dex_fees.js.map +1 -1
  3. package/dist/browser/classes/gateway.js.map +1 -1
  4. package/dist/browser/classes/gdex_stream.js.map +1 -1
  5. package/dist/browser/classes/gswap.js.map +1 -1
  6. package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
  7. package/dist/browser/classes/pending_swap_fate.js +2 -0
  8. package/dist/browser/classes/pending_swap_fate.js.map +1 -0
  9. package/dist/browser/classes/pending_swaps.js +1 -1
  10. package/dist/browser/classes/pending_swaps.js.map +1 -1
  11. package/dist/browser/classes/positions.js +1 -1
  12. package/dist/browser/classes/positions.js.map +1 -1
  13. package/dist/browser/classes/shadow_submit.js +1 -1
  14. package/dist/browser/classes/shadow_submit.js.map +1 -1
  15. package/dist/browser/classes/signers.js.map +1 -1
  16. package/dist/browser/classes/storage_adapters.js +2 -0
  17. package/dist/browser/classes/storage_adapters.js.map +1 -0
  18. package/dist/browser/classes/submitted_transaction.js.map +1 -1
  19. package/dist/browser/classes/symbols.js +1 -1
  20. package/dist/browser/classes/symbols.js.map +1 -1
  21. package/dist/browser/index.js +1 -1
  22. package/dist/browser/utils/chain_dto_signing.js.map +1 -1
  23. package/dist/browser/utils/class_key.js +2 -0
  24. package/dist/browser/utils/class_key.js.map +1 -0
  25. package/dist/browser/utils/classification.js +2 -0
  26. package/dist/browser/utils/classification.js.map +1 -0
  27. package/dist/browser/utils/dto_builders.js +1 -1
  28. package/dist/browser/utils/dto_builders.js.map +1 -1
  29. package/dist/browser/utils/eip712.js.map +1 -1
  30. package/dist/browser/utils/failure_classification.js +1 -1
  31. package/dist/browser/utils/failure_classification.js.map +1 -1
  32. package/dist/browser/utils/failure_guards.js +2 -0
  33. package/dist/browser/utils/failure_guards.js.map +1 -0
  34. package/dist/browser/utils/ordering.js +1 -1
  35. package/dist/browser/utils/ordering.js.map +1 -1
  36. package/dist/browser/utils/tick_align.js +2 -0
  37. package/dist/browser/utils/tick_align.js.map +1 -0
  38. package/dist/browser/utils/tick_math.js +2 -0
  39. package/dist/browser/utils/tick_math.js.map +1 -0
  40. package/dist/browser/utils/tick_range.js +2 -0
  41. package/dist/browser/utils/tick_range.js.map +1 -0
  42. package/dist/browser/utils/ticks.js +1 -1
  43. package/dist/browser/utils/ticks.js.map +1 -1
  44. package/dist/browser/utils/transport.js +1 -1
  45. package/dist/browser/utils/transport.js.map +1 -1
  46. package/dist/browser/utils/validation.js +1 -1
  47. package/dist/browser/utils/validation.js.map +1 -1
  48. package/dist/browser/version.js +1 -1
  49. package/dist/browser/version.js.map +1 -1
  50. package/dist/index.cjs +641 -336
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +470 -186
  53. package/dist/index.d.ts +470 -186
  54. package/dist/index.mjs +636 -337
  55. package/dist/index.mjs.map +1 -1
  56. package/package.json +1 -1
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.8";
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.8"}` });
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" });
@@ -2035,7 +2036,54 @@ const ALL_FEE_TIERS = [
2035
2036
  ];
2036
2037
 
2037
2038
  //#endregion
2038
- //#region src/utils/ticks.ts
2039
+ //#region src/utils/tick_range.ts
2040
+ function integerTickOf(tick) {
2041
+ if (typeof tick === "string") return tick.trim() === "" ? NaN : Number(tick);
2042
+ return tick;
2043
+ }
2044
+ /**
2045
+ * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick
2046
+ * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule
2047
+ * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a
2048
+ * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out
2049
+ * of range: the position is entirely token1 there, and a swap through the tick has crossed it.
2050
+ *
2051
+ * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than
2052
+ * the pool's price), not a rounded display value. A tick may be a number or the decimal string a
2053
+ * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a
2054
+ * fraction) makes the answer `false`: an app that must tell "not loaded yet" from "out of range"
2055
+ * checks for the missing value itself first.
2056
+ *
2057
+ * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both
2058
+ * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is
2059
+ * then in range at the upper edge (the contract says it is not), and two representations of the
2060
+ * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which
2061
+ * derives the tick the way the contract does and then applies this rule.
2062
+ *
2063
+ * @example
2064
+ * ```ts
2065
+ * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive
2066
+ * isTickInRange(60, -60, 60); // false: the upper tick is exclusive
2067
+ * ```
2068
+ */
2069
+ function isTickInRange(currentTick, tickLower, tickUpper) {
2070
+ const current = integerTickOf(currentTick);
2071
+ const lower = integerTickOf(tickLower);
2072
+ const upper = integerTickOf(tickUpper);
2073
+ if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) return false;
2074
+ return current >= lower && current < upper;
2075
+ }
2076
+
2077
+ //#endregion
2078
+ //#region src/utils/tick_math.ts
2079
+ /**
2080
+ * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the
2081
+ * conversions between ticks and prices, and nothing that validates a range. It imports only the
2082
+ * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog
2083
+ * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an
2084
+ * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of
2085
+ * error templates. A value that cannot be computed is `NaN`, never an exception.
2086
+ */
2039
2087
  /** Minimum tick supported by GalaChainDex. */
2040
2088
  const GC_MIN_TICK = -887272;
2041
2089
  /** Maximum tick supported by GalaChainDex. */
@@ -2044,6 +2092,7 @@ const DexMath = bignumber_js.default.clone({
2044
2092
  DECIMAL_PLACES: 60,
2045
2093
  ROUNDING_MODE: bignumber_js.default.ROUND_DOWN
2046
2094
  });
2095
+ /** `decimal.js` at the 60 significant digits the contract's price math is exact to. */
2047
2096
  const DexDecimal = decimal_js.Decimal.clone({ precision: 60 });
2048
2097
  /** Convert a tick to the corresponding square-root price. */
2049
2098
  function tickToSqrtPrice(tick) {
@@ -2078,6 +2127,26 @@ function tickToPrice(tick) {
2078
2127
  return new bignumber_js.default(new DexDecimal(1.0001).pow(tick).toString());
2079
2128
  }
2080
2129
  /**
2130
+ * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that
2131
+ * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as
2132
+ * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater
2133
+ * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,
2134
+ * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly
2135
+ * on `tickUpper`'s price is not, and no float rounding can flip either.
2136
+ *
2137
+ * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing
2138
+ * about the position, so an app that must show a neutral state checks for the missing price
2139
+ * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.
2140
+ *
2141
+ * @example
2142
+ * ```ts
2143
+ * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);
2144
+ * ```
2145
+ */
2146
+ function isSqrtPriceInRange(sqrtPrice, tickLower, tickUpper) {
2147
+ return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);
2148
+ }
2149
+ /**
2081
2150
  * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price
2082
2151
  * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that
2083
2152
  * is not positive and finite.
@@ -2091,77 +2160,18 @@ function tickFromPrice(price, options = {}) {
2091
2160
  const tick = (options.rounding === "nearest" ? exact.round() : exact.floor()).toNumber();
2092
2161
  return Number.isFinite(tick) ? tick : NaN;
2093
2162
  }
2094
- /** Align a tick down to the nearest multiple of a positive spacing. */
2095
- function alignTickDown(tick, spacing) {
2096
- assertSpacing(spacing);
2097
- return Math.floor(tick / spacing) * spacing;
2098
- }
2099
- /** Align a tick up to the nearest multiple of a positive spacing. */
2100
- function alignTickUp(tick, spacing) {
2101
- assertSpacing(spacing);
2102
- return Math.ceil(tick / spacing) * spacing;
2103
- }
2104
- /** Validate a position range against the global tick bounds and fee-tier spacing. */
2105
- function assertTickRange(lower, upper, fee) {
2106
- const spacing = TICK_SPACING_BY_FEE[fee];
2107
- if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
2108
- field: "fee",
2109
- value: fee,
2110
- allowed: ALLOWED_FEE_TIERS_TEXT
2111
- });
2112
- if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
2113
- tickLower: lower,
2114
- tickUpper: upper
2115
- });
2116
- if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
2117
- tickLower: lower,
2118
- tickUpper: upper
2119
- });
2120
- if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
2121
- tickLower: lower,
2122
- tickUpper: upper,
2123
- minTick: GC_MIN_TICK,
2124
- maxTick: GC_MAX_TICK
2125
- });
2126
- if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
2127
- tickLower: lower,
2128
- tickUpper: upper,
2129
- spacing
2130
- });
2131
- }
2132
- function assertSpacing(spacing) {
2133
- if (!Number.isInteger(spacing) || spacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
2134
- }
2135
- /**
2136
- * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
2137
- * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
2138
- * order the price is inverted here (at 60 significant digits, so a very large or very small
2139
- * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
2140
- * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
2141
- * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
2142
- *
2143
- * @example
2144
- * ```ts
2145
- * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
2146
- * const { sqrtPrice, tick } = frameSlot0(slot0);
2147
- * ```
2148
- */
2149
- function frameSlot0(slot0) {
2150
- if (slot0.flippedFromRequest !== true) return {
2151
- sqrtPrice: slot0.sqrtPrice,
2152
- tick: slot0.tick
2153
- };
2154
- const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
2155
- if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
2156
- const sqrtPrice = inverted.toString();
2157
- return {
2158
- sqrtPrice,
2159
- tick: sqrtPriceToTick(sqrtPrice)
2160
- };
2161
- }
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
  }
@@ -3645,39 +3709,13 @@ function finiteNumberOf(value) {
3645
3709
  }
3646
3710
 
3647
3711
  //#endregion
3648
- //#region src/utils/ordering.ts
3649
- /** Return two trading symbols in the contract's plain-string order. */
3650
- function orderSymbols(a, b) {
3651
- return a < b ? [a, b] : [b, a];
3652
- }
3653
- /** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
3654
- *
3655
- * @example
3656
- * ```ts
3657
- * const pair = readOrderedSymbols(['GALA', 'GUSDC']);
3658
- * console.log(pair.token0);
3659
- * ```
3712
+ //#region src/utils/class_key.ts
3713
+ /**
3714
+ * Token class keys that never throw: the `$`-joined composite key and the non-throwing parsers.
3715
+ * This module imports nothing at run time (the key type is erased), so an app shell that reads a
3716
+ * stored key pays for a few hundred bytes, never for the error class or the catalog. The parser
3717
+ * that THROWS an SDK error on a bad key (`parseTokenClassKey`) lives in `ordering.ts`.
3660
3718
  */
3661
- function readOrderedSymbols(value) {
3662
- if (Array.isArray(value) && value.length >= 2) {
3663
- const token0 = value[0];
3664
- const token1 = value[1];
3665
- if (typeof token0 === "string" && typeof token1 === "string") return {
3666
- token0,
3667
- token1
3668
- };
3669
- }
3670
- if (typeof value === "object" && value !== null) {
3671
- const record = value;
3672
- const token0 = record["token0"];
3673
- const token1 = record["token1"];
3674
- if (typeof token0 === "string" && typeof token1 === "string") return {
3675
- token0,
3676
- token1
3677
- };
3678
- }
3679
- throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
3680
- }
3681
3719
  /** Return the `$`-joined composite key used by GalaChain object identities. */
3682
3720
  function compositeKeyOf(token) {
3683
3721
  return [
@@ -3688,33 +3726,14 @@ function compositeKeyOf(token) {
3688
3726
  ].join("$");
3689
3727
  }
3690
3728
  /**
3691
- * Parse a pipe- or dollar-separated token class key.
3729
+ * Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
3730
+ * are fewer than four segments or any of the four is empty. The one place the split is written;
3731
+ * the strict `parseTokenClassKey` calls it too.
3692
3732
  *
3693
3733
  * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
3694
3734
  * them is the `collection`. Parsing from the right is required because real collections contain
3695
3735
  * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
3696
- * shifts every field. Nothing here says anything about the token's symbol: a class key carries
3697
- * no symbol, which must come from the token class or trading-symbol registry.
3698
- *
3699
- * @example
3700
- * ```ts
3701
- * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
3702
- * ```
3703
- */
3704
- function parseTokenClassKey(tokenClassKey) {
3705
- if (typeof tokenClassKey === "object") return {
3706
- collection: tokenClassKey.collection,
3707
- category: tokenClassKey.category,
3708
- type: tokenClassKey.type,
3709
- additionalKey: tokenClassKey.additionalKey
3710
- };
3711
- const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3712
- if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
3713
- return parsed;
3714
- }
3715
- /**
3716
- * Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
3717
- * are fewer than four segments or any of the four is empty. The one place the split is written.
3736
+ * shifts every field.
3718
3737
  */
3719
3738
  function splitClassKey(key, delimiter) {
3720
3739
  const segments = key.split(delimiter);
@@ -3730,7 +3749,7 @@ function splitClassKey(key, delimiter) {
3730
3749
  };
3731
3750
  }
3732
3751
  /**
3733
- * The non-throwing {@link parseTokenClassKey}: the class key, or `undefined` when `value` is not
3752
+ * The non-throwing `parseTokenClassKey`: the class key, or `undefined` when `value` is not
3734
3753
  * one. A string is split exactly as `parseTokenClassKey` splits it (`|` form when it contains a
3735
3754
  * `|`, else `$`, from the right, all four parts non-empty). Unlike `parseTokenClassKey`, an
3736
3755
  * object is VALIDATED, not just copied: all four fields must be non-empty strings. Anything else
@@ -3783,6 +3802,66 @@ function tryParseCompositeKey(value) {
3783
3802
  return typeof value === "string" ? splitClassKey(value, "$") : void 0;
3784
3803
  }
3785
3804
 
3805
+ //#endregion
3806
+ //#region src/utils/ordering.ts
3807
+ /** Return two trading symbols in the contract's plain-string order. */
3808
+ function orderSymbols(a, b) {
3809
+ return a < b ? [a, b] : [b, a];
3810
+ }
3811
+ /** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
3812
+ *
3813
+ * @example
3814
+ * ```ts
3815
+ * const pair = readOrderedSymbols(['GALA', 'GUSDC']);
3816
+ * console.log(pair.token0);
3817
+ * ```
3818
+ */
3819
+ function readOrderedSymbols(value) {
3820
+ if (Array.isArray(value) && value.length >= 2) {
3821
+ const token0 = value[0];
3822
+ const token1 = value[1];
3823
+ if (typeof token0 === "string" && typeof token1 === "string") return {
3824
+ token0,
3825
+ token1
3826
+ };
3827
+ }
3828
+ if (typeof value === "object" && value !== null) {
3829
+ const record = value;
3830
+ const token0 = record["token0"];
3831
+ const token1 = record["token1"];
3832
+ if (typeof token0 === "string" && typeof token1 === "string") return {
3833
+ token0,
3834
+ token1
3835
+ };
3836
+ }
3837
+ throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
3838
+ }
3839
+ /**
3840
+ * Parse a pipe- or dollar-separated token class key.
3841
+ *
3842
+ * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
3843
+ * them is the `collection`. Parsing from the right is required because real collections contain
3844
+ * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
3845
+ * shifts every field. Nothing here says anything about the token's symbol: a class key carries
3846
+ * no symbol, which must come from the token class or trading-symbol registry.
3847
+ *
3848
+ * @example
3849
+ * ```ts
3850
+ * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
3851
+ * ```
3852
+ */
3853
+ function parseTokenClassKey(tokenClassKey) {
3854
+ if (typeof tokenClassKey === "object") return {
3855
+ collection: tokenClassKey.collection,
3856
+ category: tokenClassKey.category,
3857
+ type: tokenClassKey.type,
3858
+ additionalKey: tokenClassKey.additionalKey
3859
+ };
3860
+ const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3861
+ if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
3862
+ return parsed;
3863
+ }
3864
+
3786
3865
  //#endregion
3787
3866
  //#region src/classes/symbols.ts
3788
3867
  const SYMBOL_CACHE_TTL_MS = 6e4;
@@ -4201,37 +4280,151 @@ function parsePoolListInfo(entry) {
4201
4280
  }
4202
4281
 
4203
4282
  //#endregion
4204
- //#region src/utils/unique_key.ts
4283
+ //#region src/utils/tick_align.ts
4205
4284
  /**
4206
- * The `uniqueKey` prefix frontend_v2 and wallet_extension have always sent
4207
- * (`galaswap-operation-<uuid>`). defi-backend does not depend on it: the chain-write verifier
4208
- * only requires a non-empty key of at most 256 characters, and apply-results accepts
4209
- * `[A-Za-z0-9._:-]{1,128}`; the only code that mints a prefixed key itself is the server-side v1
4210
- * trade builder, which nothing reads back by prefix.
4285
+ * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an
4286
+ * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error
4287
+ * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they
4288
+ * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.
4211
4289
  */
4212
- const DEFAULT_UNIQUE_KEY_PREFIX = "galaswap-operation-";
4213
- /** A canonical UUID is 36 characters; the apply-results key limit is 128. */
4214
- const MAX_UNIQUE_KEY_PREFIX_LENGTH = 92;
4215
- const UNIQUE_KEY_PREFIX_PATTERN = /^[A-Za-z0-9._:-]*$/u;
4290
+ /** True for a tick spacing the contract can use: a positive integer. The one definition. */
4291
+ function hasValidSpacing(spacing) {
4292
+ return Number.isInteger(spacing) && spacing > 0;
4293
+ }
4216
4294
  /**
4217
- * Validates a caller-supplied `uniqueKey` prefix. The whole key (`<prefix><uuid>`) must stay a
4218
- * valid apply-results key, otherwise `confirm()` could never read the outcome of the write.
4295
+ * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`
4296
+ * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose
4297
+ * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,
4298
+ * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use
4299
+ * it) gives the same value and throws for the bad spacing.
4219
4300
  *
4220
- * @throws GSwapSDKError `INVALID_UNIQUE_KEY_PREFIX` when the prefix has characters outside
4221
- * `A-Za-z0-9._:-` or is longer than 92 characters.
4301
+ * @example
4302
+ * ```ts
4303
+ * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero
4304
+ * alignTickDownOrNaN(100, 0); // NaN
4305
+ * ```
4222
4306
  */
4223
- function resolveUniqueKeyPrefix(prefix) {
4224
- if (prefix === void 0) return DEFAULT_UNIQUE_KEY_PREFIX;
4225
- if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
4226
- uniqueKeyPrefix: prefix,
4227
- maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
4228
- });
4229
- return prefix;
4307
+ function alignTickDownOrNaN(tick, spacing) {
4308
+ return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : NaN;
4230
4309
  }
4231
4310
  /**
4232
- * Validates a caller-supplied write `uniqueKey`: 1 to 128 characters of `A-Za-z0-9._:-`, the
4233
- * shape the apply-results route accepts, so the write's outcome can always be read back with
4234
- * `confirm()`. A key is one attempt's identity: reuse it only to retry that same attempt.
4311
+ * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that
4312
+ * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See
4313
+ * {@link alignTickDownOrNaN}.
4314
+ */
4315
+ function alignTickUpOrNaN(tick, spacing) {
4316
+ return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : NaN;
4317
+ }
4318
+
4319
+ //#endregion
4320
+ //#region src/utils/ticks.ts
4321
+ /**
4322
+ * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,
4323
+ * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,
4324
+ * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which
4325
+ * does not import the error class or the catalog; import it from the package entry as usual.
4326
+ */
4327
+ /** Align a tick down to the nearest multiple of a positive spacing. */
4328
+ function alignTickDown(tick, spacing) {
4329
+ assertSpacing(spacing);
4330
+ return alignTickDownOrNaN(tick, spacing);
4331
+ }
4332
+ /** Align a tick up to the nearest multiple of a positive spacing. */
4333
+ function alignTickUp(tick, spacing) {
4334
+ assertSpacing(spacing);
4335
+ return alignTickUpOrNaN(tick, spacing);
4336
+ }
4337
+ /** Validate a position range against the global tick bounds and fee-tier spacing. */
4338
+ function assertTickRange(lower, upper, fee) {
4339
+ const spacing = TICK_SPACING_BY_FEE[fee];
4340
+ if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
4341
+ field: "fee",
4342
+ value: fee,
4343
+ allowed: ALLOWED_FEE_TIERS_TEXT
4344
+ });
4345
+ if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
4346
+ tickLower: lower,
4347
+ tickUpper: upper
4348
+ });
4349
+ if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
4350
+ tickLower: lower,
4351
+ tickUpper: upper
4352
+ });
4353
+ if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
4354
+ tickLower: lower,
4355
+ tickUpper: upper,
4356
+ minTick: GC_MIN_TICK,
4357
+ maxTick: GC_MAX_TICK
4358
+ });
4359
+ if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
4360
+ tickLower: lower,
4361
+ tickUpper: upper,
4362
+ spacing
4363
+ });
4364
+ }
4365
+ function assertSpacing(spacing) {
4366
+ if (!hasValidSpacing(spacing)) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
4367
+ }
4368
+ /**
4369
+ * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
4370
+ * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
4371
+ * order the price is inverted here (at 60 significant digits, so a very large or very small
4372
+ * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
4373
+ * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
4374
+ * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
4375
+ *
4376
+ * @example
4377
+ * ```ts
4378
+ * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
4379
+ * const { sqrtPrice, tick } = frameSlot0(slot0);
4380
+ * ```
4381
+ */
4382
+ function frameSlot0(slot0) {
4383
+ if (slot0.flippedFromRequest !== true) return {
4384
+ sqrtPrice: slot0.sqrtPrice,
4385
+ tick: slot0.tick
4386
+ };
4387
+ const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
4388
+ if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
4389
+ const sqrtPrice = inverted.toString();
4390
+ return {
4391
+ sqrtPrice,
4392
+ tick: sqrtPriceToTick(sqrtPrice)
4393
+ };
4394
+ }
4395
+
4396
+ //#endregion
4397
+ //#region src/utils/unique_key.ts
4398
+ /**
4399
+ * The `uniqueKey` prefix frontend_v2 and wallet_extension have always sent
4400
+ * (`galaswap-operation-<uuid>`). defi-backend does not depend on it: the chain-write verifier
4401
+ * only requires a non-empty key of at most 256 characters, and apply-results accepts
4402
+ * `[A-Za-z0-9._:-]{1,128}`; the only code that mints a prefixed key itself is the server-side v1
4403
+ * trade builder, which nothing reads back by prefix.
4404
+ */
4405
+ const DEFAULT_UNIQUE_KEY_PREFIX = "galaswap-operation-";
4406
+ /** A canonical UUID is 36 characters; the apply-results key limit is 128. */
4407
+ const MAX_UNIQUE_KEY_PREFIX_LENGTH = 92;
4408
+ const UNIQUE_KEY_PREFIX_PATTERN = /^[A-Za-z0-9._:-]*$/u;
4409
+ /**
4410
+ * Validates a caller-supplied `uniqueKey` prefix. The whole key (`<prefix><uuid>`) must stay a
4411
+ * valid apply-results key, otherwise `confirm()` could never read the outcome of the write.
4412
+ *
4413
+ * @throws GSwapSDKError `INVALID_UNIQUE_KEY_PREFIX` when the prefix has characters outside
4414
+ * `A-Za-z0-9._:-` or is longer than 92 characters.
4415
+ */
4416
+ function resolveUniqueKeyPrefix(prefix) {
4417
+ if (prefix === void 0) return DEFAULT_UNIQUE_KEY_PREFIX;
4418
+ if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
4419
+ uniqueKeyPrefix: prefix,
4420
+ maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
4421
+ });
4422
+ return prefix;
4423
+ }
4424
+ /**
4425
+ * Validates a caller-supplied write `uniqueKey`: 1 to 128 characters of `A-Za-z0-9._:-`, the
4426
+ * shape the apply-results route accepts, so the write's outcome can always be read back with
4427
+ * `confirm()`. A key is one attempt's identity: reuse it only to retry that same attempt.
4235
4428
  *
4236
4429
  * @throws GSwapSDKError `INVALID_UNIQUE_KEY` otherwise.
4237
4430
  */
@@ -4249,8 +4442,9 @@ const decimalString = (amount) => new bignumber_js.default(amount).toFixed();
4249
4442
  /**
4250
4443
  * Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or
4251
4444
  * `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the
4252
- * side's slippage bound and an optional `priceLimit`. Key order: `token0, token1, fee, uniqueKey,
4253
- * <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`.
4254
4448
  *
4255
4449
  * @example
4256
4450
  * ```ts
@@ -5438,21 +5632,21 @@ function toDecimalString(amount) {
5438
5632
  *
5439
5633
  * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back
5440
5634
  * silently to a public swap.
5441
- * - `SHADOW_DISABLED` (400): the feature is off for this environment.
5442
5635
  * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.
5443
5636
  * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;
5444
5637
  * `message` is the gateway's verbatim string.
5445
5638
  */
5446
5639
  const SHADOW_SUBMIT_CODES = [
5447
5640
  "SHADOW_UNAVAILABLE",
5448
- "SHADOW_DISABLED",
5449
5641
  "SHADOW_UNSUPPORTED_TYPE",
5450
5642
  "SHADOW_RELAY_REJECTED"
5451
5643
  ];
5452
5644
  /**
5453
5645
  * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text
5454
- * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled`, `rejected` (carries
5455
- * 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`.
5456
5650
  */
5457
5651
  const SHADOW_FAILURE_KINDS = [
5458
5652
  "unavailable",
@@ -5469,12 +5663,12 @@ function classifyShadowSubmitStatus(status) {
5469
5663
  /**
5470
5664
  * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.
5471
5665
  * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway
5472
- * 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".
5473
5667
  */
5474
5668
  function classifyShadowSubmitError(status, code) {
5475
5669
  if (code === "SHADOW_UNAVAILABLE") return "unavailable";
5476
5670
  if (code === "SHADOW_RELAY_REJECTED") return "rejected";
5477
- if (code === "SHADOW_DISABLED" || code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5671
+ if (code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5478
5672
  return classifyShadowSubmitStatus(status);
5479
5673
  }
5480
5674
  function readShadowSubmitOutcome(method, signedBody, result) {
@@ -5716,27 +5910,43 @@ var Swaps = class {
5716
5910
 
5717
5911
  //#endregion
5718
5912
  //#region src/classes/gswap.ts
5719
- /** 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
+ */
5720
5918
  var GSwap = class {
5919
+ /** The swap backend base URL every request goes to, without a trailing slash. */
5721
5920
  dexBackendBaseUrl;
5921
+ /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */
5722
5922
  chainCallTimeoutMs;
5923
+ /** The signer given at construction, if any. */
5723
5924
  signer;
5925
+ /** The account given at construction, if any. */
5724
5926
  walletAddress;
5927
+ /** The chain-gateway client every other service reads and writes through. */
5725
5928
  gateway;
5929
+ /** The trading-symbol registry. */
5726
5930
  symbols;
5931
+ /** Read-only exact-input and exact-output quotes. */
5727
5932
  quoting;
5933
+ /** Pool, slot0 and composite-pool reads. */
5728
5934
  pools;
5935
+ /** Position reads, liquidity estimates and liquidity / pool-creation writes. */
5729
5936
  positions;
5937
+ /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */
5730
5938
  swaps;
5939
+ /** User token balances. */
5731
5940
  assets;
5732
5941
  /** Network-fee quotes (DryRun) signed with this client's signer. */
5733
5942
  fees;
5943
+ /** The realtime stream endpoint {@link GSwap.stream} connects to. */
5734
5944
  dexBackendWsUrl;
5735
5945
  webSocketImpl;
5736
5946
  streamApiKey;
5737
5947
  streamClient;
5738
5948
  /**
5739
- * 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.
5740
5950
  *
5741
5951
  * @example
5742
5952
  * ```typescript
@@ -5800,10 +6010,10 @@ function trimTrailingSlash(value) {
5800
6010
  }
5801
6011
 
5802
6012
  //#endregion
5803
- //#region src/utils/failure_classification.ts
6013
+ //#region src/utils/classification.ts
5804
6014
  /**
5805
6015
  * The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the
5806
- * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table below.
6016
+ * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.
5807
6017
  */
5808
6018
  const DEFAULT_RETRYABLE = {
5809
6019
  rejected: true,
@@ -5821,10 +6031,10 @@ const DEFAULT_RETRYABLE = {
5821
6031
  * object, safe to mutate or freeze.
5822
6032
  *
5823
6033
  * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the
5824
- * SDK's own `not_queued` for a refusal the gateway will repeat is `classification('not_queued',
5825
- * { retryable: false })` (also exported, frozen, as {@link NOT_QUEUED_FINAL}). An app may take
5826
- * Retry away from an outcome but never grant it to one that cannot have it, so only `false` is
5827
- * 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.
5828
6038
  *
5829
6039
  * @example
5830
6040
  * ```ts
@@ -5855,6 +6065,15 @@ const NOT_QUEUED_FINAL = Object.freeze(classification("not_queued", { retryable:
5855
6065
  function notSentClassification() {
5856
6066
  return classification("not_sent");
5857
6067
  }
6068
+
6069
+ //#endregion
6070
+ //#region src/utils/failure_classification.ts
6071
+ /**
6072
+ * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every
6073
+ * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing
6074
+ * else: the classification values live in `classification.ts`, the yes/no guards in
6075
+ * `failure_guards.ts`, and the error class and catalog are only named as types.
6076
+ */
5858
6077
  const REJECTED = classification("rejected");
5859
6078
  const UNKNOWN = classification("unknown");
5860
6079
  const NOT_QUEUED = classification("not_queued");
@@ -5954,90 +6173,6 @@ function classifyChainDispatchFailed(view) {
5954
6173
  return status === 422 ? REJECTED : NOT_QUEUED;
5955
6174
  }
5956
6175
  /**
5957
- * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
5958
- * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
5959
- * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
5960
- * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
5961
- * error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
5962
- * view ({@link FailureView}: `code` and `status`); every other value is `false`.
5963
- *
5964
- * @example
5965
- * ```ts
5966
- * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
5967
- * ```
5968
- */
5969
- function isUniqueKeyConsumed(error) {
5970
- const view = toFailureView(error);
5971
- return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
5972
- }
5973
- const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
5974
- "GATEWAY_DATA_MISSING",
5975
- "GATEWAY_MODE_INVALID",
5976
- "GATEWAY_SYNC_REQUEST_TRADE",
5977
- "MISSING_UNIQUE_KEY",
5978
- "UNIQUE_KEY_MISMATCH"
5979
- ];
5980
- /**
5981
- * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
5982
- * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
5983
- * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
5984
- * app shows is one line for all five ("the backend did not confirm it queued the request"), so
5985
- * the app asks this instead of keeping its own list of the codes. A gateway that says
5986
- * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
5987
- *
5988
- * @example
5989
- * ```ts
5990
- * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
5991
- * ```
5992
- */
5993
- function isUnprovenAcknowledgement(error) {
5994
- return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
5995
- }
5996
- /** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
5997
- function isCodeIn(code, codes) {
5998
- return codes.some((known) => known === code);
5999
- }
6000
- /**
6001
- * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
6002
- * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
6003
- * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
6004
- */
6005
- function hasCodeIn(error, codes) {
6006
- const view = toFailureView(error);
6007
- return view !== void 0 && isCodeIn(view.code, codes);
6008
- }
6009
- /**
6010
- * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
6011
- * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
6012
- * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
6013
- * SDK knows, and `GATEWAY_REJECTED` for one it does not).
6014
- */
6015
- const RELAYABLE_REFUSAL_CODES = [
6016
- "GATEWAY_REPORTED_ERROR",
6017
- "METHOD_NOT_ALLOWED",
6018
- "SIGNATURE_INVALID",
6019
- "SIGNER_MISMATCH",
6020
- "DTO_INVALID",
6021
- "BOUNDS_VIOLATION",
6022
- "SYMBOL_CONFLICT",
6023
- "RATE_LIMITED",
6024
- "CHAIN_DISPATCH_FAILED",
6025
- "GATEWAY_REJECTED"
6026
- ];
6027
- function isRelayableRefusal(error) {
6028
- return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
6029
- }
6030
- /**
6031
- * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
6032
- * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
6033
- * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
6034
- * The outcome is `unknown` for all six. It replaces the app's own
6035
- * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
6036
- */
6037
- function isUninterpretedAnswer(error) {
6038
- return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
6039
- }
6040
- /**
6041
6176
  * Classifies any thrown value from its code (and, for two codes, its HTTP status), never from
6042
6177
  * message text, so an app does not have to re-derive "may I offer Retry?" and "is the outcome
6043
6178
  * unknown?" for every code. The decision for each code is in this module's table; a new catalog
@@ -6114,34 +6249,6 @@ function classifyView(view) {
6114
6249
  if (code === "INVALID_PRIVATE_KEY") return { ...classifyInvalidPrivateKey(view) };
6115
6250
  return { ...BY_CODE[code] ?? INVALID_INPUT };
6116
6251
  }
6117
- /** Codes that mean "there is no market for this" however the app reached them. */
6118
- const NO_MARKET_CODES = [
6119
- "NO_POOL_AVAILABLE",
6120
- "INSUFFICIENT_LIQUIDITY",
6121
- "UNKNOWN_TOKEN"
6122
- ];
6123
- /**
6124
- * True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
6125
- * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
6126
- * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
6127
- * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
6128
- * notFound` list, so the empty-state ("No market for this pair") has one definition.
6129
- *
6130
- * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
6131
- * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
6132
- * other value is `false`.
6133
- *
6134
- * @example
6135
- * ```ts
6136
- * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
6137
- * ```
6138
- */
6139
- function isNoMarket(error) {
6140
- const view = toFailureView(error);
6141
- if (view === void 0) return false;
6142
- if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
6143
- return !isWriteView(view) && (view.notFound === true || view.status === 404);
6144
- }
6145
6252
  /**
6146
6253
  * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is
6147
6254
  * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after
@@ -6168,59 +6275,7 @@ function mayHaveBeenQueued(error) {
6168
6275
  }
6169
6276
 
6170
6277
  //#endregion
6171
- //#region src/classes/pending_swaps.ts
6172
- /** Key the wallet_extension has always used; its storage value is a plain array of entries. */
6173
- const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
6174
- /** Entries older than this are dropped the next time a wallet's swaps are listed. */
6175
- const PENDING_SWAP_EXPIRY_MS = 6048e5;
6176
- /**
6177
- * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
6178
- * in: the value lands under the key as the structured value it is (the browser clones it; nothing
6179
- * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
6180
- * store, which treats it as "storage unavailable".
6181
- *
6182
- * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
6183
- * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
6184
- * context) then fails only when the store touches storage, and that failure (a throw inside the
6185
- * function) is the same "storage unavailable" rejection.
6186
- *
6187
- * @example
6188
- * ```ts
6189
- * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
6190
- * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
6191
- * ```
6192
- */
6193
- function storageAdapterFromChromeStorage(area) {
6194
- const areaNow = () => typeof area === "function" ? area() : area;
6195
- return {
6196
- async get(key) {
6197
- const items = await areaNow().get(key);
6198
- return Object.hasOwn(items, key) ? items[key] : void 0;
6199
- },
6200
- async set(key, value) {
6201
- await areaNow().set({ [key]: value });
6202
- }
6203
- };
6204
- }
6205
- /**
6206
- * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
6207
- *
6208
- * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
6209
- * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
6210
- * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
6211
- * before reading anything and always will, so keeping the entry would retry it forever. The
6212
- * SDK never signs such a key; an entry like this is corrupt or foreign.
6213
- * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
6214
- * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
6215
- * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
6216
- * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
6217
- */
6218
- const PENDING_SWAP_PRUNE_REASONS = [
6219
- "expired",
6220
- "invalid_unique_key",
6221
- "chain_rejected",
6222
- "unconfirmable"
6223
- ];
6278
+ //#region src/classes/pending_swap_fate.ts
6224
6279
  /**
6225
6280
  * What to do with a pending swap after confirming it failed (the answer of
6226
6281
  * {@link pendingSwapFateFor}).
@@ -6230,6 +6285,9 @@ const PENDING_SWAP_PRUNE_REASONS = [
6230
6285
  * Drop it without claiming anything about the trade.
6231
6286
  * - `keep`: the trade may still have been applied (a timeout, a broken connection, a gateway
6232
6287
  * hiccup, anything not proven). Leave it pending and look again later.
6288
+ *
6289
+ * This module holds the decision and nothing of the store, so an app shell that only needs the
6290
+ * fate pays for `classifyFailure` and this table, not for `PendingSwapStore`.
6233
6291
  */
6234
6292
  const PENDING_SWAP_FATES = [
6235
6293
  "forget",
@@ -6278,6 +6336,32 @@ function pendingSwapFateOfOutcome(outcome) {
6278
6336
  function pendingSwapFateFor(error) {
6279
6337
  return pendingSwapFateOfOutcome(classifyFailure(error, { afterQueued: true }).outcome);
6280
6338
  }
6339
+
6340
+ //#endregion
6341
+ //#region src/classes/pending_swaps.ts
6342
+ /** Key the wallet_extension has always used; its storage value is a plain array of entries. */
6343
+ const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
6344
+ /** Entries older than this are dropped the next time a wallet's swaps are listed. */
6345
+ const PENDING_SWAP_EXPIRY_MS = 6048e5;
6346
+ /**
6347
+ * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
6348
+ *
6349
+ * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
6350
+ * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
6351
+ * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
6352
+ * before reading anything and always will, so keeping the entry would retry it forever. The
6353
+ * SDK never signs such a key; an entry like this is corrupt or foreign.
6354
+ * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
6355
+ * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
6356
+ * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
6357
+ * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
6358
+ */
6359
+ const PENDING_SWAP_PRUNE_REASONS = [
6360
+ "expired",
6361
+ "invalid_unique_key",
6362
+ "chain_rejected",
6363
+ "unconfirmable"
6364
+ ];
6281
6365
  /**
6282
6366
  * Remembers queued swaps so their outcome can be confirmed after the UI, popup or service worker
6283
6367
  * that submitted them is gone (`confirmAppliedTrade` with the stored `uniqueKey`).
@@ -7131,7 +7215,7 @@ function createLazyPrivateKeySigner(getPrivateKey, options = {}) {
7131
7215
  *
7132
7216
  * `scheme: 'personal-sign'` calls
7133
7217
  * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES
7134
- * 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`
7135
7219
  * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets
7136
7220
  * released before that fix hash the string with the `prefix` field still inside it and the
7137
7221
  * signature recovers to an address nobody holds, so only opt in once the fixed wallet is
@@ -7156,7 +7240,7 @@ var GalaWalletSigner = class {
7156
7240
  * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits
7157
7241
  * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.
7158
7242
  * @param options - Select native signing (default) or personal-sign explicitly.
7159
- * `'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.
7160
7244
  * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with
7161
7245
  * `window.gala.setAddress` before every signature, when the wallet offers it.
7162
7246
  */
@@ -7237,6 +7321,7 @@ var BrowserWalletSigner = class {
7237
7321
  this.walletAddress = normalizeEthereumAccount(walletAddress, false);
7238
7322
  this.scheme = options.scheme ?? "personal-sign";
7239
7323
  }
7324
+ /** The selected `0x` Ethereum account every signature is requested for. */
7240
7325
  walletAddress;
7241
7326
  scheme;
7242
7327
  /**
@@ -7259,6 +7344,74 @@ var BrowserWalletSigner = class {
7259
7344
  }
7260
7345
  };
7261
7346
 
7347
+ //#endregion
7348
+ //#region src/classes/storage_adapters.ts
7349
+ /**
7350
+ * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
7351
+ * in: the value lands under the key as the structured value it is (the browser clones it; nothing
7352
+ * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
7353
+ * store, which treats it as "storage unavailable".
7354
+ *
7355
+ * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
7356
+ * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
7357
+ * context) then fails only when the store touches storage, and that failure (a throw inside the
7358
+ * function) is the same "storage unavailable" rejection.
7359
+ *
7360
+ * @example
7361
+ * ```ts
7362
+ * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
7363
+ * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
7364
+ * ```
7365
+ */
7366
+ function storageAdapterFromChromeStorage(area) {
7367
+ const areaNow = () => typeof area === "function" ? area() : area;
7368
+ return {
7369
+ async get(key) {
7370
+ const items = await areaNow().get(key);
7371
+ return Object.hasOwn(items, key) ? items[key] : void 0;
7372
+ },
7373
+ async set(key, value) {
7374
+ await areaNow().set({ [key]: value });
7375
+ }
7376
+ };
7377
+ }
7378
+ /**
7379
+ * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape
7380
+ * frontend_v2 stores pending swaps in: the value lands under the key as JSON text. A missing key
7381
+ * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store
7382
+ * reads a value that is not an array as "no entries" and the next write repairs it, whereas a
7383
+ * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked
7384
+ * by the browser, quota exceeded on `setItem`) rejects, which the store treats as "storage
7385
+ * unavailable".
7386
+ *
7387
+ * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
7388
+ * built: where `localStorage` does not exist (server rendering, a test, a blocked context)
7389
+ * the access throws inside the function, which is the same "storage unavailable" rejection, and
7390
+ * the module that builds the adapter still loads.
7391
+ *
7392
+ * @example
7393
+ * ```ts
7394
+ * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));
7395
+ * ```
7396
+ */
7397
+ function webStorageAdapter(area) {
7398
+ const areaNow = () => typeof area === "function" ? area() : area;
7399
+ return {
7400
+ async get(key) {
7401
+ const raw = areaNow().getItem(key);
7402
+ if (raw === null) return void 0;
7403
+ try {
7404
+ return JSON.parse(raw);
7405
+ } catch {
7406
+ return raw;
7407
+ }
7408
+ },
7409
+ async set(key, value) {
7410
+ areaNow().setItem(key, JSON.stringify(value));
7411
+ }
7412
+ };
7413
+ }
7414
+
7262
7415
  //#endregion
7263
7416
  //#region src/utils/chain_dto_signing.ts
7264
7417
  /**
@@ -7267,7 +7420,7 @@ var BrowserWalletSigner = class {
7267
7420
  *
7268
7421
  * These are thin, byte-exact ports of the functions the wallet shipped in
7269
7422
  * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign
7270
- * 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
7271
7424
  * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per
7272
7425
  * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.
7273
7426
  * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.
@@ -7988,6 +8141,152 @@ function isFetchTransportFailure(error) {
7988
8141
  }
7989
8142
  }
7990
8143
 
8144
+ //#endregion
8145
+ //#region src/utils/failure_guards.ts
8146
+ /**
8147
+ * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure
8148
+ * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in
8149
+ * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased
8150
+ * at build time). An app shell that imports one of them pays for this module and nothing else.
8151
+ */
8152
+ /**
8153
+ * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
8154
+ * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
8155
+ * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
8156
+ * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
8157
+ * error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
8158
+ * view ({@link FailureView}: `code` and `status`); every other value is `false`.
8159
+ *
8160
+ * @example
8161
+ * ```ts
8162
+ * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
8163
+ * ```
8164
+ */
8165
+ function isUniqueKeyConsumed(error) {
8166
+ const view = toFailureView(error);
8167
+ return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
8168
+ }
8169
+ const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
8170
+ "GATEWAY_DATA_MISSING",
8171
+ "GATEWAY_MODE_INVALID",
8172
+ "GATEWAY_SYNC_REQUEST_TRADE",
8173
+ "MISSING_UNIQUE_KEY",
8174
+ "UNIQUE_KEY_MISMATCH"
8175
+ ];
8176
+ /**
8177
+ * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
8178
+ * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
8179
+ * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
8180
+ * app shows is one line for all five ("the backend did not confirm it queued the request"), so
8181
+ * the app asks this instead of keeping its own list of the codes. A gateway that says
8182
+ * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
8183
+ *
8184
+ * @example
8185
+ * ```ts
8186
+ * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
8187
+ * ```
8188
+ */
8189
+ function isUnprovenAcknowledgement(error) {
8190
+ return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
8191
+ }
8192
+ /** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
8193
+ function isCodeIn(code, codes) {
8194
+ return codes.some((known) => known === code);
8195
+ }
8196
+ /**
8197
+ * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
8198
+ * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
8199
+ * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
8200
+ */
8201
+ function hasCodeIn(error, codes) {
8202
+ const view = toFailureView(error);
8203
+ return view !== void 0 && isCodeIn(view.code, codes);
8204
+ }
8205
+ /**
8206
+ * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
8207
+ * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
8208
+ * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
8209
+ * SDK knows, and `GATEWAY_REJECTED` for one it does not).
8210
+ */
8211
+ const RELAYABLE_REFUSAL_CODES = [
8212
+ "GATEWAY_REPORTED_ERROR",
8213
+ "METHOD_NOT_ALLOWED",
8214
+ "SIGNATURE_INVALID",
8215
+ "SIGNER_MISMATCH",
8216
+ "DTO_INVALID",
8217
+ "BOUNDS_VIOLATION",
8218
+ "SYMBOL_CONFLICT",
8219
+ "RATE_LIMITED",
8220
+ "CHAIN_DISPATCH_FAILED",
8221
+ "GATEWAY_REJECTED"
8222
+ ];
8223
+ function isRelayableRefusal(error) {
8224
+ return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
8225
+ }
8226
+ /**
8227
+ * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
8228
+ * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
8229
+ * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
8230
+ * The outcome is `unknown` for all six. It replaces the app's own
8231
+ * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
8232
+ */
8233
+ function isUninterpretedAnswer(error) {
8234
+ return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
8235
+ }
8236
+ /**
8237
+ * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,
8238
+ * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the
8239
+ * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's
8240
+ * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it
8241
+ * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent
8242
+ * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.
8243
+ *
8244
+ * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every
8245
+ * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named
8246
+ * param, so a stray field cannot pass for a chain verdict.
8247
+ *
8248
+ * @example
8249
+ * ```ts
8250
+ * const key = chainErrorKeyOf(error);
8251
+ * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);
8252
+ * ```
8253
+ */
8254
+ function chainErrorKeyOf(error) {
8255
+ const view = toFailureView(error);
8256
+ if (view === void 0) return void 0;
8257
+ if (view.code !== "CHAIN_REJECTED" && view.code !== "CHAIN_DISPATCH_FAILED") return void 0;
8258
+ const errorKey = stringParamOf(view, "errorKey");
8259
+ return errorKey === void 0 || errorKey === "" ? void 0 : errorKey;
8260
+ }
8261
+ /** Codes that mean "there is no market for this" however the app reached them. */
8262
+ const NO_MARKET_CODES = [
8263
+ "NO_POOL_AVAILABLE",
8264
+ "INSUFFICIENT_LIQUIDITY",
8265
+ "UNKNOWN_TOKEN"
8266
+ ];
8267
+ /**
8268
+ * True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
8269
+ * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
8270
+ * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
8271
+ * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
8272
+ * notFound` list, so the empty-state ("No market for this pair") has one definition.
8273
+ *
8274
+ * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
8275
+ * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
8276
+ * other value is `false`.
8277
+ *
8278
+ * @example
8279
+ * ```ts
8280
+ * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
8281
+ * ```
8282
+ */
8283
+ function isNoMarket(error) {
8284
+ const view = toFailureView(error);
8285
+ if (view === void 0) return false;
8286
+ if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
8287
+ return !isWriteView(view) && (view.notFound === true || view.status === 404);
8288
+ }
8289
+
7991
8290
  //#endregion
7992
8291
  //#region src/utils/submit_state.ts
7993
8292
  /** The `mode` of `envelope.data`, or `undefined` when there is no such field. */
@@ -8075,7 +8374,9 @@ exports.Symbols = Symbols;
8075
8374
  exports.TICK_SPACING_BY_FEE = TICK_SPACING_BY_FEE;
8076
8375
  exports.UPDATE_REQUIRED_STATUS = UPDATE_REQUIRED_STATUS;
8077
8376
  exports.alignTickDown = alignTickDown;
8377
+ exports.alignTickDownOrNaN = alignTickDownOrNaN;
8078
8378
  exports.alignTickUp = alignTickUp;
8379
+ exports.alignTickUpOrNaN = alignTickUpOrNaN;
8079
8380
  exports.assertCanonicalPair = assertCanonicalPair;
8080
8381
  exports.assertCanonicalV2Dto = assertCanonicalV2Dto;
8081
8382
  exports.assertTickRange = assertTickRange;
@@ -8089,6 +8390,7 @@ exports.buildRemoveLiquidityDto = buildRemoveLiquidityDto;
8089
8390
  exports.buildRequestTradeDto = buildRequestTradeDto;
8090
8391
  exports.calculatePersonalSignPrefix = calculatePersonalSignPrefix;
8091
8392
  exports.canonicalDecimalString = canonicalDecimalString;
8393
+ exports.chainErrorKeyOf = chainErrorKeyOf;
8092
8394
  exports.classification = classification;
8093
8395
  exports.classifyFailure = classifyFailure;
8094
8396
  exports.classifyShadowSubmitError = classifyShadowSubmitError;
@@ -8125,9 +8427,11 @@ exports.isPreSendError = isPreSendError;
8125
8427
  exports.isProposableTradingSymbol = isProposableTradingSymbol;
8126
8428
  exports.isRelayableRefusal = isRelayableRefusal;
8127
8429
  exports.isShadowError = isShadowError;
8430
+ exports.isSqrtPriceInRange = isSqrtPriceInRange;
8128
8431
  exports.isSubmitExecuted = isSubmitExecuted;
8129
8432
  exports.isSubmitQueued = isSubmitQueued;
8130
8433
  exports.isSubmitRejected = isSubmitRejected;
8434
+ exports.isTickInRange = isTickInRange;
8131
8435
  exports.isUninterpretedAnswer = isUninterpretedAnswer;
8132
8436
  exports.isUniqueKeyConsumed = isUniqueKeyConsumed;
8133
8437
  exports.isUnprovenAcknowledgement = isUnprovenAcknowledgement;
@@ -8180,5 +8484,6 @@ exports.validateTickSpacing = validateTickSpacing;
8180
8484
  exports.validateTokenDecimals = validateTokenDecimals;
8181
8485
  exports.validateWalletAddress = validateWalletAddress;
8182
8486
  exports.walletDeclineCode = walletDeclineCode;
8487
+ exports.webStorageAdapter = webStorageAdapter;
8183
8488
  exports.withPrivateKey = withPrivateKey;
8184
8489
  //# sourceMappingURL=index.cjs.map