@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.mjs CHANGED
@@ -1315,6 +1315,7 @@ var GSwapSDKError = class GSwapSDKError extends Error {
1315
1315
  code;
1316
1316
  /** The named placeholders of the error: a flat object of primitives, safe to localize with. */
1317
1317
  params;
1318
+ /** The server's `Retry-After` in milliseconds (a `RATE_LIMITED` answer), when it sent one. */
1318
1319
  retryAfterMs;
1319
1320
  /** The HTTP status of the response that caused this error, when there was one. */
1320
1321
  status;
@@ -1640,7 +1641,7 @@ function parseJson(text) {
1640
1641
  //#endregion
1641
1642
  //#region src/version.ts
1642
1643
  /** Package version embedded by the bundler, with a source-test fallback. */
1643
- const SDK_VERSION = "1.2.0-rc.8";
1644
+ const SDK_VERSION = "1.2.0";
1644
1645
 
1645
1646
  //#endregion
1646
1647
  //#region src/utils/transport.ts
@@ -1701,7 +1702,7 @@ function buildRequestHeaders(wire, parts = {}) {
1701
1702
  entries.set(name.toLowerCase(), [name, value]);
1702
1703
  }
1703
1704
  };
1704
- 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"}` });
1705
+ 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"}` });
1705
1706
  put(parts.defaults);
1706
1707
  put(wire === null || wire === void 0 ? void 0 : wire.headers);
1707
1708
  if (parts.json === true && !entries.has("content-type")) put({ "Content-Type": "application/json" });
@@ -2005,7 +2006,54 @@ const ALL_FEE_TIERS = [
2005
2006
  ];
2006
2007
 
2007
2008
  //#endregion
2008
- //#region src/utils/ticks.ts
2009
+ //#region src/utils/tick_range.ts
2010
+ function integerTickOf(tick) {
2011
+ if (typeof tick === "string") return tick.trim() === "" ? NaN : Number(tick);
2012
+ return tick;
2013
+ }
2014
+ /**
2015
+ * True when a position over `[tickLower, tickUpper)` is IN RANGE at `currentTick`: the lower tick
2016
+ * is INCLUSIVE and the upper tick is EXCLUSIVE. That is the GalaChainDex contract's rule
2017
+ * (`DexV3Pool`: `tickCurrent >= tickLower && tickCurrent < tickUpper` is the case in which a
2018
+ * position holds both tokens and earns fees). A pool whose tick equals `tickUpper` is already out
2019
+ * of range: the position is entirely token1 there, and a swap through the tick has crossed it.
2020
+ *
2021
+ * `currentTick` is the pool's tick (`slot0.tick`, the greatest tick whose price is no greater than
2022
+ * the pool's price), not a rounded display value. A tick may be a number or the decimal string a
2023
+ * backend returns. Anything that is not an integer (`NaN`, `undefined`-like, an empty string, a
2024
+ * fraction) makes the answer `false`: an app that must tell "not loaded yet" from "out of range"
2025
+ * checks for the missing value itself first.
2026
+ *
2027
+ * Do NOT decide range by comparing a price with a tick's price (`tickToPrice`) using `<=` on both
2028
+ * ends, or by mixing a square-root price with a price. A price exactly on a tick's boundary is
2029
+ * then in range at the upper edge (the contract says it is not), and two representations of the
2030
+ * same boundary can round to opposite sides. For a pool price use {@link isSqrtPriceInRange}, which
2031
+ * derives the tick the way the contract does and then applies this rule.
2032
+ *
2033
+ * @example
2034
+ * ```ts
2035
+ * isTickInRange(-60, -60, 60); // true: the lower tick is inclusive
2036
+ * isTickInRange(60, -60, 60); // false: the upper tick is exclusive
2037
+ * ```
2038
+ */
2039
+ function isTickInRange(currentTick, tickLower, tickUpper) {
2040
+ const current = integerTickOf(currentTick);
2041
+ const lower = integerTickOf(tickLower);
2042
+ const upper = integerTickOf(tickUpper);
2043
+ if (!Number.isInteger(current) || !Number.isInteger(lower) || !Number.isInteger(upper)) return false;
2044
+ return current >= lower && current < upper;
2045
+ }
2046
+
2047
+ //#endregion
2048
+ //#region src/utils/tick_math.ts
2049
+ /**
2050
+ * Tick and price arithmetic that never throws an SDK error: the contract's tick bounds, the
2051
+ * conversions between ticks and prices, and nothing that validates a range. It imports only the
2052
+ * two number libraries it computes with, never the `GSwapSDKError` class or the error catalog
2053
+ * (functions that must throw, `alignTickDown` and `assertTickRange`, are in `ticks.ts`), so an
2054
+ * app shell that prices a tick pays for the libraries and these few functions, not for ~25 kB of
2055
+ * error templates. A value that cannot be computed is `NaN`, never an exception.
2056
+ */
2009
2057
  /** Minimum tick supported by GalaChainDex. */
2010
2058
  const GC_MIN_TICK = -887272;
2011
2059
  /** Maximum tick supported by GalaChainDex. */
@@ -2014,6 +2062,7 @@ const DexMath = BigNumber.clone({
2014
2062
  DECIMAL_PLACES: 60,
2015
2063
  ROUNDING_MODE: BigNumber.ROUND_DOWN
2016
2064
  });
2065
+ /** `decimal.js` at the 60 significant digits the contract's price math is exact to. */
2017
2066
  const DexDecimal = Decimal.clone({ precision: 60 });
2018
2067
  /** Convert a tick to the corresponding square-root price. */
2019
2068
  function tickToSqrtPrice(tick) {
@@ -2048,6 +2097,26 @@ function tickToPrice(tick) {
2048
2097
  return new BigNumber(new DexDecimal(1.0001).pow(tick).toString());
2049
2098
  }
2050
2099
  /**
2100
+ * {@link isTickInRange} for a pool's square-root price instead of its tick (a position row that
2101
+ * carries `sqrtPrice`, `tickLower` and `tickUpper`). The tick is derived from the price exactly as
2102
+ * the contract does (`sqrtPriceToTick`: the greatest tick whose square-root price is no greater
2103
+ * than the price, exact to 60 digits), then the contract's rule applies: lower tick inclusive,
2104
+ * upper tick exclusive. So a pool sitting exactly on `tickLower`'s price is in range, and exactly
2105
+ * on `tickUpper`'s price is not, and no float rounding can flip either.
2106
+ *
2107
+ * `false` for a price that is not positive and finite (not loaded, zero, `NaN`): it says nothing
2108
+ * about the position, so an app that must show a neutral state checks for the missing price
2109
+ * itself first. `tickLower` and `tickUpper` follow {@link isTickInRange}.
2110
+ *
2111
+ * @example
2112
+ * ```ts
2113
+ * const inRange = isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper);
2114
+ * ```
2115
+ */
2116
+ function isSqrtPriceInRange(sqrtPrice, tickLower, tickUpper) {
2117
+ return isTickInRange(sqrtPriceToTick(sqrtPrice), tickLower, tickUpper);
2118
+ }
2119
+ /**
2051
2120
  * Return the integer tick for a token1/token0 `price`: by default the greatest tick whose price
2052
2121
  * is no greater than `price`; `{ rounding: 'nearest' }` the closest tick. `NaN` for a price that
2053
2122
  * is not positive and finite.
@@ -2061,77 +2130,18 @@ function tickFromPrice(price, options = {}) {
2061
2130
  const tick = (options.rounding === "nearest" ? exact.round() : exact.floor()).toNumber();
2062
2131
  return Number.isFinite(tick) ? tick : NaN;
2063
2132
  }
2064
- /** Align a tick down to the nearest multiple of a positive spacing. */
2065
- function alignTickDown(tick, spacing) {
2066
- assertSpacing(spacing);
2067
- return Math.floor(tick / spacing) * spacing;
2068
- }
2069
- /** Align a tick up to the nearest multiple of a positive spacing. */
2070
- function alignTickUp(tick, spacing) {
2071
- assertSpacing(spacing);
2072
- return Math.ceil(tick / spacing) * spacing;
2073
- }
2074
- /** Validate a position range against the global tick bounds and fee-tier spacing. */
2075
- function assertTickRange(lower, upper, fee) {
2076
- const spacing = TICK_SPACING_BY_FEE[fee];
2077
- if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
2078
- field: "fee",
2079
- value: fee,
2080
- allowed: ALLOWED_FEE_TIERS_TEXT
2081
- });
2082
- if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
2083
- tickLower: lower,
2084
- tickUpper: upper
2085
- });
2086
- if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
2087
- tickLower: lower,
2088
- tickUpper: upper
2089
- });
2090
- if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
2091
- tickLower: lower,
2092
- tickUpper: upper,
2093
- minTick: GC_MIN_TICK,
2094
- maxTick: GC_MAX_TICK
2095
- });
2096
- if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
2097
- tickLower: lower,
2098
- tickUpper: upper,
2099
- spacing
2100
- });
2101
- }
2102
- function assertSpacing(spacing) {
2103
- if (!Number.isInteger(spacing) || spacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
2104
- }
2105
- /**
2106
- * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
2107
- * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
2108
- * order the price is inverted here (at 60 significant digits, so a very large or very small
2109
- * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
2110
- * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
2111
- * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
2112
- *
2113
- * @example
2114
- * ```ts
2115
- * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
2116
- * const { sqrtPrice, tick } = frameSlot0(slot0);
2117
- * ```
2118
- */
2119
- function frameSlot0(slot0) {
2120
- if (slot0.flippedFromRequest !== true) return {
2121
- sqrtPrice: slot0.sqrtPrice,
2122
- tick: slot0.tick
2123
- };
2124
- const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
2125
- if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
2126
- const sqrtPrice = inverted.toString();
2127
- return {
2128
- sqrtPrice,
2129
- tick: sqrtPriceToTick(sqrtPrice)
2130
- };
2131
- }
2132
2133
 
2133
2134
  //#endregion
2134
2135
  //#region src/utils/validation.ts
2136
+ /**
2137
+ * Validates a decimal amount: a string or `BigNumber`, never a JavaScript number.
2138
+ *
2139
+ * @param amount - The amount to check.
2140
+ * @param parameterName - The field name reported in the error's `params.field`.
2141
+ * @param allowZero - Accept zero (default `false`).
2142
+ * @throws GSwapSDKError `AMOUNT_IS_JS_NUMBER`, `AMOUNT_NOT_FINITE`, `AMOUNT_NOT_POSITIVE` (zero
2143
+ * when `allowZero` is false) or `AMOUNT_NEGATIVE`.
2144
+ */
2135
2145
  function validateNumericAmount(amount, parameterName, allowZero = false) {
2136
2146
  if (typeof amount === "number") throw new GSwapSDKError("AMOUNT_IS_JS_NUMBER", { field: parameterName });
2137
2147
  let bnAmount;
@@ -2153,6 +2163,12 @@ function validateNumericAmount(amount, parameterName, allowZero = false) {
2153
2163
  value: String(amount)
2154
2164
  });
2155
2165
  }
2166
+ /**
2167
+ * Validates a spot price and a lower/upper price range: none a JavaScript number, all positive and
2168
+ * finite (a non-finite upper bound counts as an unbounded `1e18`), and `lowerPrice <= upperPrice`.
2169
+ *
2170
+ * @throws GSwapSDKError `PRICE_VALUES_IS_JS_NUMBER`, `INVALID_PRICE_VALUES` or `INVALID_PRICE_RANGE`.
2171
+ */
2156
2172
  function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
2157
2173
  if ([
2158
2174
  spotPrice,
@@ -2180,12 +2196,24 @@ function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
2180
2196
  upperPrice: String(upperPrice)
2181
2197
  });
2182
2198
  }
2199
+ /**
2200
+ * Validates a token's decimals: a non-negative integer.
2201
+ *
2202
+ * @throws GSwapSDKError `INVALID_TOKEN_DECIMALS` (`params.field` is `parameterName`).
2203
+ */
2183
2204
  function validateTokenDecimals(decimals, parameterName) {
2184
2205
  if (decimals < 0 || !Number.isInteger(decimals)) throw new GSwapSDKError("INVALID_TOKEN_DECIMALS", {
2185
2206
  field: parameterName,
2186
2207
  value: decimals
2187
2208
  });
2188
2209
  }
2210
+ /**
2211
+ * Validates a position's tick range: two integers with `tickLower < tickUpper`, both within
2212
+ * `GC_MIN_TICK`..`GC_MAX_TICK`. It does not check alignment to a fee tier's spacing (see
2213
+ * `assertTickRange`).
2214
+ *
2215
+ * @throws GSwapSDKError `TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE` or `TICKS_OUT_OF_BOUNDS`.
2216
+ */
2189
2217
  function validateTickRange(tickLower, tickUpper) {
2190
2218
  if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
2191
2219
  tickLower,
@@ -2202,6 +2230,11 @@ function validateTickRange(tickLower, tickUpper) {
2202
2230
  maxTick: GC_MAX_TICK
2203
2231
  });
2204
2232
  }
2233
+ /**
2234
+ * Asserts that `fee` is one of the fee tiers in `ALL_FEE_TIERS` (`0`, `500`, `3000`, `10000`).
2235
+ *
2236
+ * @throws GSwapSDKError `INVALID_FEE` (`params.field` `'fee'`, `params.allowed` the tiers).
2237
+ */
2205
2238
  function validateFee(fee) {
2206
2239
  if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) throw new GSwapSDKError("INVALID_FEE", {
2207
2240
  field: "fee",
@@ -2209,9 +2242,20 @@ function validateFee(fee) {
2209
2242
  allowed: ALLOWED_FEE_TIERS_TEXT
2210
2243
  });
2211
2244
  }
2245
+ /**
2246
+ * Validates a tick spacing: a positive integer.
2247
+ *
2248
+ * @throws GSwapSDKError `INVALID_TICK_SPACING`.
2249
+ */
2212
2250
  function validateTickSpacing(tickSpacing) {
2213
2251
  if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: tickSpacing });
2214
2252
  }
2253
+ /**
2254
+ * Asserts that a wallet address was given and is a non-blank string. It does not check the address
2255
+ * format.
2256
+ *
2257
+ * @throws GSwapSDKError `MISSING_WALLET_ADDRESS` (undefined) or `INVALID_WALLET_ADDRESS` (blank).
2258
+ */
2215
2259
  function validateWalletAddress(address) {
2216
2260
  if (address === void 0) throw new GSwapSDKError("MISSING_WALLET_ADDRESS", {});
2217
2261
  if (!address || typeof address !== "string" || address.trim().length === 0) throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
@@ -2694,9 +2738,13 @@ async function shadowFailures(run) {
2694
2738
  //#region src/classes/submitted_transaction.ts
2695
2739
  /** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */
2696
2740
  var SubmittedTransaction = class {
2741
+ /** The chain method that was submitted (`RequestTrade`, `AddLiquidity`, ...). */
2697
2742
  method;
2743
+ /** The write's durable correlation key: persist it, and confirm from it alone later. */
2698
2744
  uniqueKey;
2745
+ /** The request transaction id the gateway reported, or `null` when it gave none. */
2699
2746
  transactionId;
2747
+ /** The block of the transaction, when the answer carried one; otherwise `null`. */
2700
2748
  blockNumber;
2701
2749
  /** The gateway's `data.mode`: `'sync'` (executed, `result` is the chain result) or `'queued'`. */
2702
2750
  mode;
@@ -2818,7 +2866,9 @@ var ChainGateway = class {
2818
2866
  chainCallTimeoutMs;
2819
2867
  isTransportFailure;
2820
2868
  answerOfRejectionHook;
2869
+ /** The request timeout in milliseconds (`Infinity` when no timer is armed). */
2821
2870
  requestTimeoutMs;
2871
+ /** The swap backend base URL every request is sent to, without a trailing slash. */
2822
2872
  dexBackendBaseUrl;
2823
2873
  /** Wire format shared by the read services built on this gateway. */
2824
2874
  wire;
@@ -2892,7 +2942,7 @@ var ChainGateway = class {
2892
2942
  *
2893
2943
  * Unlike `submit`, EVERY HTTP status resolves: the result is the raw `{ httpStatus, body }`,
2894
2944
  * because shadow failures are classified from the status together with the body's `code`
2895
- * (`SHADOW_UNAVAILABLE`, `SHADOW_DISABLED`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);
2945
+ * (`SHADOW_UNAVAILABLE`, `SHADOW_UNSUPPORTED_TYPE`, `SHADOW_RELAY_REJECTED`);
2896
2946
  * see `readShadowSubmitOutcome`. Only a failure to get an answer rejects, and it rejects with
2897
2947
  * `SUBMISSION_OUTCOME_UNKNOWN` (`params.reason` `'timeout'` or `'transport'`): the request may
2898
2948
  * have been accepted. Every error it throws has `error.shadow === true`, and a non-SDK object
@@ -3140,7 +3190,9 @@ function isGdexLiquidityEvent(value) {
3140
3190
  }
3141
3191
  /** A JSON-RPC error answered by the stream. */
3142
3192
  var GdexStreamError = class extends Error {
3193
+ /** The JSON-RPC error code. */
3143
3194
  code;
3195
+ /** The error's optional `data` member, as the server sent it. */
3144
3196
  data;
3145
3197
  constructor(code, message, data) {
3146
3198
  super(message);
@@ -3218,6 +3270,7 @@ var GdexStreamService = class {
3218
3270
  this.connectPromise = void 0;
3219
3271
  socket === null || socket === void 0 || socket.close(1e3, "client disconnect");
3220
3272
  }
3273
+ /** `true` while the socket is open (false while connecting, reconnecting or after `disconnect()`). */
3221
3274
  isConnected() {
3222
3275
  var _this$socket;
3223
3276
  return ((_this$socket = this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.readyState) === WEBSOCKET_OPEN;
@@ -3259,30 +3312,41 @@ var GdexStreamService = class {
3259
3312
  }
3260
3313
  });
3261
3314
  }
3315
+ /** `gdex_serverInfo`: the server's own description of itself, as it sends it. */
3262
3316
  serverInfo() {
3263
3317
  return this.request("gdex_serverInfo");
3264
3318
  }
3319
+ /** `gdex_ping`: a round trip that answers `{ pong, serverTime }`. */
3265
3320
  ping() {
3266
3321
  return this.request("gdex_ping");
3267
3322
  }
3323
+ /** `gdex_getPool`: the current state of one pool, selected by its key or hash. */
3268
3324
  getPool(selector) {
3269
3325
  return this.request("gdex_getPool", selector);
3270
3326
  }
3327
+ /** `gdex_getBalance`: an owner's balances, or only the one of `tokenClassKey` when given. */
3271
3328
  getBalance(owner, tokenClassKey) {
3272
3329
  return this.request("gdex_getBalance", tokenClassKey === void 0 ? { owner } : {
3273
3330
  owner,
3274
3331
  tokenClassKey
3275
3332
  });
3276
3333
  }
3334
+ /**
3335
+ * `gdex_getPositions`: an owner's positions, optionally in one pool, a page at a time. Pass the
3336
+ * returned `bookmark` back in as `bookmark` for the next page.
3337
+ */
3277
3338
  getPositions(opts) {
3278
3339
  return this.request("gdex_getPositions", opts);
3279
3340
  }
3341
+ /** `gdex_getBlockHeight`: the block number the server reports, with its timestamp. */
3280
3342
  getBlockHeight() {
3281
3343
  return this.request("gdex_getBlockHeight");
3282
3344
  }
3345
+ /** `gdex_quote`: a quote over the stream; give exactly one of `amountIn` or `amountOut`. */
3283
3346
  quote(params) {
3284
3347
  return this.request("gdex_quote", params);
3285
3348
  }
3349
+ /** `gdex_getToken`: the server's record of one token class, as it sends it. */
3286
3350
  getToken(tokenClassKey) {
3287
3351
  return this.request("gdex_getToken", { tokenClassKey });
3288
3352
  }
@@ -3615,39 +3679,13 @@ function finiteNumberOf(value) {
3615
3679
  }
3616
3680
 
3617
3681
  //#endregion
3618
- //#region src/utils/ordering.ts
3619
- /** Return two trading symbols in the contract's plain-string order. */
3620
- function orderSymbols(a, b) {
3621
- return a < b ? [a, b] : [b, a];
3622
- }
3623
- /** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
3624
- *
3625
- * @example
3626
- * ```ts
3627
- * const pair = readOrderedSymbols(['GALA', 'GUSDC']);
3628
- * console.log(pair.token0);
3629
- * ```
3682
+ //#region src/utils/class_key.ts
3683
+ /**
3684
+ * Token class keys that never throw: the `$`-joined composite key and the non-throwing parsers.
3685
+ * This module imports nothing at run time (the key type is erased), so an app shell that reads a
3686
+ * stored key pays for a few hundred bytes, never for the error class or the catalog. The parser
3687
+ * that THROWS an SDK error on a bad key (`parseTokenClassKey`) lives in `ordering.ts`.
3630
3688
  */
3631
- function readOrderedSymbols(value) {
3632
- if (Array.isArray(value) && value.length >= 2) {
3633
- const token0 = value[0];
3634
- const token1 = value[1];
3635
- if (typeof token0 === "string" && typeof token1 === "string") return {
3636
- token0,
3637
- token1
3638
- };
3639
- }
3640
- if (typeof value === "object" && value !== null) {
3641
- const record = value;
3642
- const token0 = record["token0"];
3643
- const token1 = record["token1"];
3644
- if (typeof token0 === "string" && typeof token1 === "string") return {
3645
- token0,
3646
- token1
3647
- };
3648
- }
3649
- throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
3650
- }
3651
3689
  /** Return the `$`-joined composite key used by GalaChain object identities. */
3652
3690
  function compositeKeyOf(token) {
3653
3691
  return [
@@ -3658,33 +3696,14 @@ function compositeKeyOf(token) {
3658
3696
  ].join("$");
3659
3697
  }
3660
3698
  /**
3661
- * Parse a pipe- or dollar-separated token class key.
3699
+ * Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
3700
+ * are fewer than four segments or any of the four is empty. The one place the split is written;
3701
+ * the strict `parseTokenClassKey` calls it too.
3662
3702
  *
3663
3703
  * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
3664
3704
  * them is the `collection`. Parsing from the right is required because real collections contain
3665
3705
  * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
3666
- * shifts every field. Nothing here says anything about the token's symbol: a class key carries
3667
- * no symbol, which must come from the token class or trading-symbol registry.
3668
- *
3669
- * @example
3670
- * ```ts
3671
- * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
3672
- * ```
3673
- */
3674
- function parseTokenClassKey(tokenClassKey) {
3675
- if (typeof tokenClassKey === "object") return {
3676
- collection: tokenClassKey.collection,
3677
- category: tokenClassKey.category,
3678
- type: tokenClassKey.type,
3679
- additionalKey: tokenClassKey.additionalKey
3680
- };
3681
- const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3682
- if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
3683
- return parsed;
3684
- }
3685
- /**
3686
- * Splits `collection<d>category<d>type<d>additionalKey` from the right, or `undefined` when there
3687
- * are fewer than four segments or any of the four is empty. The one place the split is written.
3706
+ * shifts every field.
3688
3707
  */
3689
3708
  function splitClassKey(key, delimiter) {
3690
3709
  const segments = key.split(delimiter);
@@ -3700,7 +3719,7 @@ function splitClassKey(key, delimiter) {
3700
3719
  };
3701
3720
  }
3702
3721
  /**
3703
- * The non-throwing {@link parseTokenClassKey}: the class key, or `undefined` when `value` is not
3722
+ * The non-throwing `parseTokenClassKey`: the class key, or `undefined` when `value` is not
3704
3723
  * one. A string is split exactly as `parseTokenClassKey` splits it (`|` form when it contains a
3705
3724
  * `|`, else `$`, from the right, all four parts non-empty). Unlike `parseTokenClassKey`, an
3706
3725
  * object is VALIDATED, not just copied: all four fields must be non-empty strings. Anything else
@@ -3753,6 +3772,66 @@ function tryParseCompositeKey(value) {
3753
3772
  return typeof value === "string" ? splitClassKey(value, "$") : void 0;
3754
3773
  }
3755
3774
 
3775
+ //#endregion
3776
+ //#region src/utils/ordering.ts
3777
+ /** Return two trading symbols in the contract's plain-string order. */
3778
+ function orderSymbols(a, b) {
3779
+ return a < b ? [a, b] : [b, a];
3780
+ }
3781
+ /** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
3782
+ *
3783
+ * @example
3784
+ * ```ts
3785
+ * const pair = readOrderedSymbols(['GALA', 'GUSDC']);
3786
+ * console.log(pair.token0);
3787
+ * ```
3788
+ */
3789
+ function readOrderedSymbols(value) {
3790
+ if (Array.isArray(value) && value.length >= 2) {
3791
+ const token0 = value[0];
3792
+ const token1 = value[1];
3793
+ if (typeof token0 === "string" && typeof token1 === "string") return {
3794
+ token0,
3795
+ token1
3796
+ };
3797
+ }
3798
+ if (typeof value === "object" && value !== null) {
3799
+ const record = value;
3800
+ const token0 = record["token0"];
3801
+ const token1 = record["token1"];
3802
+ if (typeof token0 === "string" && typeof token1 === "string") return {
3803
+ token0,
3804
+ token1
3805
+ };
3806
+ }
3807
+ throw new GSwapSDKError("UNORDERABLE_SYMBOLS", { received: Array.isArray(value) ? "array" : value === null ? "null" : typeof value });
3808
+ }
3809
+ /**
3810
+ * Parse a pipe- or dollar-separated token class key.
3811
+ *
3812
+ * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
3813
+ * them is the `collection`. Parsing from the right is required because real collections contain
3814
+ * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
3815
+ * shifts every field. Nothing here says anything about the token's symbol: a class key carries
3816
+ * no symbol, which must come from the token class or trading-symbol registry.
3817
+ *
3818
+ * @example
3819
+ * ```ts
3820
+ * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
3821
+ * ```
3822
+ */
3823
+ function parseTokenClassKey(tokenClassKey) {
3824
+ if (typeof tokenClassKey === "object") return {
3825
+ collection: tokenClassKey.collection,
3826
+ category: tokenClassKey.category,
3827
+ type: tokenClassKey.type,
3828
+ additionalKey: tokenClassKey.additionalKey
3829
+ };
3830
+ const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3831
+ if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
3832
+ return parsed;
3833
+ }
3834
+
3756
3835
  //#endregion
3757
3836
  //#region src/classes/symbols.ts
3758
3837
  const SYMBOL_CACHE_TTL_MS = 6e4;
@@ -4171,37 +4250,151 @@ function parsePoolListInfo(entry) {
4171
4250
  }
4172
4251
 
4173
4252
  //#endregion
4174
- //#region src/utils/unique_key.ts
4253
+ //#region src/utils/tick_align.ts
4175
4254
  /**
4176
- * The `uniqueKey` prefix frontend_v2 and wallet_extension have always sent
4177
- * (`galaswap-operation-<uuid>`). defi-backend does not depend on it: the chain-write verifier
4178
- * only requires a non-empty key of at most 256 characters, and apply-results accepts
4179
- * `[A-Za-z0-9._:-]{1,128}`; the only code that mints a prefixed key itself is the server-side v1
4180
- * trade builder, which nothing reads back by prefix.
4255
+ * Aligning a tick to a pool's tick spacing without throwing. This module imports nothing, so an
4256
+ * app shell (a price input that snaps to a tick) pays for a few dozen bytes, not for the error
4257
+ * class and catalog that `alignTickDown` and `alignTickUp` (in `ticks.ts`) carry because they
4258
+ * throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer.
4181
4259
  */
4182
- const DEFAULT_UNIQUE_KEY_PREFIX = "galaswap-operation-";
4183
- /** A canonical UUID is 36 characters; the apply-results key limit is 128. */
4184
- const MAX_UNIQUE_KEY_PREFIX_LENGTH = 92;
4185
- const UNIQUE_KEY_PREFIX_PATTERN = /^[A-Za-z0-9._:-]*$/u;
4260
+ /** True for a tick spacing the contract can use: a positive integer. The one definition. */
4261
+ function hasValidSpacing(spacing) {
4262
+ return Number.isInteger(spacing) && spacing > 0;
4263
+ }
4186
4264
  /**
4187
- * Validates a caller-supplied `uniqueKey` prefix. The whole key (`<prefix><uuid>`) must stay a
4188
- * valid apply-results key, otherwise `confirm()` could never read the outcome of the write.
4265
+ * {@link alignTickDown} that answers `NaN` instead of throwing: the greatest multiple of `spacing`
4266
+ * that is no greater than `tick`, or `NaN` when `spacing` is not a positive integer (a pool whose
4267
+ * spacing has not loaded yet) or `tick` is not a number. For an app shell and for a drag handler,
4268
+ * which must not throw while the spacing is missing. `alignTickDown` (the SDK's own call sites use
4269
+ * it) gives the same value and throws for the bad spacing.
4189
4270
  *
4190
- * @throws GSwapSDKError `INVALID_UNIQUE_KEY_PREFIX` when the prefix has characters outside
4191
- * `A-Za-z0-9._:-` or is longer than 92 characters.
4271
+ * @example
4272
+ * ```ts
4273
+ * alignTickDownOrNaN(-61, 60); // -120: it floors, it does not truncate toward zero
4274
+ * alignTickDownOrNaN(100, 0); // NaN
4275
+ * ```
4192
4276
  */
4193
- function resolveUniqueKeyPrefix(prefix) {
4194
- if (prefix === void 0) return DEFAULT_UNIQUE_KEY_PREFIX;
4195
- if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
4196
- uniqueKeyPrefix: prefix,
4197
- maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
4198
- });
4199
- return prefix;
4277
+ function alignTickDownOrNaN(tick, spacing) {
4278
+ return hasValidSpacing(spacing) ? Math.floor(tick / spacing) * spacing : NaN;
4200
4279
  }
4201
4280
  /**
4202
- * Validates a caller-supplied write `uniqueKey`: 1 to 128 characters of `A-Za-z0-9._:-`, the
4203
- * shape the apply-results route accepts, so the write's outcome can always be read back with
4204
- * `confirm()`. A key is one attempt's identity: reuse it only to retry that same attempt.
4281
+ * {@link alignTickUp} that answers `NaN` instead of throwing: the least multiple of `spacing` that
4282
+ * is no less than `tick`, or `NaN` for a spacing that is not a positive integer. See
4283
+ * {@link alignTickDownOrNaN}.
4284
+ */
4285
+ function alignTickUpOrNaN(tick, spacing) {
4286
+ return hasValidSpacing(spacing) ? Math.ceil(tick / spacing) * spacing : NaN;
4287
+ }
4288
+
4289
+ //#endregion
4290
+ //#region src/utils/ticks.ts
4291
+ /**
4292
+ * The tick functions that THROW an SDK error on a bad input (`alignTickDown`, `alignTickUp`,
4293
+ * `assertTickRange`, `frameSlot0`). The arithmetic that never throws (`tickToPrice`,
4294
+ * `tickFromPrice`, `tickToSqrtPrice`, `sqrtPriceToTick`, the bounds) is in `tick_math.ts`, which
4295
+ * does not import the error class or the catalog; import it from the package entry as usual.
4296
+ */
4297
+ /** Align a tick down to the nearest multiple of a positive spacing. */
4298
+ function alignTickDown(tick, spacing) {
4299
+ assertSpacing(spacing);
4300
+ return alignTickDownOrNaN(tick, spacing);
4301
+ }
4302
+ /** Align a tick up to the nearest multiple of a positive spacing. */
4303
+ function alignTickUp(tick, spacing) {
4304
+ assertSpacing(spacing);
4305
+ return alignTickUpOrNaN(tick, spacing);
4306
+ }
4307
+ /** Validate a position range against the global tick bounds and fee-tier spacing. */
4308
+ function assertTickRange(lower, upper, fee) {
4309
+ const spacing = TICK_SPACING_BY_FEE[fee];
4310
+ if (spacing === void 0) throw new GSwapSDKError("INVALID_FEE", {
4311
+ field: "fee",
4312
+ value: fee,
4313
+ allowed: ALLOWED_FEE_TIERS_TEXT
4314
+ });
4315
+ if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new GSwapSDKError("TICKS_NOT_INTEGERS", {
4316
+ tickLower: lower,
4317
+ tickUpper: upper
4318
+ });
4319
+ if (lower >= upper) throw new GSwapSDKError("INVALID_TICK_RANGE", {
4320
+ tickLower: lower,
4321
+ tickUpper: upper
4322
+ });
4323
+ if (lower < -887272 || upper > 887272) throw new GSwapSDKError("TICKS_OUT_OF_BOUNDS", {
4324
+ tickLower: lower,
4325
+ tickUpper: upper,
4326
+ minTick: GC_MIN_TICK,
4327
+ maxTick: GC_MAX_TICK
4328
+ });
4329
+ if (lower % spacing !== 0 || upper % spacing !== 0) throw new GSwapSDKError("TICKS_NOT_ALIGNED", {
4330
+ tickLower: lower,
4331
+ tickUpper: upper,
4332
+ spacing
4333
+ });
4334
+ }
4335
+ function assertSpacing(spacing) {
4336
+ if (!hasValidSpacing(spacing)) throw new GSwapSDKError("INVALID_TICK_SPACING", { value: spacing });
4337
+ }
4338
+ /**
4339
+ * Puts a `slot0` answer into the frame of the request. The backend always answers in the pool's
4340
+ * canonical order and says so with `flippedFromRequest`; when the caller asked for the reverse
4341
+ * order the price is inverted here (at 60 significant digits, so a very large or very small
4342
+ * reciprocal keeps its precision) and the tick is re-derived from the inverted price with the
4343
+ * contract's greatest-tick rule. Negating the tick instead is wrong for a price between ticks
4344
+ * (and `-t - 1` is wrong for a price exactly on a tick: sqrtPrice 1 / tick 0 stays 1 / 0).
4345
+ *
4346
+ * @example
4347
+ * ```ts
4348
+ * const slot0 = await gSwap.pools.getSlot0('A', 'B', 500);
4349
+ * const { sqrtPrice, tick } = frameSlot0(slot0);
4350
+ * ```
4351
+ */
4352
+ function frameSlot0(slot0) {
4353
+ if (slot0.flippedFromRequest !== true) return {
4354
+ sqrtPrice: slot0.sqrtPrice,
4355
+ tick: slot0.tick
4356
+ };
4357
+ const inverted = new DexDecimal(1).dividedBy(new DexDecimal(slot0.sqrtPrice));
4358
+ if (!inverted.isFinite() || inverted.lessThanOrEqualTo(0)) throw new GSwapSDKError("INVALID_SQRT_PRICE", { sqrtPrice: slot0.sqrtPrice });
4359
+ const sqrtPrice = inverted.toString();
4360
+ return {
4361
+ sqrtPrice,
4362
+ tick: sqrtPriceToTick(sqrtPrice)
4363
+ };
4364
+ }
4365
+
4366
+ //#endregion
4367
+ //#region src/utils/unique_key.ts
4368
+ /**
4369
+ * The `uniqueKey` prefix frontend_v2 and wallet_extension have always sent
4370
+ * (`galaswap-operation-<uuid>`). defi-backend does not depend on it: the chain-write verifier
4371
+ * only requires a non-empty key of at most 256 characters, and apply-results accepts
4372
+ * `[A-Za-z0-9._:-]{1,128}`; the only code that mints a prefixed key itself is the server-side v1
4373
+ * trade builder, which nothing reads back by prefix.
4374
+ */
4375
+ const DEFAULT_UNIQUE_KEY_PREFIX = "galaswap-operation-";
4376
+ /** A canonical UUID is 36 characters; the apply-results key limit is 128. */
4377
+ const MAX_UNIQUE_KEY_PREFIX_LENGTH = 92;
4378
+ const UNIQUE_KEY_PREFIX_PATTERN = /^[A-Za-z0-9._:-]*$/u;
4379
+ /**
4380
+ * Validates a caller-supplied `uniqueKey` prefix. The whole key (`<prefix><uuid>`) must stay a
4381
+ * valid apply-results key, otherwise `confirm()` could never read the outcome of the write.
4382
+ *
4383
+ * @throws GSwapSDKError `INVALID_UNIQUE_KEY_PREFIX` when the prefix has characters outside
4384
+ * `A-Za-z0-9._:-` or is longer than 92 characters.
4385
+ */
4386
+ function resolveUniqueKeyPrefix(prefix) {
4387
+ if (prefix === void 0) return DEFAULT_UNIQUE_KEY_PREFIX;
4388
+ if (!UNIQUE_KEY_PREFIX_PATTERN.test(prefix) || prefix.length > MAX_UNIQUE_KEY_PREFIX_LENGTH) throw new GSwapSDKError("INVALID_UNIQUE_KEY_PREFIX", {
4389
+ uniqueKeyPrefix: prefix,
4390
+ maxLength: MAX_UNIQUE_KEY_PREFIX_LENGTH
4391
+ });
4392
+ return prefix;
4393
+ }
4394
+ /**
4395
+ * Validates a caller-supplied write `uniqueKey`: 1 to 128 characters of `A-Za-z0-9._:-`, the
4396
+ * shape the apply-results route accepts, so the write's outcome can always be read back with
4397
+ * `confirm()`. A key is one attempt's identity: reuse it only to retry that same attempt.
4205
4398
  *
4206
4399
  * @throws GSwapSDKError `INVALID_UNIQUE_KEY` otherwise.
4207
4400
  */
@@ -4219,8 +4412,9 @@ const decimalString = (amount) => new BigNumber(amount).toFixed();
4219
4412
  /**
4220
4413
  * Builds the RequestTrade DTO: `exactIn` sells that much of the input token (`sell0Qty` or
4221
4414
  * `sell1Qty`), `exactOut` buys that much of the output token (`buy1Qty` or `buy0Qty`), plus the
4222
- * side's slippage bound and an optional `priceLimit`. Key order: `token0, token1, fee, uniqueKey,
4223
- * <quantity>, amountOutMinimum | amountInMaximum, priceLimit`.
4415
+ * side's slippage bound and an optional `priceLimit`. Key order is
4416
+ * `token0, token1, fee, uniqueKey`, then the one quantity, then the slippage bound, then
4417
+ * `priceLimit`.
4224
4418
  *
4225
4419
  * @example
4226
4420
  * ```ts
@@ -5408,21 +5602,21 @@ function toDecimalString(amount) {
5408
5602
  *
5409
5603
  * - `SHADOW_UNAVAILABLE` (503): marking failed or infra not configured; retryable. Never fall back
5410
5604
  * silently to a public swap.
5411
- * - `SHADOW_DISABLED` (400): the feature is off for this environment.
5412
5605
  * - `SHADOW_UNSUPPORTED_TYPE` (400): shadow requested on a non-swap method.
5413
5606
  * - `SHADOW_RELAY_REJECTED`: terminal business rejection (slippage, balance, ...), not retryable;
5414
5607
  * `message` is the gateway's verbatim string.
5415
5608
  */
5416
5609
  const SHADOW_SUBMIT_CODES = [
5417
5610
  "SHADOW_UNAVAILABLE",
5418
- "SHADOW_DISABLED",
5419
5611
  "SHADOW_UNSUPPORTED_TYPE",
5420
5612
  "SHADOW_RELAY_REJECTED"
5421
5613
  ];
5422
5614
  /**
5423
5615
  * Every `kind` of a failed {@link ShadowSubmitOutcome}, for an app that maps each to its own text
5424
- * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled`, `rejected` (carries
5425
- * the gateway's `message`) and `unknown`.
5616
+ * (`Record<ShadowFailureKind, string>`): `unavailable` (retryable), `disabled` (the shadow route
5617
+ * answered 400: the request is not a dark-swappable one, e.g. `SHADOW_UNSUPPORTED_TYPE`; Shadow
5618
+ * Swaps themselves are enabled in every environment), `rejected` (carries the gateway's `message`)
5619
+ * and `unknown`.
5426
5620
  */
5427
5621
  const SHADOW_FAILURE_KINDS = [
5428
5622
  "unavailable",
@@ -5439,12 +5633,12 @@ function classifyShadowSubmitStatus(status) {
5439
5633
  /**
5440
5634
  * Prefers the body `code` (stable across status remaps) and falls back to the HTTP status.
5441
5635
  * `SHADOW_UNAVAILABLE` is the only retryable case; `SHADOW_RELAY_REJECTED` is a terminal gateway
5442
- * rejection; the two other 400 codes and any unknown 400 map to "disabled".
5636
+ * rejection; `SHADOW_UNSUPPORTED_TYPE` and any other 400 map to "disabled".
5443
5637
  */
5444
5638
  function classifyShadowSubmitError(status, code) {
5445
5639
  if (code === "SHADOW_UNAVAILABLE") return "unavailable";
5446
5640
  if (code === "SHADOW_RELAY_REJECTED") return "rejected";
5447
- if (code === "SHADOW_DISABLED" || code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5641
+ if (code === "SHADOW_UNSUPPORTED_TYPE") return "disabled";
5448
5642
  return classifyShadowSubmitStatus(status);
5449
5643
  }
5450
5644
  function readShadowSubmitOutcome(method, signedBody, result) {
@@ -5686,27 +5880,43 @@ var Swaps = class {
5686
5880
 
5687
5881
  //#endregion
5688
5882
  //#region src/classes/gswap.ts
5689
- /** Main entry point for the current GalaChainDex SDK. */
5883
+ /**
5884
+ * Main entry point for the current GalaChainDex SDK: one client bundling the services that read
5885
+ * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,
5886
+ * `symbols`, `fees`, `stream`). See {@link GSwapOptions} for configuration.
5887
+ */
5690
5888
  var GSwap = class {
5889
+ /** The swap backend base URL every request goes to, without a trailing slash. */
5691
5890
  dexBackendBaseUrl;
5891
+ /** The request timeout in milliseconds (default 30 000; `Infinity` arms no timer). */
5692
5892
  chainCallTimeoutMs;
5893
+ /** The signer given at construction, if any. */
5693
5894
  signer;
5895
+ /** The account given at construction, if any. */
5694
5896
  walletAddress;
5897
+ /** The chain-gateway client every other service reads and writes through. */
5695
5898
  gateway;
5899
+ /** The trading-symbol registry. */
5696
5900
  symbols;
5901
+ /** Read-only exact-input and exact-output quotes. */
5697
5902
  quoting;
5903
+ /** Pool, slot0 and composite-pool reads. */
5698
5904
  pools;
5905
+ /** Position reads, liquidity estimates and liquidity / pool-creation writes. */
5699
5906
  positions;
5907
+ /** Queued swaps (`RequestTrade`), dark swaps and swap confirmation. */
5700
5908
  swaps;
5909
+ /** User token balances. */
5701
5910
  assets;
5702
5911
  /** Network-fee quotes (DryRun) signed with this client's signer. */
5703
5912
  fees;
5913
+ /** The realtime stream endpoint {@link GSwap.stream} connects to. */
5704
5914
  dexBackendWsUrl;
5705
5915
  webSocketImpl;
5706
5916
  streamApiKey;
5707
5917
  streamClient;
5708
5918
  /**
5709
- * Create an SDK client for prod or stage.
5919
+ * Create an SDK client for prod (the default) or stage, or for a `dexBackendBaseUrl` of your own.
5710
5920
  *
5711
5921
  * @example
5712
5922
  * ```typescript
@@ -5770,10 +5980,10 @@ function trimTrailingSlash(value) {
5770
5980
  }
5771
5981
 
5772
5982
  //#endregion
5773
- //#region src/utils/failure_classification.ts
5983
+ //#region src/utils/classification.ts
5774
5984
  /**
5775
5985
  * The SDK's default Retry answer for each outcome. A decision that departs from it (a refusal the
5776
- * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table below.
5986
+ * gateway will repeat, `SHADOW_NOT_QUEUED`) is written out in the table of `classifyFailure`.
5777
5987
  */
5778
5988
  const DEFAULT_RETRYABLE = {
5779
5989
  rejected: true,
@@ -5791,10 +6001,10 @@ const DEFAULT_RETRYABLE = {
5791
6001
  * object, safe to mutate or freeze.
5792
6002
  *
5793
6003
  * `options.retryable: false` WITHHOLDS Retry from an outcome that would otherwise allow it: the
5794
- * SDK's own `not_queued` for a refusal the gateway will repeat is `classification('not_queued',
5795
- * { retryable: false })` (also exported, frozen, as {@link NOT_QUEUED_FINAL}). An app may take
5796
- * Retry away from an outcome but never grant it to one that cannot have it, so only `false` is
5797
- * accepted.
6004
+ * SDK's own `not_queued` for a refusal the gateway will repeat is
6005
+ * `classification('not_queued', { retryable: false })` (also exported, frozen, as
6006
+ * {@link NOT_QUEUED_FINAL}). An app may take Retry away from an outcome but never grant it to one
6007
+ * that cannot have it, so only `false` is accepted.
5798
6008
  *
5799
6009
  * @example
5800
6010
  * ```ts
@@ -5825,6 +6035,15 @@ const NOT_QUEUED_FINAL = Object.freeze(classification("not_queued", { retryable:
5825
6035
  function notSentClassification() {
5826
6036
  return classification("not_sent");
5827
6037
  }
6038
+
6039
+ //#endregion
6040
+ //#region src/utils/failure_classification.ts
6041
+ /**
6042
+ * `classifyFailure` and `mayHaveBeenQueued`: the one module that holds the decision for every
6043
+ * catalog code (~135 names, a floor no minifier can remove). It needs the code table and nothing
6044
+ * else: the classification values live in `classification.ts`, the yes/no guards in
6045
+ * `failure_guards.ts`, and the error class and catalog are only named as types.
6046
+ */
5828
6047
  const REJECTED = classification("rejected");
5829
6048
  const UNKNOWN = classification("unknown");
5830
6049
  const NOT_QUEUED = classification("not_queued");
@@ -5924,90 +6143,6 @@ function classifyChainDispatchFailed(view) {
5924
6143
  return status === 422 ? REJECTED : NOT_QUEUED;
5925
6144
  }
5926
6145
  /**
5927
- * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
5928
- * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
5929
- * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
5930
- * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
5931
- * error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
5932
- * view ({@link FailureView}: `code` and `status`); every other value is `false`.
5933
- *
5934
- * @example
5935
- * ```ts
5936
- * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
5937
- * ```
5938
- */
5939
- function isUniqueKeyConsumed(error) {
5940
- const view = toFailureView(error);
5941
- return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
5942
- }
5943
- const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
5944
- "GATEWAY_DATA_MISSING",
5945
- "GATEWAY_MODE_INVALID",
5946
- "GATEWAY_SYNC_REQUEST_TRADE",
5947
- "MISSING_UNIQUE_KEY",
5948
- "UNIQUE_KEY_MISMATCH"
5949
- ];
5950
- /**
5951
- * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
5952
- * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
5953
- * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
5954
- * app shows is one line for all five ("the backend did not confirm it queued the request"), so
5955
- * the app asks this instead of keeping its own list of the codes. A gateway that says
5956
- * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
5957
- *
5958
- * @example
5959
- * ```ts
5960
- * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
5961
- * ```
5962
- */
5963
- function isUnprovenAcknowledgement(error) {
5964
- return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
5965
- }
5966
- /** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
5967
- function isCodeIn(code, codes) {
5968
- return codes.some((known) => known === code);
5969
- }
5970
- /**
5971
- * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
5972
- * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
5973
- * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
5974
- */
5975
- function hasCodeIn(error, codes) {
5976
- const view = toFailureView(error);
5977
- return view !== void 0 && isCodeIn(view.code, codes);
5978
- }
5979
- /**
5980
- * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
5981
- * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
5982
- * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
5983
- * SDK knows, and `GATEWAY_REJECTED` for one it does not).
5984
- */
5985
- const RELAYABLE_REFUSAL_CODES = [
5986
- "GATEWAY_REPORTED_ERROR",
5987
- "METHOD_NOT_ALLOWED",
5988
- "SIGNATURE_INVALID",
5989
- "SIGNER_MISMATCH",
5990
- "DTO_INVALID",
5991
- "BOUNDS_VIOLATION",
5992
- "SYMBOL_CONFLICT",
5993
- "RATE_LIMITED",
5994
- "CHAIN_DISPATCH_FAILED",
5995
- "GATEWAY_REJECTED"
5996
- ];
5997
- function isRelayableRefusal(error) {
5998
- return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
5999
- }
6000
- /**
6001
- * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
6002
- * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
6003
- * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
6004
- * The outcome is `unknown` for all six. It replaces the app's own
6005
- * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
6006
- */
6007
- function isUninterpretedAnswer(error) {
6008
- return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
6009
- }
6010
- /**
6011
6146
  * Classifies any thrown value from its code (and, for two codes, its HTTP status), never from
6012
6147
  * message text, so an app does not have to re-derive "may I offer Retry?" and "is the outcome
6013
6148
  * unknown?" for every code. The decision for each code is in this module's table; a new catalog
@@ -6084,34 +6219,6 @@ function classifyView(view) {
6084
6219
  if (code === "INVALID_PRIVATE_KEY") return { ...classifyInvalidPrivateKey(view) };
6085
6220
  return { ...BY_CODE[code] ?? INVALID_INPUT };
6086
6221
  }
6087
- /** Codes that mean "there is no market for this" however the app reached them. */
6088
- const NO_MARKET_CODES = [
6089
- "NO_POOL_AVAILABLE",
6090
- "INSUFFICIENT_LIQUIDITY",
6091
- "UNKNOWN_TOKEN"
6092
- ];
6093
- /**
6094
- * True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
6095
- * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
6096
- * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
6097
- * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
6098
- * notFound` list, so the empty-state ("No market for this pair") has one definition.
6099
- *
6100
- * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
6101
- * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
6102
- * other value is `false`.
6103
- *
6104
- * @example
6105
- * ```ts
6106
- * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
6107
- * ```
6108
- */
6109
- function isNoMarket(error) {
6110
- const view = toFailureView(error);
6111
- if (view === void 0) return false;
6112
- if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
6113
- return !isWriteView(view) && (view.notFound === true || view.status === 404);
6114
- }
6115
6222
  /**
6116
6223
  * True when the failed call was a WRITE that may nevertheless have been queued: its outcome is
6117
6224
  * `unknown` (`classifyFailure(error).outcome === 'unknown'`: a timeout or broken connection after
@@ -6138,59 +6245,7 @@ function mayHaveBeenQueued(error) {
6138
6245
  }
6139
6246
 
6140
6247
  //#endregion
6141
- //#region src/classes/pending_swaps.ts
6142
- /** Key the wallet_extension has always used; its storage value is a plain array of entries. */
6143
- const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
6144
- /** Entries older than this are dropped the next time a wallet's swaps are listed. */
6145
- const PENDING_SWAP_EXPIRY_MS = 6048e5;
6146
- /**
6147
- * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
6148
- * in: the value lands under the key as the structured value it is (the browser clones it; nothing
6149
- * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
6150
- * store, which treats it as "storage unavailable".
6151
- *
6152
- * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
6153
- * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
6154
- * context) then fails only when the store touches storage, and that failure (a throw inside the
6155
- * function) is the same "storage unavailable" rejection.
6156
- *
6157
- * @example
6158
- * ```ts
6159
- * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
6160
- * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
6161
- * ```
6162
- */
6163
- function storageAdapterFromChromeStorage(area) {
6164
- const areaNow = () => typeof area === "function" ? area() : area;
6165
- return {
6166
- async get(key) {
6167
- const items = await areaNow().get(key);
6168
- return Object.hasOwn(items, key) ? items[key] : void 0;
6169
- },
6170
- async set(key, value) {
6171
- await areaNow().set({ [key]: value });
6172
- }
6173
- };
6174
- }
6175
- /**
6176
- * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
6177
- *
6178
- * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
6179
- * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
6180
- * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
6181
- * before reading anything and always will, so keeping the entry would retry it forever. The
6182
- * SDK never signs such a key; an entry like this is corrupt or foreign.
6183
- * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
6184
- * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
6185
- * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
6186
- * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
6187
- */
6188
- const PENDING_SWAP_PRUNE_REASONS = [
6189
- "expired",
6190
- "invalid_unique_key",
6191
- "chain_rejected",
6192
- "unconfirmable"
6193
- ];
6248
+ //#region src/classes/pending_swap_fate.ts
6194
6249
  /**
6195
6250
  * What to do with a pending swap after confirming it failed (the answer of
6196
6251
  * {@link pendingSwapFateFor}).
@@ -6200,6 +6255,9 @@ const PENDING_SWAP_PRUNE_REASONS = [
6200
6255
  * Drop it without claiming anything about the trade.
6201
6256
  * - `keep`: the trade may still have been applied (a timeout, a broken connection, a gateway
6202
6257
  * hiccup, anything not proven). Leave it pending and look again later.
6258
+ *
6259
+ * This module holds the decision and nothing of the store, so an app shell that only needs the
6260
+ * fate pays for `classifyFailure` and this table, not for `PendingSwapStore`.
6203
6261
  */
6204
6262
  const PENDING_SWAP_FATES = [
6205
6263
  "forget",
@@ -6248,6 +6306,32 @@ function pendingSwapFateOfOutcome(outcome) {
6248
6306
  function pendingSwapFateFor(error) {
6249
6307
  return pendingSwapFateOfOutcome(classifyFailure(error, { afterQueued: true }).outcome);
6250
6308
  }
6309
+
6310
+ //#endregion
6311
+ //#region src/classes/pending_swaps.ts
6312
+ /** Key the wallet_extension has always used; its storage value is a plain array of entries. */
6313
+ const PENDING_SWAPS_STORAGE_KEY = "pendingSwaps.v1";
6314
+ /** Entries older than this are dropped the next time a wallet's swaps are listed. */
6315
+ const PENDING_SWAP_EXPIRY_MS = 6048e5;
6316
+ /**
6317
+ * Why the store dropped a pending swap (the `reason` of {@link PrunedPendingSwap}).
6318
+ *
6319
+ * - `expired`: older than {@link PENDING_SWAP_EXPIRY_MS}.
6320
+ * - `invalid_unique_key`: its `uniqueKey` is not a valid apply-results key (1 to 128 characters
6321
+ * of `A-Za-z0-9._:-`). `confirmAppliedTrade` refuses such a key with `INVALID_UNIQUE_KEY`
6322
+ * before reading anything and always will, so keeping the entry would retry it forever. The
6323
+ * SDK never signs such a key; an entry like this is corrupt or foreign.
6324
+ * - `chain_rejected`: {@link PendingSwapStore.settle} dropped it because a confirmation proved the
6325
+ * chain REFUSED the trade (`pendingSwapFateFor` is `forget`): it did not happen.
6326
+ * - `unconfirmable`: {@link PendingSwapStore.settle} dropped it because a confirmation failed in a
6327
+ * way that never changes (`forget_quietly`: the key itself is refused): nothing can be learned.
6328
+ */
6329
+ const PENDING_SWAP_PRUNE_REASONS = [
6330
+ "expired",
6331
+ "invalid_unique_key",
6332
+ "chain_rejected",
6333
+ "unconfirmable"
6334
+ ];
6251
6335
  /**
6252
6336
  * Remembers queued swaps so their outcome can be confirmed after the UI, popup or service worker
6253
6337
  * that submitted them is gone (`confirmAppliedTrade` with the stored `uniqueKey`).
@@ -7101,7 +7185,7 @@ function createLazyPrivateKeySigner(getPrivateKey, options = {}) {
7101
7185
  *
7102
7186
  * `scheme: 'personal-sign'` calls
7103
7187
  * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES
7104
- * a wallet build that contains wallet_extension commit 3ad7ae6 (strips the embedded `prefix`
7188
+ * a wallet build that contains wallet_extension commit 34ca4e4 (strips the embedded `prefix`
7105
7189
  * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets
7106
7190
  * released before that fix hash the string with the `prefix` field still inside it and the
7107
7191
  * signature recovers to an address nobody holds, so only opt in once the fixed wallet is
@@ -7126,7 +7210,7 @@ var GalaWalletSigner = class {
7126
7210
  * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits
7127
7211
  * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.
7128
7212
  * @param options - Select native signing (default) or personal-sign explicitly.
7129
- * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 3ad7ae6.
7213
+ * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 34ca4e4.
7130
7214
  * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with
7131
7215
  * `window.gala.setAddress` before every signature, when the wallet offers it.
7132
7216
  */
@@ -7207,6 +7291,7 @@ var BrowserWalletSigner = class {
7207
7291
  this.walletAddress = normalizeEthereumAccount(walletAddress, false);
7208
7292
  this.scheme = options.scheme ?? "personal-sign";
7209
7293
  }
7294
+ /** The selected `0x` Ethereum account every signature is requested for. */
7210
7295
  walletAddress;
7211
7296
  scheme;
7212
7297
  /**
@@ -7229,6 +7314,74 @@ var BrowserWalletSigner = class {
7229
7314
  }
7230
7315
  };
7231
7316
 
7317
+ //#endregion
7318
+ //#region src/classes/storage_adapters.ts
7319
+ /**
7320
+ * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
7321
+ * in: the value lands under the key as the structured value it is (the browser clones it; nothing
7322
+ * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
7323
+ * store, which treats it as "storage unavailable".
7324
+ *
7325
+ * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
7326
+ * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
7327
+ * context) then fails only when the store touches storage, and that failure (a throw inside the
7328
+ * function) is the same "storage unavailable" rejection.
7329
+ *
7330
+ * @example
7331
+ * ```ts
7332
+ * const store = new PendingSwapStore(storageAdapterFromChromeStorage(chrome.storage.local));
7333
+ * const lazy = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local));
7334
+ * ```
7335
+ */
7336
+ function storageAdapterFromChromeStorage(area) {
7337
+ const areaNow = () => typeof area === "function" ? area() : area;
7338
+ return {
7339
+ async get(key) {
7340
+ const items = await areaNow().get(key);
7341
+ return Object.hasOwn(items, key) ? items[key] : void 0;
7342
+ },
7343
+ async set(key, value) {
7344
+ await areaNow().set({ [key]: value });
7345
+ }
7346
+ };
7347
+ }
7348
+ /**
7349
+ * A {@link StorageAdapter} over a Web Storage area (`localStorage`, `sessionStorage`), the shape
7350
+ * frontend_v2 stores pending swaps in: the value lands under the key as JSON text. A missing key
7351
+ * resolves `undefined`. CORRUPT JSON resolves as the raw string, never a rejection (the store
7352
+ * reads a value that is not an array as "no entries" and the next write repairs it, whereas a
7353
+ * `get` that rejects forever would make every `remember` a no-op). A throwing area (storage blocked
7354
+ * by the browser, quota exceeded on `setItem`) rejects, which the store treats as "storage
7355
+ * unavailable".
7356
+ *
7357
+ * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
7358
+ * built: where `localStorage` does not exist (server rendering, a test, a blocked context)
7359
+ * the access throws inside the function, which is the same "storage unavailable" rejection, and
7360
+ * the module that builds the adapter still loads.
7361
+ *
7362
+ * @example
7363
+ * ```ts
7364
+ * const store = new PendingSwapStore(webStorageAdapter(() => localStorage));
7365
+ * ```
7366
+ */
7367
+ function webStorageAdapter(area) {
7368
+ const areaNow = () => typeof area === "function" ? area() : area;
7369
+ return {
7370
+ async get(key) {
7371
+ const raw = areaNow().getItem(key);
7372
+ if (raw === null) return void 0;
7373
+ try {
7374
+ return JSON.parse(raw);
7375
+ } catch {
7376
+ return raw;
7377
+ }
7378
+ },
7379
+ async set(key, value) {
7380
+ areaNow().setItem(key, JSON.stringify(value));
7381
+ }
7382
+ };
7383
+ }
7384
+
7232
7385
  //#endregion
7233
7386
  //#region src/utils/chain_dto_signing.ts
7234
7387
  /**
@@ -7237,7 +7390,7 @@ var BrowserWalletSigner = class {
7237
7390
  *
7238
7391
  * These are thin, byte-exact ports of the functions the wallet shipped in
7239
7392
  * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign
7240
- * payload resolver from its commit 3ad7ae6), re-expressed over the SDK's own primitives. Every
7393
+ * payload resolver from its commit 34ca4e4), re-expressed over the SDK's own primitives. Every
7241
7394
  * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per
7242
7395
  * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.
7243
7396
  * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.
@@ -7958,6 +8111,152 @@ function isFetchTransportFailure(error) {
7958
8111
  }
7959
8112
  }
7960
8113
 
8114
+ //#endregion
8115
+ //#region src/utils/failure_guards.ts
8116
+ /**
8117
+ * The yes/no questions an app asks about a failure from its CODE alone. They read only the failure
8118
+ * view and a short list of codes: no table of every code (that is `classifyFailure`'s, in
8119
+ * `failure_classification.ts`), no error class and no catalog (the imports above are types, erased
8120
+ * at build time). An app shell that imports one of them pays for this module and nothing else.
8121
+ */
8122
+ /**
8123
+ * True when the gateway answered that the write's `uniqueKey` was ALREADY CONSUMED: a
8124
+ * `CHAIN_DISPATCH_FAILED` with HTTP status 409. The first attempt under that key may be applied
8125
+ * (`classifyFailure` says `unknown`), so the app confirms the key it holds instead of submitting
8126
+ * again or showing the server's text. It replaces `error.code === 'CHAIN_DISPATCH_FAILED' &&
8127
+ * error.status === 409` and the regex on "already saved". Accepts an SDK error or a plain-object
8128
+ * view ({@link FailureView}: `code` and `status`); every other value is `false`.
8129
+ *
8130
+ * @example
8131
+ * ```ts
8132
+ * if (isUniqueKeyConsumed(error)) return confirmAndShowResult(error.uniqueKey);
8133
+ * ```
8134
+ */
8135
+ function isUniqueKeyConsumed(error) {
8136
+ const view = toFailureView(error);
8137
+ return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
8138
+ }
8139
+ const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
8140
+ "GATEWAY_DATA_MISSING",
8141
+ "GATEWAY_MODE_INVALID",
8142
+ "GATEWAY_SYNC_REQUEST_TRADE",
8143
+ "MISSING_UNIQUE_KEY",
8144
+ "UNIQUE_KEY_MISMATCH"
8145
+ ];
8146
+ /**
8147
+ * True when a write got a 2xx answer that does NOT prove it was queued under the signed key: no
8148
+ * `data`, an unreadable `mode`, a synchronous RequestTrade, or a missing or foreign `uniqueKey`.
8149
+ * The outcome is `unknown` (it may have been queued: confirm `error.uniqueKey`), and the copy an
8150
+ * app shows is one line for all five ("the backend did not confirm it queued the request"), so
8151
+ * the app asks this instead of keeping its own list of the codes. A gateway that says
8152
+ * `error: true` (`GATEWAY_REPORTED_ERROR`) is a refusal with its own message, not in this set.
8153
+ *
8154
+ * @example
8155
+ * ```ts
8156
+ * if (isUnprovenAcknowledgement(error)) keepPendingAndConfirm(error.uniqueKey);
8157
+ * ```
8158
+ */
8159
+ function isUnprovenAcknowledgement(error) {
8160
+ return hasCodeIn(error, UNPROVEN_ACKNOWLEDGEMENT_CODES);
8161
+ }
8162
+ /** True when `code` is one of `codes` (a list of catalog codes), by exact spelling. */
8163
+ function isCodeIn(code, codes) {
8164
+ return codes.some((known) => known === code);
8165
+ }
8166
+ /**
8167
+ * True when `error` is an SDK error OR a plain-object view of one (see {@link FailureView}) whose
8168
+ * `code` is one of `codes`. The code is compared with the catalog's own spelling, so a wallet
8169
+ * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
8170
+ */
8171
+ function hasCodeIn(error, codes) {
8172
+ const view = toFailureView(error);
8173
+ return view !== void 0 && isCodeIn(view.code, codes);
8174
+ }
8175
+ /**
8176
+ * The codes whose `params.serverMessage` is the gateway's own answer to THIS write, which an app
8177
+ * may show as it is (and falls back to its own line when it is empty): a refusal the gateway made
8178
+ * (`GATEWAY_REPORTED_ERROR`, a 2xx with `error: true`) or a bounce it named (the gateway codes the
8179
+ * SDK knows, and `GATEWAY_REJECTED` for one it does not).
8180
+ */
8181
+ const RELAYABLE_REFUSAL_CODES = [
8182
+ "GATEWAY_REPORTED_ERROR",
8183
+ "METHOD_NOT_ALLOWED",
8184
+ "SIGNATURE_INVALID",
8185
+ "SIGNER_MISMATCH",
8186
+ "DTO_INVALID",
8187
+ "BOUNDS_VIOLATION",
8188
+ "SYMBOL_CONFLICT",
8189
+ "RATE_LIMITED",
8190
+ "CHAIN_DISPATCH_FAILED",
8191
+ "GATEWAY_REJECTED"
8192
+ ];
8193
+ function isRelayableRefusal(error) {
8194
+ return hasCodeIn(error, RELAYABLE_REFUSAL_CODES);
8195
+ }
8196
+ /**
8197
+ * True when a write got a 2xx answer the SDK refused to interpret, so the answer itself is in
8198
+ * `error.body` (or `error.bodyText`) for the app to read: the five unproven acknowledgements
8199
+ * (`isUnprovenAcknowledgement`) and `GATEWAY_REPORTED_ERROR` (a gateway that says `error: true`).
8200
+ * The outcome is `unknown` for all six. It replaces the app's own
8201
+ * `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')` pair.
8202
+ */
8203
+ function isUninterpretedAnswer(error) {
8204
+ return isUnprovenAcknowledgement(error) || hasCodeIn(error, ["GATEWAY_REPORTED_ERROR"]);
8205
+ }
8206
+ /**
8207
+ * The chain's own machine-readable `ErrorKey` of a failure (`'TOKEN_NOT_FOUND'`,
8208
+ * `'NOT_ENOUGH_LIQUIDITY'`, ...), for an app that maps a chain refusal to its own copy: the
8209
+ * `params.errorKey` of a `CHAIN_REJECTED` (an apply result, or a body that carries the chain's
8210
+ * error) and of a `CHAIN_DISPATCH_FAILED` (the gateway adds the chain's key to the body it
8211
+ * answered). `undefined` when the failure is neither, or when it carries no key (the gateway sent
8212
+ * none: the SDK writes `''`, which is not a key). Map the KEY, never the message text.
8213
+ *
8214
+ * Accepts an SDK error or a plain-object view ({@link FailureView}: `code` and `params`); every
8215
+ * other value is `undefined`. Other codes are `undefined` even when they have an `errorKey`-named
8216
+ * param, so a stray field cannot pass for a chain verdict.
8217
+ *
8218
+ * @example
8219
+ * ```ts
8220
+ * const key = chainErrorKeyOf(error);
8221
+ * if (key === 'NOT_ENOUGH_LIQUIDITY') showTooThin(); else showGeneric(error);
8222
+ * ```
8223
+ */
8224
+ function chainErrorKeyOf(error) {
8225
+ const view = toFailureView(error);
8226
+ if (view === void 0) return void 0;
8227
+ if (view.code !== "CHAIN_REJECTED" && view.code !== "CHAIN_DISPATCH_FAILED") return void 0;
8228
+ const errorKey = stringParamOf(view, "errorKey");
8229
+ return errorKey === void 0 || errorKey === "" ? void 0 : errorKey;
8230
+ }
8231
+ /** Codes that mean "there is no market for this" however the app reached them. */
8232
+ const NO_MARKET_CODES = [
8233
+ "NO_POOL_AVAILABLE",
8234
+ "INSUFFICIENT_LIQUIDITY",
8235
+ "UNKNOWN_TOKEN"
8236
+ ];
8237
+ /**
8238
+ * True when a failure means "there is no market to trade this pair": `NO_POOL_AVAILABLE` (no pool
8239
+ * at any fee tier), `INSUFFICIENT_LIQUIDITY` (a pool too thin to quote), `UNKNOWN_TOKEN` (the DEX
8240
+ * has no trading symbol for the token), or a READ that was answered 404 (a quote the backend
8241
+ * cannot find, `error.notFound`). It replaces an app's own `code === ... || code === ... ||
8242
+ * notFound` list, so the empty-state ("No market for this pair") has one definition.
8243
+ *
8244
+ * A write that was answered 404 (it carries a `uniqueKey`) is a missing route, not a missing
8245
+ * market, and is not this. Accepts an SDK error or a plain-object view ({@link FailureView}); every
8246
+ * other value is `false`.
8247
+ *
8248
+ * @example
8249
+ * ```ts
8250
+ * if (isNoMarket(error)) showEmptyState(t('swap.noMarket')); else showError(error);
8251
+ * ```
8252
+ */
8253
+ function isNoMarket(error) {
8254
+ const view = toFailureView(error);
8255
+ if (view === void 0) return false;
8256
+ if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
8257
+ return !isWriteView(view) && (view.notFound === true || view.status === 404);
8258
+ }
8259
+
7961
8260
  //#endregion
7962
8261
  //#region src/utils/submit_state.ts
7963
8262
  /** The `mode` of `envelope.data`, or `undefined` when there is no such field. */
@@ -7999,5 +8298,5 @@ function classifySubmitEnvelope(envelope) {
7999
8298
  }
8000
8299
 
8001
8300
  //#endregion
8002
- export { ALL_FEE_TIERS, AppliedTradeError, Assets, BrowserWalletSigner, CanonicalSymbols, ChainGateway, DEFAULT_UNIQUE_KEY_PREFIX, DEX_FEE_METHODS, DRY_RUN_METHOD, DRY_RUN_UNIQUE_KEY_PREFIX, DexFees, EIP712_CAPABLE_METHODS, FAILURE_OUTCOMES, FEE_TIER, GC_MAX_TICK, GC_MIN_TICK, GSWAP_ENVIRONMENTS, GSWAP_ERROR_CATALOG, GSWAP_ERROR_PHASES, GSWAP_ERROR_PHASE_BY_CODE, GSwap, GSwapSDKError, GalaWalletSigner, GdexStreamError, GdexStreamService, INVALID_PRIVATE_KEY_REASONS, NOT_QUEUED_FINAL, PENDING_SWAPS_STORAGE_KEY, PENDING_SWAP_EXPIRY_MS, PENDING_SWAP_FATES, PENDING_SWAP_PRUNE_REASONS, PendingSwapStore, Pools, Positions, PrivateKeySigner, Quoting, SHADOW_FAILURE_KINDS, SHADOW_SUBMIT_CODES, SIGNING_FAILURE_REASONS, SUBMISSION_OUTCOME_UNKNOWN_REASONS, SubmittedTransaction, Swaps, Symbols, TICK_SPACING_BY_FEE, UPDATE_REQUIRED_STATUS, alignTickDown, alignTickUp, assertCanonicalPair, assertCanonicalV2Dto, assertTickRange, assertUniqueKey, buildAddLiquidityDto, buildCollectPositionFeesDto, buildCreatePoolDto, buildDryRunWrapper, buildEIP712Payload, buildRemoveLiquidityDto, buildRequestTradeDto, calculatePersonalSignPrefix, canonicalDecimalString, classification, classifyFailure, classifyShadowSubmitError, classifyShadowSubmitStatus, classifySubmitEnvelope, compositeKeyOf, confirmAppliedTrade, confirmationStateOf, createLazyPrivateKeySigner, createUniqueKey, eip1193ProviderFromEthers, eip712DomainFor, ethAddressOfPrivateKey, ethereumAddressOfAccount, fixpointPrefixFor, frameSlot0, generateEIP712Types, getObjectProperty, getPayloadToSign, getStringProperty, gswapErrorTemplates, hashTypedData, httpRequestorFromAxios, isConfirmationAborted, isConfirmationTimeout, isCurrentContractDexMessage, isDexFeeMethod, isFetchTransportFailure, isGSwapError, isGSwapErrorLike, isGdexLiquidityEvent, isNoMarket, isPreSendError, isProposableTradingSymbol, isRelayableRefusal, isShadowError, isSubmitExecuted, isSubmitQueued, isSubmitRejected, isUninterpretedAnswer, isUniqueKeyConsumed, isUnprovenAcknowledgement, isValidUniqueKey, isWalletUserRejection, isWriteView, mayHaveBeenQueued, normalizePrivateKey, notSentClassification, orderSymbols, parseJson, parseTokenClassKey, pendingSwapFateFor, pendingSwapFateOfOutcome, personalSignPrefixFor, queryTokenOf, rawTokenOf, readOrderedSymbols, readShadowSubmitOutcome, renderGSwapErrorTemplate, resolvePersonalSignChainDtoPayload, resolveUniqueKeyPrefix, serialize, signChainDtoHash, signChainDtoNative, signChainDtoPersonalSign, signNative, signPersonalMessage, signRawObject, signSerializedNative, signTypedDataPayload, sqrtPriceToTick, storageAdapterFromChromeStorage, stripEip712DomainType, swapRouteFromQuote, tickFromPrice, tickToPrice, tickToSqrtPrice, toChainDto, toFailureView, tokenClassDollarKey, tradingSymbolOf, tryParseCompositeKey, tryParseTokenClassKey, validateFee, validateNumericAmount, validatePriceValues, validateTickRange, validateTickSpacing, validateTokenDecimals, validateWalletAddress, walletDeclineCode, withPrivateKey };
8301
+ export { ALL_FEE_TIERS, AppliedTradeError, Assets, BrowserWalletSigner, CanonicalSymbols, ChainGateway, DEFAULT_UNIQUE_KEY_PREFIX, DEX_FEE_METHODS, DRY_RUN_METHOD, DRY_RUN_UNIQUE_KEY_PREFIX, DexFees, EIP712_CAPABLE_METHODS, FAILURE_OUTCOMES, FEE_TIER, GC_MAX_TICK, GC_MIN_TICK, GSWAP_ENVIRONMENTS, GSWAP_ERROR_CATALOG, GSWAP_ERROR_PHASES, GSWAP_ERROR_PHASE_BY_CODE, GSwap, GSwapSDKError, GalaWalletSigner, GdexStreamError, GdexStreamService, INVALID_PRIVATE_KEY_REASONS, NOT_QUEUED_FINAL, PENDING_SWAPS_STORAGE_KEY, PENDING_SWAP_EXPIRY_MS, PENDING_SWAP_FATES, PENDING_SWAP_PRUNE_REASONS, PendingSwapStore, Pools, Positions, PrivateKeySigner, Quoting, SHADOW_FAILURE_KINDS, SHADOW_SUBMIT_CODES, SIGNING_FAILURE_REASONS, SUBMISSION_OUTCOME_UNKNOWN_REASONS, SubmittedTransaction, Swaps, Symbols, TICK_SPACING_BY_FEE, UPDATE_REQUIRED_STATUS, alignTickDown, alignTickDownOrNaN, alignTickUp, alignTickUpOrNaN, assertCanonicalPair, assertCanonicalV2Dto, assertTickRange, assertUniqueKey, buildAddLiquidityDto, buildCollectPositionFeesDto, buildCreatePoolDto, buildDryRunWrapper, buildEIP712Payload, buildRemoveLiquidityDto, buildRequestTradeDto, calculatePersonalSignPrefix, canonicalDecimalString, chainErrorKeyOf, classification, classifyFailure, classifyShadowSubmitError, classifyShadowSubmitStatus, classifySubmitEnvelope, compositeKeyOf, confirmAppliedTrade, confirmationStateOf, createLazyPrivateKeySigner, createUniqueKey, eip1193ProviderFromEthers, eip712DomainFor, ethAddressOfPrivateKey, ethereumAddressOfAccount, fixpointPrefixFor, frameSlot0, generateEIP712Types, getObjectProperty, getPayloadToSign, getStringProperty, gswapErrorTemplates, hashTypedData, httpRequestorFromAxios, isConfirmationAborted, isConfirmationTimeout, isCurrentContractDexMessage, isDexFeeMethod, isFetchTransportFailure, isGSwapError, isGSwapErrorLike, isGdexLiquidityEvent, isNoMarket, isPreSendError, isProposableTradingSymbol, isRelayableRefusal, isShadowError, isSqrtPriceInRange, isSubmitExecuted, isSubmitQueued, isSubmitRejected, isTickInRange, isUninterpretedAnswer, isUniqueKeyConsumed, isUnprovenAcknowledgement, isValidUniqueKey, isWalletUserRejection, isWriteView, mayHaveBeenQueued, normalizePrivateKey, notSentClassification, orderSymbols, parseJson, parseTokenClassKey, pendingSwapFateFor, pendingSwapFateOfOutcome, personalSignPrefixFor, queryTokenOf, rawTokenOf, readOrderedSymbols, readShadowSubmitOutcome, renderGSwapErrorTemplate, resolvePersonalSignChainDtoPayload, resolveUniqueKeyPrefix, serialize, signChainDtoHash, signChainDtoNative, signChainDtoPersonalSign, signNative, signPersonalMessage, signRawObject, signSerializedNative, signTypedDataPayload, sqrtPriceToTick, storageAdapterFromChromeStorage, stripEip712DomainType, swapRouteFromQuote, tickFromPrice, tickToPrice, tickToSqrtPrice, toChainDto, toFailureView, tokenClassDollarKey, tradingSymbolOf, tryParseCompositeKey, tryParseTokenClassKey, validateFee, validateNumericAmount, validatePriceValues, validateTickRange, validateTickSpacing, validateTokenDecimals, validateWalletAddress, walletDeclineCode, webStorageAdapter, withPrivateKey };
8003
8302
  //# sourceMappingURL=index.mjs.map