@gala-chain/gswap-sdk 1.2.0 → 2.0.0-rc.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 (138) hide show
  1. package/README.md +42 -8
  2. package/dist/browser/classes/apply_results.js +1 -1
  3. package/dist/browser/classes/apply_results.js.map +1 -1
  4. package/dist/browser/classes/assets.js +1 -1
  5. package/dist/browser/classes/assets.js.map +1 -1
  6. package/dist/browser/classes/dex_fees.js +1 -1
  7. package/dist/browser/classes/dex_fees.js.map +1 -1
  8. package/dist/browser/classes/gateway.js +1 -1
  9. package/dist/browser/classes/gateway.js.map +1 -1
  10. package/dist/browser/classes/gdex_stream.js +1 -1
  11. package/dist/browser/classes/gdex_stream.js.map +1 -1
  12. package/dist/browser/classes/gswap.js +1 -1
  13. package/dist/browser/classes/gswap.js.map +1 -1
  14. package/dist/browser/classes/gswap_error_catalog.js +2 -0
  15. package/dist/browser/classes/gswap_error_catalog.js.map +1 -0
  16. package/dist/browser/classes/gswap_error_phase_table.js +2 -0
  17. package/dist/browser/classes/gswap_error_phase_table.js.map +1 -0
  18. package/dist/browser/classes/gswap_sdk_error.js +1 -1
  19. package/dist/browser/classes/gswap_sdk_error.js.map +1 -1
  20. package/dist/browser/classes/http_client.js +1 -1
  21. package/dist/browser/classes/http_client.js.map +1 -1
  22. package/dist/browser/classes/leaderboard.js +2 -0
  23. package/dist/browser/classes/leaderboard.js.map +1 -0
  24. package/dist/browser/classes/market.js +2 -0
  25. package/dist/browser/classes/market.js.map +1 -0
  26. package/dist/browser/classes/pending_swap_fate.js.map +1 -1
  27. package/dist/browser/classes/pending_swaps.js +1 -1
  28. package/dist/browser/classes/pending_swaps.js.map +1 -1
  29. package/dist/browser/classes/pools.js +1 -1
  30. package/dist/browser/classes/pools.js.map +1 -1
  31. package/dist/browser/classes/positions.js +1 -1
  32. package/dist/browser/classes/positions.js.map +1 -1
  33. package/dist/browser/classes/quoting.js +1 -1
  34. package/dist/browser/classes/quoting.js.map +1 -1
  35. package/dist/browser/classes/shadow_submit.js.map +1 -1
  36. package/dist/browser/classes/storage_adapters.js.map +1 -1
  37. package/dist/browser/classes/submitted_transaction.js +1 -1
  38. package/dist/browser/classes/submitted_transaction.js.map +1 -1
  39. package/dist/browser/classes/swaps.js +1 -1
  40. package/dist/browser/classes/swaps.js.map +1 -1
  41. package/dist/browser/classes/symbols.js +1 -1
  42. package/dist/browser/classes/symbols.js.map +1 -1
  43. package/dist/browser/index.js +1 -1
  44. package/dist/browser/types/env.js.map +1 -1
  45. package/dist/browser/types/fees.js.map +1 -1
  46. package/dist/browser/types/market.js +2 -0
  47. package/dist/browser/types/market.js.map +1 -0
  48. package/dist/browser/utils/classification.js.map +1 -1
  49. package/dist/browser/utils/confirmation_schedule.js.map +1 -1
  50. package/dist/browser/utils/confirmation_state.js +1 -1
  51. package/dist/browser/utils/confirmation_state.js.map +1 -1
  52. package/dist/browser/utils/debug.js.map +1 -1
  53. package/dist/browser/utils/dto_builders.js +1 -1
  54. package/dist/browser/utils/dto_builders.js.map +1 -1
  55. package/dist/browser/utils/failure_classification.js +1 -1
  56. package/dist/browser/utils/failure_classification.js.map +1 -1
  57. package/dist/browser/utils/failure_guards.js +1 -1
  58. package/dist/browser/utils/failure_guards.js.map +1 -1
  59. package/dist/browser/utils/lenient.js +1 -1
  60. package/dist/browser/utils/lenient.js.map +1 -1
  61. package/dist/browser/utils/ordering.js +1 -1
  62. package/dist/browser/utils/ordering.js.map +1 -1
  63. package/dist/browser/utils/reconnection.js +1 -1
  64. package/dist/browser/utils/reconnection.js.map +1 -1
  65. package/dist/browser/utils/resolve_pre_send.js +2 -0
  66. package/dist/browser/utils/resolve_pre_send.js.map +1 -0
  67. package/dist/browser/utils/server_message.js.map +1 -1
  68. package/dist/browser/utils/shadow_errors.js +1 -1
  69. package/dist/browser/utils/shadow_errors.js.map +1 -1
  70. package/dist/browser/utils/submit_state.js.map +1 -1
  71. package/dist/browser/utils/tick_align.js.map +1 -1
  72. package/dist/browser/utils/tick_math.js.map +1 -1
  73. package/dist/browser/utils/tick_range.js.map +1 -1
  74. package/dist/browser/utils/ticks.js +1 -1
  75. package/dist/browser/utils/ticks.js.map +1 -1
  76. package/dist/browser/utils/validation.js +1 -1
  77. package/dist/browser/utils/validation.js.map +1 -1
  78. package/dist/index.cjs +1033 -2925
  79. package/dist/index.cjs.map +1 -1
  80. package/dist/index.d.cts +439 -1604
  81. package/dist/index.d.ts +439 -1604
  82. package/dist/index.mjs +964 -2810
  83. package/dist/index.mjs.map +1 -1
  84. package/package.json +36 -60
  85. package/dist/browser/classes/error_catalog.js +0 -2
  86. package/dist/browser/classes/error_catalog.js.map +0 -1
  87. package/dist/browser/classes/error_phase_table.js +0 -2
  88. package/dist/browser/classes/error_phase_table.js.map +0 -1
  89. package/dist/browser/classes/error_phases.js +0 -2
  90. package/dist/browser/classes/error_phases.js.map +0 -1
  91. package/dist/browser/classes/signers.js +0 -2
  92. package/dist/browser/classes/signers.js.map +0 -1
  93. package/dist/browser/utils/axios_requestor.js +0 -2
  94. package/dist/browser/utils/axios_requestor.js.map +0 -1
  95. package/dist/browser/utils/chain_dto_signing.js +0 -3
  96. package/dist/browser/utils/chain_dto_signing.js.map +0 -1
  97. package/dist/browser/utils/class_key.js +0 -2
  98. package/dist/browser/utils/class_key.js.map +0 -1
  99. package/dist/browser/utils/eip712.js +0 -4
  100. package/dist/browser/utils/eip712.js.map +0 -1
  101. package/dist/browser/utils/error_brand.js +0 -2
  102. package/dist/browser/utils/error_brand.js.map +0 -1
  103. package/dist/browser/utils/ethers_provider.js +0 -2
  104. package/dist/browser/utils/ethers_provider.js.map +0 -1
  105. package/dist/browser/utils/failure_outcomes.js +0 -2
  106. package/dist/browser/utils/failure_outcomes.js.map +0 -1
  107. package/dist/browser/utils/failure_view.js +0 -2
  108. package/dist/browser/utils/failure_view.js.map +0 -1
  109. package/dist/browser/utils/fetch_failure.js +0 -2
  110. package/dist/browser/utils/fetch_failure.js.map +0 -1
  111. package/dist/browser/utils/pre_send.js +0 -2
  112. package/dist/browser/utils/pre_send.js.map +0 -1
  113. package/dist/browser/utils/signing.js +0 -3
  114. package/dist/browser/utils/signing.js.map +0 -1
  115. package/dist/browser/utils/transport.js +0 -2
  116. package/dist/browser/utils/transport.js.map +0 -1
  117. package/dist/browser/utils/typed_data.js +0 -2
  118. package/dist/browser/utils/typed_data.js.map +0 -1
  119. package/dist/browser/utils/unique_key.js +0 -2
  120. package/dist/browser/utils/unique_key.js.map +0 -1
  121. package/dist/browser/utils/unique_key_syntax.js +0 -2
  122. package/dist/browser/utils/unique_key_syntax.js.map +0 -1
  123. package/dist/browser/utils/wallet_rejection.js +0 -2
  124. package/dist/browser/utils/wallet_rejection.js.map +0 -1
  125. package/dist/browser/version.js +0 -2
  126. package/dist/browser/version.js.map +0 -1
  127. package/dist/browser/wallet.js +0 -2
  128. package/dist/browser/wallet.js.map +0 -1
  129. package/dist/wallet.cjs +0 -159
  130. package/dist/wallet.cjs.map +0 -1
  131. package/dist/wallet.d.cts +0 -74
  132. package/dist/wallet.d.ts +0 -74
  133. package/dist/wallet.mjs +0 -156
  134. package/dist/wallet.mjs.map +0 -1
  135. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/defineProperty.js +0 -0
  136. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPrimitive.js +0 -0
  137. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPropertyKey.js +0 -0
  138. /package/dist/browser/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/typeof.js +0 -0
package/dist/index.cjs CHANGED
@@ -26,14 +26,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  }) : target, mod));
27
27
 
28
28
  //#endregion
29
+ let _gala_chain_gala_core_sdk = require("@gala-chain/gala-core-sdk");
29
30
  let bignumber_js = require("bignumber.js");
30
31
  bignumber_js = __toESM(bignumber_js, 1);
31
32
  let decimal_js = require("decimal.js");
32
33
  let debug = require("debug");
33
34
  debug = __toESM(debug, 1);
34
- let _noble_curves_secp256k1 = require("@noble/curves/secp256k1");
35
- let _noble_hashes_sha3 = require("@noble/hashes/sha3");
36
- let _noble_hashes_utils = require("@noble/hashes/utils");
37
35
 
38
36
  //#region src/utils/confirmation_schedule.ts
39
37
  const DEFAULT_TIMEOUT_MS = 6e4;
@@ -125,352 +123,30 @@ function readServerMessage(error) {
125
123
  }
126
124
 
127
125
  //#endregion
128
- //#region src/utils/unique_key_syntax.ts
129
- /**
130
- * The shape of a write `uniqueKey`, with NO imports: the pending-swap store and the failure guards
131
- * need only this check, and importing it from `unique_key.ts` would drag in `GSwapSDKError` and the
132
- * whole error catalog for it.
133
- */
134
- /** The swap backend's apply-results key constraint (`apply-results.dto.ts`). */
135
- const UNIQUE_KEY_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/u;
136
- /**
137
- * True when `uniqueKey` is a usable write key: 1 to 128 characters of `A-Za-z0-9._:-`, the shape
138
- * the apply-results route accepts. The one definition behind `assertUniqueKey`, `confirm()` and
139
- * the pending-swap store, so they can never disagree about what a valid key is.
140
- */
141
- function isValidUniqueKey(uniqueKey) {
142
- return typeof uniqueKey === "string" && UNIQUE_KEY_PATTERN.test(uniqueKey);
143
- }
144
-
145
- //#endregion
146
- //#region src/utils/error_brand.ts
147
- /**
148
- * The brand every `GSwapSDKError` carries, and the duck-type check for the "failure shape". This
149
- * module has NO imports on purpose: it is part of the light `@gala-chain/gswap-sdk/wallet` entry,
150
- * which must never pull the error catalog or the main bundle in.
151
- */
152
- /**
153
- * The brand of an SDK error: `error[GSWAP_ERROR_BRAND] === true`. It is a registered symbol
154
- * (`Symbol.for`), so two copies of the SDK in one page (a wallet bundle and an app bundle) still
155
- * recognise each other's errors, which `instanceof` cannot do.
156
- */
157
- const GSWAP_ERROR_BRAND = Symbol.for("@gala-chain/gswap-sdk/error");
158
- function isRecord$4(value) {
159
- return typeof value === "object" && value !== null;
160
- }
161
- /** True when `value` carries the SDK error brand (a real `GSwapSDKError`, from any copy of the SDK). */
162
- function hasGSwapErrorBrand(value) {
163
- return isRecord$4(value) && value[GSWAP_ERROR_BRAND] === true;
164
- }
165
- /**
166
- * True when `value` is an SDK error (it carries the brand) or a plain-object VIEW of one: a string
167
- * `code` and an object `params`, which is the shape of `GSwapSDKError` and of the wrapper objects
168
- * an app builds from one (`{ code, params, status?, phase?, ... }`). A wallet's own error (an
169
- * EIP-1193 numeric `code`, an ethers error with a string `code` and no `params`) is neither. It
170
- * says the value has the SDK's shape, not that `code` is a code the SDK knows.
171
- *
172
- * @example
173
- * ```ts
174
- * if (isGSwapErrorLike(error)) report(error.code, error.params); // no `instanceof`, no SDK import
175
- * ```
176
- */
177
- function isGSwapErrorLike(value) {
178
- if (hasGSwapErrorBrand(value)) return true;
179
- return isRecord$4(value) && typeof value["code"] === "string" && isRecord$4(value["params"]) && !Array.isArray(value["params"]);
180
- }
181
-
182
- //#endregion
183
- //#region src/classes/error_phases.ts
184
- /**
185
- * How far an operation had got when it failed, measured against the request it exists to send:
186
- * for a write, the POST that carries the signed DTO to the gateway; for a read, the GET.
187
- *
188
- * - `pre_send`: NOTHING was transmitted. Everything up to the request (validation, symbol
189
- * resolution, the signer, the wallet, a key provider) ran and failed, so no write can have been
190
- * queued. A write that failed `pre_send` is never "maybe applied".
191
- * - `in_flight`: the request left (or may have left) and no answer was read: a timeout, a broken
192
- * connection, a stream that dropped. For a write the outcome is unknown.
193
- * - `post_send`: an answer was read, or the write was already accepted: a refusal, an
194
- * acknowledgement that proves nothing, an unusable body, and every failure of a confirmation.
195
- *
196
- * Each catalog entry declares the phase its code is thrown in; a throw site where the same code
197
- * can occur in another phase overrides it (`GSwapErrorContext.phase`). It is a typed property of
198
- * every `GSwapSDKError` (`error.phase`) and `isPreSendError(error)` reads it.
199
- *
200
- * This module has no imports, on purpose: it is the closed set of phases, shared by the catalog,
201
- * the light phase table (`error_phase_table.ts`) and the failure view.
202
- */
203
- const GSWAP_ERROR_PHASES = [
204
- "pre_send",
205
- "in_flight",
206
- "post_send"
207
- ];
208
-
209
- //#endregion
210
- //#region src/utils/failure_outcomes.ts
211
- /**
212
- * What a failure means for the operation that raised it, as one vocabulary for every app.
213
- *
214
- * - `rejected`: the CHAIN refused the request (a definite no). Nothing was applied, so a NEW
215
- * request is safe.
216
- * - `unknown`: the request MAY have been applied (a timeout, a broken connection, an
217
- * acknowledgement that proves nothing, a failed confirmation). Never submit again under a fresh
218
- * key: keep `error.uniqueKey` and confirm it.
219
- * - `not_queued`: the gateway refused the write before queueing it. Nothing is pending.
220
- * - `not_sent`: the request never left (`error.phase === 'pre_send'`) for a reason outside the
221
- * call itself: the signer or the wallet failed (locked, unreachable, the person declined), the
222
- * key provider or the token resolver failed, or no key was available yet. Nothing is pending and
223
- * nothing was transmitted, so repeating the call is safe and may succeed once the cause (an
224
- * unlocked wallet) is gone.
225
- * - `invalid_input`: the call itself cannot work (a bad argument, a missing signer or wallet, an
226
- * unknown token or pool, a corrupt stored key). Repeating the same call fails the same way.
227
- * Such an error is also pre-send (`isPreSendError`), but the input is what has to change.
228
- * - `transient`: a read or connection failed with no state change. Repeating the same call is safe
229
- * and may succeed.
126
+ //#region src/classes/gswap_error_catalog.ts
127
+ /**
128
+ * The catalog of every error code gswap-sdk ITSELF throws (the DEX codes): the SINGLE source of
129
+ * truth for its `code`, the named parameters it carries and the English template its `message` is
130
+ * generated from. The codes of the signing, transport and wallet layer (`INVALID_PRIVATE_KEY`,
131
+ * `REQUEST_TIMEOUT`, `SIGNING_FAILED`, `TYPED_DATA_*`, ...) live in `@gala-chain/gala-core-sdk`'s
132
+ * `GALA_ERROR_CATALOG`; no code is defined in both. A `GSwapSDKError` can carry a code of either
133
+ * catalog (`GSwapErrorCode` is the union), and reads its template from both.
230
134
  *
231
- * This module has no imports: the failure view (`FailureView.outcome`) and the classifier both
232
- * read the closed set from here.
233
- */
234
- const FAILURE_OUTCOMES = [
235
- "rejected",
236
- "unknown",
237
- "not_queued",
238
- "not_sent",
239
- "invalid_input",
240
- "transient"
241
- ];
242
-
243
- //#endregion
244
- //#region src/utils/failure_view.ts
245
- function isRecord$3(value) {
246
- return typeof value === "object" && value !== null;
247
- }
248
- /**
249
- * Reads the failure view of any value: a `GSwapSDKError`, or a plain object with a string `code`
250
- * (and, optionally, `params`, `status`, `phase`, `uniqueKey`, `shadow`, `notFound`). Anything else
251
- * (a string, a wallet error with a numeric `code`, `null`) has no view and is `undefined`.
252
- *
253
- * Having a view does not mean the SDK knows the code: an ethers error is `{ code:
254
- * 'ACTION_REJECTED' }` and has a view too. The SDK's guards compare the code with the catalog.
255
- *
256
- * @example
257
- * ```ts
258
- * const view = toFailureView(error); // an SDK error, or an app's `{ code, params, status }` wrapper
259
- * if (view?.code === 'CHAIN_REJECTED') showChainRejection(view.params);
260
- * ```
261
- */
262
- function toFailureView(value) {
263
- if (!isRecord$3(value)) return void 0;
264
- const { code, params, status, phase, uniqueKey, write, outcome, retryable, shadow, notFound } = value;
265
- if (typeof code !== "string" || code === "") return void 0;
266
- return {
267
- code,
268
- params: isRecord$3(params) && !Array.isArray(params) ? params : void 0,
269
- status: typeof status === "number" && Number.isFinite(status) ? status : void 0,
270
- phase: GSWAP_ERROR_PHASES.find((known) => known === phase),
271
- uniqueKey: typeof uniqueKey === "string" && uniqueKey !== "" ? uniqueKey : void 0,
272
- write: typeof write === "boolean" ? write : void 0,
273
- outcome: FAILURE_OUTCOMES.find((known) => known === outcome),
274
- retryable: retryable === false ? false : void 0,
275
- shadow: typeof shadow === "boolean" ? shadow : void 0,
276
- notFound: typeof notFound === "boolean" ? notFound : void 0
277
- };
278
- }
279
- /**
280
- * True when a failure is a WRITE's: it names a `uniqueKey`, or it does not say `write: false`.
281
- * Fail-closed (see {@link FailureView}): only an explicit read is a read.
282
- */
283
- function isWriteView(view) {
284
- return view.uniqueKey !== void 0 || view.write !== false;
285
- }
286
- /** A param of a view, when it is a string. */
287
- function stringParamOf(view, name) {
288
- var _view$params;
289
- const value = (_view$params = view.params) === null || _view$params === void 0 ? void 0 : _view$params[name];
290
- return typeof value === "string" ? value : void 0;
291
- }
292
- /** A param of a view, when it is a finite number. */
293
- function numberParamOf(view, name) {
294
- var _view$params2;
295
- const value = (_view$params2 = view.params) === null || _view$params2 === void 0 ? void 0 : _view$params2[name];
296
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
297
- }
298
-
299
- //#endregion
300
- //#region src/classes/error_phase_table.ts
301
- /**
302
- * The phase of every catalog code, WITHOUT the catalog. The failure guards (`classifyFailure`,
303
- * `mayHaveBeenQueued`, ...) need only a code's phase, and the catalog's English templates are
304
- * ~20 kB: reading the phase from here keeps an app shell that imports a guard from loading them.
305
- * The catalog entry is still where a code is declared; this table is checked against it AT
306
- * COMPILE TIME, in both directions (a missing code, an extra code or a different phase is a type
307
- * error), so the two cannot drift.
308
- */
309
- const GSWAP_ERROR_PHASE_BY_CODE = {
310
- HTTP_ERROR: "post_send",
311
- UPDATE_REQUIRED: "post_send",
312
- REQUEST_TIMEOUT: "in_flight",
313
- TRANSPORT_ERROR: "in_flight",
314
- REQUEST_FAILED: "in_flight",
315
- INVALID_TIMEOUT: "pre_send",
316
- METHOD_NOT_SUPPORTED: "pre_send",
317
- SUBMISSION_OUTCOME_UNKNOWN: "in_flight",
318
- GATEWAY_REPORTED_ERROR: "post_send",
319
- GATEWAY_DATA_MISSING: "post_send",
320
- GATEWAY_MODE_INVALID: "post_send",
321
- GATEWAY_SYNC_REQUEST_TRADE: "post_send",
322
- MISSING_UNIQUE_KEY: "post_send",
323
- UNIQUE_KEY_MISMATCH: "post_send",
324
- SHADOW_NOT_QUEUED: "post_send",
325
- SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: "pre_send",
326
- METHOD_NOT_ALLOWED: "post_send",
327
- SIGNATURE_INVALID: "post_send",
328
- SIGNER_MISMATCH: "post_send",
329
- DTO_INVALID: "post_send",
330
- BOUNDS_VIOLATION: "post_send",
331
- SYMBOL_CONFLICT: "post_send",
332
- RATE_LIMITED: "post_send",
333
- CHAIN_DISPATCH_FAILED: "post_send",
334
- GATEWAY_REJECTED: "post_send",
335
- CHAIN_REJECTED: "post_send",
336
- INVALID_CHAIN_RESPONSE: "post_send",
337
- INVALID_POSITION_RESPONSE: "post_send",
338
- CONFIRMATION_TIMEOUT: "post_send",
339
- CONFIRMATION_ABORTED: "post_send",
340
- CONFIRMATION_FAILED: "post_send",
341
- CONFIRMATION_MALFORMED: "post_send",
342
- CONFIRMATION_KEY_MISMATCH: "post_send",
343
- NO_SIGNER: "pre_send",
344
- NO_WALLET_ADDRESS: "post_send",
345
- NO_POOL_AVAILABLE: "post_send",
346
- INSUFFICIENT_LIQUIDITY: "post_send",
347
- UNKNOWN_TOKEN: "pre_send",
348
- SYMBOL_NOT_FOUND: "pre_send",
349
- STREAM_API_KEY_UNUSABLE: "pre_send",
350
- STREAM_WEBSOCKET_UNAVAILABLE: "pre_send",
351
- STREAM_NOT_CONNECTED: "pre_send",
352
- STREAM_DISCONNECTED: "in_flight",
353
- STREAM_REQUEST_TIMEOUT: "in_flight",
354
- STREAM_CONNECT_FAILED: "in_flight",
355
- STREAM_CLOSED_BEFORE_CONNECT: "in_flight",
356
- STREAM_CONNECTION_CLOSED: "in_flight",
357
- GALA_WALLET_NOT_AVAILABLE: "pre_send",
358
- WALLET_UNAVAILABLE: "pre_send",
359
- MALFORMED_WALLET_REQUEST: "pre_send",
360
- UNSUPPORTED_WALLET_METHOD: "pre_send",
361
- INVALID_SIGNATURE: "pre_send",
362
- INVALID_CHAIN_ID: "pre_send",
363
- SIGNER_ADDRESS_MISMATCH: "pre_send",
364
- INVALID_PRIVATE_KEY: "pre_send",
365
- SIGNING_FAILED: "pre_send",
366
- KEY_PROVIDER_FAILED: "pre_send",
367
- TOKEN_RESOLUTION_FAILED: "pre_send",
368
- INVALID_SIGNING_HASH_LENGTH: "pre_send",
369
- MISSING_WALLET_ADDRESS: "pre_send",
370
- INVALID_WALLET_ADDRESS: "pre_send",
371
- INVALID_DECIMAL: "pre_send",
372
- PERSONAL_SIGN_NOT_JSON: "pre_send",
373
- PERSONAL_SIGN_NOT_OBJECT: "pre_send",
374
- PERSONAL_SIGN_BAD_PREFIX: "pre_send",
375
- PERSONAL_SIGN_ENVELOPE_FIELDS: "pre_send",
376
- PERSONAL_SIGN_NOT_CANONICAL: "pre_send",
377
- EIP712_NAME_COLLISION: "pre_send",
378
- EIP712_UNSUPPORTED_VALUE: "pre_send",
379
- TYPED_DATA_NOT_STRING: "pre_send",
380
- TYPED_DATA_UNPAIRED_SURROGATE: "pre_send",
381
- TYPED_DATA_NOT_HEX_BYTES: "pre_send",
382
- TYPED_DATA_NOT_SAFE_INTEGER: "pre_send",
383
- TYPED_DATA_NOT_INTEGER: "pre_send",
384
- TYPED_DATA_NOT_BOOLEAN: "pre_send",
385
- TYPED_DATA_BAD_ADDRESS: "pre_send",
386
- TYPED_DATA_BAD_CHECKSUM: "pre_send",
387
- TYPED_DATA_BYTES_LENGTH: "pre_send",
388
- TYPED_DATA_OUT_OF_BOUNDS: "pre_send",
389
- TYPED_DATA_UNSUPPORTED_TYPE: "pre_send",
390
- TYPED_DATA_FIELDS_NOT_LIST: "pre_send",
391
- TYPED_DATA_FIELD_MALFORMED: "pre_send",
392
- TYPED_DATA_INVALID_FIELD_NAME: "pre_send",
393
- TYPED_DATA_DUPLICATE_FIELD: "pre_send",
394
- TYPED_DATA_INVALID_TYPE_NAME: "pre_send",
395
- TYPED_DATA_CIRCULAR_TYPE: "pre_send",
396
- TYPED_DATA_UNKNOWN_FIELD_TYPE: "pre_send",
397
- TYPED_DATA_NO_PRIMARY_TYPE: "pre_send",
398
- TYPED_DATA_AMBIGUOUS_PRIMARY_TYPE: "pre_send",
399
- TYPED_DATA_ARRAY_EXPECTED: "pre_send",
400
- TYPED_DATA_ARRAY_LENGTH_MISMATCH: "pre_send",
401
- TYPED_DATA_STRUCT_NOT_OBJECT: "pre_send",
402
- TYPED_DATA_MISSING_FIELD: "pre_send",
403
- TYPED_DATA_DOMAIN_NOT_OBJECT: "pre_send",
404
- TYPED_DATA_INVALID_DOMAIN_KEY: "pre_send",
405
- NON_CANONICAL_PAIR: "pre_send",
406
- UNORDERABLE_SYMBOLS: "pre_send",
407
- INVALID_TOKEN_CLASS_KEY: "pre_send",
408
- INCOMPLETE_TOKEN_CLASS_KEY: "pre_send",
409
- INVALID_TRADING_SYMBOL: "pre_send",
410
- NO_VALID_TRADING_SYMBOL: "pre_send",
411
- TOKEN_SYMBOL_NOT_REGISTERED: "pre_send",
412
- SYMBOL_DISAGREES_WITH_REGISTRY: "pre_send",
413
- CREATE_POOL_NEEDS_CLASS_KEY: "pre_send",
414
- INVALID_UNIQUE_KEY: "pre_send",
415
- INVALID_UNIQUE_KEY_PREFIX: "pre_send",
416
- AMOUNT_IS_JS_NUMBER: "pre_send",
417
- AMOUNT_NOT_FINITE: "pre_send",
418
- AMOUNT_NOT_POSITIVE: "pre_send",
419
- AMOUNT_NEGATIVE: "pre_send",
420
- PRICE_VALUES_IS_JS_NUMBER: "pre_send",
421
- INVALID_PRICE_VALUES: "pre_send",
422
- INVALID_PRICE_RANGE: "pre_send",
423
- INVALID_PRICE_BOUNDS: "pre_send",
424
- PRICE_BOUNDS_ORDER: "pre_send",
425
- INVALID_STARTING_PRICE: "pre_send",
426
- INVALID_SQRT_PRICE: "pre_send",
427
- INVALID_TOKEN_DECIMALS: "pre_send",
428
- TICKS_NOT_INTEGERS: "pre_send",
429
- INVALID_TICK_RANGE: "pre_send",
430
- TICKS_OUT_OF_BOUNDS: "pre_send",
431
- TICKS_NOT_ALIGNED: "pre_send",
432
- INVALID_TICK_SPACING: "pre_send",
433
- INVALID_FEE: "pre_send",
434
- EXACT_AMOUNT_REQUIRED: "pre_send",
435
- EXACTLY_ONE_OF_REQUIRED: "pre_send",
436
- AT_MOST_ONE_OF_ALLOWED: "pre_send",
437
- POOL_MISMATCH: "pre_send",
438
- INVALID_DTO: "pre_send",
439
- DTO_NOT_CANONICAL: "pre_send",
440
- SEARCH_TOO_LONG: "pre_send",
441
- INVALID_SORT_BY: "pre_send",
442
- INVALID_SORT_ORDER: "pre_send",
443
- INVALID_PAGE: "pre_send",
444
- INVALID_LIMIT: "pre_send"
445
- };
446
- /** True for a code the SDK catalog defines. */
447
- function isCatalogCode(code) {
448
- return Object.hasOwn(GSWAP_ERROR_PHASE_BY_CODE, code);
449
- }
450
- /** The phase of a view: the one it states, else the catalog's phase for its code, else `undefined`. */
451
- function phaseOfView(view) {
452
- if (view.phase !== void 0) return view.phase;
453
- return isCatalogCode(view.code) ? GSWAP_ERROR_PHASE_BY_CODE[view.code] : void 0;
454
- }
455
-
456
- //#endregion
457
- //#region src/classes/error_catalog.ts
458
- /**
459
- * Why a private key was refused (`INVALID_PRIVATE_KEY.params.reason`). A token for the app to map
460
- * to its own text, never English and never any part of the key.
135
+ * - `code` is the only discriminator. It is stable: apps branch on it, never on message text.
136
+ * - `params` are the named placeholders of the error: a flat object of primitives (string,
137
+ * number, boolean) that an app feeds to its own localization (i18next, ICU, FormatJS).
138
+ * Raw server payloads are never params (they are `error.body` / `error.bodyText`), and no
139
+ * secret (private key, signature, raw DTO) ever is.
140
+ * - `template` is English with `{placeholder}` markers. `error.message` is generated from it
141
+ * and the params, so the two cannot drift. It is for logs and developers: it is not stable and
142
+ * must not be shown to users or matched on.
461
143
  *
462
- * - `wrong_length`: raw bytes that are not 32 bytes long.
463
- * - `bad_encoding`: a string that is neither 64 hex characters (optionally `0x`-prefixed, 63 is
464
- * left-padded) nor a 44-character base64 string.
465
- * - `not_on_curve`: 32 bytes that are not a valid secp256k1 secret scalar.
466
- * - `no_key_provided`: a lazy key provider returned something that is not a string.
144
+ * Every placeholder in a template is a declared param and every declared param is a placeholder,
145
+ * except the few `unrendered` params that carry server text for the app and are kept out of
146
+ * `message` on purpose (pinned by tests/error_catalog.test.ts). Facts that are not placeholders (HTTP status, URL,
147
+ * `uniqueKey`, transaction ids, the raw body, the cause) are typed properties of the error, see
148
+ * `GalaErrorContext`.
467
149
  */
468
- const INVALID_PRIVATE_KEY_REASONS = [
469
- "wrong_length",
470
- "bad_encoding",
471
- "not_on_curve",
472
- "no_key_provided"
473
- ];
474
150
  /**
475
151
  * Why the outcome of a write submission is unknown (`SUBMISSION_OUTCOME_UNKNOWN.params.reason`).
476
152
  * Both say the same thing about the swap (it MAY have been queued: never resubmit under a fresh
@@ -482,20 +158,9 @@ const INVALID_PRIVATE_KEY_REASONS = [
482
158
  * does NOT prove the swap was not sent.
483
159
  */
484
160
  const SUBMISSION_OUTCOME_UNKNOWN_REASONS = ["timeout", "transport"];
485
- /**
486
- * Why a signer could not produce a signature (`SIGNING_FAILED.params.reason`). A token for the
487
- * app to map to its own text.
488
- *
489
- * - `user_rejected`: the person declined in their wallet (an EIP-1193 `4001`, an ethers
490
- * `ACTION_REJECTED`, or a wallet that words it "User rejected/denied ..."). Nothing is wrong:
491
- * they may simply try again.
492
- * - `failed`: anything else the signer threw (a locked wallet, an unreachable extension, a wallet
493
- * that refused). The original error is `cause`.
494
- */
495
- const SIGNING_FAILURE_REASONS = ["user_rejected", "failed"];
496
161
  /** The fee tiers as they appear in `INVALID_FEE.allowed`. */
497
162
  const ALLOWED_FEE_TIERS_TEXT = "0,500,3000,10000";
498
- /** The whole catalog. Add a code here before throwing it anywhere. */
163
+ /** The whole DEX catalog. Add a code here before throwing it anywhere in gswap-sdk. */
499
164
  const GSWAP_ERROR_CATALOG = {
500
165
  HTTP_ERROR: {
501
166
  phase: "post_send",
@@ -512,32 +177,11 @@ const GSWAP_ERROR_CATALOG = {
512
177
  template: "The backend refused this app version and requires an update (HTTP {status}); nothing was queued.",
513
178
  params: { status: "number" }
514
179
  },
515
- REQUEST_TIMEOUT: {
516
- phase: "in_flight",
517
- template: "Request to {url} timed out after {timeoutMs} ms.",
518
- params: {
519
- url: "string",
520
- timeoutMs: "number"
521
- }
522
- },
523
- TRANSPORT_ERROR: {
524
- phase: "in_flight",
525
- template: "The request to {url} failed before the server answered.",
526
- params: { url: "string" }
527
- },
528
180
  REQUEST_FAILED: {
529
181
  phase: "in_flight",
530
182
  template: "The {operation} request failed.",
531
183
  params: { operation: "string" }
532
184
  },
533
- INVALID_TIMEOUT: {
534
- phase: "pre_send",
535
- template: "{field} must be a positive number of milliseconds, or Infinity for no timeout (got {value}).",
536
- params: {
537
- field: "string",
538
- value: "number"
539
- }
540
- },
541
185
  METHOD_NOT_SUPPORTED: {
542
186
  phase: "pre_send",
543
187
  template: "The method {method} is not supported; swaps are queued through RequestTrade.",
@@ -767,370 +411,109 @@ const GSWAP_ERROR_CATALOG = {
767
411
  template: "GDEX stream connection closed (code {closeCode}).",
768
412
  params: { closeCode: "number" }
769
413
  },
770
- GALA_WALLET_NOT_AVAILABLE: {
414
+ TOKEN_RESOLUTION_FAILED: {
771
415
  phase: "pre_send",
772
- template: "Gala wallet is not available. Please ensure the Gala wallet is connected.",
773
- params: {}
416
+ template: "Token {token} could not be looked up; nothing was sent.",
417
+ params: { token: "string" }
774
418
  },
775
- WALLET_UNAVAILABLE: {
419
+ MISSING_WALLET_ADDRESS: {
776
420
  phase: "pre_send",
777
- template: "No wallet is connected.",
421
+ template: "Invalid wallet address: No wallet address provided. Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK.",
778
422
  params: {}
779
423
  },
780
- MALFORMED_WALLET_REQUEST: {
781
- phase: "pre_send",
782
- template: "Wallet {method} request is malformed.",
783
- params: { method: "string" }
784
- },
785
- UNSUPPORTED_WALLET_METHOD: {
424
+ NON_CANONICAL_PAIR: {
786
425
  phase: "pre_send",
787
- template: "Unsupported wallet method {method}.",
788
- params: { method: "string" }
426
+ template: "The pair {token0}/{token1} is not in canonical order: token0 must sort before token1.",
427
+ params: {
428
+ token0: "string",
429
+ token1: "string"
430
+ }
789
431
  },
790
- INVALID_SIGNATURE: {
432
+ UNORDERABLE_SYMBOLS: {
791
433
  phase: "pre_send",
792
- template: "Wallet returned an invalid {scheme} signature.",
793
- params: { scheme: "string" }
434
+ template: "Unable to order trading symbols: expected a pair of symbols, got {received}.",
435
+ params: { received: "string" }
794
436
  },
795
- INVALID_CHAIN_ID: {
437
+ INVALID_TOKEN_CLASS_KEY: {
796
438
  phase: "pre_send",
797
- template: "Wallet returned an invalid chain id ({chainId}).",
798
- params: { chainId: "string" }
439
+ template: "Invalid token class key \"{tokenClassKey}\": expected a collection followed by category, type and additionalKey",
440
+ params: { tokenClassKey: "string" }
799
441
  },
800
- SIGNER_ADDRESS_MISMATCH: {
442
+ INCOMPLETE_TOKEN_CLASS_KEY: {
801
443
  phase: "pre_send",
802
- template: "The signing key does not belong to the expected account.",
803
- params: {}
444
+ template: "Token class key \"{compositeKey}\" is missing {part}.",
445
+ params: {
446
+ compositeKey: "string",
447
+ part: "string"
448
+ }
804
449
  },
805
- INVALID_PRIVATE_KEY: {
450
+ INVALID_TRADING_SYMBOL: {
806
451
  phase: "pre_send",
807
- template: "Invalid private key: {reason}.",
808
- params: { reason: INVALID_PRIVATE_KEY_REASONS }
452
+ template: "Invalid trading symbol \"{symbol}\": must be 1-32 ASCII letters and digits and not a reserved word (Token, Unit, none).",
453
+ params: { symbol: "string" }
809
454
  },
810
- SIGNING_FAILED: {
455
+ NO_VALID_TRADING_SYMBOL: {
811
456
  phase: "pre_send",
812
- template: "Signing the {method} request failed ({reason}); nothing was sent.",
457
+ template: "No valid trading symbol for token class {classKey}: \"{displaySymbol}\" is not an acceptable symbol and none is registered",
813
458
  params: {
814
- method: "string",
815
- reason: SIGNING_FAILURE_REASONS
459
+ classKey: "string",
460
+ displaySymbol: "string"
816
461
  }
817
462
  },
818
- KEY_PROVIDER_FAILED: {
463
+ TOKEN_SYMBOL_NOT_REGISTERED: {
819
464
  phase: "pre_send",
820
- template: "The signing key could not be fetched; nothing was sent.",
821
- params: {}
465
+ template: "Token {token} is not registered in the trading-symbol registry yet; pass token0Symbol/token1Symbol (the token class symbol) to propose one. A symbol cannot be derived from a class key.",
466
+ params: { token: "string" }
822
467
  },
823
- TOKEN_RESOLUTION_FAILED: {
468
+ SYMBOL_DISAGREES_WITH_REGISTRY: {
824
469
  phase: "pre_send",
825
- template: "Token {token} could not be looked up; nothing was sent.",
826
- params: { token: "string" }
470
+ template: "Supplied symbol {suppliedSymbol} for {token} disagrees with the registered trading symbol {registeredSymbol}.",
471
+ params: {
472
+ token: "string",
473
+ suppliedSymbol: "string",
474
+ registeredSymbol: "string"
475
+ }
827
476
  },
828
- INVALID_SIGNING_HASH_LENGTH: {
477
+ CREATE_POOL_NEEDS_CLASS_KEY: {
829
478
  phase: "pre_send",
830
- template: "secp256k1 can only sign a 32-byte hash (got {length}).",
831
- params: { length: "number" }
479
+ template: "createPool needs each token as a class key; {token} is a bare trading symbol, which does not carry one.",
480
+ params: { token: "string" }
832
481
  },
833
- MISSING_WALLET_ADDRESS: {
482
+ AMOUNT_IS_JS_NUMBER: {
834
483
  phase: "pre_send",
835
- template: "Invalid wallet address: No wallet address provided. Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK.",
836
- params: {}
484
+ template: "Invalid {field}: use a decimal string or BigNumber, not a JavaScript number",
485
+ params: { field: "string" }
837
486
  },
838
- INVALID_WALLET_ADDRESS: {
487
+ AMOUNT_NOT_FINITE: {
839
488
  phase: "pre_send",
840
- template: "Invalid {field}: \"{value}\" is not an accepted wallet address form.",
489
+ template: "Invalid {field}: must be a finite number (got {value})",
841
490
  params: {
842
491
  field: "string",
843
492
  value: "string"
844
493
  }
845
494
  },
846
- INVALID_DECIMAL: {
847
- phase: "pre_send",
848
- template: "Invalid decimal quantity: {value}",
849
- params: { value: "string" }
850
- },
851
- PERSONAL_SIGN_NOT_JSON: {
495
+ AMOUNT_NOT_POSITIVE: {
852
496
  phase: "pre_send",
853
- template: "Personal-sign DTO is not valid JSON",
854
- params: {}
497
+ template: "Invalid {field}: must be positive (got {value})",
498
+ params: {
499
+ field: "string",
500
+ value: "string"
501
+ }
855
502
  },
856
- PERSONAL_SIGN_NOT_OBJECT: {
503
+ AMOUNT_NEGATIVE: {
857
504
  phase: "pre_send",
858
- template: "Personal-sign DTO must be a JSON object",
859
- params: {}
505
+ template: "Invalid {field}: must not be negative (got {value})",
506
+ params: {
507
+ field: "string",
508
+ value: "string"
509
+ }
860
510
  },
861
- PERSONAL_SIGN_BAD_PREFIX: {
511
+ PRICE_VALUES_IS_JS_NUMBER: {
862
512
  phase: "pre_send",
863
- template: "Personal-sign DTO prefix is not an EIP-191 \"Ethereum Signed Message\" header",
513
+ template: "Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers",
864
514
  params: {}
865
515
  },
866
- PERSONAL_SIGN_ENVELOPE_FIELDS: {
867
- phase: "pre_send",
868
- template: "Personal-sign DTO carries signing-envelope field(s): {fields}",
869
- params: { fields: "string" }
870
- },
871
- PERSONAL_SIGN_NOT_CANONICAL: {
872
- phase: "pre_send",
873
- template: "Personal-sign DTO is not in canonical serialized form",
874
- params: {}
875
- },
876
- EIP712_NAME_COLLISION: {
877
- phase: "pre_send",
878
- template: "Name collisions are not supported when deriving EIP-712 types ({name}).",
879
- params: { name: "string" }
880
- },
881
- EIP712_UNSUPPORTED_VALUE: {
882
- phase: "pre_send",
883
- template: "Unsupported EIP-712 value of type {valueType}.",
884
- params: { valueType: "string" }
885
- },
886
- TYPED_DATA_NOT_STRING: {
887
- phase: "pre_send",
888
- template: "Invalid typed data: {what} must be a string",
889
- params: { what: "string" }
890
- },
891
- TYPED_DATA_UNPAIRED_SURROGATE: {
892
- phase: "pre_send",
893
- template: "Invalid typed data: {what} has an unpaired surrogate",
894
- params: { what: "string" }
895
- },
896
- TYPED_DATA_NOT_HEX_BYTES: {
897
- phase: "pre_send",
898
- template: "Invalid typed data: {what} must be an even-length 0x hex string",
899
- params: { what: "string" }
900
- },
901
- TYPED_DATA_NOT_SAFE_INTEGER: {
902
- phase: "pre_send",
903
- template: "Invalid typed data: {what} must be a safe integer",
904
- params: { what: "string" }
905
- },
906
- TYPED_DATA_NOT_INTEGER: {
907
- phase: "pre_send",
908
- template: "Invalid typed data: {what} must be an integer",
909
- params: { what: "string" }
910
- },
911
- TYPED_DATA_NOT_BOOLEAN: {
912
- phase: "pre_send",
913
- template: "Invalid typed data: bool must be a boolean",
914
- params: {}
915
- },
916
- TYPED_DATA_BAD_ADDRESS: {
917
- phase: "pre_send",
918
- template: "Invalid typed data: address must be 0x followed by 40 hex digits",
919
- params: {}
920
- },
921
- TYPED_DATA_BAD_CHECKSUM: {
922
- phase: "pre_send",
923
- template: "Invalid typed data: address has a bad checksum",
924
- params: {}
925
- },
926
- TYPED_DATA_BYTES_LENGTH: {
927
- phase: "pre_send",
928
- template: "Invalid typed data: {type} must be exactly {width} bytes",
929
- params: {
930
- type: "string",
931
- width: "number"
932
- }
933
- },
934
- TYPED_DATA_OUT_OF_BOUNDS: {
935
- phase: "pre_send",
936
- template: "Invalid typed data: value out of bounds for {type}",
937
- params: { type: "string" }
938
- },
939
- TYPED_DATA_UNSUPPORTED_TYPE: {
940
- phase: "pre_send",
941
- template: "Invalid typed data: unsupported type \"{type}\"",
942
- params: { type: "string" }
943
- },
944
- TYPED_DATA_FIELDS_NOT_LIST: {
945
- phase: "pre_send",
946
- template: "Invalid typed data: type {typeName} must be a list of fields",
947
- params: { typeName: "string" }
948
- },
949
- TYPED_DATA_FIELD_MALFORMED: {
950
- phase: "pre_send",
951
- template: "Invalid typed data: type {typeName} has a field without a string name and type",
952
- params: { typeName: "string" }
953
- },
954
- TYPED_DATA_INVALID_FIELD_NAME: {
955
- phase: "pre_send",
956
- template: "Invalid typed data: invalid field name \"{name}\"",
957
- params: { name: "string" }
958
- },
959
- TYPED_DATA_DUPLICATE_FIELD: {
960
- phase: "pre_send",
961
- template: "Invalid typed data: duplicate field \"{name}\" in {typeName}",
962
- params: {
963
- name: "string",
964
- typeName: "string"
965
- }
966
- },
967
- TYPED_DATA_INVALID_TYPE_NAME: {
968
- phase: "pre_send",
969
- template: "Invalid typed data: invalid type name \"{name}\"",
970
- params: { name: "string" }
971
- },
972
- TYPED_DATA_CIRCULAR_TYPE: {
973
- phase: "pre_send",
974
- template: "Invalid typed data: circular type reference in {typeName}",
975
- params: { typeName: "string" }
976
- },
977
- TYPED_DATA_UNKNOWN_FIELD_TYPE: {
978
- phase: "pre_send",
979
- template: "Invalid typed data: unknown type \"{type}\" in {typeName}",
980
- params: {
981
- type: "string",
982
- typeName: "string"
983
- }
984
- },
985
- TYPED_DATA_NO_PRIMARY_TYPE: {
986
- phase: "pre_send",
987
- template: "Invalid typed data: missing primary type",
988
- params: {}
989
- },
990
- TYPED_DATA_AMBIGUOUS_PRIMARY_TYPE: {
991
- phase: "pre_send",
992
- template: "Invalid typed data: ambiguous primary types or unused types ({roots})",
993
- params: { roots: "string" }
994
- },
995
- TYPED_DATA_ARRAY_EXPECTED: {
996
- phase: "pre_send",
997
- template: "Invalid typed data: {type} array value must be an array",
998
- params: { type: "string" }
999
- },
1000
- TYPED_DATA_ARRAY_LENGTH_MISMATCH: {
1001
- phase: "pre_send",
1002
- template: "Invalid typed data: array length mismatch",
1003
- params: {}
1004
- },
1005
- TYPED_DATA_STRUCT_NOT_OBJECT: {
1006
- phase: "pre_send",
1007
- template: "Invalid typed data: {typeName} value must be an object",
1008
- params: { typeName: "string" }
1009
- },
1010
- TYPED_DATA_MISSING_FIELD: {
1011
- phase: "pre_send",
1012
- template: "Invalid typed data: {typeName} value is missing field \"{field}\"",
1013
- params: {
1014
- typeName: "string",
1015
- field: "string"
1016
- }
1017
- },
1018
- TYPED_DATA_DOMAIN_NOT_OBJECT: {
1019
- phase: "pre_send",
1020
- template: "Invalid typed data: domain must be an object",
1021
- params: {}
1022
- },
1023
- TYPED_DATA_INVALID_DOMAIN_KEY: {
1024
- phase: "pre_send",
1025
- template: "Invalid typed data: invalid typed-data domain key {key}",
1026
- params: { key: "string" }
1027
- },
1028
- NON_CANONICAL_PAIR: {
1029
- phase: "pre_send",
1030
- template: "The pair {token0}/{token1} is not in canonical order: token0 must sort before token1.",
1031
- params: {
1032
- token0: "string",
1033
- token1: "string"
1034
- }
1035
- },
1036
- UNORDERABLE_SYMBOLS: {
1037
- phase: "pre_send",
1038
- template: "Unable to order trading symbols: expected a pair of symbols, got {received}.",
1039
- params: { received: "string" }
1040
- },
1041
- INVALID_TOKEN_CLASS_KEY: {
1042
- phase: "pre_send",
1043
- template: "Invalid token class key \"{tokenClassKey}\": expected a collection followed by category, type and additionalKey",
1044
- params: { tokenClassKey: "string" }
1045
- },
1046
- INCOMPLETE_TOKEN_CLASS_KEY: {
1047
- phase: "pre_send",
1048
- template: "Token class key \"{compositeKey}\" is missing {part}.",
1049
- params: {
1050
- compositeKey: "string",
1051
- part: "string"
1052
- }
1053
- },
1054
- INVALID_TRADING_SYMBOL: {
1055
- phase: "pre_send",
1056
- template: "Invalid trading symbol \"{symbol}\": must be 1-32 ASCII letters and digits and not a reserved word (Token, Unit, none).",
1057
- params: { symbol: "string" }
1058
- },
1059
- NO_VALID_TRADING_SYMBOL: {
1060
- phase: "pre_send",
1061
- template: "No valid trading symbol for token class {classKey}: \"{displaySymbol}\" is not an acceptable symbol and none is registered",
1062
- params: {
1063
- classKey: "string",
1064
- displaySymbol: "string"
1065
- }
1066
- },
1067
- TOKEN_SYMBOL_NOT_REGISTERED: {
1068
- phase: "pre_send",
1069
- template: "Token {token} is not registered in the trading-symbol registry yet; pass token0Symbol/token1Symbol (the token class symbol) to propose one. A symbol cannot be derived from a class key.",
1070
- params: { token: "string" }
1071
- },
1072
- SYMBOL_DISAGREES_WITH_REGISTRY: {
1073
- phase: "pre_send",
1074
- template: "Supplied symbol {suppliedSymbol} for {token} disagrees with the registered trading symbol {registeredSymbol}.",
1075
- params: {
1076
- token: "string",
1077
- suppliedSymbol: "string",
1078
- registeredSymbol: "string"
1079
- }
1080
- },
1081
- CREATE_POOL_NEEDS_CLASS_KEY: {
1082
- phase: "pre_send",
1083
- template: "createPool needs each token as a class key; {token} is a bare trading symbol, which does not carry one.",
1084
- params: { token: "string" }
1085
- },
1086
- INVALID_UNIQUE_KEY: {
1087
- phase: "pre_send",
1088
- template: "The uniqueKey \"{uniqueKey}\" must be 1-128 characters of A-Z, a-z, 0-9, \".\", \"_\", \":\" or \"-\".",
1089
- params: { uniqueKey: "string" }
1090
- },
1091
- INVALID_UNIQUE_KEY_PREFIX: {
1092
- phase: "pre_send",
1093
- template: "uniqueKeyPrefix \"{uniqueKeyPrefix}\" must be at most {maxLength} characters of A-Z, a-z, 0-9, \".\", \"_\", \":\" or \"-\".",
1094
- params: {
1095
- uniqueKeyPrefix: "string",
1096
- maxLength: "number"
1097
- }
1098
- },
1099
- AMOUNT_IS_JS_NUMBER: {
1100
- phase: "pre_send",
1101
- template: "Invalid {field}: use a decimal string or BigNumber, not a JavaScript number",
1102
- params: { field: "string" }
1103
- },
1104
- AMOUNT_NOT_FINITE: {
1105
- phase: "pre_send",
1106
- template: "Invalid {field}: must be a finite number (got {value})",
1107
- params: {
1108
- field: "string",
1109
- value: "string"
1110
- }
1111
- },
1112
- AMOUNT_NOT_POSITIVE: {
1113
- phase: "pre_send",
1114
- template: "Invalid {field}: must be positive (got {value})",
1115
- params: {
1116
- field: "string",
1117
- value: "string"
1118
- }
1119
- },
1120
- AMOUNT_NEGATIVE: {
1121
- phase: "pre_send",
1122
- template: "Invalid {field}: must not be negative (got {value})",
1123
- params: {
1124
- field: "string",
1125
- value: "string"
1126
- }
1127
- },
1128
- PRICE_VALUES_IS_JS_NUMBER: {
1129
- phase: "pre_send",
1130
- template: "Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers",
1131
- params: {}
1132
- },
1133
- INVALID_PRICE_VALUES: {
516
+ INVALID_PRICE_VALUES: {
1134
517
  phase: "pre_send",
1135
518
  template: "Invalid price values: all prices must be finite and positive (spot {spotPrice}, lower {lowerPrice}, upper {upperPrice})",
1136
519
  params: {
@@ -1309,156 +692,217 @@ const GSWAP_ERROR_CATALOG = {
1309
692
  min: "number",
1310
693
  max: "number"
1311
694
  }
695
+ },
696
+ INVALID_MARKET_TOKEN: {
697
+ phase: "pre_send",
698
+ template: "A market read names a token by a symbol or class key of 1 to 120 letters, digits and . _ $ + / : | - characters (got \"{token}\").",
699
+ params: { token: "string" }
700
+ },
701
+ INVALID_TIMEFRAME: {
702
+ phase: "pre_send",
703
+ template: "timeframe \"{value}\" is not allowed; it must be one of {allowed}.",
704
+ params: {
705
+ value: "string",
706
+ allowed: "string"
707
+ }
708
+ },
709
+ INVALID_SEASON_ID: {
710
+ phase: "pre_send",
711
+ template: "seasonId must be an integer of at least 1 (got {value}).",
712
+ params: { value: "string" }
713
+ },
714
+ INVALID_POLL_INTERVAL: {
715
+ phase: "pre_send",
716
+ template: "intervalMs must be a finite number of milliseconds of at least 1 (got {value}).",
717
+ params: { value: "string" }
1312
718
  }
1313
719
  };
1314
720
  /**
1315
- * The English template of every error code, `{placeholder}` markers included. An optional seed
1316
- * or fallback for an app's own translations; the SDK's `message` is generated from it.
721
+ * The catalog `GSwapSDKError` reads templates and phases from: core's entries and the DEX entries,
722
+ * merged (never redefined: the two key sets are disjoint, pinned by tests/error_catalog.test.ts).
723
+ */
724
+ const GSWAP_SDK_ERROR_ENTRIES = {
725
+ ..._gala_chain_gala_core_sdk.GALA_ERROR_CATALOG,
726
+ ...GSWAP_ERROR_CATALOG
727
+ };
728
+ /**
729
+ * The English template of every DEX error code, `{placeholder}` markers included. An optional seed
730
+ * or fallback for an app's own translations; the SDK's `message` is generated from it. The core
731
+ * codes' templates are `galaErrorTemplates` from `@gala-chain/gala-core-sdk`: an app that seeds
732
+ * every code a `GSwapSDKError` can carry merges the two.
1317
733
  */
1318
734
  const gswapErrorTemplates = Object.fromEntries(Object.entries(GSWAP_ERROR_CATALOG).map(([code, entry]) => [code, entry.template]));
1319
- const PLACEHOLDER = /\{([A-Za-z0-9_]+)\}/gu;
1320
- /** Fills a template's `{placeholders}` from `params`; an unknown placeholder is left as written. */
1321
- function renderGSwapErrorTemplate(template, params) {
1322
- return template.replace(PLACEHOLDER, (whole, name) => {
1323
- const value = params[name];
1324
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : whole;
1325
- });
1326
- }
1327
735
 
1328
736
  //#endregion
1329
- //#region src/classes/gswap_sdk_error.ts
1330
- /**
1331
- * The HTTP status of a version wall: the backend refuses an app version that is too old (HTTP 426
1332
- * Upgrade Required). It is `UPDATE_REQUIRED` on every request the SDK sends, whatever else the body
1333
- * says; a confirmation read keeps `CONFIRMATION_FAILED` because the write it confirms may be applied.
1334
- */
1335
- const UPDATE_REQUIRED_STATUS = 426;
737
+ //#region src/classes/gswap_error_phase_table.ts
1336
738
  /**
1337
- * Error raised by the SDK for validation, gateway, chain, or transaction failures.
1338
- *
1339
- * Branch on {@link code} (stable) and render {@link params} through your own localization.
1340
- * {@link message} is English generated from the catalog template for logs and developers: it
1341
- * is not stable and must never be shown to a user or matched on.
739
+ * The phase of every DEX catalog code, WITHOUT the catalog. The failure guards (`classifyFailure`,
740
+ * `mayHaveBeenQueued`, ...) need only a code's phase, and the catalog's English templates are
741
+ * ~15 kB: reading the phase from here keeps an app shell that imports a guard from loading them.
742
+ * The catalog entry is still where a code is declared; this table is checked against it AT
743
+ * COMPILE TIME, in both directions (a missing code, an extra code or a different phase is a type
744
+ * error), so the two cannot drift. The core codes' phases are core's `GALA_ERROR_PHASE_BY_CODE`.
1342
745
  */
1343
- var GSwapSDKError = class GSwapSDKError extends Error {
1344
- /** The stable, machine-readable code. */
1345
- code;
1346
- /** The named placeholders of the error: a flat object of primitives, safe to localize with. */
1347
- params;
1348
- /** The server's `Retry-After` in milliseconds (a `RATE_LIMITED` answer), when it sent one. */
1349
- retryAfterMs;
1350
- /** The HTTP status of the response that caused this error, when there was one. */
1351
- status;
1352
- /**
1353
- * The response body parsed as JSON, when the failing response had one; `undefined` for a body
1354
- * that was not JSON (see {@link bodyText}). Never part of {@link message}.
1355
- */
1356
- body;
1357
- /**
1358
- * The raw text of a failing response whose body was NOT JSON (a proxy's HTML 502, a WAF page,
1359
- * an empty body). It is kept here for diagnostics and is never copied into {@link message},
1360
- * so it cannot reach a user interface by accident.
1361
- */
1362
- bodyText;
1363
- /** The URL the failing request went to, when there was one. */
1364
- url;
1365
- /** The `uniqueKey` of the write this error is about, when there is one. */
1366
- uniqueKey;
1367
- /** The transaction id of the queued request, when known. */
1368
- requestTransactionId;
1369
- /** The transaction id of the apply, when known. */
1370
- applyTransactionId;
1371
- /** The block the apply landed in, when known. */
1372
- blockNumber;
1373
- /**
1374
- * How far the operation had got when this was thrown, against the request it exists to send
1375
- * (see {@link GSwapErrorPhase}): `pre_send` means NOTHING was transmitted, so a write that
1376
- * failed this way cannot have been queued; `in_flight` means the request left and no answer was
1377
- * read; `post_send` means an answer was read or the write was already accepted. Every catalog
1378
- * code declares its phase, and a throw site can refine it. Read it with
1379
- * {@link isPreSendError}; `classifyFailure` already folds it into `outcome` and `retryable`.
1380
- */
1381
- phase;
1382
- /**
1383
- * True when this error came from the shadow (dark) path: `swapShadow`, `submitSwapShadow` or
1384
- * `ChainGateway.submitShadow`, whatever failed there (a validation error, the signer, the
1385
- * transport, `SHADOW_NOT_QUEUED`). The classification is the same as on the public path; this
1386
- * is how an app applies its own dark-swap policy (the wallet and frontend_v2 never offer a
1387
- * public fallback or Retry after one). A shadow gateway refusal that RESOLVES (`{ ok: false }`)
1388
- * is not an error and has no flag: the call itself says it was shadow.
1389
- */
1390
- shadow;
1391
- /**
1392
- * Whether this failure is a WRITE's, as the guards read it: `false` only for the failure of a
1393
- * READ (a quote, a pool list, an apply-results read), which has no `uniqueKey` to confirm and
1394
- * nothing pending, so a 5xx there is `transient` and retryable. It is `true` for everything else,
1395
- * and always when {@link uniqueKey} is set. That is fail-closed: a failure that does not say it
1396
- * is a read is judged a write, where a 5xx is `unknown` and never retried. Apps that carry an
1397
- * error through their own wrapper copy this field next to `uniqueKey` (`FailureView.write`).
1398
- */
1399
- write;
1400
- /**
1401
- * On `SIGNING_FAILED`: the code the wallet put on the error its signer threw, when it set one: an
1402
- * EIP-1193 / JSON-RPC number such as `4001` (the person declined) or `-32603`, or an ethers /
1403
- * viem string such as `'ACTION_REJECTED'`. It is read from the `cause`'s own `code` and is
1404
- * always a short primitive; `undefined` when the wallet sent none, and on every other code. It is
1405
- * a typed field, not a param: it is data for an app's analytics or its own wallet-specific
1406
- * wording, never part of `message`, and `params.reason` stays the stable thing to branch on.
1407
- */
1408
- walletCode;
1409
- constructor(code, params, context = {}) {
1410
- super(renderGSwapErrorTemplate(GSWAP_ERROR_CATALOG[code].template, params), context.cause === void 0 ? void 0 : { cause: context.cause });
1411
- this.name = "GSwapSDKError";
1412
- this.code = code;
1413
- this.params = params;
1414
- this.retryAfterMs = context.retryAfterMs;
1415
- this.status = context.status;
1416
- this.body = typeof context.body === "string" ? void 0 : context.body;
1417
- this.bodyText = typeof context.body === "string" ? context.body : void 0;
1418
- this.url = context.url;
1419
- this.uniqueKey = context.uniqueKey;
1420
- this.requestTransactionId = context.requestTransactionId;
1421
- this.applyTransactionId = context.applyTransactionId;
1422
- this.blockNumber = context.blockNumber;
1423
- this.phase = context.phase ?? GSWAP_ERROR_CATALOG[code].phase;
1424
- this.shadow = context.shadow ?? false;
1425
- this.write = context.uniqueKey !== void 0 && context.uniqueKey !== "" ? true : context.write !== false;
1426
- this.walletCode = context.walletCode;
1427
- }
1428
- /**
1429
- * The SDK error brand (`Symbol.for('@gala-chain/gswap-sdk/error')`), always `true`. The
1430
- * dependency-free helpers (`isWalletUserRejection`, `isGSwapErrorLike`) recognise an SDK error
1431
- * by it instead of `instanceof`, so they work across copies of the SDK and without importing
1432
- * this class. It lives on the prototype: it is not an own property and is never copied or logged.
1433
- */
1434
- get [GSWAP_ERROR_BRAND]() {
1435
- return true;
1436
- }
1437
- /**
1438
- * True when the failure means "that market, pool or position does not exist" rather than
1439
- * "something went wrong": an HTTP 404, a pair with no pool at any fee tier
1440
- * (`NO_POOL_AVAILABLE`), or a token the DEX contract has no trading symbol for
1441
- * (`UNKNOWN_TOKEN`). A pool that exists but is too thin (`INSUFFICIENT_LIQUIDITY`) is NOT
1442
- * not-found.
1443
- */
1444
- get notFound() {
1445
- return this.status === 404 || this.code === "NO_POOL_AVAILABLE" || this.code === "UNKNOWN_TOKEN";
1446
- }
1447
- /** Create the standard missing-signer error. */
1448
- static noSignerError() {
1449
- return new GSwapSDKError("NO_SIGNER", {});
1450
- }
1451
- /** Create the error used when confirming a position write without a configured wallet address. */
1452
- static noWalletAddressError() {
1453
- return new GSwapSDKError("NO_WALLET_ADDRESS", {});
1454
- }
1455
- /**
1456
- * Create the error used when no pool can quote the requested pair. `source` is the backend
1457
- * answer that said so; its status and body are kept.
1458
- */
1459
- static noPoolAvailableError(tokenIn, tokenOut, fee, source) {
1460
- return new GSwapSDKError("NO_POOL_AVAILABLE", {
1461
- tokenIn: tokenText(tokenIn),
746
+ const GSWAP_ERROR_PHASE_BY_CODE = {
747
+ HTTP_ERROR: "post_send",
748
+ UPDATE_REQUIRED: "post_send",
749
+ REQUEST_FAILED: "in_flight",
750
+ METHOD_NOT_SUPPORTED: "pre_send",
751
+ SUBMISSION_OUTCOME_UNKNOWN: "in_flight",
752
+ GATEWAY_REPORTED_ERROR: "post_send",
753
+ GATEWAY_DATA_MISSING: "post_send",
754
+ GATEWAY_MODE_INVALID: "post_send",
755
+ GATEWAY_SYNC_REQUEST_TRADE: "post_send",
756
+ MISSING_UNIQUE_KEY: "post_send",
757
+ UNIQUE_KEY_MISMATCH: "post_send",
758
+ SHADOW_NOT_QUEUED: "post_send",
759
+ SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS: "pre_send",
760
+ METHOD_NOT_ALLOWED: "post_send",
761
+ SIGNATURE_INVALID: "post_send",
762
+ SIGNER_MISMATCH: "post_send",
763
+ DTO_INVALID: "post_send",
764
+ BOUNDS_VIOLATION: "post_send",
765
+ SYMBOL_CONFLICT: "post_send",
766
+ RATE_LIMITED: "post_send",
767
+ CHAIN_DISPATCH_FAILED: "post_send",
768
+ GATEWAY_REJECTED: "post_send",
769
+ CHAIN_REJECTED: "post_send",
770
+ INVALID_CHAIN_RESPONSE: "post_send",
771
+ INVALID_POSITION_RESPONSE: "post_send",
772
+ CONFIRMATION_TIMEOUT: "post_send",
773
+ CONFIRMATION_ABORTED: "post_send",
774
+ CONFIRMATION_FAILED: "post_send",
775
+ CONFIRMATION_MALFORMED: "post_send",
776
+ CONFIRMATION_KEY_MISMATCH: "post_send",
777
+ NO_SIGNER: "pre_send",
778
+ NO_WALLET_ADDRESS: "post_send",
779
+ NO_POOL_AVAILABLE: "post_send",
780
+ INSUFFICIENT_LIQUIDITY: "post_send",
781
+ UNKNOWN_TOKEN: "pre_send",
782
+ SYMBOL_NOT_FOUND: "pre_send",
783
+ STREAM_API_KEY_UNUSABLE: "pre_send",
784
+ STREAM_WEBSOCKET_UNAVAILABLE: "pre_send",
785
+ STREAM_NOT_CONNECTED: "pre_send",
786
+ STREAM_DISCONNECTED: "in_flight",
787
+ STREAM_REQUEST_TIMEOUT: "in_flight",
788
+ STREAM_CONNECT_FAILED: "in_flight",
789
+ STREAM_CLOSED_BEFORE_CONNECT: "in_flight",
790
+ STREAM_CONNECTION_CLOSED: "in_flight",
791
+ TOKEN_RESOLUTION_FAILED: "pre_send",
792
+ MISSING_WALLET_ADDRESS: "pre_send",
793
+ NON_CANONICAL_PAIR: "pre_send",
794
+ UNORDERABLE_SYMBOLS: "pre_send",
795
+ INVALID_TOKEN_CLASS_KEY: "pre_send",
796
+ INCOMPLETE_TOKEN_CLASS_KEY: "pre_send",
797
+ INVALID_TRADING_SYMBOL: "pre_send",
798
+ NO_VALID_TRADING_SYMBOL: "pre_send",
799
+ TOKEN_SYMBOL_NOT_REGISTERED: "pre_send",
800
+ SYMBOL_DISAGREES_WITH_REGISTRY: "pre_send",
801
+ CREATE_POOL_NEEDS_CLASS_KEY: "pre_send",
802
+ AMOUNT_IS_JS_NUMBER: "pre_send",
803
+ AMOUNT_NOT_FINITE: "pre_send",
804
+ AMOUNT_NOT_POSITIVE: "pre_send",
805
+ AMOUNT_NEGATIVE: "pre_send",
806
+ PRICE_VALUES_IS_JS_NUMBER: "pre_send",
807
+ INVALID_PRICE_VALUES: "pre_send",
808
+ INVALID_PRICE_RANGE: "pre_send",
809
+ INVALID_PRICE_BOUNDS: "pre_send",
810
+ PRICE_BOUNDS_ORDER: "pre_send",
811
+ INVALID_STARTING_PRICE: "pre_send",
812
+ INVALID_SQRT_PRICE: "pre_send",
813
+ INVALID_TOKEN_DECIMALS: "pre_send",
814
+ TICKS_NOT_INTEGERS: "pre_send",
815
+ INVALID_TICK_RANGE: "pre_send",
816
+ TICKS_OUT_OF_BOUNDS: "pre_send",
817
+ TICKS_NOT_ALIGNED: "pre_send",
818
+ INVALID_TICK_SPACING: "pre_send",
819
+ INVALID_FEE: "pre_send",
820
+ EXACT_AMOUNT_REQUIRED: "pre_send",
821
+ EXACTLY_ONE_OF_REQUIRED: "pre_send",
822
+ AT_MOST_ONE_OF_ALLOWED: "pre_send",
823
+ POOL_MISMATCH: "pre_send",
824
+ INVALID_DTO: "pre_send",
825
+ DTO_NOT_CANONICAL: "pre_send",
826
+ SEARCH_TOO_LONG: "pre_send",
827
+ INVALID_SORT_BY: "pre_send",
828
+ INVALID_SORT_ORDER: "pre_send",
829
+ INVALID_PAGE: "pre_send",
830
+ INVALID_LIMIT: "pre_send",
831
+ INVALID_MARKET_TOKEN: "pre_send",
832
+ INVALID_TIMEFRAME: "pre_send",
833
+ INVALID_SEASON_ID: "pre_send",
834
+ INVALID_POLL_INTERVAL: "pre_send"
835
+ };
836
+ /** True for a DEX code (gswap-sdk's own catalog). */
837
+ function isDexCatalogCode(code) {
838
+ return Object.hasOwn(GSWAP_ERROR_PHASE_BY_CODE, code);
839
+ }
840
+ /** True for a code a `GSwapSDKError` can carry: a core code or a DEX code. */
841
+ function isCatalogCode(code) {
842
+ return (0, _gala_chain_gala_core_sdk.isGalaCatalogCode)(code) || isDexCatalogCode(code);
843
+ }
844
+ /**
845
+ * The phase of a view: the one it states, else the catalog's phase for its code (core's or the
846
+ * DEX catalog's), else `undefined`.
847
+ */
848
+ function phaseOfView(view) {
849
+ if (view.phase !== void 0) return view.phase;
850
+ if ((0, _gala_chain_gala_core_sdk.isGalaCatalogCode)(view.code)) return _gala_chain_gala_core_sdk.GALA_ERROR_PHASE_BY_CODE[view.code];
851
+ return isDexCatalogCode(view.code) ? GSWAP_ERROR_PHASE_BY_CODE[view.code] : void 0;
852
+ }
853
+
854
+ //#endregion
855
+ //#region src/classes/gswap_sdk_error.ts
856
+ /**
857
+ * The HTTP status of a version wall: the backend refuses an app version that is too old (HTTP 426
858
+ * Upgrade Required). It is `UPDATE_REQUIRED` on every request the SDK sends, whatever else the body
859
+ * says; a confirmation read keeps `CONFIRMATION_FAILED` because the write it confirms may be applied.
860
+ */
861
+ const UPDATE_REQUIRED_STATUS = 426;
862
+ /**
863
+ * Error raised by gswap-sdk for validation, gateway, chain, or transaction failures. It is a
864
+ * `GalaSDKError` (`@gala-chain/gala-core-sdk`), and can carry any code of the core catalog or of
865
+ * gswap-sdk's own DEX catalog: the signing, transport and wallet failures of a gswap flow are core
866
+ * codes, thrown either as a `GSwapSDKError` by gswap-sdk or as a plain `GalaSDKError` by core
867
+ * itself (a signer, the fetch requestor). Catch both with `isGSwapError` (or core's `isGalaError`);
868
+ * `instanceof GSwapSDKError` alone misses the second kind.
869
+ *
870
+ * Branch on {@link code} (stable) and render {@link params} through your own localization.
871
+ * {@link message} is English generated from the catalog template for logs and developers: it
872
+ * is not stable and must never be shown to a user or matched on.
873
+ */
874
+ var GSwapSDKError = class GSwapSDKError extends _gala_chain_gala_core_sdk.GalaSDKError {
875
+ /** Core's catalog entries and the DEX entries: a `GSwapSDKError` can carry a code of either. */
876
+ static catalog = GSWAP_SDK_ERROR_ENTRIES;
877
+ constructor(code, params, context = {}) {
878
+ super(code, params, context);
879
+ this.name = "GSwapSDKError";
880
+ }
881
+ /**
882
+ * True when the failure means "that market, pool or position does not exist" rather than
883
+ * "something went wrong": an HTTP 404, a pair with no pool at any fee tier
884
+ * (`NO_POOL_AVAILABLE`), or a token the DEX contract has no trading symbol for
885
+ * (`UNKNOWN_TOKEN`). A pool that exists but is too thin (`INSUFFICIENT_LIQUIDITY`) is NOT
886
+ * not-found.
887
+ */
888
+ get notFound() {
889
+ return super.notFound || this.code === "NO_POOL_AVAILABLE" || this.code === "UNKNOWN_TOKEN";
890
+ }
891
+ /** Create the standard missing-signer error. */
892
+ static noSignerError() {
893
+ return new GSwapSDKError("NO_SIGNER", {});
894
+ }
895
+ /** Create the error used when confirming a position write without a configured wallet address. */
896
+ static noWalletAddressError() {
897
+ return new GSwapSDKError("NO_WALLET_ADDRESS", {});
898
+ }
899
+ /**
900
+ * Create the error used when no pool can quote the requested pair. `source` is the backend
901
+ * answer that said so; its status and body are kept.
902
+ */
903
+ static noPoolAvailableError(tokenIn, tokenOut, fee, source) {
904
+ return new GSwapSDKError("NO_POOL_AVAILABLE", {
905
+ tokenIn: tokenText(tokenIn),
1462
906
  tokenOut: tokenText(tokenOut),
1463
907
  fee: feeText(fee)
1464
908
  }, sourceContext(source));
@@ -1571,7 +1015,7 @@ var GSwapSDKError = class GSwapSDKError extends Error {
1571
1015
  /** Convert an unexpected HTTP response into an SDK error. */
1572
1016
  static async fromErrorResponse(url, response) {
1573
1017
  const bodyText = await response.text();
1574
- const bodyJson = parseJson(bodyText);
1018
+ const bodyJson = (0, _gala_chain_gala_core_sdk.parseJson)(bodyText);
1575
1019
  const errorObject = getObjectProperty(bodyJson, "error");
1576
1020
  const errorKey = getStringProperty(errorObject, "ErrorKey");
1577
1021
  const message = getStringProperty(errorObject, "Message");
@@ -1620,7 +1064,7 @@ function sourceContext(source) {
1620
1064
  };
1621
1065
  }
1622
1066
  function isGSwapError(value, code) {
1623
- return value instanceof GSwapSDKError && (code === void 0 || value.code === code);
1067
+ return value instanceof _gala_chain_gala_core_sdk.GalaSDKError && (code === void 0 || value.code === code);
1624
1068
  }
1625
1069
  /**
1626
1070
  * True when `value` is an SDK error that was thrown BEFORE anything was transmitted
@@ -1635,8 +1079,9 @@ function isGSwapError(value, code) {
1635
1079
  * error is pre-send too, and repeating the same call fails the same way.
1636
1080
  *
1637
1081
  * It also answers for a plain-object view of an SDK error (`{ code, phase? }`, see
1638
- * `FailureView`): the view's own `phase`, else the catalog's phase for its `code`. It is a plain
1639
- * `boolean`, not a type guard (a view is not a `GSwapSDKError`); use `isGSwapError` to narrow.
1082
+ * `FailureView`): the view's own `phase`, else the catalog's phase for its `code` (a core code or
1083
+ * a DEX code). It is a plain `boolean`, not a type guard (a view is not a `GSwapSDKError`); use
1084
+ * `isGSwapError` to narrow.
1640
1085
  *
1641
1086
  * @example
1642
1087
  * ```ts
@@ -1644,7 +1089,7 @@ function isGSwapError(value, code) {
1644
1089
  * ```
1645
1090
  */
1646
1091
  function isPreSendError(value) {
1647
- const view = toFailureView(value);
1092
+ const view = (0, _gala_chain_gala_core_sdk.toFailureView)(value);
1648
1093
  return view !== void 0 && phaseOfView(view) === "pre_send";
1649
1094
  }
1650
1095
  /** Narrow an object property without trusting a cast at a network boundary. */
@@ -1659,165 +1104,6 @@ function getStringProperty(value, property) {
1659
1104
  const propertyValue = value[property];
1660
1105
  return typeof propertyValue === "string" ? propertyValue : void 0;
1661
1106
  }
1662
- /** Parse a response body, preserving non-JSON text for error reporting. */
1663
- function parseJson(text) {
1664
- try {
1665
- return JSON.parse(text);
1666
- } catch {
1667
- return;
1668
- }
1669
- }
1670
-
1671
- //#endregion
1672
- //#region src/version.ts
1673
- /** Package version embedded by the bundler, with a source-test fallback. */
1674
- const SDK_VERSION = "1.2.0";
1675
-
1676
- //#endregion
1677
- //#region src/utils/transport.ts
1678
- /**
1679
- * Arms the abort timer for a request. `Infinity` means "never time out": `setTimeout` would turn
1680
- * it into 1 ms, so no timer is armed at all. Returns a function that disarms it.
1681
- */
1682
- function armTimeout(controller, timeoutMs) {
1683
- if (timeoutMs === Infinity) return () => void 0;
1684
- const timer = setTimeout(() => controller.abort(), timeoutMs);
1685
- return () => clearTimeout(timer);
1686
- }
1687
- /**
1688
- * Validates a request timeout in milliseconds: a positive finite number, or `Infinity` for none.
1689
- *
1690
- * @throws GSwapSDKError `INVALID_TIMEOUT` (`params.field` = `name`) otherwise.
1691
- */
1692
- function validateTimeoutMs(timeoutMs, name) {
1693
- if (timeoutMs === Infinity || Number.isFinite(timeoutMs) && timeoutMs > 0) return timeoutMs;
1694
- throw new GSwapSDKError("INVALID_TIMEOUT", {
1695
- field: name,
1696
- value: timeoutMs
1697
- });
1698
- }
1699
- const READABLE_QUERY_SAFE = /[A-Za-z0-9\-._~!'()*$|:,]/u;
1700
- function encodeReadable(text) {
1701
- let out = "";
1702
- for (const char of text) if (char === " ") out += "+";
1703
- else if (READABLE_QUERY_SAFE.test(char)) out += char;
1704
- else out += encodeScalar(char);
1705
- return out;
1706
- }
1707
- /** Percent-encodes one code point; a lone surrogate becomes U+FFFD, as `URLSearchParams` does. */
1708
- function encodeScalar(char) {
1709
- try {
1710
- return encodeURIComponent(char);
1711
- } catch {
1712
- return "%EF%BF%BD";
1713
- }
1714
- }
1715
- /** Serializes GET parameters, in insertion order, in the encoding the wire options select. */
1716
- function buildQueryString(params, encoding = "standard") {
1717
- if (encoding === "readable") return Object.entries(params).map(([key, value]) => `${encodeReadable(key)}=${encodeReadable(value)}`).join("&");
1718
- return new URLSearchParams(params).toString();
1719
- }
1720
- /**
1721
- * The request headers for ANY SDK request, GET or POST, from one place so the wire options reach
1722
- * every request alike. Order, which is the order the requestor sees them in: `User-Agent`
1723
- * (`wire.userAgent`, default `GalaChain-SDK/<version>`, `false` omits it), `parts.defaults`,
1724
- * `wire.headers`, `Content-Type` (JSON bodies only), `parts.fixed`. A later entry replaces an
1725
- * earlier one of the same name regardless of case, so a header is never sent twice.
1726
- */
1727
- function buildRequestHeaders(wire, parts = {}) {
1728
- const entries = /* @__PURE__ */ new Map();
1729
- const put = (headers, last = false) => {
1730
- for (const [name, value] of Object.entries(headers ?? {})) {
1731
- if (last) entries.delete(name.toLowerCase());
1732
- entries.set(name.toLowerCase(), [name, value]);
1733
- }
1734
- };
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"}` });
1736
- put(parts.defaults);
1737
- put(wire === null || wire === void 0 ? void 0 : wire.headers);
1738
- if (parts.json === true && !entries.has("content-type")) put({ "Content-Type": "application/json" });
1739
- put(parts.fixed, true);
1740
- return Object.fromEntries(entries.values());
1741
- }
1742
- /**
1743
- * The default requestor: the global `fetch`, with a failure before any answer (offline, DNS,
1744
- * CORS) coded as `TRANSPORT_ERROR` and the original error kept as `cause`. An aborted request is
1745
- * left to {@link requestWithTimeout}, which knows whether the timeout or the caller aborted it.
1746
- * A requestor the app supplies is not wrapped: its rejection reaches the caller unchanged.
1747
- */
1748
- const fetchRequestor = async (url, init) => {
1749
- try {
1750
- return await fetch(url, init);
1751
- } catch (error) {
1752
- var _init$signal;
1753
- if ((init === null || init === void 0 || (_init$signal = init.signal) === null || _init$signal === void 0 ? void 0 : _init$signal.aborted) === true) throw error;
1754
- throw new GSwapSDKError("TRANSPORT_ERROR", { url }, {
1755
- url,
1756
- cause: error
1757
- });
1758
- }
1759
- };
1760
- async function requestWithTimeout(requestor, url, options, timeoutMs) {
1761
- const controller = new AbortController();
1762
- const disarm = armTimeout(controller, timeoutMs);
1763
- const externalSignal = options.signal;
1764
- const abortFromCaller = () => controller.abort();
1765
- externalSignal === null || externalSignal === void 0 || externalSignal.addEventListener("abort", abortFromCaller, { once: true });
1766
- try {
1767
- return await requestor(url, {
1768
- ...options,
1769
- signal: controller.signal
1770
- });
1771
- } catch (error) {
1772
- if ((externalSignal === null || externalSignal === void 0 ? void 0 : externalSignal.aborted) === true) throw error;
1773
- if (controller.signal.aborted) throw new GSwapSDKError("REQUEST_TIMEOUT", {
1774
- url,
1775
- timeoutMs
1776
- }, {
1777
- url,
1778
- cause: error
1779
- });
1780
- throw error;
1781
- } finally {
1782
- disarm();
1783
- externalSignal === null || externalSignal === void 0 || externalSignal.removeEventListener("abort", abortFromCaller);
1784
- }
1785
- }
1786
- async function readResponseBody(response) {
1787
- const text = await response.text();
1788
- return parseJson(text) ?? text;
1789
- }
1790
- /** Read a case-insensitive response header from either supported header shape. */
1791
- function readHeader(response, name) {
1792
- var _Object$entries$find;
1793
- const headers = response.headers;
1794
- if (headers === void 0) return void 0;
1795
- if (hasHeaderGetter(headers)) {
1796
- const value = headers.get(name);
1797
- return value === null || value === "" ? void 0 : value;
1798
- }
1799
- const value = (_Object$entries$find = Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())) === null || _Object$entries$find === void 0 ? void 0 : _Object$entries$find[1];
1800
- return value === void 0 || value === "" ? void 0 : value;
1801
- }
1802
- /** Read a Retry-After header (delta-seconds or an HTTP date) as non-negative milliseconds. */
1803
- function readRetryAfter(response) {
1804
- const raw = readHeader(response, "retry-after");
1805
- if (raw === void 0) return void 0;
1806
- const seconds = Number(raw);
1807
- if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
1808
- const timestamp = Date.parse(raw);
1809
- return Number.isNaN(timestamp) ? void 0 : Math.max(0, timestamp - Date.now());
1810
- }
1811
- /** Read a non-negative integer block number header. */
1812
- function readBlockNumberHeader(response, headerName = "x-block-number") {
1813
- const raw = readHeader(response, headerName);
1814
- if (raw === void 0) return void 0;
1815
- const blockNumber = Number(raw);
1816
- return Number.isInteger(blockNumber) && blockNumber >= 0 ? blockNumber : void 0;
1817
- }
1818
- function hasHeaderGetter(headers) {
1819
- return "get" in headers && typeof headers.get === "function";
1820
- }
1821
1107
 
1822
1108
  //#endregion
1823
1109
  //#region src/classes/apply_results.ts
@@ -1876,8 +1162,8 @@ var AppliedTradeError = class extends GSwapSDKError {
1876
1162
  */
1877
1163
  async function confirmAppliedTrade(client, input, options) {
1878
1164
  const { uniqueKey } = input;
1879
- if (!isValidUniqueKey(uniqueKey)) throw new AppliedTradeError("INVALID_UNIQUE_KEY", { uniqueKey: String(uniqueKey) }, { uniqueKey });
1880
- const requestor = client.httpRequestor ?? fetchRequestor;
1165
+ if (!(0, _gala_chain_gala_core_sdk.isValidUniqueKey)(uniqueKey)) throw new AppliedTradeError("INVALID_UNIQUE_KEY", { uniqueKey: String(uniqueKey) }, { uniqueKey });
1166
+ const requestor = client.httpRequestor ?? _gala_chain_gala_core_sdk.fetchRequestor;
1881
1167
  const requestTimeoutMs = client.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
1882
1168
  const signal = options === null || options === void 0 ? void 0 : options.signal;
1883
1169
  const abortError = (cause) => new AppliedTradeError("CONFIRMATION_ABORTED", {}, {
@@ -1893,12 +1179,12 @@ async function confirmAppliedTrade(client, input, options) {
1893
1179
  let response;
1894
1180
  let body;
1895
1181
  try {
1896
- response = await requestWithTimeout(requestor, url, {
1182
+ response = await (0, _gala_chain_gala_core_sdk.requestWithTimeout)(requestor, url, {
1897
1183
  method: "GET",
1898
- headers: buildRequestHeaders(client.wire),
1184
+ headers: (0, _gala_chain_gala_core_sdk.buildRequestHeaders)(client.wire),
1899
1185
  ...signal === void 0 ? {} : { signal }
1900
1186
  }, requestTimeoutMs);
1901
- body = await readResponseBody(response);
1187
+ body = await (0, _gala_chain_gala_core_sdk.readResponseBody)(response);
1902
1188
  } catch (error) {
1903
1189
  throwIfAborted(signal, abortError);
1904
1190
  lastError = error;
@@ -1908,7 +1194,7 @@ async function confirmAppliedTrade(client, input, options) {
1908
1194
  throwIfAborted(signal, abortError);
1909
1195
  if (response.status === 200) return readAppliedResult(input, response, body, url);
1910
1196
  if (response.status === 404 || response.status === 429 || isTransient(response.status)) {
1911
- const retryAfter = response.status === 429 ? readRetryAfter(response) : void 0;
1197
+ const retryAfter = response.status === 429 ? (0, _gala_chain_gala_core_sdk.readRetryAfter)(response) : void 0;
1912
1198
  if (!await schedule.waitForRead(retryAfter)) break;
1913
1199
  continue;
1914
1200
  }
@@ -1940,8 +1226,8 @@ function readAppliedResult(input, response, body, url) {
1940
1226
  url
1941
1227
  });
1942
1228
  const status = record === null || record === void 0 ? void 0 : record["Status"];
1943
- const applyTransactionId = readHeader(response, "x-apply-transaction-id") ?? null;
1944
- const blockNumber = readBlockNumberHeader(response, "x-apply-block-number") ?? null;
1229
+ const applyTransactionId = (0, _gala_chain_gala_core_sdk.readHeader)(response, "x-apply-transaction-id") ?? null;
1230
+ const blockNumber = (0, _gala_chain_gala_core_sdk.readBlockNumberHeader)(response, "x-apply-block-number") ?? null;
1945
1231
  if (status === 0) {
1946
1232
  const errorKey = getStringProperty(record, "ErrorKey") ?? "CHAIN_ERROR";
1947
1233
  const chainMessage = getStringProperty(record, "Message") ?? "";
@@ -1958,9 +1244,9 @@ function readAppliedResult(input, response, body, url) {
1958
1244
  url
1959
1245
  });
1960
1246
  }
1961
- if (status !== 1) throw malformed$1(input, response, body, url);
1247
+ if (status !== 1) throw malformed(input, response, body, url);
1962
1248
  const result = parseTradeExecution(record === null || record === void 0 ? void 0 : record["Data"]);
1963
- if (result === void 0) throw malformed$1(input, response, body, url);
1249
+ if (result === void 0) throw malformed(input, response, body, url);
1964
1250
  return {
1965
1251
  uniqueKey,
1966
1252
  transactionId: applyTransactionId,
@@ -1969,7 +1255,7 @@ function readAppliedResult(input, response, body, url) {
1969
1255
  result
1970
1256
  };
1971
1257
  }
1972
- function malformed$1(input, response, body, url) {
1258
+ function malformed(input, response, body, url) {
1973
1259
  return new AppliedTradeError("CONFIRMATION_MALFORMED", {}, {
1974
1260
  uniqueKey: input.uniqueKey,
1975
1261
  status: response.status,
@@ -2369,7 +1655,10 @@ var Assets = class {
2369
1655
  function parseUserAssets(value) {
2370
1656
  const data = getObjectProperty(value, "data");
2371
1657
  const tokens = data === null || data === void 0 ? void 0 : data["token"];
2372
- if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "user assets response" }, { body: value });
1658
+ if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "user assets response" }, {
1659
+ body: value,
1660
+ write: false
1661
+ });
2373
1662
  const count = data === null || data === void 0 ? void 0 : data["count"];
2374
1663
  return {
2375
1664
  tokens: tokens.map((token) => ({
@@ -2385,178 +1674,6 @@ function isRawUserAsset(value) {
2385
1674
  return typeof entry["image"] === "string" && typeof entry["name"] === "string" && typeof entry["decimals"] === "string" && /^\d+$/u.test(entry["decimals"]) && typeof entry["verify"] === "boolean" && typeof entry["symbol"] === "string" && typeof entry["quantity"] === "string";
2386
1675
  }
2387
1676
 
2388
- //#endregion
2389
- //#region src/utils/wallet_rejection.ts
2390
- /**
2391
- * What the SDK knows about a failure thrown by a WALLET (the signer an app supplies, or wallet
2392
- * code of the app's own): the code the wallet put on it, and whether it means the person declined.
2393
- * Both read only the wallet's own error value; neither shows or forwards its text.
2394
- */
2395
- /** Codes the EIP-1193 / ethers / viem families use for "the person declined in the wallet". */
2396
- const REJECTION_CODES = [
2397
- 4001,
2398
- "ACTION_REJECTED",
2399
- "USER_REJECTED"
2400
- ];
2401
- /** The `name` viem / wagmi give the error of a declined request. */
2402
- const REJECTION_NAME = "UserRejectedRequestError";
2403
- /**
2404
- * Wordings of a decline, matched case-insensitively as substrings. This is a LAST RESORT for
2405
- * wallets that set neither a `code` nor a `name`: it reads a third party's text, so it is broad on
2406
- * purpose (a superset of the matchers the Gala wallet and frontend_v2 used) and can in principle
2407
- * match an unrelated message that uses these words.
2408
- */
2409
- const REJECTION_PHRASES = [
2410
- "user rejected",
2411
- "user denied",
2412
- "user cancel",
2413
- "rejected the request",
2414
- "request rejected",
2415
- "rejected by user",
2416
- "action_rejected",
2417
- "cancelled",
2418
- "canceled"
2419
- ];
2420
- /** Properties wallets nest their text under (EIP-1193, ethers, viem, Gala wallet). */
2421
- const TEXT_KEYS = [
2422
- "message",
2423
- "Message",
2424
- "shortMessage",
2425
- "details",
2426
- "errorDetails",
2427
- "reason"
2428
- ];
2429
- /** Wallet errors nest their text at most a level or two deep; the bound also stops a cyclic object. */
2430
- const MAX_TEXT_DEPTH = 3;
2431
- function isRecord$2(value) {
2432
- return typeof value === "object" && value !== null;
2433
- }
2434
- function textsOf(value, depth = 0) {
2435
- if (typeof value === "string") return [value];
2436
- if (!isRecord$2(value) || depth >= MAX_TEXT_DEPTH) return [];
2437
- return TEXT_KEYS.flatMap((key) => textsOf(value[key], depth + 1));
2438
- }
2439
- function wordsADecline(text) {
2440
- const lower = text.toLowerCase();
2441
- return REJECTION_PHRASES.some((phrase) => lower.includes(phrase)) || lower.includes("signature") && lower.includes("cancel");
2442
- }
2443
- /**
2444
- * True when a wallet's error (or just its message text) says the person DECLINED the request in
2445
- * their wallet. This is exactly the test behind `SIGNING_FAILED` with `params.reason ===
2446
- * 'user_rejected'`, exported for wallet code outside the SDK (connect and registration flows, a
2447
- * v1 write path) so an app keeps no matcher of its own.
2448
- *
2449
- * It is decided from the wallet's own fields first: a `code` of `4001` (EIP-1193), `'ACTION_REJECTED'`
2450
- * (ethers) or `'USER_REJECTED'`, or `name === 'UserRejectedRequestError'` (viem). Only when those are
2451
- * absent is the wallet's TEXT read (`message`, `Message`, `shortMessage`, `details`, `errorDetails`,
2452
- * `reason`, up to three levels deep, or a bare string): "user rejected", "user denied", "user
2453
- * cancelled", "request rejected", "rejected by user", "rejected the request", "cancelled" /
2454
- * "canceled", or a "signature ... cancel" sentence. The wording fallback is a last resort for
2455
- * wallets that do not set codes; prefer `code` and `name` wherever you control the wallet.
2456
- *
2457
- * An SDK error is never read by its text: a `SIGNING_FAILED` is a decline exactly when its
2458
- * `params.reason` is `user_rejected`, and every other SDK error is not one. The same holds for a
2459
- * plain-object VIEW of an SDK error (`{ code: 'SIGNING_FAILED', params: { reason } }`, the shape
2460
- * of an app's wrapper): a string `code` plus an object `params` is decided by the code alone, with
2461
- * the wallet code list above still honoured for a view that is not branded, and its English is
2462
- * never read. This works without `instanceof`, so it is safe across two copies of the SDK.
2463
- *
2464
- * @example
2465
- * ```ts
2466
- * try {
2467
- * await wallet.connect();
2468
- * } catch (error) {
2469
- * if (isWalletUserRejection(error)) return; // the person said no: not an error to report
2470
- * report(error);
2471
- * }
2472
- * ```
2473
- */
2474
- function isWalletUserRejection(value) {
2475
- if (isGSwapErrorLike(value)) {
2476
- if (value.code === "SIGNING_FAILED") return value.params["reason"] === "user_rejected";
2477
- return !hasGSwapErrorBrand(value) && REJECTION_CODES.includes(value.code);
2478
- }
2479
- if (isRecord$2(value)) {
2480
- if (REJECTION_CODES.includes(value["code"]) || value["name"] === REJECTION_NAME) return true;
2481
- }
2482
- return textsOf(value).some(wordsADecline);
2483
- }
2484
- /** The longest wallet code kept: real ones (`4001`, `ACTION_REJECTED`) are short. */
2485
- const MAX_WALLET_CODE_LENGTH = 64;
2486
- /**
2487
- * The code a wallet put on its error: an EIP-1193 / JSON-RPC number (`4001`, `-32603`) or an
2488
- * ethers / viem string (`'ACTION_REJECTED'`), read from the error's own top-level `code`. Anything
2489
- * else (no code, a non-finite number, an empty or very long string, an object) is `undefined`, so
2490
- * the value is always a safe primitive. Used for `GSwapSDKError.walletCode`.
2491
- *
2492
- * @example
2493
- * ```ts
2494
- * walletDeclineCode({ code: 4001, message: 'User rejected the request.' }); // 4001
2495
- * walletDeclineCode(new Error('locked')); // undefined
2496
- * ```
2497
- */
2498
- function walletDeclineCode(value) {
2499
- if (typeof value !== "object" || value === null) return void 0;
2500
- const { code } = value;
2501
- if (typeof code === "number") return Number.isFinite(code) ? code : void 0;
2502
- if (typeof code === "string" && code.length > 0 && code.length <= MAX_WALLET_CODE_LENGTH) return code;
2503
- }
2504
-
2505
- //#endregion
2506
- //#region src/utils/pre_send.ts
2507
- /**
2508
- * The boundary of "nothing was sent". Every place where the SDK hands control to code the APP
2509
- * supplied BEFORE the request leaves (the signer, the token resolver) goes through here, so a
2510
- * failure of that code reaches the caller as a catalogued, pre-send SDK error with the original as
2511
- * `cause`, never as a bare value the SDK cannot classify. An SDK error thrown by that code is
2512
- * already catalogued and passes through untouched. Nothing here is used after the request has
2513
- * been sent: an app's own rejection AFTER send stays what it is, because the SDK cannot know what
2514
- * the server did with the write.
2515
- */
2516
- /**
2517
- * Signs a DTO with the app's signer. Whatever the signer throws that is not already an SDK error
2518
- * (a locked wallet, an unreachable extension, a wallet that declined) is `SIGNING_FAILED`
2519
- * (`reason` `user_rejected` or `failed`, the original as `cause`), and a signer that returns
2520
- * something other than an object is `SIGNING_FAILED` too: both are pre-send, so a retry is safe.
2521
- *
2522
- * @throws GSwapSDKError SIGNING_FAILED, or the SDK error the signer itself threw.
2523
- */
2524
- async function signPreSend(signer, method, dto) {
2525
- let signed;
2526
- try {
2527
- signed = await signer.signObject(method, dto);
2528
- } catch (cause) {
2529
- if (isGSwapError(cause)) throw cause;
2530
- const reason = isWalletUserRejection(cause) ? "user_rejected" : "failed";
2531
- throw new GSwapSDKError("SIGNING_FAILED", {
2532
- method,
2533
- reason
2534
- }, {
2535
- cause,
2536
- walletCode: walletDeclineCode(cause)
2537
- });
2538
- }
2539
- if (typeof signed !== "object" || signed === null) throw new GSwapSDKError("SIGNING_FAILED", {
2540
- method,
2541
- reason: "failed"
2542
- }, { cause: signed });
2543
- return signed;
2544
- }
2545
- /**
2546
- * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry
2547
- * through the app's HTTP stack). A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED`
2548
- * (`token` names what was being resolved, the original is `cause`); an SDK error passes through.
2549
- *
2550
- * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.
2551
- */
2552
- async function resolvePreSend(token, run) {
2553
- try {
2554
- return await run();
2555
- } catch (cause) {
2556
- throw isGSwapError(cause) ? cause : new GSwapSDKError("TOKEN_RESOLUTION_FAILED", { token }, { cause });
2557
- }
2558
- }
2559
-
2560
1677
  //#endregion
2561
1678
  //#region src/classes/dex_fees.ts
2562
1679
  /** DEX methods the backend accepts a fee quote for (its allow-list enumerates the same six). */
@@ -2603,11 +1720,11 @@ function toChainDto(message) {
2603
1720
  * `uniqueKey`, distinct from the DTO's.
2604
1721
  */
2605
1722
  function buildDryRunWrapper(signer, callerPublicKey, method, dto, uniqueKeyPrefix = DRY_RUN_UNIQUE_KEY_PREFIX) {
2606
- return signPreSend(signer, DRY_RUN_METHOD, {
1723
+ return (0, _gala_chain_gala_core_sdk.signPreSend)(signer, DRY_RUN_METHOD, {
2607
1724
  callerPublicKey,
2608
1725
  method,
2609
1726
  dto,
2610
- uniqueKey: `${uniqueKeyPrefix}${globalThis.crypto.randomUUID()}`
1727
+ uniqueKey: (0, _gala_chain_gala_core_sdk.createUniqueKey)(uniqueKeyPrefix)
2611
1728
  });
2612
1729
  }
2613
1730
  /**
@@ -2634,7 +1751,7 @@ var DexFees = class {
2634
1751
  wire;
2635
1752
  constructor(client, signer) {
2636
1753
  this.signer = signer;
2637
- this.requestor = client.httpRequestor ?? fetchRequestor;
1754
+ this.requestor = client.httpRequestor ?? _gala_chain_gala_core_sdk.fetchRequestor;
2638
1755
  this.baseUrl = client.dexBackendBaseUrl.replace(/\/$/u, "");
2639
1756
  this.requestTimeoutMs = client.requestTimeoutMs ?? 3e4;
2640
1757
  this.wire = client.wire;
@@ -2664,9 +1781,9 @@ var DexFees = class {
2664
1781
  let ok;
2665
1782
  let body;
2666
1783
  try {
2667
- const response = await requestWithTimeout(this.requestor, url, {
1784
+ const response = await (0, _gala_chain_gala_core_sdk.requestWithTimeout)(this.requestor, url, {
2668
1785
  method: "POST",
2669
- headers: buildRequestHeaders(this.wire, {
1786
+ headers: (0, _gala_chain_gala_core_sdk.buildRequestHeaders)(this.wire, {
2670
1787
  json: true,
2671
1788
  defaults: { Accept: "application/json" }
2672
1789
  }),
@@ -2674,7 +1791,7 @@ var DexFees = class {
2674
1791
  }, this.requestTimeoutMs);
2675
1792
  status = response.status;
2676
1793
  ok = response.ok;
2677
- body = ok ? await readResponseBody(response) : void 0;
1794
+ body = ok ? await (0, _gala_chain_gala_core_sdk.readResponseBody)(response) : void 0;
2678
1795
  } catch {
2679
1796
  return null;
2680
1797
  }
@@ -2725,13 +1842,15 @@ const shadowRejections = /* @__PURE__ */ new WeakSet();
2725
1842
  function isShadowError(value) {
2726
1843
  var _toFailureView;
2727
1844
  if (isGSwapError(value)) return value.shadow;
2728
- if (((_toFailureView = toFailureView(value)) === null || _toFailureView === void 0 ? void 0 : _toFailureView.shadow) === true) return true;
1845
+ if (((_toFailureView = (0, _gala_chain_gala_core_sdk.toFailureView)(value)) === null || _toFailureView === void 0 ? void 0 : _toFailureView.shadow) === true) return true;
2729
1846
  return typeof value === "object" && value !== null && shadowRejections.has(value);
2730
1847
  }
2731
1848
  /**
2732
1849
  * The same failure, marked as shadow. An SDK error is COPIED (same code, params, status, body,
2733
- * url, ids, cause, phase and stack), never mutated: one error object can be shared by several
2734
- * callers (a registry read many swaps wait on), and only the shadow caller's copy is shadow.
1850
+ * url, ids, cause, phase, read/write, wallet code and stack), never mutated: one error object can
1851
+ * be shared by several callers (a registry read many swaps wait on), and only the shadow caller's
1852
+ * copy is shadow. Everything the deciders read is carried over, so the copy classifies exactly as
1853
+ * the original (a failed READ stays a read, never a "maybe queued" write).
2735
1854
  */
2736
1855
  function asShadowError(error) {
2737
1856
  if (isGSwapError(error)) {
@@ -2747,6 +1866,8 @@ function asShadowError(error) {
2747
1866
  retryAfterMs: error.retryAfterMs,
2748
1867
  cause: error.cause,
2749
1868
  phase: error.phase,
1869
+ write: error.write,
1870
+ walletCode: error.walletCode,
2750
1871
  shadow: true
2751
1872
  });
2752
1873
  if (error.stack !== void 0) copy.stack = error.stack;
@@ -2829,6 +1950,12 @@ var SubmittedTransaction = class {
2829
1950
  * For RequestTrade, calling this method is required to learn the outcome: the queued
2830
1951
  * acknowledgement proves acceptance, not execution.
2831
1952
  *
1953
+ * Every failure is the write's (it carries `uniqueKey`, so `mayHaveBeenQueued` is true): a
1954
+ * re-read that cannot succeed is `CONFIRMATION_FAILED` (a terminal HTTP status) or
1955
+ * `CONFIRMATION_MALFORMED` (an unusable answer); one that may (no answer, a 5xx, 404, 408,
1956
+ * 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error
1957
+ * as `cause`. Confirm the same transaction again; never resubmit the write.
1958
+ *
2832
1959
  * @example
2833
1960
  * ```ts
2834
1961
  * const applied = await submitted.confirm({ initialDelayMs: 3_000 });
@@ -2866,9 +1993,10 @@ var SubmittedTransaction = class {
2866
1993
  });
2867
1994
  const schedule = createConfirmationSchedule(options, 0, abortError);
2868
1995
  await schedule.waitForRead();
1996
+ let lastError;
2869
1997
  while (true) {
2870
1998
  const controller = new AbortController();
2871
- const disarm = armTimeout(controller, this.requestTimeoutMs);
1999
+ const disarm = (0, _gala_chain_gala_core_sdk.armTimeout)(controller, this.requestTimeoutMs);
2872
2000
  const forwardAbort = () => controller.abort();
2873
2001
  callerSignal === null || callerSignal === void 0 || callerSignal.addEventListener("abort", forwardAbort, { once: true });
2874
2002
  try {
@@ -2876,27 +2004,60 @@ var SubmittedTransaction = class {
2876
2004
  if (result.confirmed) return result.position;
2877
2005
  } catch (error) {
2878
2006
  throwIfAborted(callerSignal, abortError);
2879
- throw error;
2007
+ const terminal = terminalPositionReadFailure(this.uniqueKey, error);
2008
+ if (terminal !== void 0) throw terminal;
2009
+ lastError = error;
2880
2010
  } finally {
2881
2011
  disarm();
2882
2012
  callerSignal === null || callerSignal === void 0 || callerSignal.removeEventListener("abort", forwardAbort);
2883
2013
  }
2884
2014
  if (!await schedule.waitForRead()) break;
2885
2015
  }
2886
- throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey);
2016
+ throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);
2887
2017
  }
2888
2018
  };
2889
-
2890
- //#endregion
2891
- //#region src/classes/gateway.ts
2892
- /** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */
2893
- var ChainGateway = class {
2894
- requestor;
2895
- walletAddress;
2896
- chainCallTimeoutMs;
2897
- isTransportFailure;
2898
- answerOfRejectionHook;
2899
- /** The request timeout in milliseconds (`Infinity` when no timer is armed). */
2019
+ /** HTTP answers a confirmation reads again (as the apply-results poll does), not terminal ones. */
2020
+ function isRetriedStatus(status) {
2021
+ return status === 404 || status === 408 || status === 429 || status >= 500;
2022
+ }
2023
+ /**
2024
+ * The confirmation error for a position re-read that failed TERMINALLY (an answer that reading
2025
+ * again cannot change), or `undefined` when it is worth reading again.
2026
+ */
2027
+ function terminalPositionReadFailure(uniqueKey, error) {
2028
+ if (!isGSwapError(error)) return void 0;
2029
+ if (error.code === "INVALID_POSITION_RESPONSE" || error.code === "INVALID_CHAIN_RESPONSE") return new GSwapSDKError("CONFIRMATION_MALFORMED", {}, {
2030
+ uniqueKey,
2031
+ url: error.url,
2032
+ body: error.body ?? error.bodyText,
2033
+ cause: error
2034
+ });
2035
+ const status = error.status;
2036
+ if ((error.code === "HTTP_ERROR" || error.code === "UPDATE_REQUIRED") && status !== void 0 && !isRetriedStatus(status)) {
2037
+ const serverMessage = error.params["serverMessage"];
2038
+ return new GSwapSDKError("CONFIRMATION_FAILED", {
2039
+ status,
2040
+ serverMessage: typeof serverMessage === "string" ? serverMessage : ""
2041
+ }, {
2042
+ uniqueKey,
2043
+ status,
2044
+ url: error.url,
2045
+ body: error.body ?? error.bodyText,
2046
+ cause: error
2047
+ });
2048
+ }
2049
+ }
2050
+
2051
+ //#endregion
2052
+ //#region src/classes/gateway.ts
2053
+ /** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */
2054
+ var ChainGateway = class {
2055
+ requestor;
2056
+ walletAddress;
2057
+ chainCallTimeoutMs;
2058
+ isTransportFailure;
2059
+ answerOfRejectionHook;
2060
+ /** The request timeout in milliseconds (`Infinity` when no timer is armed). */
2900
2061
  requestTimeoutMs;
2901
2062
  /** The swap backend base URL every request is sent to, without a trailing slash. */
2902
2063
  dexBackendBaseUrl;
@@ -2905,9 +2066,9 @@ var ChainGateway = class {
2905
2066
  /** Create a chain gateway client. */
2906
2067
  constructor(options) {
2907
2068
  this.dexBackendBaseUrl = trimTrailingSlash$1(options.dexBackendBaseUrl);
2908
- this.requestor = options.httpRequestor ?? fetchRequestor;
2069
+ this.requestor = options.httpRequestor ?? _gala_chain_gala_core_sdk.fetchRequestor;
2909
2070
  this.walletAddress = options.walletAddress;
2910
- this.chainCallTimeoutMs = validateTimeoutMs(options.chainCallTimeoutMs ?? 3e4, "chainCallTimeoutMs");
2071
+ this.chainCallTimeoutMs = (0, _gala_chain_gala_core_sdk.validateTimeoutMs)(options.chainCallTimeoutMs ?? 3e4, "chainCallTimeoutMs");
2911
2072
  this.requestTimeoutMs = this.chainCallTimeoutMs;
2912
2073
  this.wire = options.wire ?? {};
2913
2074
  this.isTransportFailure = options.isTransportFailure;
@@ -2917,7 +2078,7 @@ var ChainGateway = class {
2917
2078
  if (method === "Trade") throw new GSwapSDKError("METHOD_NOT_SUPPORTED", { method });
2918
2079
  const url = this.writeUrl(method);
2919
2080
  const walletAddress = (options === null || options === void 0 ? void 0 : options.walletAddress) ?? this.walletAddress;
2920
- const headers = buildRequestHeaders(this.wire, {
2081
+ const headers = (0, _gala_chain_gala_core_sdk.buildRequestHeaders)(this.wire, {
2921
2082
  json: true,
2922
2083
  fixed: walletAddress === void 0 ? {} : { "X-Wallet-Address": walletAddress }
2923
2084
  });
@@ -2946,9 +2107,9 @@ var ChainGateway = class {
2946
2107
  if (resultStatus !== void 0 && resultStatus !== 1) throw GSwapSDKError.fromChainError(getStringProperty(embeddedResult, "ErrorKey") ?? "CHAIN_ERROR", getStringProperty(embeddedResult, "Message") ?? "", context);
2947
2108
  }
2948
2109
  }
2949
- const headerTransactionId = readHeader(response, "x-transaction-id");
2110
+ const headerTransactionId = (0, _gala_chain_gala_core_sdk.readHeader)(response, "x-transaction-id");
2950
2111
  const resolvedTransactionId = transactionId === void 0 || transactionId === "" ? headerTransactionId : transactionId;
2951
- const blockNumber = bodyBlockNumber === null || bodyBlockNumber === void 0 ? readBlockNumberHeader(response) : isBlockNumber(bodyBlockNumber) ? bodyBlockNumber : void 0;
2112
+ const blockNumber = bodyBlockNumber === null || bodyBlockNumber === void 0 ? (0, _gala_chain_gala_core_sdk.readBlockNumberHeader)(response) : isBlockNumber(bodyBlockNumber) ? bodyBlockNumber : void 0;
2952
2113
  return new SubmittedTransaction({
2953
2114
  method,
2954
2115
  uniqueKey,
@@ -2991,7 +2152,7 @@ var ChainGateway = class {
2991
2152
  if (method === "Trade") throw new GSwapSDKError("METHOD_NOT_SUPPORTED", { method });
2992
2153
  const walletAddress = (options === null || options === void 0 ? void 0 : options.walletAddress) ?? this.walletAddress;
2993
2154
  if (walletAddress === void 0) throw new GSwapSDKError("SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS", {});
2994
- const headers = buildRequestHeaders(this.wire, {
2155
+ const headers = (0, _gala_chain_gala_core_sdk.buildRequestHeaders)(this.wire, {
2995
2156
  json: true,
2996
2157
  fixed: {
2997
2158
  "X-Wallet-Address": walletAddress,
@@ -3030,7 +2191,7 @@ var ChainGateway = class {
3030
2191
  });
3031
2192
  let response;
3032
2193
  try {
3033
- response = await requestWithTimeout(this.requestor, url, {
2194
+ response = await (0, _gala_chain_gala_core_sdk.requestWithTimeout)(this.requestor, url, {
3034
2195
  method: "POST",
3035
2196
  headers,
3036
2197
  body: payload
@@ -3045,7 +2206,7 @@ var ChainGateway = class {
3045
2206
  try {
3046
2207
  return {
3047
2208
  response,
3048
- body: await readResponseBody(response)
2209
+ body: await (0, _gala_chain_gala_core_sdk.readResponseBody)(response)
3049
2210
  };
3050
2211
  } catch (error) {
3051
2212
  throw outcomeUnknown("transport", error);
@@ -3130,7 +2291,7 @@ function gatewayError(response, body, url, uniqueKey) {
3130
2291
  const nested = getObjectProperty(body, "error");
3131
2292
  const code = getStringProperty(object, "code") ?? getStringProperty(nested, "code") ?? getStringProperty(nested, "ErrorKey") ?? "HTTP_ERROR";
3132
2293
  const message = serverMessageOfBody(body);
3133
- const retryAfterMs = response.status === 429 ? readRetryAfter(response) : void 0;
2294
+ const retryAfterMs = response.status === 429 ? (0, _gala_chain_gala_core_sdk.readRetryAfter)(response) : void 0;
3134
2295
  if (code === "HTTP_ERROR") return new GSwapSDKError("HTTP_ERROR", {
3135
2296
  status: response.status,
3136
2297
  url,
@@ -3623,7 +2784,7 @@ var HttpClient = class {
3623
2784
  * Create an HTTP client around fetch or an injected requestor. `wire` selects the query
3624
2785
  * encoding and the `User-Agent` (see {@link WireOptions}).
3625
2786
  */
3626
- constructor(httpRequestor = fetchRequestor, timeoutMs = 3e4, wire = {}) {
2787
+ constructor(httpRequestor = _gala_chain_gala_core_sdk.fetchRequestor, timeoutMs = 3e4, wire = {}) {
3627
2788
  this.httpRequestor = httpRequestor;
3628
2789
  this.timeoutMs = timeoutMs;
3629
2790
  this.wire = wire;
@@ -3632,14 +2793,14 @@ var HttpClient = class {
3632
2793
  const url = `${baseUrl}${basePath}${endpoint}`;
3633
2794
  debugLog(`Sending request to ${url} with body:`, body);
3634
2795
  const hasBody = Boolean(body);
3635
- const response = await requestWithTimeout(this.httpRequestor, url, {
2796
+ const response = await (0, _gala_chain_gala_core_sdk.requestWithTimeout)(this.httpRequestor, url, {
3636
2797
  method,
3637
- headers: buildRequestHeaders(this.wire, { json: hasBody }),
2798
+ headers: (0, _gala_chain_gala_core_sdk.buildRequestHeaders)(this.wire, { json: hasBody }),
3638
2799
  ...hasBody ? { body: JSON.stringify(body) } : {},
3639
2800
  ...(options === null || options === void 0 ? void 0 : options.signal) === void 0 ? {} : { signal: options.signal }
3640
- }, this.timeoutMs);
2801
+ }, this.timeoutMs, { write: false });
3641
2802
  if (!response.ok) throw await GSwapSDKError.fromErrorResponse(url, response);
3642
- const json = await readResponseBody(response);
2803
+ const json = await (0, _gala_chain_gala_core_sdk.readResponseBody)(response);
3643
2804
  debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);
3644
2805
  return json;
3645
2806
  }
@@ -3649,7 +2810,7 @@ var HttpClient = class {
3649
2810
  }
3650
2811
  /** Send a GET request with URL-encoded query parameters and decode its response. */
3651
2812
  async sendGetRequest(baseUrl, basePath, endpoint, params, options) {
3652
- const endpointWithParams = params ? `${endpoint}?${buildQueryString(params, this.wire.queryEncoding)}` : endpoint;
2813
+ const endpointWithParams = params ? `${endpoint}?${(0, _gala_chain_gala_core_sdk.buildQueryString)(params, this.wire.queryEncoding)}` : endpoint;
3653
2814
  return this.sendRequest("GET", baseUrl, basePath, endpointWithParams, void 0, options);
3654
2815
  }
3655
2816
  };
@@ -3673,10 +2834,13 @@ function entryRejected(reason) {
3673
2834
  /**
3674
2835
  * Reads a list answer row by row: a row that cannot be used is skipped and reported, instead of
3675
2836
  * rejecting the whole list because of one bad row. An answer that is not a list at all is still
3676
- * `INVALID_CHAIN_RESPONSE`: nothing in it can be trusted.
2837
+ * `INVALID_CHAIN_RESPONSE` (a read's: `write: false`): nothing in it can be trusted.
3677
2838
  */
3678
2839
  function readEntries(source, data, parse, onInvalidEntry) {
3679
- if (!Array.isArray(data)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: `${source} list` }, { body: data });
2840
+ if (!Array.isArray(data)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: `${source} list` }, {
2841
+ body: data,
2842
+ write: false
2843
+ });
3680
2844
  const rows = [];
3681
2845
  data.forEach((entry, index) => {
3682
2846
  const parsed = parse(entry);
@@ -3709,97 +2873,462 @@ function finiteNumberOf(value) {
3709
2873
  }
3710
2874
 
3711
2875
  //#endregion
3712
- //#region src/utils/class_key.ts
2876
+ //#region src/classes/leaderboard.ts
3713
2877
  /**
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`.
2878
+ * The swap backend's trading-competition reads: seasons (`GET /leaderboard/seasons`) and a
2879
+ * season's rankings (`GET /leaderboard?seasonId=`). Public reads: no signer, no wallet. A row that
2880
+ * is not usable is skipped and reported to `onInvalidEntry`; an answer that is not the expected
2881
+ * list is `INVALID_CHAIN_RESPONSE`.
3718
2882
  */
3719
- /** Return the `$`-joined composite key used by GalaChain object identities. */
3720
- function compositeKeyOf(token) {
3721
- return [
3722
- token.collection,
3723
- token.category,
3724
- token.type,
3725
- token.additionalKey
3726
- ].join("$");
2883
+ var Leaderboard = class {
2884
+ dexBackendBaseUrl;
2885
+ httpClient;
2886
+ options;
2887
+ /**
2888
+ * Creates a leaderboard service. `options.onInvalidEntry` is told about every season or entry
2889
+ * row that was skipped as unusable.
2890
+ *
2891
+ * @example
2892
+ * ```ts
2893
+ * const leaderboard = new Leaderboard('https://dex-backend-prod1.defi.gala.com', httpClient);
2894
+ * ```
2895
+ */
2896
+ constructor(dexBackendBaseUrl, httpClient, options = {}) {
2897
+ this.dexBackendBaseUrl = dexBackendBaseUrl;
2898
+ this.httpClient = httpClient;
2899
+ this.options = options;
2900
+ }
2901
+ /**
2902
+ * Every active season, in the backend's order (newest first).
2903
+ *
2904
+ * @example
2905
+ * ```ts
2906
+ * const seasons = await gSwap.leaderboard.getSeasons();
2907
+ * console.log(seasons.map((season) => season.name));
2908
+ * ```
2909
+ */
2910
+ async getSeasons(options) {
2911
+ const response = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/leaderboard", "/seasons", void 0, signalOption$1(options));
2912
+ return readEntries("seasons", response, parseSeason, (options === null || options === void 0 ? void 0 : options.onInvalidEntry) ?? this.options.onInvalidEntry);
2913
+ }
2914
+ /**
2915
+ * The season running at `options.now` (default: now; `start` and `end` both count as inside),
2916
+ * or `null` between seasons. When seasons overlap, the first in the backend's order.
2917
+ *
2918
+ * @example
2919
+ * ```ts
2920
+ * const season = await gSwap.leaderboard.getCurrentSeason();
2921
+ * console.log(season === null ? 'no season running' : season.name);
2922
+ * ```
2923
+ */
2924
+ async getCurrentSeason(options) {
2925
+ const now = ((options === null || options === void 0 ? void 0 : options.now) ?? /* @__PURE__ */ new Date()).getTime();
2926
+ return (await this.getSeasons(options)).find((season) => season.start.getTime() <= now && now <= season.end.getTime()) ?? null;
2927
+ }
2928
+ /**
2929
+ * A season's rankings (the backend's top 100 wallets). `seasonId` must be an integer of at
2930
+ * least 1 (`INVALID_SEASON_ID` before anything is sent); a season with no rankings, or none at
2931
+ * all, is an empty list.
2932
+ *
2933
+ * @example
2934
+ * ```ts
2935
+ * const { entries } = await gSwap.leaderboard.getLeaderboard(1);
2936
+ * console.log(entries[0]?.wallet, entries[0]?.totalXp);
2937
+ * ```
2938
+ */
2939
+ async getLeaderboard(seasonId, options) {
2940
+ var _asEntryRecord;
2941
+ if (typeof seasonId !== "number" || !Number.isSafeInteger(seasonId) || seasonId < 1) throw new GSwapSDKError("INVALID_SEASON_ID", { value: String(seasonId) });
2942
+ const response = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/leaderboard", "", { seasonId: String(seasonId) }, signalOption$1(options));
2943
+ const rows = (_asEntryRecord = asEntryRecord(response)) === null || _asEntryRecord === void 0 ? void 0 : _asEntryRecord["leaderboard"];
2944
+ if (!Array.isArray(rows)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "leaderboard" }, {
2945
+ body: response,
2946
+ write: false
2947
+ });
2948
+ return {
2949
+ seasonId,
2950
+ entries: readEntries("leaderboard", rows, parseEntry, (options === null || options === void 0 ? void 0 : options.onInvalidEntry) ?? this.options.onInvalidEntry)
2951
+ };
2952
+ }
2953
+ /**
2954
+ * The rankings of the season running at `options.now` (see
2955
+ * {@link Leaderboard.getCurrentSeason}), or `null` between seasons.
2956
+ *
2957
+ * @example
2958
+ * ```ts
2959
+ * const current = await gSwap.leaderboard.getCurrentLeaderboard();
2960
+ * if (current !== null) console.log(current.seasonId, current.entries.length);
2961
+ * ```
2962
+ */
2963
+ async getCurrentLeaderboard(options) {
2964
+ const season = await this.getCurrentSeason(options);
2965
+ return season === null ? null : this.getLeaderboard(season.id, options);
2966
+ }
2967
+ };
2968
+ function signalOption$1(options) {
2969
+ return (options === null || options === void 0 ? void 0 : options.signal) === void 0 ? void 0 : { signal: options.signal };
2970
+ }
2971
+ function positiveInteger(value) {
2972
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : void 0;
2973
+ }
2974
+ function isoDate(value) {
2975
+ if (typeof value !== "string") return void 0;
2976
+ const date = new Date(value);
2977
+ return Number.isNaN(date.getTime()) ? void 0 : date;
2978
+ }
2979
+ function parseSeason(entry) {
2980
+ const record = asEntryRecord(entry);
2981
+ if (record === void 0) return entryRejected("not an object");
2982
+ const id = positiveInteger(record["id"]);
2983
+ if (id === void 0) return entryRejected("id is not an integer of at least 1");
2984
+ const name = record["name"];
2985
+ if (typeof name !== "string") return entryRejected("name is not a string");
2986
+ const start = isoDate(record["start"]);
2987
+ const end = isoDate(record["end"]);
2988
+ if (start === void 0 || end === void 0) return entryRejected("start or end is not a date");
2989
+ if (start.getTime() > end.getTime()) return entryRejected("start is after end");
2990
+ const rulesId = record["rules_id"];
2991
+ if (typeof rulesId !== "number" || !Number.isSafeInteger(rulesId) || rulesId < 0) return entryRejected("rules_id is not an integer");
2992
+ return entryOk({
2993
+ id,
2994
+ name,
2995
+ start,
2996
+ end,
2997
+ rulesId
2998
+ });
3727
2999
  }
3728
- /**
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.
3732
- *
3733
- * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
3734
- * them is the `collection`. Parsing from the right is required because real collections contain
3735
- * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
3736
- * shifts every field.
3737
- */
3738
- function splitClassKey(key, delimiter) {
3739
- const segments = key.split(delimiter);
3740
- const tail = segments.slice(-3);
3741
- const collection = segments.slice(0, -3).join(delimiter);
3742
- if (segments.length < 4 || collection.length === 0 || tail.some((part) => part.length === 0)) return;
3743
- const [category, type, additionalKey] = tail;
3000
+ /** A non-negative decimal, as the backend's DECIMAL columns are serialized (or a finite number). */
3001
+ const DECIMAL = /^\d+(?:\.\d+)?$/u;
3002
+ function decimalOf(value) {
3003
+ const text = typeof value === "number" ? String(value) : value;
3004
+ return typeof text === "string" && DECIMAL.test(text) ? text : void 0;
3005
+ }
3006
+ function parseTitle(value) {
3007
+ const record = asEntryRecord(value);
3008
+ if (record === void 0) return void 0;
3009
+ const { name, type, order } = record;
3010
+ if (typeof name !== "string" || typeof type !== "string") return void 0;
3011
+ if (typeof order !== "number" || !Number.isFinite(order)) return void 0;
3744
3012
  return {
3745
- collection,
3746
- category,
3013
+ name,
3747
3014
  type,
3748
- additionalKey
3015
+ order
3749
3016
  };
3750
3017
  }
3018
+ function parseEntry(entry) {
3019
+ const record = asEntryRecord(entry);
3020
+ if (record === void 0) return entryRejected("not an object");
3021
+ const wallet = record["wallet"];
3022
+ if (typeof wallet !== "string" || wallet === "") return entryRejected("wallet is not a string");
3023
+ const rank = positiveInteger(record["rank"]);
3024
+ if (rank === void 0) return entryRejected("rank is not an integer of at least 1");
3025
+ const rawTotal = record["total_xp"];
3026
+ const totalXp = rawTotal === void 0 || rawTotal === null ? null : decimalOf(rawTotal);
3027
+ if (totalXp === void 0) return entryRejected("total_xp is not a decimal");
3028
+ const distributionPercent = decimalOf(record["distribution_percent"]);
3029
+ const liquidityXp = decimalOf(record["liquidity_xp"]);
3030
+ const tradingXp = decimalOf(record["trading_xp"]);
3031
+ if (distributionPercent === void 0 || liquidityXp === void 0 || tradingXp === void 0) return entryRejected("distribution_percent, liquidity_xp or trading_xp is not a decimal");
3032
+ const rawTitles = record["mastery_titles"];
3033
+ if (!Array.isArray(rawTitles)) return entryRejected("mastery_titles is not a list");
3034
+ const masteryTitles = [];
3035
+ for (const raw of rawTitles) {
3036
+ const title = parseTitle(raw);
3037
+ if (title === void 0) return entryRejected("a mastery title is not { name, type, order }");
3038
+ masteryTitles.push(title);
3039
+ }
3040
+ return entryOk({
3041
+ wallet,
3042
+ rank,
3043
+ totalXp,
3044
+ distributionPercent,
3045
+ liquidityXp,
3046
+ tradingXp,
3047
+ masteryTitles
3048
+ });
3049
+ }
3050
+
3051
+ //#endregion
3052
+ //#region src/types/market.ts
3053
+ /**
3054
+ * The swap backend's market data and trading-competition reads: what `GSwap.market` and
3055
+ * `GSwap.leaderboard` return. Values are the backend's, unconverted: USD prices as numbers, times
3056
+ * as unix seconds or `Date`s, XP as decimal strings.
3057
+ */
3058
+ /** The windows `GET /market/price-series` serves (the backend refuses any other with a 400). */
3059
+ const PRICE_SERIES_TIMEFRAMES = [
3060
+ "1D",
3061
+ "1W",
3062
+ "1M",
3063
+ "1Y",
3064
+ "ALL"
3065
+ ];
3066
+ /** The most tokens one `GET /market/price` request may name (the backend's limit). */
3067
+ const MARKET_PRICE_BATCH_LIMIT = 500;
3068
+
3069
+ //#endregion
3070
+ //#region src/classes/market.ts
3751
3071
  /**
3752
- * The non-throwing `parseTokenClassKey`: the class key, or `undefined` when `value` is not
3753
- * one. A string is split exactly as `parseTokenClassKey` splits it (`|` form when it contains a
3754
- * `|`, else `$`, from the right, all four parts non-empty). Unlike `parseTokenClassKey`, an
3755
- * object is VALIDATED, not just copied: all four fields must be non-empty strings. Anything else
3756
- * (`undefined`, `null`, a number, an array) is `undefined`, so it is safe on untrusted input (a
3757
- * stored token, a URL parameter, a wallet row) without a `try`/`catch`.
3758
- *
3759
- * Use {@link tryParseCompositeKey} instead when only the `$` form is valid input.
3072
+ * The ids `GET /market/price` and `GET /market/price-series` accept (the backend's own allowlist):
3073
+ * a symbol, or a class key in the `$` or `|` form. A comma would split the price request.
3074
+ */
3075
+ const MARKET_TOKEN_PATTERN = /^[A-Za-z0-9._$+/:|-]{1,120}$/u;
3076
+ /**
3077
+ * Market data from the swap backend: USD prices (`GET /market/price`), price series
3078
+ * (`GET /market/price-series`) and the platform volume totals (`GET /v2/trade/volume`). Public
3079
+ * reads: no signer, no wallet.
3760
3080
  *
3761
- * @example
3762
- * ```ts
3763
- * const key = tryParseTokenClassKey(row.compositeKey);
3764
- * if (key === undefined) return failClosed(); // no class is known: never invent one from a symbol
3765
- * ```
3081
+ * A token is named by a symbol (`GALA`) or a class key (`GALA$Unit$none$none`,
3082
+ * `GALA|Unit|none|none` or the object). The backend answers each token under the exact id it was
3083
+ * asked for, so the answer is read back under that id: a token the backend has no entry for is
3084
+ * `undefined`, never another token's price.
3766
3085
  */
3767
- function tryParseTokenClassKey(value) {
3768
- if (typeof value === "string") return splitClassKey(value, value.includes("|") ? "|" : "$");
3769
- if (typeof value !== "object" || value === null) return void 0;
3770
- try {
3771
- const { collection, category, type, additionalKey } = value;
3772
- if (typeof collection !== "string" || typeof category !== "string" || typeof type !== "string" || typeof additionalKey !== "string" || collection === "" || category === "" || type === "" || additionalKey === "") return;
3086
+ var Market = class {
3087
+ dexBackendBaseUrl;
3088
+ httpClient;
3089
+ options;
3090
+ /**
3091
+ * Creates a market service. `options.onInvalidEntry` is told about every price or price point
3092
+ * that was skipped as unusable.
3093
+ *
3094
+ * @example
3095
+ * ```ts
3096
+ * const market = new Market('https://dex-backend-prod1.defi.gala.com', httpClient);
3097
+ * ```
3098
+ */
3099
+ constructor(dexBackendBaseUrl, httpClient, options = {}) {
3100
+ this.dexBackendBaseUrl = dexBackendBaseUrl;
3101
+ this.httpClient = httpClient;
3102
+ this.options = options;
3103
+ }
3104
+ /**
3105
+ * USD prices of 1 to 500 tokens, in the order asked (a token named twice is asked for once).
3106
+ * The ids go in as many requests as their length needs (see {@link MARKET_PRICE_QUERY_BYTES}),
3107
+ * one after another; any request failing fails the call. A token the backend did not answer
3108
+ * for is `undefined`; one it answered for unusably is `undefined` too, and reported to
3109
+ * `onInvalidEntry`. An answer that is not an object is `INVALID_CHAIN_RESPONSE`.
3110
+ *
3111
+ * @example
3112
+ * ```ts
3113
+ * const [gala, gusdc] = await gSwap.market.getPrices(['GALA$Unit$none$none', 'GUSDC$Unit$none$none']);
3114
+ * console.log(gala?.price, gusdc?.price);
3115
+ * ```
3116
+ */
3117
+ async getPrices(tokens, options) {
3118
+ if (!Array.isArray(tokens) || tokens.length < 1 || tokens.length > 500) throw new GSwapSDKError("INVALID_TOKEN_BATCH", {
3119
+ method: "getPrices",
3120
+ count: Array.isArray(tokens) ? tokens.length : 0,
3121
+ max: 500
3122
+ });
3123
+ const ids = tokens.map(marketTokenOf);
3124
+ const answered = /* @__PURE__ */ new Map();
3125
+ for (const batch of priceBatches([...new Set(ids)])) {
3126
+ const response = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/market", "/price", { assetIds: batch.join(",") }, signalOption(options));
3127
+ const answer = asEntryRecord(response);
3128
+ if (answer === void 0) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "market prices" }, {
3129
+ body: response,
3130
+ write: false
3131
+ });
3132
+ for (const id of batch) if (Object.hasOwn(answer, id)) answered.set(id, answer[id]);
3133
+ }
3134
+ const onInvalidEntry = (options === null || options === void 0 ? void 0 : options.onInvalidEntry) ?? this.options.onInvalidEntry;
3135
+ return ids.map((id, index) => {
3136
+ if (!answered.has(id)) return void 0;
3137
+ const entry = answered.get(id);
3138
+ const parsed = parseMarketPrice(id, entry);
3139
+ if (parsed.ok) return parsed.value;
3140
+ try {
3141
+ onInvalidEntry === null || onInvalidEntry === void 0 || onInvalidEntry({
3142
+ source: "prices",
3143
+ index,
3144
+ entry,
3145
+ reason: parsed.reason
3146
+ });
3147
+ } catch {}
3148
+ });
3149
+ }
3150
+ /**
3151
+ * The USD price of one token, or `undefined` when the backend has no entry for it (see
3152
+ * {@link Market.getPrices}).
3153
+ *
3154
+ * @example
3155
+ * ```ts
3156
+ * const gala = await gSwap.market.getPrice('GALA$Unit$none$none');
3157
+ * if (gala?.price != null) console.log(`GALA: $${gala.price}`);
3158
+ * ```
3159
+ */
3160
+ async getPrice(token, options) {
3161
+ const [price] = await this.getPrices([token], options);
3162
+ return price;
3163
+ }
3164
+ /**
3165
+ * A token's USD price line for one window (1D, 1W, 1M, 1Y or ALL; any other is
3166
+ * `INVALID_TIMEFRAME` before anything is sent). The whole series in one answer, oldest first; a
3167
+ * token the backend has no prices for is an empty series. An unusable point is skipped and
3168
+ * reported to `onInvalidEntry`; an answer that is not a series is `INVALID_CHAIN_RESPONSE`.
3169
+ *
3170
+ * @example
3171
+ * ```ts
3172
+ * const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W');
3173
+ * console.log(series.prices.length, series.currentPrice);
3174
+ * ```
3175
+ */
3176
+ async getPriceSeries(token, timeframe, options) {
3177
+ if (!PRICE_SERIES_TIMEFRAMES.includes(timeframe)) throw new GSwapSDKError("INVALID_TIMEFRAME", {
3178
+ value: String(timeframe),
3179
+ allowed: PRICE_SERIES_TIMEFRAMES.join(", ")
3180
+ });
3181
+ const id = marketTokenOf(token);
3182
+ const response = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/market", "/price-series", {
3183
+ token: id,
3184
+ timeframe
3185
+ }, signalOption(options));
3186
+ const answer = asEntryRecord(response);
3187
+ const currentPrice = answer === void 0 ? void 0 : nullableFinite(answer["currentPrice"]);
3188
+ const change24h = answer === void 0 ? void 0 : nullableFinite(answer["change24h"]);
3189
+ if (answer === void 0 || !Array.isArray(answer["prices"]) || currentPrice === void 0 || change24h === void 0) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "price series" }, {
3190
+ body: response,
3191
+ write: false
3192
+ });
3773
3193
  return {
3774
- collection,
3775
- category,
3776
- type,
3777
- additionalKey
3194
+ token: id,
3195
+ timeframe,
3196
+ prices: readEntries("priceSeries", answer["prices"], parsePricePoint, (options === null || options === void 0 ? void 0 : options.onInvalidEntry) ?? this.options.onInvalidEntry),
3197
+ currentPrice,
3198
+ change24h
3778
3199
  };
3779
- } catch {
3780
- return;
3781
3200
  }
3201
+ /**
3202
+ * TVL, volume and trade totals across every current-contract pool. Every field must be a finite
3203
+ * number, or the answer is `INVALID_CHAIN_RESPONSE`.
3204
+ *
3205
+ * @example
3206
+ * ```ts
3207
+ * const volume = await gSwap.market.getVolumeSummary();
3208
+ * console.log(`24h: $${volume.volume1d.toFixed(0)} (${(volume.volume1dDelta * 100).toFixed(1)} %)`);
3209
+ * ```
3210
+ */
3211
+ async getVolumeSummary(options) {
3212
+ var _asEntryRecord;
3213
+ const response = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/v2/trade", "/volume", void 0, signalOption(options));
3214
+ const summary = parseVolumeSummary(asEntryRecord((_asEntryRecord = asEntryRecord(response)) === null || _asEntryRecord === void 0 ? void 0 : _asEntryRecord["data"]));
3215
+ if (summary === void 0) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "volume summary" }, {
3216
+ body: response,
3217
+ write: false
3218
+ });
3219
+ return summary;
3220
+ }
3221
+ };
3222
+ /**
3223
+ * The most query bytes one `GET /market/price` carries. The backend refuses a request line over
3224
+ * 16 KB (Node's default header limit: 300 launchpad keys, 17.7 KB encoded, answer HTTP 431,
3225
+ * recorded on prod 2026-10-13), so a long list is split well under it (about 135 launchpad keys
3226
+ * per request, 270 short ones).
3227
+ */
3228
+ const MARKET_PRICE_QUERY_BYTES = 8e3;
3229
+ /**
3230
+ * The ids in request-sized batches: at most {@link MARKET_PRICE_BATCH_LIMIT} ids and
3231
+ * {@link MARKET_PRICE_QUERY_BYTES} of encoded `assetIds` each (the standard encoding's size, the
3232
+ * larger of the two, with a `%2C` per id).
3233
+ */
3234
+ function priceBatches(ids) {
3235
+ const batches = [];
3236
+ let batch = [];
3237
+ let bytes = 0;
3238
+ for (const id of ids) {
3239
+ const size = encodeURIComponent(id).length + 3;
3240
+ if (batch.length > 0 && (bytes + size > 8e3 || batch.length === 500)) {
3241
+ batches.push(batch);
3242
+ batch = [];
3243
+ bytes = 0;
3244
+ }
3245
+ batch.push(id);
3246
+ bytes += size;
3247
+ }
3248
+ if (batch.length > 0) batches.push(batch);
3249
+ return batches;
3782
3250
  }
3783
3251
  /**
3784
- * Parses a `$`-joined composite key (`Collection$Category$Type$AdditionalKey`, what
3785
- * {@link compositeKeyOf} writes) and nothing else, or `undefined`. It is {@link tryParseTokenClassKey}
3786
- * for a string that may ONLY be in the `$` form: a key that contains `|` is NOT read as the pipe
3787
- * form here (it stays part of a segment), and only a string is accepted. The split is from the
3788
- * right, so a collection that itself contains `$` (production's `$GMUSIC`, stage's
3789
- * `$GMUSIC_TEST1`) stays whole; `'GALA'`, `'GALA$Unit$none'`, `'ETIME$$$'`, `'GALA$Unit$none$'` and
3790
- * `'$$$$'` are `undefined`.
3791
- *
3792
- * It replaces an app's own `parseCompositeKey(key): Components | null` (`?? null`), which had
3793
- * exactly these semantics.
3794
- *
3795
- * @example
3796
- * ```ts
3797
- * tryParseCompositeKey('$GMUSIC_TEST1$Unit$none$none')?.collection; // '$GMUSIC_TEST1'
3798
- * tryParseCompositeKey('GALA$Unit$none'); // undefined
3799
- * ```
3252
+ * The id a market read sends for a token: a string as given (a symbol or a class key in either
3253
+ * form), an object key in its `$` form. Anything the backend's allowlist refuses is refused here.
3800
3254
  */
3801
- function tryParseCompositeKey(value) {
3802
- return typeof value === "string" ? splitClassKey(value, "$") : void 0;
3255
+ function marketTokenOf(token) {
3256
+ if (typeof token !== "string") {
3257
+ if (!(0, _gala_chain_gala_core_sdk.isTokenClassKey)(token)) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey: describeValue(token) });
3258
+ return checkedMarketToken((0, _gala_chain_gala_core_sdk.compositeKeyOf)(token));
3259
+ }
3260
+ return checkedMarketToken(token);
3261
+ }
3262
+ function checkedMarketToken(id) {
3263
+ if (!MARKET_TOKEN_PATTERN.test(id)) throw new GSwapSDKError("INVALID_MARKET_TOKEN", { token: id });
3264
+ return id;
3265
+ }
3266
+ function describeValue(value) {
3267
+ try {
3268
+ return JSON.stringify(value) ?? String(value);
3269
+ } catch {
3270
+ return Object.prototype.toString.call(value);
3271
+ }
3272
+ }
3273
+ function signalOption(options) {
3274
+ return (options === null || options === void 0 ? void 0 : options.signal) === void 0 ? void 0 : { signal: options.signal };
3275
+ }
3276
+ /** A finite number, `null` for `null`, `undefined` for anything else (an unusable value). */
3277
+ function nullableFinite(value) {
3278
+ if (value === null) return null;
3279
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3280
+ }
3281
+ function finite(value) {
3282
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3283
+ }
3284
+ function parseMarketPrice(token, entry) {
3285
+ const record = asEntryRecord(entry);
3286
+ if (record === void 0) return entryRejected("not an object");
3287
+ const price = nullableFinite(record["price"]);
3288
+ if (price === void 0 || price !== null && price < 0) return entryRejected("price is not a non-negative number or null");
3289
+ const change24h = nullableFinite(record["change24h"]);
3290
+ if (change24h === void 0) return entryRejected("change24h is not a number or null");
3291
+ const listed = record["listed"];
3292
+ if (typeof listed !== "boolean") return entryRejected("listed is not a boolean");
3293
+ return entryOk({
3294
+ token,
3295
+ price,
3296
+ change24h,
3297
+ listed
3298
+ });
3299
+ }
3300
+ function parsePricePoint(entry) {
3301
+ const record = asEntryRecord(entry);
3302
+ const time = finite(record === null || record === void 0 ? void 0 : record["time"]);
3303
+ const price = finite(record === null || record === void 0 ? void 0 : record["price"]);
3304
+ if (time === void 0 || !Number.isInteger(time) || time < 0) return entryRejected("time is not unix seconds");
3305
+ if (price === void 0 || price < 0) return entryRejected("price is not a non-negative number");
3306
+ return entryOk({
3307
+ time,
3308
+ price
3309
+ });
3310
+ }
3311
+ const VOLUME_FIELDS = [
3312
+ "tvl",
3313
+ "volume1d",
3314
+ "volume7d",
3315
+ "volume30d",
3316
+ "trades1d",
3317
+ "volume1dDelta",
3318
+ "volume7dDelta",
3319
+ "volume30dDelta"
3320
+ ];
3321
+ function parseVolumeSummary(data) {
3322
+ if (data === void 0) return void 0;
3323
+ const summary = {};
3324
+ for (const field of VOLUME_FIELDS) {
3325
+ const value = finite(data[field]);
3326
+ if (value === void 0) return void 0;
3327
+ summary[field] = value;
3328
+ }
3329
+ const trades = summary.trades1d;
3330
+ if (trades === void 0 || !Number.isInteger(trades) || trades < 0) return void 0;
3331
+ return summary;
3803
3332
  }
3804
3333
 
3805
3334
  //#endregion
@@ -3857,11 +3386,30 @@ function parseTokenClassKey(tokenClassKey) {
3857
3386
  type: tokenClassKey.type,
3858
3387
  additionalKey: tokenClassKey.additionalKey
3859
3388
  };
3860
- const parsed = splitClassKey(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3389
+ const parsed = (0, _gala_chain_gala_core_sdk.splitClassKey)(tokenClassKey, tokenClassKey.includes("|") ? "|" : "$");
3861
3390
  if (parsed === void 0) throw new GSwapSDKError("INVALID_TOKEN_CLASS_KEY", { tokenClassKey });
3862
3391
  return parsed;
3863
3392
  }
3864
3393
 
3394
+ //#endregion
3395
+ //#region src/utils/resolve_pre_send.ts
3396
+ /**
3397
+ * Runs a token-resolution step (a resolver's `resolve` / `orderPair`, which may read the registry
3398
+ * through the app's HTTP stack) on the "nothing was sent" boundary, like core's `signPreSend` does
3399
+ * for the signer. A failure that is not an SDK error is `TOKEN_RESOLUTION_FAILED` (`token` names
3400
+ * what was being resolved, the original is `cause`); an SDK error of any product (every one is a
3401
+ * `GalaSDKError`, core's transport errors included) passes through.
3402
+ *
3403
+ * @throws GSwapSDKError TOKEN_RESOLUTION_FAILED, or the SDK error the step itself threw.
3404
+ */
3405
+ async function resolvePreSend(token, run) {
3406
+ try {
3407
+ return await run();
3408
+ } catch (cause) {
3409
+ throw (0, _gala_chain_gala_core_sdk.isGalaError)(cause) ? cause : new GSwapSDKError("TOKEN_RESOLUTION_FAILED", { token }, { cause });
3410
+ }
3411
+ }
3412
+
3865
3413
  //#endregion
3866
3414
  //#region src/classes/symbols.ts
3867
3415
  const SYMBOL_CACHE_TTL_MS = 6e4;
@@ -3925,11 +3473,11 @@ var Symbols = class {
3925
3473
  /** Resolve a symbol or token class key to its registered symbol metadata. */
3926
3474
  async resolve(ref) {
3927
3475
  let symbols = await this.list();
3928
- const composite = typeof ref === "string" ? isCompositeKey(ref) ? compositeKeyOf(parseTokenClassKey(ref)) : void 0 : compositeKeyOf(ref);
3929
- const resolved = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite);
3476
+ const composite = typeof ref === "string" ? isCompositeKey(ref) ? (0, _gala_chain_gala_core_sdk.compositeKeyOf)(parseTokenClassKey(ref)) : void 0 : (0, _gala_chain_gala_core_sdk.compositeKeyOf)(ref);
3477
+ const resolved = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && (0, _gala_chain_gala_core_sdk.compositeKeyOf)(entry) === composite);
3930
3478
  if (resolved === void 0) {
3931
3479
  symbols = await this.refresh();
3932
- const refreshed = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite);
3480
+ const refreshed = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && (0, _gala_chain_gala_core_sdk.compositeKeyOf)(entry) === composite);
3933
3481
  if (refreshed === void 0) throw GSwapSDKError.unknownTokenError(ref);
3934
3482
  return refreshed;
3935
3483
  }
@@ -3964,7 +3512,7 @@ var Symbols = class {
3964
3512
  } catch (error) {
3965
3513
  if (options.registryFailure !== "ignore") throw error;
3966
3514
  }
3967
- const wanted = compositeKeyOf(classKey);
3515
+ const wanted = (0, _gala_chain_gala_core_sdk.compositeKeyOf)(classKey);
3968
3516
  const registered = registry.find((entry) => entry.collection === classKey.collection && entry.category === classKey.category && entry.type === classKey.type && entry.additionalKey === classKey.additionalKey);
3969
3517
  if (registered !== void 0) return registered.symbol;
3970
3518
  if (isProposableTradingSymbol(displaySymbol)) return displaySymbol;
@@ -4010,7 +3558,7 @@ function isCompositeKey(ref) {
4010
3558
  }
4011
3559
  /** A token reference as the caller wrote it: a string verbatim, a class key as its `$` composite. */
4012
3560
  function rawTokenOf(ref) {
4013
- return typeof ref === "string" ? ref : compositeKeyOf(ref);
3561
+ return typeof ref === "string" ? ref : (0, _gala_chain_gala_core_sdk.compositeKeyOf)(ref);
4014
3562
  }
4015
3563
  /** The trading symbol of a reference, or `SYMBOL_NOT_FOUND` when the resolver has none. */
4016
3564
  async function tradingSymbolOf(resolver, ref) {
@@ -4108,6 +3656,70 @@ var Pools = class {
4108
3656
  return readEntries("pools", response.data, parsePoolListInfo, (options === null || options === void 0 ? void 0 : options.onInvalidEntry) ?? this.options.onInvalidEntry);
4109
3657
  }
4110
3658
  /**
3659
+ * Watches for pools created from now on, by polling {@link Pools.getPools} every `intervalMs`
3660
+ * (the polling alternative to the realtime stream's `GSwap.stream.subscribePoolCreated`, for a
3661
+ * client that cannot hold a WebSocket open). The first answer is the baseline: a pool that
3662
+ * existed then is never reported. Each later pool is judged once, when it first appears, against
3663
+ * `minTvl` and `tokens`. A poll never overlaps the previous one (a tick that finds one still in
3664
+ * flight is skipped), and nothing is reported after the returned function stops the watcher.
3665
+ *
3666
+ * @example
3667
+ * ```ts
3668
+ * const stop = gSwap.pools.watchNewPools((pool) => console.log('new pool', pool.poolRef), {
3669
+ * intervalMs: 60_000,
3670
+ * tokens: ['GALA'],
3671
+ * });
3672
+ * // later
3673
+ * stop();
3674
+ * ```
3675
+ */
3676
+ watchNewPools(onPool, options = {}) {
3677
+ const intervalMs = options.intervalMs ?? 3e4;
3678
+ if (typeof intervalMs !== "number" || !Number.isFinite(intervalMs) || intervalMs < 1) throw new GSwapSDKError("INVALID_POLL_INTERVAL", { value: String(intervalMs) });
3679
+ let known;
3680
+ let stopped = false;
3681
+ let polling = false;
3682
+ const report = (error) => {
3683
+ try {
3684
+ var _options$onError;
3685
+ (_options$onError = options.onError) === null || _options$onError === void 0 || _options$onError.call(options, error);
3686
+ } catch {}
3687
+ };
3688
+ const wanted = (pool) => (options.minTvl === void 0 || (pool.tvlUsd ?? 0) >= options.minTvl) && (options.tokens === void 0 || options.tokens.includes(pool.token0) || options.tokens.includes(pool.token1));
3689
+ const poll = async () => {
3690
+ if (stopped || polling) return;
3691
+ polling = true;
3692
+ try {
3693
+ const pools = await this.getPools();
3694
+ if (known === void 0) {
3695
+ known = new Set(pools.map((pool) => pool.poolRef));
3696
+ return;
3697
+ }
3698
+ for (const pool of pools) {
3699
+ if (stopped) return;
3700
+ if (known.has(pool.poolRef)) continue;
3701
+ known.add(pool.poolRef);
3702
+ if (!wanted(pool)) continue;
3703
+ try {
3704
+ onPool(pool);
3705
+ } catch (error) {
3706
+ report(error);
3707
+ }
3708
+ }
3709
+ } catch (error) {
3710
+ if (!stopped) report(error);
3711
+ } finally {
3712
+ polling = false;
3713
+ }
3714
+ };
3715
+ poll();
3716
+ const timer = setInterval(() => void poll(), intervalMs);
3717
+ return () => {
3718
+ stopped = true;
3719
+ clearInterval(timer);
3720
+ };
3721
+ }
3722
+ /**
4111
3723
  * Fetches one pool from the backend, preserving whether the request order was flipped.
4112
3724
  *
4113
3725
  * @example
@@ -4169,8 +3781,11 @@ var Pools = class {
4169
3781
  try {
4170
3782
  return (await this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", endpoint, params)).data;
4171
3783
  } catch (error) {
4172
- if (error instanceof GSwapSDKError) throw error;
4173
- throw new GSwapSDKError("REQUEST_FAILED", { operation: "pool" }, { cause: error });
3784
+ if (isGSwapError(error)) throw error;
3785
+ throw new GSwapSDKError("REQUEST_FAILED", { operation: "pool" }, {
3786
+ cause: error,
3787
+ write: false
3788
+ });
4174
3789
  }
4175
3790
  }
4176
3791
  };
@@ -4393,49 +4008,6 @@ function frameSlot0(slot0) {
4393
4008
  };
4394
4009
  }
4395
4010
 
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.
4428
- *
4429
- * @throws GSwapSDKError `INVALID_UNIQUE_KEY` otherwise.
4430
- */
4431
- function assertUniqueKey(uniqueKey) {
4432
- if (!isValidUniqueKey(uniqueKey)) throw new GSwapSDKError("INVALID_UNIQUE_KEY", { uniqueKey: String(uniqueKey) });
4433
- }
4434
- /** A fresh per-attempt key: `<prefix><random UUID>`. */
4435
- function createUniqueKey(prefix) {
4436
- return `${prefix}${globalThis.crypto.randomUUID()}`;
4437
- }
4438
-
4439
4011
  //#endregion
4440
4012
  //#region src/utils/dto_builders.ts
4441
4013
  const decimalString = (amount) => new bignumber_js.default(amount).toFixed();
@@ -4459,7 +4031,7 @@ const decimalString = (amount) => new bignumber_js.default(amount).toFixed();
4459
4031
  function buildRequestTradeDto(input) {
4460
4032
  validateFee(input.fee);
4461
4033
  assertCanonicalPair(input.token0, input.token1);
4462
- assertUniqueKey(input.uniqueKey);
4034
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(input.uniqueKey);
4463
4035
  const dto = {
4464
4036
  token0: input.token0,
4465
4037
  token1: input.token1,
@@ -4495,7 +4067,7 @@ function assertPoolPosition(input) {
4495
4067
  validateFee(input.fee);
4496
4068
  assertCanonicalPair(input.token0, input.token1);
4497
4069
  assertTickRange(input.tickLower, input.tickUpper, input.fee);
4498
- assertUniqueKey(input.uniqueKey);
4070
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(input.uniqueKey);
4499
4071
  }
4500
4072
  /**
4501
4073
  * Builds the AddLiquidity DTO: exactly one of `depositQuantityToken0` / `depositQuantityToken1`
@@ -4558,7 +4130,7 @@ function buildCollectPositionFeesDto(input) {
4558
4130
  */
4559
4131
  function buildCreatePoolDto(input) {
4560
4132
  validateFee(input.fee);
4561
- assertUniqueKey(input.uniqueKey);
4133
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(input.uniqueKey);
4562
4134
  assertCanonicalPair(input.token0Symbol, input.token1Symbol);
4563
4135
  for (const symbol of [input.token0Symbol, input.token1Symbol]) if (!isProposableTradingSymbol(symbol)) throw new GSwapSDKError("INVALID_TRADING_SYMBOL", { symbol });
4564
4136
  for (const key of [input.token0Key, input.token1Key]) assertClassKey(key);
@@ -4781,7 +4353,7 @@ var Positions = class {
4781
4353
  this.signer = signer;
4782
4354
  this.walletAddress = walletAddress;
4783
4355
  this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs ?? 3e4, gateway.wire);
4784
- this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);
4356
+ this.uniqueKeyPrefix = (0, _gala_chain_gala_core_sdk.resolveUniqueKeyPrefix)(options.uniqueKeyPrefix);
4785
4357
  this.onInvalidEntry = options.onInvalidEntry;
4786
4358
  }
4787
4359
  http;
@@ -4849,7 +4421,10 @@ var Positions = class {
4849
4421
  if ((signal === null || signal === void 0 ? void 0 : signal.aborted) === true) throw error;
4850
4422
  return {
4851
4423
  kind: "unknown",
4852
- error: isGSwapError(error) ? error : new GSwapSDKError("REQUEST_FAILED", { operation: "position" }, { cause: error })
4424
+ error: isGSwapError(error) ? error : new GSwapSDKError("REQUEST_FAILED", { operation: "position" }, {
4425
+ cause: error,
4426
+ write: false
4427
+ })
4853
4428
  };
4854
4429
  }
4855
4430
  }
@@ -5220,7 +4795,7 @@ var Positions = class {
5220
4795
  }
5221
4796
  async submit(method, dto, confirmation) {
5222
4797
  if (this.signer === void 0) throw GSwapSDKError.noSignerError();
5223
- const signed = await signPreSend(this.signer, method, dto);
4798
+ const signed = await (0, _gala_chain_gala_core_sdk.signPreSend)(this.signer, method, dto);
5224
4799
  const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
5225
4800
  const owner = this.walletAddress;
5226
4801
  const positionConfirmation = this.buildPositionConfirmation(confirmation, owner);
@@ -5316,7 +4891,7 @@ var Positions = class {
5316
4891
  }
5317
4892
  }
5318
4893
  isNotFound(error) {
5319
- return error instanceof GSwapSDKError && error.status === 404;
4894
+ return isGSwapError(error) && error.status === 404;
5320
4895
  }
5321
4896
  canonicalTicks(tickLower, tickUpper, flipped) {
5322
4897
  return flipped ? {
@@ -5341,8 +4916,8 @@ var Positions = class {
5341
4916
  }
5342
4917
  /** The caller's `uniqueKey` (validated), else a fresh one. */
5343
4918
  uniqueKeyFor(supplied) {
5344
- if (supplied === void 0) return createUniqueKey(this.uniqueKeyPrefix);
5345
- assertUniqueKey(supplied);
4919
+ if (supplied === void 0) return (0, _gala_chain_gala_core_sdk.createUniqueKey)(this.uniqueKeyPrefix);
4920
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(supplied);
5346
4921
  return supplied;
5347
4922
  }
5348
4923
  /**
@@ -5354,7 +4929,7 @@ var Positions = class {
5354
4929
  }
5355
4930
  async resolveCreateToken(ref, symbolOverride) {
5356
4931
  try {
5357
- const lookupRef = typeof ref === "object" ? compositeKeyOf(ref) : ref;
4932
+ const lookupRef = typeof ref === "object" ? (0, _gala_chain_gala_core_sdk.compositeKeyOf)(ref) : ref;
5358
4933
  const resolved = await resolvePreSend(rawTokenOf(ref), () => this.symbols.resolve(lookupRef));
5359
4934
  if (symbolOverride !== void 0 && symbolOverride !== "" && symbolOverride !== resolved.symbol) throw new GSwapSDKError("SYMBOL_DISAGREES_WITH_REGISTRY", {
5360
4935
  token: rawTokenOf(ref),
@@ -5373,7 +4948,7 @@ var Positions = class {
5373
4948
  })
5374
4949
  };
5375
4950
  } catch (error) {
5376
- if (!(error instanceof GSwapSDKError) || error.code !== "UNKNOWN_TOKEN") throw error;
4951
+ if (!isGSwapError(error, "UNKNOWN_TOKEN")) throw error;
5377
4952
  let classKey;
5378
4953
  try {
5379
4954
  classKey = parseTokenClassKey(ref);
@@ -5458,7 +5033,10 @@ function parsePosition(value) {
5458
5033
  function readPositionBody(data) {
5459
5034
  const parsed = parsePosition(data);
5460
5035
  if (parsed.ok) return parsed.value;
5461
- throw new GSwapSDKError("INVALID_POSITION_RESPONSE", { reason: parsed.reason }, { body: data });
5036
+ throw new GSwapSDKError("INVALID_POSITION_RESPONSE", { reason: parsed.reason }, {
5037
+ body: data,
5038
+ write: false
5039
+ });
5462
5040
  }
5463
5041
 
5464
5042
  //#endregion
@@ -5526,7 +5104,10 @@ var Quoting = class {
5526
5104
  }
5527
5105
  };
5528
5106
  function mapQuote(value) {
5529
- if (!isQuoteWire(value)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "quote" }, { body: value });
5107
+ if (!isQuoteWire(value)) throw new GSwapSDKError("INVALID_CHAIN_RESPONSE", { resource: "quote" }, {
5108
+ body: value,
5109
+ write: false
5110
+ });
5530
5111
  const wire = value;
5531
5112
  const currentPrice = wire.currentPrice !== void 0 ? new bignumber_js.default(wire.currentPrice) : orientPrice(wire.currentSqrtPrice, wire.tokenInIsToken0);
5532
5113
  const newPrice = wire.newPrice !== void 0 ? new bignumber_js.default(wire.newPrice) : orientPrice(wire.newSqrtPrice, wire.tokenInIsToken0);
@@ -5611,7 +5192,10 @@ function mapQuoteError(error, tokenIn, tokenOut, fee, queried) {
5611
5192
  if (error.status === 400 && /insufficient liquidity/iu.test(message)) return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee, error);
5612
5193
  return error;
5613
5194
  }
5614
- return new GSwapSDKError("REQUEST_FAILED", { operation: "quote" }, { cause: error });
5195
+ return new GSwapSDKError("REQUEST_FAILED", { operation: "quote" }, {
5196
+ cause: error,
5197
+ write: false
5198
+ });
5615
5199
  }
5616
5200
  function validateOptionalFee(fee) {
5617
5201
  if (fee !== void 0 && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) throw new GSwapSDKError("INVALID_FEE", {
@@ -5765,7 +5349,7 @@ var Swaps = class {
5765
5349
  this.symbols = symbols;
5766
5350
  this.signer = signer;
5767
5351
  this.walletAddress = walletAddress;
5768
- this.uniqueKeyPrefix = resolveUniqueKeyPrefix(options.uniqueKeyPrefix);
5352
+ this.uniqueKeyPrefix = (0, _gala_chain_gala_core_sdk.resolveUniqueKeyPrefix)(options.uniqueKeyPrefix);
5769
5353
  }
5770
5354
  uniqueKeyPrefix;
5771
5355
  /**
@@ -5817,8 +5401,8 @@ var Swaps = class {
5817
5401
  */
5818
5402
  async buildSwap(tokenIn, tokenOut, fee, amount, options) {
5819
5403
  validateFee(fee);
5820
- const uniqueKey = (options === null || options === void 0 ? void 0 : options.uniqueKey) ?? createUniqueKey(this.uniqueKeyPrefix);
5821
- assertUniqueKey(uniqueKey);
5404
+ const uniqueKey = (options === null || options === void 0 ? void 0 : options.uniqueKey) ?? (0, _gala_chain_gala_core_sdk.createUniqueKey)(this.uniqueKeyPrefix);
5405
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(uniqueKey);
5822
5406
  const tokenInSymbol = await tradingSymbolOf(this.symbols, tokenIn);
5823
5407
  const tokenOutSymbol = await tradingSymbolOf(this.symbols, tokenOut);
5824
5408
  const ordered = this.orientPool(tokenInSymbol, tokenOutSymbol, options === null || options === void 0 ? void 0 : options.pool);
@@ -5860,7 +5444,7 @@ var Swaps = class {
5860
5444
  async signRequestTrade(dto) {
5861
5445
  assertCanonicalV2Dto("RequestTrade", dto);
5862
5446
  if (this.signer === void 0) throw GSwapSDKError.noSignerError();
5863
- return signPreSend(this.signer, "RequestTrade", dto);
5447
+ return (0, _gala_chain_gala_core_sdk.signPreSend)(this.signer, "RequestTrade", dto);
5864
5448
  }
5865
5449
  /** The pool's two symbols in contract order: the quote's own when pinned, else string order. */
5866
5450
  orientPool(tokenInSymbol, tokenOutSymbol, pool) {
@@ -5890,7 +5474,7 @@ var Swaps = class {
5890
5474
  * ```
5891
5475
  */
5892
5476
  async confirmSwap(uniqueKey, options) {
5893
- assertUniqueKey(uniqueKey);
5477
+ (0, _gala_chain_gala_core_sdk.assertUniqueKey)(uniqueKey);
5894
5478
  return new SubmittedTransaction({
5895
5479
  method: "RequestTrade",
5896
5480
  uniqueKey,
@@ -5913,7 +5497,8 @@ var Swaps = class {
5913
5497
  /**
5914
5498
  * Main entry point for the current GalaChainDex SDK: one client bundling the services that read
5915
5499
  * and write through the swap backend (`quoting`, `swaps`, `pools`, `positions`, `assets`,
5916
- * `symbols`, `fees`, `stream`). See {@link GSwapOptions} for configuration.
5500
+ * `market`, `leaderboard`, `symbols`, `fees`, `stream`). See {@link GSwapOptions} for
5501
+ * configuration.
5917
5502
  */
5918
5503
  var GSwap = class {
5919
5504
  /** The swap backend base URL every request goes to, without a trailing slash. */
@@ -5938,6 +5523,10 @@ var GSwap = class {
5938
5523
  swaps;
5939
5524
  /** User token balances. */
5940
5525
  assets;
5526
+ /** USD prices, price series and the platform volume totals. */
5527
+ market;
5528
+ /** Trading-competition seasons and rankings. */
5529
+ leaderboard;
5941
5530
  /** Network-fee quotes (DryRun) signed with this client's signer. */
5942
5531
  fees;
5943
5532
  /** The realtime stream endpoint {@link GSwap.stream} connects to. */
@@ -5980,6 +5569,8 @@ var GSwap = class {
5980
5569
  this.positions = new Positions(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);
5981
5570
  this.swaps = new Swaps(this.gateway, resolver, this.signer, this.walletAddress, keyOptions);
5982
5571
  this.assets = new Assets(this.dexBackendBaseUrl, httpClient);
5572
+ this.market = new Market(this.dexBackendBaseUrl, httpClient, lenient);
5573
+ this.leaderboard = new Leaderboard(this.dexBackendBaseUrl, httpClient, lenient);
5983
5574
  this.fees = new DexFees(this.gateway, this.signer);
5984
5575
  this.dexBackendWsUrl = (options === null || options === void 0 ? void 0 : options.dexBackendWsUrl) ?? ((options === null || options === void 0 ? void 0 : options.dexBackendBaseUrl) === void 0 ? environment.dexBackendWsUrl : `${this.dexBackendBaseUrl.replace(/^http/u, "ws")}/ws`);
5985
5576
  this.webSocketImpl = options === null || options === void 0 ? void 0 : options.webSocketImpl;
@@ -6096,6 +5687,13 @@ const BY_CODE = {
6096
5687
  GATEWAY_SYNC_REQUEST_TRADE: UNKNOWN,
6097
5688
  MISSING_UNIQUE_KEY: UNKNOWN,
6098
5689
  UNIQUE_KEY_MISMATCH: UNKNOWN,
5690
+ GATEWAY_WRITE_OUTCOME_UNKNOWN: UNKNOWN,
5691
+ GATEWAY_RESPONSE_INVALID: UNKNOWN,
5692
+ BRIDGE_RESPONSE_INVALID: UNKNOWN,
5693
+ BRIDGE_WRITE_OUTCOME_UNKNOWN: UNKNOWN,
5694
+ BRIDGE_OUT_OUTCOME_UNKNOWN: UNKNOWN,
5695
+ BRIDGE_DEPOSIT_OUTCOME_UNKNOWN: UNKNOWN,
5696
+ BRIDGE_STATUS_TIMEOUT: UNKNOWN,
6099
5697
  SHADOW_NOT_QUEUED: NOT_QUEUED_FINAL,
6100
5698
  METHOD_NOT_ALLOWED: NOT_QUEUED,
6101
5699
  SIGNATURE_INVALID: NOT_QUEUED,
@@ -6108,6 +5706,14 @@ const BY_CODE = {
6108
5706
  CHAIN_REJECTED: REJECTED,
6109
5707
  INVALID_CHAIN_RESPONSE: TRANSIENT,
6110
5708
  INVALID_POSITION_RESPONSE: TRANSIENT,
5709
+ GATEWAY_READ_REJECTED: TRANSIENT,
5710
+ GATEWAY_READ_RESPONSE_INVALID: TRANSIENT,
5711
+ BRIDGE_READ_RESPONSE_INVALID: TRANSIENT,
5712
+ BRIDGE_TOKEN_NOT_FOUND: INVALID_INPUT,
5713
+ TOKEN_NOT_WRAPPABLE: INVALID_INPUT,
5714
+ BRIDGE_CHAIN_READ_FAILED: TRANSIENT,
5715
+ TOKEN_CLASS_NOT_FOUND: INVALID_INPUT,
5716
+ PAGINATION_LIMIT_EXCEEDED: INVALID_INPUT,
6111
5717
  CONFIRMATION_TIMEOUT: UNKNOWN,
6112
5718
  CONFIRMATION_ABORTED: UNKNOWN,
6113
5719
  CONFIRMATION_FAILED: UNKNOWN,
@@ -6121,6 +5727,7 @@ const BY_CODE = {
6121
5727
  SIGNING_FAILED: NOT_SENT,
6122
5728
  KEY_PROVIDER_FAILED: NOT_SENT,
6123
5729
  TOKEN_RESOLUTION_FAILED: NOT_SENT,
5730
+ TOKEN_NAME_RESOLUTION_FAILED: NOT_SENT,
6124
5731
  NO_WALLET_ADDRESS: INVALID_INPUT,
6125
5732
  NO_POOL_AVAILABLE: INVALID_INPUT,
6126
5733
  INSUFFICIENT_LIQUIDITY: INVALID_INPUT
@@ -6132,11 +5739,11 @@ const BY_CODE = {
6132
5739
  * it is `not_sent` and Retry is safe.
6133
5740
  */
6134
5741
  function classifyInvalidPrivateKey(view) {
6135
- return stringParamOf(view, "reason") === "no_key_provided" ? NOT_SENT : INVALID_INPUT;
5742
+ return (0, _gala_chain_gala_core_sdk.stringParamOf)(view, "reason") === "no_key_provided" ? NOT_SENT : INVALID_INPUT;
6136
5743
  }
6137
5744
  /** The status of an HTTP failure: the one it carries, else its `status` param. */
6138
5745
  function statusOfView(view) {
6139
- return view.status ?? numberParamOf(view, "status");
5746
+ return view.status ?? (0, _gala_chain_gala_core_sdk.numberParamOf)(view, "status");
6140
5747
  }
6141
5748
  /**
6142
5749
  * An HTTP failure with no gateway or chain code: its meaning depends on the status and on read vs
@@ -6145,7 +5752,7 @@ function statusOfView(view) {
6145
5752
  function classifyHttpError(view) {
6146
5753
  const status = statusOfView(view);
6147
5754
  if (status === void 0) return UNKNOWN;
6148
- if (isWriteView(view)) {
5755
+ if ((0, _gala_chain_gala_core_sdk.isWriteView)(view)) {
6149
5756
  if (status === 429) return NOT_QUEUED;
6150
5757
  if (status === 408 || status >= 500) return UNKNOWN;
6151
5758
  return NOT_QUEUED_FINAL;
@@ -6153,13 +5760,21 @@ function classifyHttpError(view) {
6153
5760
  return status === 408 || status === 429 || status >= 500 ? TRANSIENT : INVALID_INPUT;
6154
5761
  }
6155
5762
  /**
5763
+ * A core `./bridge` GalaConnect HTTP failure: like {@link classifyHttpError}, except that a
5764
+ * WRITE answered 409 is `unknown`: GalaChain's "this uniqueKey was already consumed", after which
5765
+ * an earlier attempt under the key may be applied (a bridge-out that locked the tokens).
5766
+ */
5767
+ function classifyGalaConnectHttpError(view) {
5768
+ return (0, _gala_chain_gala_core_sdk.isWriteView)(view) && statusOfView(view) === 409 ? UNKNOWN : classifyHttpError(view);
5769
+ }
5770
+ /**
6156
5771
  * The version wall (HTTP 426). On a write the gateway refused it before queueing anything, and a
6157
5772
  * repeat of the same app version is refused the same way, so it is `not_queued` with no Retry. On a
6158
5773
  * read nothing changed either, and only an update helps: `invalid_input`, no Retry. Both say "show
6159
5774
  * the update screen", not "try again".
6160
5775
  */
6161
5776
  function classifyUpdateRequired(view) {
6162
- return isWriteView(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;
5777
+ return (0, _gala_chain_gala_core_sdk.isWriteView)(view) ? NOT_QUEUED_FINAL : INVALID_INPUT;
6163
5778
  }
6164
5779
  /**
6165
5780
  * The chain dispatch failed. The gateway echoes the upstream status: 409 is "this uniqueKey was
@@ -6173,7 +5788,17 @@ function classifyChainDispatchFailed(view) {
6173
5788
  return status === 422 ? REJECTED : NOT_QUEUED;
6174
5789
  }
6175
5790
  /**
6176
- * Classifies any thrown value from its code (and, for two codes, its HTTP status), never from
5791
+ * GalaChain answered a core `GatewayWrites` token-contract write with a `Status` other than 1: the
5792
+ * chain's verdict, so the write was not applied (`rejected`), except where the verdict does not
5793
+ * prove that: a 409 is "this uniqueKey was already consumed" (an earlier attempt under it may be
5794
+ * applied), and a 5xx, or no status at all, cannot be judged.
5795
+ */
5796
+ function classifyGatewayWriteRejected(view) {
5797
+ const status = view.status;
5798
+ return status === void 0 || status === 409 || status >= 500 ? UNKNOWN : REJECTED;
5799
+ }
5800
+ /**
5801
+ * Classifies any thrown value from its code (and, for a few codes, its HTTP status), never from
6177
5802
  * message text, so an app does not have to re-derive "may I offer Retry?" and "is the outcome
6178
5803
  * unknown?" for every code. The decision for each code is in this module's table; a new catalog
6179
5804
  * code cannot be added without one.
@@ -6223,7 +5848,7 @@ function classifyChainDispatchFailed(view) {
6223
5848
  * ```
6224
5849
  */
6225
5850
  function classifyFailure(error, options = {}) {
6226
- const result = classifyView(toFailureView(error));
5851
+ const result = classifyView((0, _gala_chain_gala_core_sdk.toFailureView)(error));
6227
5852
  return options.afterQueued === true && result.outcome !== "rejected" ? {
6228
5853
  ...result,
6229
5854
  retryable: false
@@ -6231,7 +5856,7 @@ function classifyFailure(error, options = {}) {
6231
5856
  }
6232
5857
  /**
6233
5858
  * The classification of a failure view: the table decision for its code, the status-dependent
6234
- * decision for the four codes whose meaning needs it, and for a code the catalog does not define
5859
+ * decision for the codes whose meaning needs it, and for a code the catalog does not define
6235
5860
  * (a wallet error, an ethers `ACTION_REJECTED`, a typo, an app's own error): `unknown` unless the
6236
5861
  * view DECLARES its `outcome` (an app's error, `{ code: 'POSITION_STALE', outcome: 'not_sent' }`),
6237
5862
  * then the SDK's own classification of that outcome. A value with no view is `unknown`.
@@ -6243,7 +5868,9 @@ function classifyView(view) {
6243
5868
  return view.retryable === false ? classification(view.outcome, { retryable: false }) : classification(view.outcome);
6244
5869
  }
6245
5870
  const { code } = view;
6246
- if (code === "HTTP_ERROR") return { ...classifyHttpError(view) };
5871
+ if (code === "HTTP_ERROR" || code === "GATEWAY_HTTP_ERROR") return { ...classifyHttpError(view) };
5872
+ if (code === "GALACONNECT_HTTP_ERROR") return { ...classifyGalaConnectHttpError(view) };
5873
+ if (code === "GATEWAY_WRITE_REJECTED" || code === "BRIDGE_REQUEST_REJECTED") return { ...classifyGatewayWriteRejected(view) };
6247
5874
  if (code === "UPDATE_REQUIRED") return { ...classifyUpdateRequired(view) };
6248
5875
  if (code === "CHAIN_DISPATCH_FAILED") return { ...classifyChainDispatchFailed(view) };
6249
5876
  if (code === "INVALID_PRIVATE_KEY") return { ...classifyInvalidPrivateKey(view) };
@@ -6422,7 +6049,7 @@ var PendingSwapStore = class {
6422
6049
  * `invalid_unique_key`.
6423
6050
  */
6424
6051
  remember(swap) {
6425
- if (!isValidUniqueKey(swap.uniqueKey)) {
6052
+ if (!(0, _gala_chain_gala_core_sdk.isValidUniqueKey)(swap.uniqueKey)) {
6426
6053
  this.report([{
6427
6054
  swap,
6428
6055
  reason: "invalid_unique_key"
@@ -6500,7 +6127,7 @@ var PendingSwapStore = class {
6500
6127
  }) ?? [];
6501
6128
  }
6502
6129
  pruneReasonOf(entry, now) {
6503
- if (!isValidUniqueKey(entry.uniqueKey)) return "invalid_unique_key";
6130
+ if (!(0, _gala_chain_gala_core_sdk.isValidUniqueKey)(entry.uniqueKey)) return "invalid_unique_key";
6504
6131
  return now - entry.createdAt < 6048e5 ? void 0 : "expired";
6505
6132
  }
6506
6133
  /** Tells `onPrune` about each dropped entry; the hook is diagnostics and cannot break the store. */
@@ -6561,796 +6188,12 @@ var PendingSwapStore = class {
6561
6188
  };
6562
6189
 
6563
6190
  //#endregion
6564
- //#region src/utils/eip712.ts
6565
- /**
6566
- * Genuine EIP-712 typed-data signing for the four v2 dex-contract operations proven (2026-09-16,
6567
- * live bisection against stage — see defi-backend's `chain-findings-artifact` memory /
6568
- * https://claude.ai/artifact/3N9MevSjoQdU7gqnVB3dfU) to recover the `client|` identity correctly
6569
- * via `eth_signTypedData_v4`, unlike `personal_sign` (which only ever resolves the bare `eth|`
6570
- * form — see `BrowserWalletSigner`'s own doc comment). Mirrors frontend_v2's
6571
- * `src/Services/eip712Types.ts` + `readWriteUtilsV2.ts`'s `EIP712_FIELD_COMPLETERS` exactly —
6572
- * ported here rather than shared as a package because gswap-sdk has no frontend_v2 dependency
6573
- * and should not gain one for four small functions.
6574
- */
6191
+ //#region src/classes/storage_adapters.ts
6575
6192
  /**
6576
- * Derives the EIP-712 `types` for a DTO from its runtime shape.
6577
- *
6578
- * The generated `types` travel with the signed payload and are what BOTH sides hash, so they
6579
- * must enumerate EVERY field the chain-side DTO will carry. GalaChain refuses any signature
6580
- * whose `types` leave a DTO field uncovered (`assertNoUnsignedFields`, the fix for the
6581
- * 2026-08-18 unsigned-field-injection drain); when that happens signature recovery fails
6582
- * outright and the chain reports "Missing signerPublicKey or signerAddress field in dto".
6583
- */
6584
- function generateEIP712Types(typeName, params) {
6585
- const types = {};
6586
- types[typeName] = [];
6587
- function fieldsFor(name) {
6588
- const fields = types[name];
6589
- /* c8 ignore next */
6590
- if (!fields) throw new Error(`Missing EIP-712 type definition for ${name}`);
6591
- return fields;
6592
- }
6593
- function addField(name, fieldValue, parentTypeName, onlyGetType = false) {
6594
- if (Array.isArray(fieldValue)) {
6595
- const type = fieldValue.length > 0 ? addField(name, fieldValue[0], parentTypeName, true) : "string";
6596
- if (!onlyGetType) fieldsFor(parentTypeName).push({
6597
- name,
6598
- type: (type ?? name) + "[]"
6599
- });
6600
- } else if (typeof fieldValue === "object" && fieldValue !== null) {
6601
- if (types[name]) throw new GSwapSDKError("EIP712_NAME_COLLISION", { name });
6602
- types[name] = [];
6603
- Object.entries(fieldValue).forEach(([key, value]) => {
6604
- addField(key, value, name);
6605
- });
6606
- if (!onlyGetType) fieldsFor(parentTypeName).push({
6607
- name,
6608
- type: name
6609
- });
6610
- } else {
6611
- let eipType;
6612
- switch (typeof fieldValue) {
6613
- case "string":
6614
- eipType = "string";
6615
- break;
6616
- case "number":
6617
- eipType = "int256";
6618
- break;
6619
- case "boolean":
6620
- eipType = "bool";
6621
- break;
6622
- case "bigint":
6623
- case "symbol":
6624
- case "undefined":
6625
- case "function":
6626
- case "object": throw new GSwapSDKError("EIP712_UNSUPPORTED_VALUE", { valueType: typeof fieldValue });
6627
- }
6628
- if (onlyGetType) return eipType;
6629
- fieldsFor(parentTypeName).push({
6630
- name,
6631
- type: eipType
6632
- });
6633
- }
6634
- }
6635
- Object.entries(params).forEach(([key, value]) => {
6636
- addField(key, value, typeName);
6637
- });
6638
- return types;
6639
- }
6640
- /**
6641
- * Builds the EIP-712 domain from the wallet's LIVE `eth_chainId` result, exactly like frontend_v2
6642
- * (DEFI-1895): a wallet hashes whatever domain it is handed, and MetaMask refuses a `chainId` that
6643
- * differs from its active network, so a hardcoded `1` breaks every wallet that is not on Mainnet.
6644
- * defi-backend recovers the signer from the `domain` the payload carries (live-proven for chain
6645
- * ids 1, 56 and 11155111), so following the wallet is correct on every network.
6646
- *
6647
- * @param chainId - The raw `eth_chainId` result: a `0x` hex string (the JSON-RPC form) or an integer.
6648
- * @throws GSwapSDKError (`INVALID_CHAIN_ID`) when the wallet answers with anything else.
6649
- */
6650
- function eip712DomainFor(chainId) {
6651
- const parsed = typeof chainId === "string" && /^0x[0-9a-fA-F]+$/u.test(chainId) ? Number(chainId) : typeof chainId === "number" ? chainId : NaN;
6652
- if (!Number.isSafeInteger(parsed) || parsed <= 0) throw new GSwapSDKError("INVALID_CHAIN_ID", { chainId: typeof chainId === "string" || typeof chainId === "number" ? String(chainId) : typeof chainId });
6653
- return {
6654
- name: "ethereum",
6655
- chainId: parsed
6656
- };
6657
- }
6658
- /**
6659
- * The four v2 operations proven to recover the signer correctly via genuine EIP-712: `RequestTrade`
6660
- * never had the problem (one numeric field). `AddLiquidity`/`RemoveLiquidity`/
6661
- * `CollectPositionFees` each need their `types` completed with a handful of fields their real
6662
- * server-side DTO always carries — see the `complete*Fields` functions below. `CreatePool` is a
6663
- * genuinely different, unsolved problem (nested `TokenClassKey` structs, not a flat
6664
- * missing-field gap) and is NOT in this set — callers must keep using `personal-sign` for it.
6665
- */
6666
- const EIP712_CAPABLE_METHODS = /* @__PURE__ */ new Set([
6667
- "RequestTrade",
6668
- "AddLiquidity",
6669
- "RemoveLiquidity",
6670
- "CollectPositionFees"
6671
- ]);
6672
- /**
6673
- * Every `complete*Fields` function below shares the same two live-proven rules:
6674
- * 1. Numeric completeness fields MUST be JS `number`, never numeric strings —
6675
- * `generateEIP712Types` infers a field's Solidity type from `typeof`, and declaring one as
6676
- * EIP-712 `string` instead of `int256` breaks recovery identically to omitting the field
6677
- * entirely (verified live on AddLiquidity: `amount0Min: '0'` fails with the exact same
6678
- * "Missing signerPublicKey" error as `amount0Min` being absent; `amount0Min: 0` succeeds).
6679
- * 2. `positionId` has no such constraint — an empty string works, and does not target an
6680
- * existing position (`positionId: ''` created a fresh position on AddLiquidity, not an add
6681
- * to position id `''`; on RemoveLiquidity/CollectPositionFees the real position is still
6682
- * resolved from `token0`/`token1`/`fee`/`tickLower`/`tickUpper`, not from this field).
6683
- */
6684
- function numericOr0(dto, field) {
6685
- return typeof dto[field] === "number" ? dto[field] : 0;
6686
- }
6687
- /**
6688
- * `AddLiquidity`'s real server-side DTO always carries `amount0Desired`/`amount0Min`/
6689
- * `amount1Desired`/`amount1Min`/`positionId` once reconstructed, regardless of which deposit
6690
- * convention the caller used (`Positions.addLiquidityByTicks` only ever sends
6691
- * `depositQuantityToken0`/`depositQuantityToken1`). Proven empirically by bisection: none of the
6692
- * five alone fixes recovery, all five together does (live 201, tx `407d9b24...`, block
6693
- * `2429022`).
6694
- */
6695
- function completeAddLiquidityFields(dto) {
6696
- return {
6697
- ...dto,
6698
- amount0Desired: numericOr0(dto, "amount0Desired"),
6699
- amount0Min: numericOr0(dto, "amount0Min"),
6700
- amount1Desired: numericOr0(dto, "amount1Desired"),
6701
- amount1Min: numericOr0(dto, "amount1Min"),
6702
- positionId: dto["positionId"] ?? ""
6703
- };
6704
- }
6705
- /**
6706
- * `RemoveLiquidity`'s real server-side DTO always carries `amount`/`amount0Min`/`amount1Min`/
6707
- * `positionId` — `Positions.removeLiquidity` only ever sends a `withdrawalQuantityTokenX` (or
6708
- * neither, for a full close). Proven empirically: every subset of these four fails, all four
6709
- * together succeeds (live, random-signer probe — recovery confirmed by the response moving from
6710
- * "Missing signerPublicKey" to a genuine position-not-found 404).
6711
- */
6712
- function completeRemoveLiquidityFields(dto) {
6713
- return {
6714
- ...dto,
6715
- amount: numericOr0(dto, "amount"),
6716
- amount0Min: numericOr0(dto, "amount0Min"),
6717
- amount1Min: numericOr0(dto, "amount1Min"),
6718
- positionId: dto["positionId"] ?? ""
6719
- };
6720
- }
6721
- /**
6722
- * `CollectPositionFees`'s real server-side DTO always carries `amount0Requested`/
6723
- * `amount1Requested`/`positionId` — `Positions.collectPositionFees` sends only the five identity
6724
- * fields. Proven empirically the same way as `completeRemoveLiquidityFields`.
6725
- */
6726
- function completeCollectPositionFeesFields(dto) {
6727
- return {
6728
- ...dto,
6729
- amount0Requested: numericOr0(dto, "amount0Requested"),
6730
- amount1Requested: numericOr0(dto, "amount1Requested"),
6731
- positionId: dto["positionId"] ?? ""
6732
- };
6733
- }
6734
- const EIP712_FIELD_COMPLETERS = {
6735
- AddLiquidity: completeAddLiquidityFields,
6736
- RemoveLiquidity: completeRemoveLiquidityFields,
6737
- CollectPositionFees: completeCollectPositionFeesFields
6738
- };
6739
- /**
6740
- * Completes a DTO's fields for EIP-712 signing (a no-op for methods with no known gap, e.g.
6741
- * `RequestTrade`) and derives its `types`. Exported separately from the signing call itself so tests
6742
- * can assert on the exact payload without needing a live provider.
6743
- */
6744
- function buildEIP712Payload(methodName, dto) {
6745
- const completer = EIP712_FIELD_COMPLETERS[methodName];
6746
- const completedDto = completer ? completer(dto) : dto;
6747
- return {
6748
- completedDto,
6749
- types: generateEIP712Types(methodName, completedDto)
6750
- };
6751
- }
6752
-
6753
- //#endregion
6754
- //#region src/utils/signing.ts
6755
- /**
6756
- * SDK-owned signing primitives.
6757
- *
6758
- * Everything the SDK needs to produce a GalaChain signature lives here, with no dependency on
6759
- * `@gala-chain/api` (which drags `secp256k1` native bindings, `reflect-metadata`, `class-validator`
6760
- * and its own `bignumber.js` major into every consumer). The only runtime dependencies are the
6761
- * audited, pure-JS `@noble/curves` (secp256k1) and `@noble/hashes` (keccak256), which run
6762
- * unchanged in browsers, MV3 service workers, Node and React Native/Hermes.
6763
- *
6764
- * Every function here is pinned byte-for-byte to the signatures produced by `@gala-chain/api`
6765
- * (`serialize`, `signatures.getSignature`), `@gala-chain/connect`, the Gala Wallet extension and
6766
- * frontend_v2 by the golden-vector suite in `tests/signing-golden.test.ts`.
6767
- */
6768
- const textEncoder$1 = new TextEncoder();
6769
- function toDeterministicNode(node) {
6770
- if (node === null || node === void 0) return node;
6771
- if (node instanceof RegExp) return node.toString();
6772
- const candidate = node;
6773
- return typeof candidate.toJSON === "function" ? Reflect.apply(candidate.toJSON, node, []) : node;
6774
- }
6775
- function deterministicNode(rawNode) {
6776
- const node = toDeterministicNode(rawNode);
6777
- if (node === void 0) return void 0;
6778
- if (typeof node !== "object" || node === null) return JSON.stringify(node);
6779
- if (Array.isArray(node)) return `[${node.map((item) => deterministicNode(item) ?? "null").join(",")}]`;
6780
- const record = node;
6781
- const members = [];
6782
- for (const key of Object.keys(record).sort()) {
6783
- const value = deterministicNode(record[key]);
6784
- if (value === void 0) continue;
6785
- members.push(`${JSON.stringify(key)}:${value}`);
6786
- }
6787
- return `{${members.join(",")}}`;
6788
- }
6789
- /**
6790
- * GalaChain's deterministic JSON: object keys sorted (UTF-16 code-unit order) at every depth, no
6791
- * whitespace, `undefined`/function members dropped, `toJSON()` honored. Byte-identical to
6792
- * `serialize` from `@gala-chain/api` / `json-stringify-deterministic` for every JSON-shaped
6793
- * value, which is all a DTO ever is.
6794
- *
6795
- * @throws TypeError for circular structures and BigInt values (as `JSON.stringify` does) and
6796
- * when the value itself has no JSON representation (`undefined`, a function, a symbol).
6797
- */
6798
- function serialize(value) {
6799
- JSON.stringify(value);
6800
- const result = deterministicNode(value);
6801
- if (result === void 0) throw new TypeError("Cannot serialize a value with no JSON representation.");
6802
- return result;
6803
- }
6804
- /**
6805
- * The exact string GalaChain hashes for a DTO: the (optional, string) `prefix` field PREPENDED to
6806
- * the deterministic serialization of the DTO WITHOUT `signature`, `multisig`, `trace` and `prefix`.
6807
- * Equivalent to `@gala-chain/api` 3.x `getPayloadToSign` for every non-EIP-712 DTO.
6808
- */
6809
- function getPayloadToSign(dto) {
6810
- const { prefix, ...rest } = dto;
6811
- delete rest["signature"];
6812
- delete rest["multisig"];
6813
- delete rest["trace"];
6814
- return (typeof prefix === "string" ? prefix : "") + serialize(rest);
6815
- }
6816
- const ETHEREUM_SIGNED_MESSAGE = String.fromCharCode(25) + "Ethereum Signed Message:\n";
6817
- /**
6818
- * The EIP-191 header for `message`: `"\x19Ethereum Signed Message:\n"` + the message's UTF-8 BYTE
6819
- * length. This is what a wallet's `personal_sign` prepends, and what the chain recomputes when it
6820
- * recovers a personal-signed DTO.
6821
- */
6822
- function calculatePersonalSignPrefix(message) {
6823
- return ETHEREUM_SIGNED_MESSAGE + String(textEncoder$1.encode(message).length);
6824
- }
6825
- /**
6826
- * The EIP-191 header for `serialize(dto)` (any `prefix` already on the DTO is ignored). This is
6827
- * deliberately the same string the signers hand a wallet to sign, so the header's length can never
6828
- * disagree with the signed message. Wallet-neutral: it is the value both a browser wallet's
6829
- * `personal_sign` and Gala Wallet's `gala_signChainDto` (personal-sign scheme) prepend.
6830
- */
6831
- function personalSignPrefixFor(dto) {
6832
- const withoutPrefix = { ...dto };
6833
- delete withoutPrefix["prefix"];
6834
- return calculatePersonalSignPrefix(serialize(withoutPrefix));
6835
- }
6836
- /**
6837
- * The `@gala-chain/connect`-style prefix frontend_v2 puts in the body of an EIP-712 write: the
6838
- * EIP-191 header whose number counts the prefix string ITSELF plus the body (the UTF-8 length of
6839
- * `getPayloadToSign({ ...dto, prefix })`), found by fixpoint because adding the prefix changes the
6840
- * length (a body of 99 bytes settles on 101).
6841
- *
6842
- * It is NOT a personal-sign prefix (a personal-sign write with this value recovers a phantom
6843
- * signer; use `personalSignPrefixFor`). Under EIP-712 the field is an untyped extra that the
6844
- * typed-data hash ignores and defi-backend recomputes, so it only exists to keep the submitted
6845
- * body byte-identical to what frontend_v2 has always sent.
6846
- */
6847
- function fixpointPrefixFor(dto) {
6848
- const withoutPrefix = { ...dto };
6849
- delete withoutPrefix["prefix"];
6850
- let payloadLength = textEncoder$1.encode(getPayloadToSign(withoutPrefix)).length;
6851
- let prefix = ETHEREUM_SIGNED_MESSAGE + String(payloadLength);
6852
- let previousLength = -1;
6853
- while (payloadLength !== previousLength) {
6854
- previousLength = payloadLength;
6855
- prefix = ETHEREUM_SIGNED_MESSAGE + String(payloadLength);
6856
- payloadLength = textEncoder$1.encode(getPayloadToSign({
6857
- ...withoutPrefix,
6858
- prefix
6859
- })).length;
6860
- }
6861
- return prefix;
6862
- }
6863
- function invalidPrivateKey(reason) {
6864
- return new GSwapSDKError("INVALID_PRIVATE_KEY", { reason });
6865
- }
6866
- const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6867
- function decodeBase64(input) {
6868
- if (!/^[A-Za-z0-9+/]+={0,2}$/u.test(input) || input.length % 4 !== 0) return void 0;
6869
- const unpadded = input.replace(/=+$/u, "");
6870
- const bytes = [];
6871
- let buffer = 0;
6872
- let bits = 0;
6873
- for (const char of unpadded) {
6874
- buffer = buffer << 6 | BASE64_ALPHABET.indexOf(char);
6875
- bits += 6;
6876
- if (bits >= 8) {
6877
- bits -= 8;
6878
- bytes.push(buffer >> bits & 255);
6879
- }
6880
- }
6881
- return Uint8Array.from(bytes);
6882
- }
6883
- function decodeHex(input) {
6884
- const bytes = new Uint8Array(input.length / 2);
6885
- for (let index = 0; index < bytes.length; index += 1) bytes[index] = parseInt(input.slice(index * 2, index * 2 + 2), 16);
6886
- return bytes;
6887
- }
6888
- /**
6889
- * Normalizes a secp256k1 private key to a fresh 32-byte array (the caller may zero it). Also
6890
- * accepts 32 raw bytes, which are validated and copied. For strings it accepts what `@gala-chain/api`'s
6891
- * `normalizePrivateKey` accepted for a usable key: 64 hex characters (optionally `0x`-prefixed;
6892
- * a 63-character hex key is left-padded with a zero) or a 44-character base64 string.
6893
- *
6894
- * @throws GSwapSDKError (`INVALID_PRIVATE_KEY`; `params.reason` is one of
6895
- * `INVALID_PRIVATE_KEY_REASONS`: `wrong_length` for raw bytes that are not 32 long,
6896
- * `bad_encoding` for any other string shape, `not_on_curve` for an out-of-range scalar).
6897
- */
6898
- function normalizePrivateKey(input) {
6899
- if (typeof input !== "string") {
6900
- if (!(input instanceof Uint8Array) || input.length !== 32) throw invalidPrivateKey("wrong_length");
6901
- if (!_noble_curves_secp256k1.secp256k1.utils.isValidSecretKey(input)) throw invalidPrivateKey("not_on_curve");
6902
- return Uint8Array.from(input);
6903
- }
6904
- const withoutPrefix = input.startsWith("0x") ? input.slice(2) : input;
6905
- let key;
6906
- if (/^[0-9a-fA-F]{63,64}$/u.test(withoutPrefix)) key = decodeHex(withoutPrefix.length === 63 ? `0${withoutPrefix}` : withoutPrefix);
6907
- else if (withoutPrefix.length === 44) key = decodeBase64(withoutPrefix);
6908
- if ((key === null || key === void 0 ? void 0 : key.length) !== 32) throw invalidPrivateKey("bad_encoding");
6909
- if (!_noble_curves_secp256k1.secp256k1.utils.isValidSecretKey(key)) throw invalidPrivateKey("not_on_curve");
6910
- return key;
6911
- }
6912
- /**
6913
- * Signs a 32-byte keccak256 hash and returns GalaChain's recoverable signature: 64 hex `r` +
6914
- * 64 hex `s` + `1b`/`1c` (`v`), lowercase, no `0x`. Deterministic (RFC 6979) and low-S, exactly
6915
- * what `@gala-chain/api` and the Gala Wallet produce. A DER signature carries no recovery byte
6916
- * and cannot be used: the chain RECOVERS the signer from the signature.
6917
- */
6918
- function signHash(privateKey, hash) {
6919
- if (hash.length !== 32) throw new GSwapSDKError("INVALID_SIGNING_HASH_LENGTH", { length: hash.length });
6920
- const signature = _noble_curves_secp256k1.secp256k1.sign(hash, privateKey, {
6921
- prehash: false,
6922
- lowS: true
6923
- });
6924
- return (0, _noble_hashes_utils.bytesToHex)(signature.toBytes("compact")) + (signature.recovery === 1 ? "1c" : "1b");
6925
- }
6926
- /**
6927
- * The lowercase `0x` Ethereum address (last 20 bytes of keccak256 of the uncompressed public key)
6928
- * of a normalized private key. The Gala `eth|` identity of a key is this address.
6929
- */
6930
- function ethAddressOfPrivateKey(privateKey) {
6931
- const publicKey = _noble_curves_secp256k1.secp256k1.getPublicKey(privateKey, false);
6932
- return `0x${(0, _noble_hashes_utils.bytesToHex)((0, _noble_hashes_sha3.keccak_256)(publicKey.slice(1)).slice(-20))}`;
6933
- }
6934
- /** keccak256 of a string's UTF-8 bytes. */
6935
- function keccak256Utf8(data) {
6936
- return (0, _noble_hashes_sha3.keccak_256)(textEncoder$1.encode(data));
6937
- }
6938
- /**
6939
- * GalaChain NATIVE signature over an already-serialized DTO: keccak256 of the exact bytes, with no
6940
- * prefix and no signature envelope. The caller owns serialization, so the bytes shown to a user
6941
- * and the bytes signed can never diverge.
6942
- */
6943
- function signSerializedNative(privateKey, serializedDto) {
6944
- return signHash(privateKey, keccak256Utf8(serializedDto));
6945
- }
6946
- /**
6947
- * GalaChain NATIVE signature for a DTO: keccak256 of `getPayloadToSign(dto)`, signed with
6948
- * secp256k1. Byte-identical to `signatures.getSignature` from `@gala-chain/api`.
6949
- */
6950
- function signNative(privateKey, dto) {
6951
- return signSerializedNative(privateKey, getPayloadToSign(dto));
6952
- }
6953
- /**
6954
- * Personal-sign hash and signature: keccak256(`prefix` + `message`), both hashed VERBATIM with no
6955
- * further EIP-191 wrapping. Passing `prefix = calculatePersonalSignPrefix(message)` reproduces a
6956
- * wallet's `personal_sign` of `message`. Gala Wallet's `gala_signChainDto` (personal-sign
6957
- * scheme) hashes `prefix` + the exact string it is handed, which can differ from the bare message
6958
- * (see the `signatureOverPrefixlessBody` vectors); that quirk is why the two inputs stay separate.
6959
- */
6960
- function signPersonalMessage(privateKey, prefix, message) {
6961
- return signHash(privateKey, keccak256Utf8(prefix + message));
6962
- }
6963
-
6964
- //#endregion
6965
- //#region src/classes/signers.ts
6966
- function getWalletProvider() {
6967
- var _globalObject$window;
6968
- const wallet = (_globalObject$window = globalThis.window) === null || _globalObject$window === void 0 ? void 0 : _globalObject$window.gala;
6969
- if (!wallet) throw new GSwapSDKError("GALA_WALLET_NOT_AVAILABLE", {});
6970
- return wallet;
6971
- }
6972
- function getNativeSignature(value) {
6973
- if (typeof value !== "string") throw new GSwapSDKError("INVALID_SIGNATURE", { scheme: "native" });
6974
- if (!/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) throw new GSwapSDKError("INVALID_SIGNATURE", { scheme: "native" });
6975
- return value;
6976
- }
6977
- function getPersonalSignature(value) {
6978
- if (typeof value !== "string" || !/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) throw new GSwapSDKError("INVALID_SIGNATURE", { scheme: "personal-sign" });
6979
- return value;
6980
- }
6981
- /**
6982
- * The `0x`-prefixed Ethereum address a Gala account is signed by, or `undefined` when the account
6983
- * names no key (a `client|` alias or a bare GalaChain id is not derivable from a key). Accepts
6984
- * `0x` plus 40 hex digits and `eth|` plus 40 hex digits, with or without `0x`; the caller's casing
6985
- * is kept. For {@link LazyPrivateKeySignerOptions.expectedAddress}, which should only be set for
6986
- * an account whose key can be checked.
6987
- *
6988
- * @example
6989
- * ```ts
6990
- * createLazyPrivateKeySigner(getKey, { expectedAddress: ethereumAddressOfAccount(account) });
6991
- * ```
6992
- */
6993
- function ethereumAddressOfAccount(account) {
6994
- const match = /^(?:eth\|(?:0x)?|0x)([0-9a-fA-F]{40})$/u.exec(account);
6995
- return (match === null || match === void 0 ? void 0 : match[1]) === void 0 ? void 0 : `0x${match[1]}`;
6996
- }
6997
- function normalizeEthereumAccount(address, allowGalaPrefix) {
6998
- const normalized = allowGalaPrefix ? ethereumAddressOfAccount(address) ?? address : address;
6999
- if (!/^0x[0-9a-fA-F]{40}$/u.test(normalized)) throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
7000
- field: "walletAddress",
7001
- value: address
7002
- });
7003
- return normalized;
7004
- }
7005
- /**
7006
- * The account handed to Gala Wallet as the signer address. An Ethereum account is held to the
7007
- * same strict check as ever (`0x` plus 40 hex digits; `eth|` plus 40 hex digits, with or without
7008
- * `0x`, is normalized to it). A GalaChain id the wallet can also be asked to sign for is passed
7009
- * through verbatim: `client|` plus 24 hex digits, or the bare 24 hex digits that frontend_v2 keeps
7010
- * in `state.user.wallet` after a direct `client|` login. Nothing else is accepted.
7011
- */
7012
- function normalizeGalaWalletAccount(address) {
7013
- const eth = /^eth\|(?:0x)?([0-9a-fA-F]{40})$/u.exec(address);
7014
- if ((eth === null || eth === void 0 ? void 0 : eth[1]) !== void 0) return `0x${eth[1]}`;
7015
- if (/^0x[0-9a-fA-F]{40}$/u.test(address) || /^(?:client\|)?[0-9a-fA-F]{24}$/u.test(address)) return address;
7016
- throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
7017
- field: "walletAddress",
7018
- value: address
7019
- });
7020
- }
7021
- /** An identity Gala Wallet can act as: an account form above, any `eth|`/`client|` alias, verbatim. */
7022
- function assertWalletIdentity(identity) {
7023
- if (!/^(?:eth\|(?:0x)?[0-9a-fA-F]{40}|0x[0-9a-fA-F]{40}|(?:client\|)?[0-9a-fA-F]{24})$/u.test(identity)) throw new GSwapSDKError("INVALID_WALLET_ADDRESS", {
7024
- field: "selectAddress",
7025
- value: identity
7026
- });
7027
- }
7028
- /** Provider-wide queue: `setAddress` + the signature request must not interleave across signers. */
7029
- const walletIdentityQueue = /* @__PURE__ */ new WeakMap();
7030
- /**
7031
- * Runs `signWith` with `identity` selected on a Gala Wallet that supports `setAddress`. Gala
7032
- * Wallet holds ONE current account, so two signatures for different identities in flight at once
7033
- * would sign as whichever selection came last; the pair (select, sign) is therefore serialized
7034
- * per provider. A failed selection fails the signature (nothing is requested).
7035
- */
7036
- function withSelectedIdentity(wallet, identity, signWith) {
7037
- const { setAddress } = wallet;
7038
- if (identity === void 0 || typeof setAddress !== "function") return signWith();
7039
- const run = (walletIdentityQueue.get(wallet) ?? Promise.resolve()).catch(() => void 0).then(async () => {
7040
- await setAddress.call(wallet, identity);
7041
- return signWith();
7042
- });
7043
- walletIdentityQueue.set(wallet, run);
7044
- return run;
7045
- }
7046
- function personalSign(provider, dto, walletAddress, methodName) {
7047
- const prefix = personalSignPrefixFor(dto);
7048
- const payload = {
7049
- ...dto,
7050
- prefix
7051
- };
7052
- const params = methodName !== void 0 ? [
7053
- serialize(payload),
7054
- walletAddress,
7055
- methodName
7056
- ] : [serialize(dto), walletAddress];
7057
- return provider.request({
7058
- method: methodName !== void 0 ? "gala_signChainDto" : "personal_sign",
7059
- params
7060
- }).then((value) => ({
7061
- ...payload,
7062
- signature: getPersonalSignature(value)
7063
- }));
7064
- }
7065
- /**
7066
- * Signs a DTO via genuine EIP-712 (`eth_signTypedData_v4`) — correctly resolves the `client|`
7067
- * identity, unlike `personal_sign`, for the operations in `EIP712_CAPABLE_METHODS`.
7068
- *
7069
- * Constructs the raw JSON-RPC payload by hand (`{domain, types: {...types, EIP712Domain},
7070
- * primaryType, message}`) rather than depending on ethers.js, matching exactly what
7071
- * `ethers.TypedDataEncoder.getPayload`/`Wallet.signTypedData` produce internally — verified
7072
- * byte-for-byte equivalent (same recovered address from the same signature against both
7073
- * constructions) before this shipped, since gswap-sdk deliberately has no ethers dependency.
7074
- */
7075
- async function signEIP712(provider, methodName, dto, walletAddress) {
7076
- const { completedDto, types } = buildEIP712Payload(methodName, dto);
7077
- const domain = eip712DomainFor(await provider.request({
7078
- method: "eth_chainId",
7079
- params: []
7080
- }));
7081
- const prefix = fixpointPrefixFor(completedDto);
7082
- const message = {
7083
- ...completedDto,
7084
- prefix
7085
- };
7086
- const eip712Domain = [{
7087
- name: "name",
7088
- type: "string"
7089
- }, {
7090
- name: "chainId",
7091
- type: "uint256"
7092
- }];
7093
- const payload = {
7094
- domain,
7095
- types: {
7096
- ...types,
7097
- EIP712Domain: eip712Domain
7098
- },
7099
- primaryType: methodName,
7100
- message
7101
- };
7102
- const value = await provider.request({
7103
- method: "eth_signTypedData_v4",
7104
- params: [walletAddress, JSON.stringify(payload)]
7105
- });
7106
- return {
7107
- ...message,
7108
- signature: getPersonalSignature(value),
7109
- types,
7110
- domain
7111
- };
7112
- }
7113
- /**
7114
- * A GalaChain native signer backed by a secp256k1 private key.
7115
- *
7116
- * Native signing produces the bare GalaChain signature format, without a personal-sign prefix
7117
- * or EIP-712 metadata. The private-key identity is recovered by the chain.
7118
- */
7119
- var PrivateKeySigner = class {
7120
- privateKey;
7121
- /**
7122
- * Creates a native signer from a hex or base64 secp256k1 private key.
7123
- *
7124
- * @example
7125
- * ```typescript
7126
- * const signer = new PrivateKeySigner('1'.padStart(64, '0'));
7127
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
7128
- * ```
7129
- */
7130
- constructor(privateKey) {
7131
- this.privateKey = normalizePrivateKey(privateKey);
7132
- }
7133
- /**
7134
- * Signs the DTO with GalaChain native signing.
7135
- *
7136
- * @example
7137
- * ```typescript
7138
- * const signed = await signer.signObject('RequestTrade', {
7139
- * token0: 'GALA',
7140
- * token1: 'GUSDC',
7141
- * fee: 3000,
7142
- * });
7143
- * ```
7144
- */
7145
- signObject(_methodName, dto) {
7146
- const signature = signNative(this.privateKey, dto);
7147
- return Promise.resolve({
7148
- ...dto,
7149
- signature
7150
- });
7151
- }
7152
- };
7153
- /**
7154
- * Calls the app's key provider. Whatever it throws or rejects with is the app's own failure to
7155
- * produce a key before anything was signed or sent, so it becomes `KEY_PROVIDER_FAILED` (the
7156
- * original is `cause`); an SDK error is already catalogued and passes through.
7157
- */
7158
- async function keyFrom(getPrivateKey) {
7159
- try {
7160
- return await getPrivateKey();
7161
- } catch (cause) {
7162
- throw isGSwapError(cause) ? cause : new GSwapSDKError("KEY_PROVIDER_FAILED", {}, { cause });
7163
- }
7164
- }
7165
- /**
7166
- * Creates the native-signing equivalent of {@link PrivateKeySigner} for apps that must not hold a
7167
- * key in a long-lived object (an extension that reads its session key at sign time).
7168
- *
7169
- * `getPrivateKey` is called once per `signObject` call, never cached, never shared between calls
7170
- * (concurrent signatures each fetch their own key), and the normalized key bytes are zeroed
7171
- * before `signObject` settles, also on failure. A rejection or exception from `getPrivateKey` (the
7172
- * app's "wallet is locked", a storage read that failed) is a `KEY_PROVIDER_FAILED` error with the
7173
- * original error as `cause`: nothing has been sent, so `classifyFailure` says `not_sent` and Retry
7174
- * is safe, and the app needs no error class of its own to tell this apart. A provider that returns
7175
- * no usable string (`''`, `undefined`) is `INVALID_PRIVATE_KEY` with `reason: 'no_key_provided'`,
7176
- * classified the same way; any other key that is not a valid secp256k1 key string is an
7177
- * `INVALID_PRIVATE_KEY` error. An SDK error the provider throws itself is passed through.
7178
- * Signatures are byte-identical to `new PrivateKeySigner(key).signObject(...)`.
7179
- *
7180
- * A JavaScript string cannot be wiped; the provider owns the lifetime of the string it returns.
7181
- *
7182
- * @example
7183
- * ```typescript
7184
- * const signer = createLazyPrivateKeySigner(
7185
- * () => SecurityHelper.getSessionSecret(SecurityHelper.SESSION_PRIVATE_KEY_KEY),
7186
- * { expectedAddress: account.address },
7187
- * );
7188
- * const gswap = new GSwap({ signer });
7189
- * ```
7190
- */
7191
- function createLazyPrivateKeySigner(getPrivateKey, options = {}) {
7192
- const expected = options.expectedAddress;
7193
- const expectedLower = expected === void 0 ? void 0 : normalizeEthereumAccount(expected, true).toLowerCase();
7194
- return { async signObject(_methodName, dto) {
7195
- const provided = await keyFrom(getPrivateKey);
7196
- if (typeof provided !== "string" || provided === "") throw new GSwapSDKError("INVALID_PRIVATE_KEY", { reason: "no_key_provided" });
7197
- const key = normalizePrivateKey(provided);
7198
- try {
7199
- if (expectedLower !== void 0 && ethAddressOfPrivateKey(key) !== expectedLower) throw new GSwapSDKError("SIGNER_ADDRESS_MISMATCH", {});
7200
- return {
7201
- ...dto,
7202
- signature: signNative(key, dto)
7203
- };
7204
- } finally {
7205
- key.fill(0);
7206
- }
7207
- } };
7208
- }
7209
- /**
7210
- * A Gala Wallet signer using native GalaChain signing, with an opt-in personal-sign mode.
7211
- *
7212
- * The selected Ethereum account is passed to Gala Wallet. There is NO automatic fallback: a
7213
- * wallet that rejects `native` surfaces its error to the caller, because the only alternative,
7214
- * `personal-sign`, silently recovers a phantom signer on every released Gala Wallet.
7215
- *
7216
- * `scheme: 'personal-sign'` calls
7217
- * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])` and REQUIRES
7218
- * a wallet build that contains wallet_extension commit 34ca4e4 (strips the embedded `prefix`
7219
- * field and hashes `prefix` + the prefix-less canonical body, the chain's scheme). Wallets
7220
- * released before that fix hash the string with the `prefix` field still inside it and the
7221
- * signature recovers to an address nobody holds, so only opt in once the fixed wallet is
7222
- * released. See SIGNING-PARITY.md.
7223
- */
7224
- var GalaWalletSigner = class {
7225
- /** The wallet address supplied to Gala Wallet for each signing request. */
7226
- walletAddress;
7227
- /** The signing scheme used for every request; it never changes after construction. */
7228
- scheme;
7229
- /**
7230
- * Creates a Gala Wallet signer.
7231
- *
7232
- * @example
7233
- * ```typescript
7234
- * const signer = new GalaWalletSigner('0x0123456789012345678901234567890123456789');
7235
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
7236
- * ```
7237
- *
7238
- * @param walletAddress - The account passed to Gala Wallet as the signer address. An Ethereum
7239
- * account is `0x` plus 40 hex digits (Gala Wallet's `eth|...` form is normalized to it and held
7240
- * to the same check); a GalaChain id is `client|` plus 24 hex digits, or the bare 24 hex digits
7241
- * frontend_v2 keeps for a direct `client|` login, and is passed through unchanged.
7242
- * @param options - Select native signing (default) or personal-sign explicitly.
7243
- * `'personal-sign'` requires a Gala Wallet build with wallet_extension commit 34ca4e4.
7244
- * `selectAddress` is the identity (`client|...` / `eth|...`) Gala Wallet is switched to with
7245
- * `window.gala.setAddress` before every signature, when the wallet offers it.
7246
- */
7247
- constructor(walletAddress, options = {}) {
7248
- this.walletAddress = normalizeGalaWalletAccount(walletAddress);
7249
- this.scheme = options.scheme ?? "native";
7250
- if (options.selectAddress !== void 0) assertWalletIdentity(options.selectAddress);
7251
- this.selectAddress = options.selectAddress;
7252
- }
7253
- /** The identity Gala Wallet is switched to before each signature, if one was given. */
7254
- selectAddress;
7255
- /**
7256
- * Signs a DTO through `gala_signChainDto`.
7257
- *
7258
- * @example
7259
- * ```typescript
7260
- * const signed = await signer.signObject('AddLiquidity', {
7261
- * token0: 'GALA',
7262
- * token1: 'GUSDC',
7263
- * tickLower: -60,
7264
- * tickUpper: 60,
7265
- * });
7266
- * ```
7267
- */
7268
- async signObject(methodName, dto) {
7269
- const wallet = getWalletProvider();
7270
- return withSelectedIdentity(wallet, this.selectAddress, async () => {
7271
- if (this.scheme === "personal-sign") return personalSign(wallet, dto, this.walletAddress, methodName);
7272
- const signature = await wallet.request({
7273
- method: "gala_signChainDto",
7274
- params: [
7275
- serialize(dto),
7276
- this.walletAddress,
7277
- methodName,
7278
- "native"
7279
- ]
7280
- });
7281
- return {
7282
- ...dto,
7283
- signature: getNativeSignature(signature)
7284
- };
7285
- });
7286
- }
7287
- };
7288
- /**
7289
- * A personal-sign signer for MetaMask and other EIP-1193 browser wallets.
7290
- *
7291
- * The chain recovers this signature using the EIP-191 wrap applied by the wallet to
7292
- * `personal_sign`. This is the browser-wallet path used by the v2 frontend and resolves the
7293
- * bare `eth|` identity.
7294
- */
7295
- var BrowserWalletSigner = class {
7296
- provider;
7297
- /**
7298
- * Creates a browser-wallet signer.
7299
- *
7300
- * Defaults to `personal_sign` — unchanged from every existing integration, since it only ever
7301
- * resolves the bare `eth|` identity and changing that silently would be a real behavior
7302
- * break for anyone already depending on it. Pass `{ scheme: 'eip712' }` to correctly resolve
7303
- * a registered `client|` alias instead, for `RequestTrade`/`AddLiquidity`/`RemoveLiquidity`/
7304
- * `CollectPositionFees` (`EIP712_CAPABLE_METHODS`) — `CreatePool` and any other method still
7305
- * falls back to `personal_sign` even in `'eip712'` mode, since its EIP-712 signing is a
7306
- * separate, unsolved chain-side problem.
7307
- *
7308
- * @example
7309
- * ```typescript
7310
- * const signer = new BrowserWalletSigner(window.ethereum, '0x0123456789012345678901234567890123456789');
7311
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
7312
- * ```
7313
- * @example
7314
- * ```typescript
7315
- * // Correctly resolves a registered client| alias instead of the bare eth| address.
7316
- * const signer = new BrowserWalletSigner(window.ethereum, walletAddress, { scheme: 'eip712' });
7317
- * ```
7318
- */
7319
- constructor(provider, walletAddress, options = {}) {
7320
- this.provider = provider;
7321
- this.walletAddress = normalizeEthereumAccount(walletAddress, false);
7322
- this.scheme = options.scheme ?? "personal-sign";
7323
- }
7324
- /** The selected `0x` Ethereum account every signature is requested for. */
7325
- walletAddress;
7326
- scheme;
7327
- /**
7328
- * Signs the DTO with `eth_signTypedData_v4` (when constructed with `{ scheme: 'eip712' }` and
7329
- * `methodName` is in `EIP712_CAPABLE_METHODS`) or the EIP-1193 `personal_sign` method
7330
- * (otherwise — the default).
7331
- *
7332
- * @example
7333
- * ```typescript
7334
- * const signed = await signer.signObject('RequestTrade', {
7335
- * token0: 'GALA',
7336
- * token1: 'GUSDC',
7337
- * fee: 3000,
7338
- * });
7339
- * ```
7340
- */
7341
- signObject(methodName, dto) {
7342
- if (this.scheme === "eip712" && EIP712_CAPABLE_METHODS.has(methodName)) return signEIP712(this.provider, methodName, dto, this.walletAddress);
7343
- return personalSign(this.provider, dto, this.walletAddress);
7344
- }
7345
- };
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".
6193
+ * A {@link StorageAdapter} over a `chrome.storage` area, the shape the wallet stores pending swaps
6194
+ * in: the value lands under the key as the structured value it is (the browser clones it; nothing
6195
+ * is serialized here). A missing key resolves `undefined`; a rejection of the area reaches the
6196
+ * store, which treats it as "storage unavailable".
7354
6197
  *
7355
6198
  * Pass a FUNCTION that returns the area to look it up at each call instead of when the adapter is
7356
6199
  * built: a module that is imported where `chrome` does not exist yet (a test, a closing extension
@@ -7412,658 +6255,6 @@ function webStorageAdapter(area) {
7412
6255
  };
7413
6256
  }
7414
6257
 
7415
- //#endregion
7416
- //#region src/utils/chain_dto_signing.ts
7417
- /**
7418
- * String-key signing entry points for apps that hold a private key only briefly (the Gala Wallet
7419
- * extension reads its session key at sign time and must not keep it in a long-lived object).
7420
- *
7421
- * These are thin, byte-exact ports of the functions the wallet shipped in
7422
- * `wallet_extension/src/helpers/wallet/signing.ts` (including the fail-closed personal-sign
7423
- * payload resolver from its commit 34ca4e4), re-expressed over the SDK's own primitives. Every
7424
- * function takes the key as a string (`0x`-optional hex, or base64) or as bytes, normalizes it per
7425
- * call, and zeroes the normalized copy before returning, so nothing in this module retains a key.
7426
- * A JavaScript string cannot be wiped; the caller owns the lifetime of the string it passes in.
7427
- */
7428
- /**
7429
- * Runs `action` with a private normalized copy of the key, zeroed afterwards (also when `action`
7430
- * throws). Bytes given by the caller are copied, never modified: the caller owns them.
7431
- */
7432
- function withPrivateKey(privateKey, action) {
7433
- const key = normalizePrivateKey(privateKey);
7434
- try {
7435
- return action(key);
7436
- } finally {
7437
- key.fill(0);
7438
- }
7439
- }
7440
- /**
7441
- * GalaChain NATIVE signature over an already-serialized DTO: keccak256 of the exact bytes with no
7442
- * prefix and no envelope (wallet `signChainDtoNative`). The caller owns serialization, so the
7443
- * bytes a user reviewed and the bytes signed cannot diverge.
7444
- *
7445
- * @returns 130 lowercase hex characters, `r || s || v` with `v` = `1b`/`1c`, no `0x`.
7446
- */
7447
- function signChainDtoNative(privateKey, serializedDto) {
7448
- return withPrivateKey(privateKey, (key) => signSerializedNative(key, serializedDto));
7449
- }
7450
- /**
7451
- * The personal-sign hash primitive (wallet `signChainDtoHash`): keccak256(`prefix` + `message`),
7452
- * both verbatim, with no further EIP-191 wrap. `message` must be the DTO's serialization WITHOUT
7453
- * its `prefix` field; callers holding a dApp-supplied string go through `signChainDtoPersonalSign`,
7454
- * which derives both inputs from it.
7455
- */
7456
- function signChainDtoHash(privateKey, prefix, message) {
7457
- return withPrivateKey(privateKey, (key) => signPersonalMessage(key, prefix, message));
7458
- }
7459
- const PERSONAL_SIGN_HEADER = String.fromCharCode(25) + "Ethereum Signed Message:\n";
7460
- const PERSONAL_SIGN_LENGTH_PATTERN = /^(?:0|[1-9][0-9]*)$/u;
7461
- function isPersonalSignHeader(prefix) {
7462
- return prefix.startsWith(PERSONAL_SIGN_HEADER) && PERSONAL_SIGN_LENGTH_PATTERN.test(prefix.slice(26));
7463
- }
7464
- /**
7465
- * Top-level fields that would make the chain (`getPayloadToSign`) or defi-backend's personal-sign
7466
- * verifier hash something other than `prefix + serialize(dto minus prefix)`. An unsigned DTO from
7467
- * a dApp never legitimately carries any of them, so they fail closed. Order is part of the error
7468
- * message the wallet shows its user.
7469
- */
7470
- const PERSONAL_SIGN_FORBIDDEN_FIELDS = [
7471
- "signature",
7472
- "multisig",
7473
- "trace",
7474
- "types",
7475
- "domain",
7476
- "stringsInstructions"
7477
- ];
7478
- /**
7479
- * Derives what to hash for a `gala_signChainDto` personal-sign request from the exact string the
7480
- * dApp sent (and the approval card displayed): wallet `resolvePersonalSignChainDtoPayload`.
7481
- *
7482
- * The dApp submits `{ ...dto, prefix, signature }`, which the chain recovers from
7483
- * `keccak256(prefix + serialize(dto WITHOUT prefix))`. So when the string embeds a `prefix`
7484
- * field, that field is removed and the remainder re-serialized; the prefix used is the dApp's own
7485
- * value byte for byte. A string with no `prefix` field is hashed verbatim with an empty prefix
7486
- * (chain-equivalent to a native signature of that exact string).
7487
- *
7488
- * Fails closed (throws `GSwapSDKError` `PERSONAL_SIGN_NOT_JSON`, `PERSONAL_SIGN_NOT_OBJECT`,
7489
- * `PERSONAL_SIGN_BAD_PREFIX`, `PERSONAL_SIGN_ENVELOPE_FIELDS` or `PERSONAL_SIGN_NOT_CANONICAL`) on:
7490
- * malformed JSON; JSON that is not a plain object; a `prefix` that is not an EIP-191
7491
- * "Ethereum Signed Message" header; any signing-envelope field (`signature`, `multisig`, `trace`,
7492
- * `types`, `domain`, `stringsInstructions`); and a string that is not already the canonical
7493
- * serialization of what it parses to (duplicate keys, lossy numbers, key-order tricks the card
7494
- * would render differently). Stripping `prefix` is therefore the ONLY byte change between the
7495
- * reviewed string and the signed message.
7496
- */
7497
- function resolvePersonalSignChainDtoPayload(data) {
7498
- let parsed;
7499
- try {
7500
- parsed = JSON.parse(data);
7501
- } catch {
7502
- throw new GSwapSDKError("PERSONAL_SIGN_NOT_JSON", {});
7503
- }
7504
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new GSwapSDKError("PERSONAL_SIGN_NOT_OBJECT", {});
7505
- const dto = parsed;
7506
- if (!Object.prototype.hasOwnProperty.call(dto, "prefix")) return {
7507
- prefix: "",
7508
- message: data
7509
- };
7510
- const { prefix, ...withoutPrefix } = dto;
7511
- if (typeof prefix !== "string" || !isPersonalSignHeader(prefix)) throw new GSwapSDKError("PERSONAL_SIGN_BAD_PREFIX", {});
7512
- const forbidden = PERSONAL_SIGN_FORBIDDEN_FIELDS.filter((field) => Object.prototype.hasOwnProperty.call(withoutPrefix, field));
7513
- if (forbidden.length > 0) throw new GSwapSDKError("PERSONAL_SIGN_ENVELOPE_FIELDS", { fields: forbidden.join(", ") });
7514
- if (serialize(dto) !== data) throw new GSwapSDKError("PERSONAL_SIGN_NOT_CANONICAL", {});
7515
- return {
7516
- prefix,
7517
- message: serialize(withoutPrefix)
7518
- };
7519
- }
7520
- /**
7521
- * Signs a GalaChain personal-sign scheme DTO from the exact string a dApp sent through
7522
- * `gala_signChainDto` (wallet `signChainDtoPersonalSign`). See
7523
- * `resolvePersonalSignChainDtoPayload` for what is signed and what is refused; the signature
7524
- * recovers, under the chain's `getPayloadToSign`, to this key for the DTO the dApp submits with
7525
- * its `prefix`, and equals a `personal_sign` of the bare body when that prefix is the EIP-191
7526
- * header of the bare body's byte length.
7527
- *
7528
- * @throws GSwapSDKError (`PERSONAL_SIGN_*`, see `resolvePersonalSignChainDtoPayload`) before any
7529
- * signing when the input is refused.
7530
- */
7531
- function signChainDtoPersonalSign(privateKey, data) {
7532
- const { prefix, message } = resolvePersonalSignChainDtoPayload(data);
7533
- return signChainDtoHash(privateKey, prefix, message);
7534
- }
7535
- /**
7536
- * Raw object signing (wallet `signObject`), used for transfers, bridge and fee-dry-run DTOs the
7537
- * wallet signs itself. Removes ONLY `signature`, signs `keccak256(serialize(rest))` natively
7538
- * (no `prefix` handling, and `trace` / `multisig` stay in the signed bytes, unlike
7539
- * `signNative`), and returns `{ signature, ...rest }` with the signature as the FIRST key, exactly
7540
- * like the wallet. Callers that must not sign extra fields strip them first.
7541
- */
7542
- function signRawObject(privateKey, obj) {
7543
- const rest = { ...obj };
7544
- delete rest["signature"];
7545
- return {
7546
- signature: signChainDtoNative(privateKey, serialize(rest)),
7547
- ...rest
7548
- };
7549
- }
7550
- /**
7551
- * Drops the `EIP712Domain` entry from a dApp-supplied types map (a typed-data encoder derives the
7552
- * domain type itself and rejects an explicit one). The order of the remaining types is preserved.
7553
- */
7554
- function stripEip712DomainType(types) {
7555
- const stripped = {};
7556
- for (const typeName of Object.keys(types)) if (typeName !== "EIP712Domain") stripped[typeName] = types[typeName];
7557
- return stripped;
7558
- }
7559
- /**
7560
- * `collection$category$type$additionalKey` for a token-class object (wallet `decodeTokenData`).
7561
- * Lenient on purpose: any missing or non-string part becomes `''`, so a display layer never
7562
- * throws on odd input.
7563
- */
7564
- function tokenClassDollarKey(token) {
7565
- const part = (field) => {
7566
- const value = token === null || token === void 0 ? void 0 : token[field];
7567
- return typeof value === "string" ? value : "";
7568
- };
7569
- return `${part("collection")}$${part("category")}$${part("type")}$${part("additionalKey")}`;
7570
- }
7571
- /**
7572
- * A quantity in the form GalaChain's `IsBigNumber` validator accepts: FIXED notation, no leading
7573
- * zeros, no trailing decimal zeros (`BigNumber#toFixed()`; never `toString()`, which turns
7574
- * `0.00000001` into `1e-8`, and never a JS number in between).
7575
- *
7576
- * @throws GSwapSDKError (`INVALID_DECIMAL`) for a value that is not a finite number. The wallet's
7577
- * `cleanNumber` returned the string `'NaN'` there; signing that text can only fail on chain.
7578
- */
7579
- function canonicalDecimalString(value) {
7580
- let parsed = new bignumber_js.default(NaN);
7581
- try {
7582
- parsed = new bignumber_js.default(value);
7583
- } catch {}
7584
- if (!parsed.isFinite()) throw new GSwapSDKError("INVALID_DECIMAL", { value: String(value) });
7585
- return parsed.toFixed();
7586
- }
7587
-
7588
- //#endregion
7589
- //#region src/utils/typed_data.ts
7590
- /**
7591
- * EIP-712 (`eth_signTypedData_v4`) hashing and signing for ARBITRARY dApp typed data, built on the
7592
- * SDK's own primitives (`@noble/curves`, `@noble/hashes`) so a wallet can sign a dApp's typed-data
7593
- * approval without ethers. It replaces the wallet's `new ethers.Wallet(key).signTypedData(...)`
7594
- * and is pinned to it: the golden suite reproduces every fixture signature exactly and a seeded
7595
- * differential fuzz compares the digest and signature with ethers for every supported type.
7596
- *
7597
- * Compared with ethers this encoder is deliberately STRICTER (it fails closed rather than coerce):
7598
- * `bool` accepts only a boolean, numbers accept only safe integers / decimal or `0x` strings,
7599
- * strings must be well-formed UTF-16, struct values must be objects whose fields are their own
7600
- * properties, and every struct, field and type name must be a plain identifier. Anything ethers
7601
- * accepts that is NOT in that set is refused here instead of being signed in a different shape
7602
- * from what a user reviewed.
7603
- */
7604
- const textEncoder = new TextEncoder();
7605
- const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/u;
7606
- const TYPE_SYNTAX = /^([A-Za-z_$][A-Za-z0-9_$]*)((?:\[(?:0|[1-9][0-9]*)?\])*)$/u;
7607
- const BIGINT_DECIMAL = /^-?[0-9]+$/u;
7608
- const BIGINT_HEX = /^-?0x[0-9a-fA-F]+$/u;
7609
- /** The EIP-712 domain members and their types, in the order ethers (and the spec) hash them. */
7610
- const DOMAIN_FIELDS = [
7611
- {
7612
- name: "name",
7613
- type: "string"
7614
- },
7615
- {
7616
- name: "version",
7617
- type: "string"
7618
- },
7619
- {
7620
- name: "chainId",
7621
- type: "uint256"
7622
- },
7623
- {
7624
- name: "verifyingContract",
7625
- type: "address"
7626
- },
7627
- {
7628
- name: "salt",
7629
- type: "bytes32"
7630
- }
7631
- ];
7632
- function concat(parts) {
7633
- const out = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));
7634
- let offset = 0;
7635
- for (const part of parts) {
7636
- out.set(part, offset);
7637
- offset += part.length;
7638
- }
7639
- return out;
7640
- }
7641
- function bigintToWord(value) {
7642
- const word = /* @__PURE__ */ new Uint8Array(32);
7643
- let rest = value < 0n ? value + (1n << 256n) : value;
7644
- for (let index = 31; index >= 0; index -= 1) {
7645
- word[index] = Number(rest & 255n);
7646
- rest >>= 8n;
7647
- }
7648
- return word;
7649
- }
7650
- function hexToBytes(hex) {
7651
- const body = hex.slice(2);
7652
- const out = new Uint8Array(body.length / 2);
7653
- for (let index = 0; index < out.length; index += 1) out[index] = parseInt(body.slice(index * 2, index * 2 + 2), 16);
7654
- return out;
7655
- }
7656
- function toBytes(value, what) {
7657
- if (value instanceof Uint8Array) return value;
7658
- if (typeof value === "string" && /^0x(?:[0-9a-fA-F]{2})*$/u.test(value)) return hexToBytes(value);
7659
- throw new GSwapSDKError("TYPED_DATA_NOT_HEX_BYTES", { what });
7660
- }
7661
- function toBigInt(value, what) {
7662
- if (typeof value === "bigint") return value;
7663
- if (typeof value === "number") {
7664
- if (!Number.isSafeInteger(value)) throw new GSwapSDKError("TYPED_DATA_NOT_SAFE_INTEGER", { what });
7665
- return BigInt(value);
7666
- }
7667
- if (typeof value === "string") {
7668
- if (BIGINT_DECIMAL.test(value)) return BigInt(value);
7669
- if (BIGINT_HEX.test(value)) return value.startsWith("-") ? -BigInt(value.slice(1)) : BigInt(value);
7670
- }
7671
- throw new GSwapSDKError("TYPED_DATA_NOT_INTEGER", { what });
7672
- }
7673
- function utf8(value, what) {
7674
- if (typeof value !== "string") throw new GSwapSDKError("TYPED_DATA_NOT_STRING", { what });
7675
- for (let index = 0; index < value.length; index += 1) {
7676
- const unit = value.charCodeAt(index);
7677
- if (unit >= 55296 && unit <= 56319) {
7678
- const next = value.charCodeAt(index + 1);
7679
- if (!(next >= 56320 && next <= 57343)) throw new GSwapSDKError("TYPED_DATA_UNPAIRED_SURROGATE", { what });
7680
- index += 1;
7681
- } else if (unit >= 56320 && unit <= 57343) throw new GSwapSDKError("TYPED_DATA_UNPAIRED_SURROGATE", { what });
7682
- }
7683
- return textEncoder.encode(value);
7684
- }
7685
- /** EIP-55: a mixed-case address must carry the right checksum; all-lower / all-upper is accepted. */
7686
- function addressBytes(value) {
7687
- if (typeof value !== "string" || !/^0x[0-9a-fA-F]{40}$/u.test(value)) throw new GSwapSDKError("TYPED_DATA_BAD_ADDRESS", {});
7688
- const digits = value.slice(2);
7689
- if (/[A-F]/u.test(digits) && /[a-f]/u.test(digits)) {
7690
- const hash = (0, _noble_hashes_sha3.keccak_256)(textEncoder.encode(digits.toLowerCase()));
7691
- for (let index = 0; index < 40; index += 1) {
7692
- const nibble = hash[index >> 1] >> (index % 2 === 0 ? 4 : 0) & 15;
7693
- const char = digits.charAt(index);
7694
- if (char !== (nibble >= 8 ? char.toUpperCase() : char.toLowerCase())) throw new GSwapSDKError("TYPED_DATA_BAD_CHECKSUM", {});
7695
- }
7696
- }
7697
- return hexToBytes(value);
7698
- }
7699
- /** The encoder for a non-struct, non-array type, or undefined when `base` is not one. */
7700
- function leafEncoder(base) {
7701
- if (base === "string") return (value) => (0, _noble_hashes_sha3.keccak_256)(utf8(value, "string"));
7702
- if (base === "bytes") return (value) => (0, _noble_hashes_sha3.keccak_256)(toBytes(value, "bytes"));
7703
- if (base === "bool") return (value) => {
7704
- if (typeof value !== "boolean") throw new GSwapSDKError("TYPED_DATA_NOT_BOOLEAN", {});
7705
- return bigintToWord(value ? 1n : 0n);
7706
- };
7707
- if (base === "address") return (value) => concat([/* @__PURE__ */ new Uint8Array(12), addressBytes(value)]);
7708
- const fixed = /^bytes([1-9][0-9]?)$/u.exec(base);
7709
- if (fixed !== null) {
7710
- const width = Number(fixed[1]);
7711
- if (width > 32 || String(width) !== fixed[1]) return void 0;
7712
- return (value) => {
7713
- const bytes = toBytes(value, base);
7714
- if (bytes.length !== width) throw new GSwapSDKError("TYPED_DATA_BYTES_LENGTH", {
7715
- type: base,
7716
- width
7717
- });
7718
- return concat([bytes, new Uint8Array(32 - width)]);
7719
- };
7720
- }
7721
- const integer = /^(u?)int([1-9][0-9]*)$/u.exec(base);
7722
- if (integer !== null) {
7723
- const width = Number(integer[2]);
7724
- if (width % 8 !== 0 || width > 256 || String(width) !== integer[2]) return void 0;
7725
- const signed = integer[1] === "";
7726
- const lower = signed ? -(1n << BigInt(width - 1)) : 0n;
7727
- const upper = signed ? (1n << BigInt(width - 1)) - 1n : (1n << BigInt(width)) - 1n;
7728
- return (value) => {
7729
- const number = toBigInt(value, base);
7730
- if (number < lower || number > upper) throw new GSwapSDKError("TYPED_DATA_OUT_OF_BOUNDS", { type: base });
7731
- return bigintToWord(number);
7732
- };
7733
- }
7734
- }
7735
- function parseType(type) {
7736
- const match = TYPE_SYNTAX.exec(type);
7737
- if (match === null) throw new GSwapSDKError("TYPED_DATA_UNSUPPORTED_TYPE", { type });
7738
- const dimensions = [...(match[2] ?? "").matchAll(/\[([0-9]*)\]/gu)].map((dimension) => dimension[1] === "" ? -1 : Number(dimension[1]));
7739
- return {
7740
- base: match[1],
7741
- dimensions
7742
- };
7743
- }
7744
- function parseFields(typeName, rawFields) {
7745
- if (!Array.isArray(rawFields)) throw new GSwapSDKError("TYPED_DATA_FIELDS_NOT_LIST", { typeName });
7746
- const seen = /* @__PURE__ */ new Set();
7747
- return rawFields.map((raw) => {
7748
- const field = raw;
7749
- if (typeof (field === null || field === void 0 ? void 0 : field.name) !== "string" || typeof field.type !== "string") throw new GSwapSDKError("TYPED_DATA_FIELD_MALFORMED", { typeName });
7750
- if (!IDENTIFIER.test(field.name)) throw new GSwapSDKError("TYPED_DATA_INVALID_FIELD_NAME", { name: field.name });
7751
- if (seen.has(field.name)) throw new GSwapSDKError("TYPED_DATA_DUPLICATE_FIELD", {
7752
- name: field.name,
7753
- typeName
7754
- });
7755
- seen.add(field.name);
7756
- const parsed = parseType(field.type);
7757
- const base = parsed.base === "uint" || parsed.base === "int" ? `${parsed.base}256` : parsed.base;
7758
- return {
7759
- name: field.name,
7760
- type: base + field.type.slice(parsed.base.length)
7761
- };
7762
- });
7763
- }
7764
- /**
7765
- * Builds the struct encoder for a set of type definitions: validates the type graph (unknown or
7766
- * circular references, duplicate fields) and infers the primary type as the single type no other
7767
- * type references, exactly like ethers' `TypedDataEncoder`.
7768
- */
7769
- function createStructEncoder(rawTypes) {
7770
- const names = Object.keys(rawTypes);
7771
- const fields = /* @__PURE__ */ new Map();
7772
- for (const name of names) {
7773
- if (!IDENTIFIER.test(name)) throw new GSwapSDKError("TYPED_DATA_INVALID_TYPE_NAME", { name });
7774
- fields.set(name, parseFields(name, rawTypes[name]));
7775
- }
7776
- const children = /* @__PURE__ */ new Map();
7777
- const parents = /* @__PURE__ */ new Map();
7778
- for (const name of names) {
7779
- children.set(name, /* @__PURE__ */ new Set());
7780
- parents.set(name, /* @__PURE__ */ new Set());
7781
- }
7782
- for (const [name, list] of fields) for (const field of list) {
7783
- var _children$get, _parents$get;
7784
- const { base } = parseType(field.type);
7785
- if (base === name) throw new GSwapSDKError("TYPED_DATA_CIRCULAR_TYPE", { typeName: name });
7786
- if (leafEncoder(base) !== void 0) continue;
7787
- if (!fields.has(base)) throw new GSwapSDKError("TYPED_DATA_UNKNOWN_FIELD_TYPE", {
7788
- type: base,
7789
- typeName: name
7790
- });
7791
- (_children$get = children.get(name)) === null || _children$get === void 0 || _children$get.add(base);
7792
- (_parents$get = parents.get(base)) === null || _parents$get === void 0 || _parents$get.add(name);
7793
- }
7794
- const roots = names.filter((name) => {
7795
- var _parents$get2;
7796
- return ((_parents$get2 = parents.get(name)) === null || _parents$get2 === void 0 ? void 0 : _parents$get2.size) === 0;
7797
- });
7798
- if (roots.length === 0) throw new GSwapSDKError("TYPED_DATA_NO_PRIMARY_TYPE", {});
7799
- if (roots.length > 1) throw new GSwapSDKError("TYPED_DATA_AMBIGUOUS_PRIMARY_TYPE", { roots: roots.join(", ") });
7800
- const primaryType = roots[0];
7801
- const visiting = /* @__PURE__ */ new Set();
7802
- const checked = /* @__PURE__ */ new Set();
7803
- const checkCircular = (name) => {
7804
- if (visiting.has(name)) throw new GSwapSDKError("TYPED_DATA_CIRCULAR_TYPE", { typeName: name });
7805
- if (checked.has(name)) return;
7806
- visiting.add(name);
7807
- for (const child of children.get(name) ?? []) checkCircular(child);
7808
- visiting.delete(name);
7809
- checked.add(name);
7810
- };
7811
- checkCircular(primaryType);
7812
- const dependencies = (name, found) => {
7813
- for (const child of children.get(name) ?? []) if (!found.has(child)) {
7814
- found.add(child);
7815
- dependencies(child, found);
7816
- }
7817
- return found;
7818
- };
7819
- const encodeOne = (name) => `${name}(${(fields.get(name) ?? []).map((field) => `${field.type} ${field.name}`).join(",")})`;
7820
- const typeHashes = /* @__PURE__ */ new Map();
7821
- for (const name of names) {
7822
- const sorted = [...dependencies(name, /* @__PURE__ */ new Set())].filter((dep) => dep !== name).sort();
7823
- typeHashes.set(name, (0, _noble_hashes_sha3.keccak_256)(textEncoder.encode([name, ...sorted].map(encodeOne).join(""))));
7824
- }
7825
- const encodeValue = (parsed, value, depth) => {
7826
- const dimension = parsed.dimensions[parsed.dimensions.length - 1 - depth];
7827
- if (dimension !== void 0) {
7828
- if (!Array.isArray(value)) throw new GSwapSDKError("TYPED_DATA_ARRAY_EXPECTED", { type: parsed.base });
7829
- if (dimension !== -1 && dimension !== value.length) throw new GSwapSDKError("TYPED_DATA_ARRAY_LENGTH_MISMATCH", {});
7830
- return (0, _noble_hashes_sha3.keccak_256)(concat(value.map((item) => encodeValue(parsed, item, depth + 1))));
7831
- }
7832
- const leaf = leafEncoder(parsed.base);
7833
- if (leaf !== void 0) return leaf(value);
7834
- return hashStruct(parsed.base, value);
7835
- };
7836
- function hashStruct(typeName, value) {
7837
- const list = fields.get(typeName);
7838
- const typeHash = typeHashes.get(typeName);
7839
- if (list === void 0 || typeHash === void 0) throw new Error(`Internal error: no encoder for struct ${typeName}`);
7840
- if (value === null || typeof value !== "object" || Array.isArray(value)) throw new GSwapSDKError("TYPED_DATA_STRUCT_NOT_OBJECT", { typeName });
7841
- const record = value;
7842
- const words = list.map((field) => {
7843
- if (!Object.prototype.hasOwnProperty.call(record, field.name)) throw new GSwapSDKError("TYPED_DATA_MISSING_FIELD", {
7844
- typeName,
7845
- field: field.name
7846
- });
7847
- return encodeValue(parseType(field.type), record[field.name], 0);
7848
- });
7849
- return (0, _noble_hashes_sha3.keccak_256)(concat([typeHash, ...words]));
7850
- }
7851
- return {
7852
- primaryType,
7853
- hashStruct
7854
- };
7855
- }
7856
- function hashDomain(domain) {
7857
- if (domain === null || typeof domain !== "object" || Array.isArray(domain)) throw new GSwapSDKError("TYPED_DATA_DOMAIN_NOT_OBJECT", {});
7858
- for (const key of Object.keys(domain)) if (!DOMAIN_FIELDS.some((field) => field.name === key)) throw new GSwapSDKError("TYPED_DATA_INVALID_DOMAIN_KEY", { key: JSON.stringify(key) });
7859
- return createStructEncoder({ EIP712Domain: DOMAIN_FIELDS.filter((field) => Object.prototype.hasOwnProperty.call(domain, field.name)) }).hashStruct("EIP712Domain", domain);
7860
- }
7861
- /**
7862
- * The EIP-712 digest `keccak256(0x1901 || domainSeparator || hashStruct(primaryType, message))`
7863
- * that a wallet signs for `eth_signTypedData_v4`. The primary type is inferred, as ethers does.
7864
- *
7865
- * @throws GSwapSDKError (`TYPED_DATA_*`) for any type graph or value it cannot encode
7866
- * exactly (see the module note on strictness).
7867
- */
7868
- function hashTypedData(payload) {
7869
- const domainHash = hashDomain(payload.domain);
7870
- const encoder = createStructEncoder(payload.types);
7871
- const structHash = encoder.hashStruct(encoder.primaryType, payload.message);
7872
- return (0, _noble_hashes_sha3.keccak_256)(concat([
7873
- Uint8Array.of(25, 1),
7874
- domainHash,
7875
- structHash
7876
- ]));
7877
- }
7878
- /**
7879
- * Signs a dApp's EIP-712 typed-data approval (the wallet's `signTypedMessage` path), replacing
7880
- * `new ethers.Wallet(key).signTypedData(domain, types, message)`. `types` must already have
7881
- * `EIP712Domain` removed (`stripEip712DomainType`).
7882
- *
7883
- * @returns `0x` + r + s + v with `v` = `0x1b`/`0x1c` (27/28): ethers' serialized signature form,
7884
- * recoverable with `verifyTypedData` / `eth_signTypedData_v4` verifiers. Rejects (never throws
7885
- * synchronously) on invalid input.
7886
- */
7887
- async function signTypedDataPayload(privateKey, payload) {
7888
- const digest = hashTypedData(payload);
7889
- return withPrivateKey(privateKey, (key) => `0x${signHash(key, digest)}`);
7890
- }
7891
-
7892
- //#endregion
7893
- //#region src/utils/axios_requestor.ts
7894
- function isRecord$1(value) {
7895
- return typeof value === "object" && value !== null && !Array.isArray(value);
7896
- }
7897
- /**
7898
- * An axios interceptor may resolve something that is not a response at all (for example a string
7899
- * for ECONNREFUSED). That is a transport failure, not an HTTP answer.
7900
- */
7901
- function isAxiosLikeResponse(value) {
7902
- return isRecord$1(value) && typeof value["status"] === "number";
7903
- }
7904
- function readAxiosHeader(headers, name) {
7905
- if (!isRecord$1(headers)) return null;
7906
- const getter = headers["get"];
7907
- if (typeof getter === "function") {
7908
- const value = getter.call(headers, name);
7909
- return typeof value === "string" ? value : null;
7910
- }
7911
- const match = Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase());
7912
- return typeof (match === null || match === void 0 ? void 0 : match[1]) === "string" ? match[1] : null;
7913
- }
7914
- function toHttpResponse(answer, url) {
7915
- if (!isAxiosLikeResponse(answer)) throw new GSwapSDKError("TRANSPORT_ERROR", { url }, { url });
7916
- const { status, data, headers } = answer;
7917
- return {
7918
- ok: status >= 200 && status < 300,
7919
- status,
7920
- json: () => Promise.resolve(data),
7921
- text: () => Promise.resolve(typeof data === "string" ? data : JSON.stringify(data)),
7922
- headers: { get: (name) => readAxiosHeader(headers, name) }
7923
- };
7924
- }
7925
- function headersFor(init, omit) {
7926
- const omitted = new Set(omit.map((name) => name.toLowerCase()));
7927
- const raw = init === null || init === void 0 ? void 0 : init.headers;
7928
- const entries = raw === void 0 ? [] : raw instanceof Headers ? [...raw.entries()] : Array.isArray(raw) ? raw.map(([name, value]) => [String(name), String(value)]) : Object.entries(raw).map(([name, value]) => [name, String(value)]);
7929
- return Object.fromEntries(entries.filter(([name]) => !omitted.has(name.toLowerCase())));
7930
- }
7931
- /**
7932
- * An SDK {@link HttpRequestor} over an axios instance, so the SDK's requests travel through the
7933
- * app's own base URL, interceptors and error handling.
7934
- *
7935
- * A POST's string body is parsed back to the object the SDK serialized it from (axios serializes
7936
- * again, and an interceptor may read the object); a GET goes through `instance.get`. The answer
7937
- * is an HTTP response whose `json()`/`text()` read `response.data`. An answer that is not an
7938
- * axios response is a `TRANSPORT_ERROR` rejection, and so is a rejection that means no HTTP
7939
- * answer arrived (the original error is `cause`): any rejection with `rejectOnHttpError: false`
7940
- * (every status resolves there), an axios error without a `response` with `true`. Any other
7941
- * rejection (an interceptor's error for a 4xx, say) is rethrown unchanged, and so is an abort.
7942
- *
7943
- * Pair it with `ChainGateway`'s `dexBackendBaseUrl: ''` when the instance owns the base URL.
7944
- *
7945
- * @example
7946
- * ```ts
7947
- * const submitGateway = new ChainGateway({
7948
- * dexBackendBaseUrl: '',
7949
- * httpRequestor: httpRequestorFromAxios(chainGatewayInstance, { rejectOnHttpError: true }),
7950
- * });
7951
- * ```
7952
- */
7953
- function httpRequestorFromAxios(instance, options) {
7954
- const omit = options.omitHeaders ?? ["content-type"];
7955
- return async (uri, init) => {
7956
- const signal = (init === null || init === void 0 ? void 0 : init.signal) ?? void 0;
7957
- const config = {
7958
- headers: headersFor(init, omit),
7959
- ...signal ? { signal } : {},
7960
- ...options.rejectOnHttpError ? {} : { validateStatus: () => true }
7961
- };
7962
- const isPost = ((init === null || init === void 0 ? void 0 : init.method) ?? "GET").toUpperCase() === "POST";
7963
- const body = isPost && typeof (init === null || init === void 0 ? void 0 : init.body) === "string" ? JSON.parse(init.body) : void 0;
7964
- let answer;
7965
- try {
7966
- answer = await (isPost ? instance.post(uri, body, config) : instance.get(uri, config));
7967
- } catch (error) {
7968
- if ((signal === null || signal === void 0 ? void 0 : signal.aborted) === true || !isTransportRejection(error, options.rejectOnHttpError)) throw error;
7969
- throw new GSwapSDKError("TRANSPORT_ERROR", { url: uri }, {
7970
- url: uri,
7971
- cause: error
7972
- });
7973
- }
7974
- return toHttpResponse(answer, uri);
7975
- };
7976
- }
7977
- /**
7978
- * Whether an axios rejection means no HTTP answer arrived. With `rejectOnHttpError: false` every
7979
- * status resolves, so any rejection is one. With `true`, a 4xx/5xx rejects too, so only an axios
7980
- * error that carries no `response` is (an interceptor's own error is an app answer and passes
7981
- * through; an app whose interceptors turn network errors into their own class names it in
7982
- * `ChainGatewayOptions.isTransportFailure`).
7983
- */
7984
- function isTransportRejection(error, rejectOnHttpError) {
7985
- if (!rejectOnHttpError) return true;
7986
- return isRecord$1(error) && error["isAxiosError"] === true && error["response"] === void 0;
7987
- }
7988
-
7989
- //#endregion
7990
- //#region src/utils/ethers_provider.ts
7991
- function isRecord(value) {
7992
- return typeof value === "object" && value !== null && !Array.isArray(value);
7993
- }
7994
- function isTypedDataTypes(value) {
7995
- return isRecord(value) && Object.values(value).every((fields) => Array.isArray(fields) && fields.every((field) => isRecord(field) && typeof field["name"] === "string" && typeof field["type"] === "string"));
7996
- }
7997
- function malformed(method) {
7998
- return new GSwapSDKError("MALFORMED_WALLET_REQUEST", { method });
7999
- }
8000
- /** Splits `eth_signTypedData_v4` params (`[account, JSON payload]`) into what ethers' signer takes. */
8001
- function readTypedDataRequest(params) {
8002
- const raw = params === null || params === void 0 ? void 0 : params[1];
8003
- let payload;
8004
- try {
8005
- payload = typeof raw === "string" ? JSON.parse(raw) : raw;
8006
- } catch {
8007
- throw malformed("eth_signTypedData_v4");
8008
- }
8009
- if (!isRecord(payload)) throw malformed("eth_signTypedData_v4");
8010
- const { domain, types, message } = payload;
8011
- if (!isRecord(domain) || !isTypedDataTypes(types) || !isRecord(message)) throw malformed("eth_signTypedData_v4");
8012
- return {
8013
- domain,
8014
- types: stripEip712DomainType(types),
8015
- message
8016
- };
8017
- }
8018
- /**
8019
- * An EIP-1193 provider over an ethers v6 provider, for {@link BrowserWalletSigner}: apps whose
8020
- * wallet connection is an ethers `BrowserProvider` sign through the very ethers calls they always
8021
- * made, with no hand-written shim.
8022
- *
8023
- * - `eth_chainId` is `provider.send('eth_chainId', [])`: the wallet's LIVE chain. Never
8024
- * `provider.getNetwork()`, which ethers caches and does not invalidate on `chainChanged`, so a
8025
- * user who switches networks after connecting would sign against a stale chainId.
8026
- * - `eth_signTypedData_v4` parses the `[account, JSON]` params and calls
8027
- * `signer.signTypedData(domain, types, message)` with `EIP712Domain` removed from `types`.
8028
- * - `personal_sign` is `options.personalSign(message)` when given, else `signer.signMessage`.
8029
- * - Anything else is `UNSUPPORTED_WALLET_METHOD`; a malformed request is
8030
- * `MALFORMED_WALLET_REQUEST`; a missing provider is `WALLET_UNAVAILABLE`.
8031
- *
8032
- * `provider` may be `null`/`undefined` (nothing connected): a request that needs it then fails
8033
- * with `WALLET_UNAVAILABLE` rather than at construction, so a signer can be built before the
8034
- * connection state is known.
8035
- *
8036
- * @example
8037
- * ```ts
8038
- * const signer = new BrowserWalletSigner(eip1193ProviderFromEthers(browserProvider), account, {
8039
- * scheme: 'eip712',
8040
- * });
8041
- * ```
8042
- */
8043
- function eip1193ProviderFromEthers(provider, options = {}) {
8044
- const connected = () => {
8045
- if (provider === null || provider === void 0) throw new GSwapSDKError("WALLET_UNAVAILABLE", {});
8046
- return provider;
8047
- };
8048
- return { request: async ({ method, params }) => {
8049
- switch (method) {
8050
- case "eth_chainId": return connected().send("eth_chainId", []);
8051
- case "eth_signTypedData_v4": {
8052
- const wallet = connected();
8053
- const { domain, types, message } = readTypedDataRequest(params);
8054
- return (await wallet.getSigner()).signTypedData(domain, types, message);
8055
- }
8056
- case "personal_sign": {
8057
- const message = params === null || params === void 0 ? void 0 : params[0];
8058
- if (typeof message !== "string") throw malformed("personal_sign");
8059
- if (options.personalSign !== void 0) return options.personalSign(message);
8060
- return (await connected().getSigner()).signMessage(message);
8061
- }
8062
- default: throw new GSwapSDKError("UNSUPPORTED_WALLET_METHOD", { method });
8063
- }
8064
- } };
8065
- }
8066
-
8067
6258
  //#endregion
8068
6259
  //#region src/utils/confirmation_state.ts
8069
6260
  /** The state of every confirmation code (a typo is caught by the all-codes test). */
@@ -8091,7 +6282,7 @@ const STATE_OF_CODE = {
8091
6282
  */
8092
6283
  function confirmationStateOf(error) {
8093
6284
  var _toFailureView, _Object$entries$find;
8094
- const code = (_toFailureView = toFailureView(error)) === null || _toFailureView === void 0 ? void 0 : _toFailureView.code;
6285
+ const code = (_toFailureView = (0, _gala_chain_gala_core_sdk.toFailureView)(error)) === null || _toFailureView === void 0 ? void 0 : _toFailureView.code;
8095
6286
  if (code === void 0) return void 0;
8096
6287
  return (_Object$entries$find = Object.entries(STATE_OF_CODE).find(([known]) => known === code)) === null || _Object$entries$find === void 0 ? void 0 : _Object$entries$find[1];
8097
6288
  }
@@ -8104,43 +6295,6 @@ function isConfirmationTimeout(error) {
8104
6295
  return confirmationStateOf(error) === "timeout";
8105
6296
  }
8106
6297
 
8107
- //#endregion
8108
- //#region src/utils/fetch_failure.ts
8109
- /**
8110
- * True when a rejection of a `fetch`-based requestor means NO HTTP ANSWER ARRIVED: the network
8111
- * failed, the connection was reset, the host did not resolve, CORS blocked it. For a write that
8112
- * is not a refusal (the request may have been queued), so this is the default
8113
- * `ChainGatewayOptions.isTransportFailure` for a requestor that wraps `fetch` and rejects with
8114
- * its own errors.
8115
- *
8116
- * - Yes: a `TypeError` (what `fetch` rejects with in every engine: `Failed to fetch`, `Load failed`,
8117
- * `NetworkError when attempting to fetch resource`, undici's `fetch failed`), recognised by name
8118
- * too so one from another realm (an extension page, an iframe) still counts, and a
8119
- * `DOMException` named `NetworkError`.
8120
- * - No: an abort (`AbortError`) or a timeout (`TimeoutError`). The SDK's own request layer knows
8121
- * whether its timer or the caller's signal aborted, and reports those itself
8122
- * (`REQUEST_TIMEOUT`, or the caller's own abort unchanged); claiming them here would turn the
8123
- * caller's cancel into "maybe queued".
8124
- * - No: anything else, including an SDK error and a value that is not an object.
8125
- *
8126
- * It never throws.
8127
- *
8128
- * @example
8129
- * ```ts
8130
- * new ChainGateway({ dexBackendBaseUrl, httpRequestor: galaFetch, isTransportFailure: isFetchTransportFailure });
8131
- * ```
8132
- */
8133
- function isFetchTransportFailure(error) {
8134
- if (typeof error !== "object" || error === null) return false;
8135
- try {
8136
- const name = "name" in error ? error.name : void 0;
8137
- if (name === "AbortError" || name === "TimeoutError") return false;
8138
- return error instanceof TypeError || name === "TypeError" || name === "NetworkError";
8139
- } catch {
8140
- return false;
8141
- }
8142
- }
8143
-
8144
6298
  //#endregion
8145
6299
  //#region src/utils/failure_guards.ts
8146
6300
  /**
@@ -8163,7 +6317,7 @@ function isFetchTransportFailure(error) {
8163
6317
  * ```
8164
6318
  */
8165
6319
  function isUniqueKeyConsumed(error) {
8166
- const view = toFailureView(error);
6320
+ const view = (0, _gala_chain_gala_core_sdk.toFailureView)(error);
8167
6321
  return (view === null || view === void 0 ? void 0 : view.code) === "CHAIN_DISPATCH_FAILED" && view.status === 409;
8168
6322
  }
8169
6323
  const UNPROVEN_ACKNOWLEDGEMENT_CODES = [
@@ -8199,7 +6353,7 @@ function isCodeIn(code, codes) {
8199
6353
  * error (`{ code: 'ACTION_REJECTED' }`, a numeric `4001`) is never a member.
8200
6354
  */
8201
6355
  function hasCodeIn(error, codes) {
8202
- const view = toFailureView(error);
6356
+ const view = (0, _gala_chain_gala_core_sdk.toFailureView)(error);
8203
6357
  return view !== void 0 && isCodeIn(view.code, codes);
8204
6358
  }
8205
6359
  /**
@@ -8252,10 +6406,10 @@ function isUninterpretedAnswer(error) {
8252
6406
  * ```
8253
6407
  */
8254
6408
  function chainErrorKeyOf(error) {
8255
- const view = toFailureView(error);
6409
+ const view = (0, _gala_chain_gala_core_sdk.toFailureView)(error);
8256
6410
  if (view === void 0) return void 0;
8257
6411
  if (view.code !== "CHAIN_REJECTED" && view.code !== "CHAIN_DISPATCH_FAILED") return void 0;
8258
- const errorKey = stringParamOf(view, "errorKey");
6412
+ const errorKey = (0, _gala_chain_gala_core_sdk.stringParamOf)(view, "errorKey");
8259
6413
  return errorKey === void 0 || errorKey === "" ? void 0 : errorKey;
8260
6414
  }
8261
6415
  /** Codes that mean "there is no market for this" however the app reached them. */
@@ -8281,10 +6435,10 @@ const NO_MARKET_CODES = [
8281
6435
  * ```
8282
6436
  */
8283
6437
  function isNoMarket(error) {
8284
- const view = toFailureView(error);
6438
+ const view = (0, _gala_chain_gala_core_sdk.toFailureView)(error);
8285
6439
  if (view === void 0) return false;
8286
6440
  if (isCodeIn(view.code, NO_MARKET_CODES)) return true;
8287
- return !isWriteView(view) && (view.notFound === true || view.status === 404);
6441
+ return !(0, _gala_chain_gala_core_sdk.isWriteView)(view) && (view.notFound === true || view.status === 404);
8288
6442
  }
8289
6443
 
8290
6444
  //#endregion
@@ -8331,42 +6485,38 @@ function classifySubmitEnvelope(envelope) {
8331
6485
  exports.ALL_FEE_TIERS = ALL_FEE_TIERS;
8332
6486
  exports.AppliedTradeError = AppliedTradeError;
8333
6487
  exports.Assets = Assets;
8334
- exports.BrowserWalletSigner = BrowserWalletSigner;
8335
6488
  exports.CanonicalSymbols = CanonicalSymbols;
8336
6489
  exports.ChainGateway = ChainGateway;
8337
- exports.DEFAULT_UNIQUE_KEY_PREFIX = DEFAULT_UNIQUE_KEY_PREFIX;
8338
6490
  exports.DEX_FEE_METHODS = DEX_FEE_METHODS;
8339
6491
  exports.DRY_RUN_METHOD = DRY_RUN_METHOD;
8340
6492
  exports.DRY_RUN_UNIQUE_KEY_PREFIX = DRY_RUN_UNIQUE_KEY_PREFIX;
8341
6493
  exports.DexFees = DexFees;
8342
- exports.EIP712_CAPABLE_METHODS = EIP712_CAPABLE_METHODS;
8343
- exports.FAILURE_OUTCOMES = FAILURE_OUTCOMES;
8344
6494
  exports.FEE_TIER = FEE_TIER;
8345
6495
  exports.GC_MAX_TICK = GC_MAX_TICK;
8346
6496
  exports.GC_MIN_TICK = GC_MIN_TICK;
8347
6497
  exports.GSWAP_ENVIRONMENTS = GSWAP_ENVIRONMENTS;
8348
6498
  exports.GSWAP_ERROR_CATALOG = GSWAP_ERROR_CATALOG;
8349
- exports.GSWAP_ERROR_PHASES = GSWAP_ERROR_PHASES;
8350
6499
  exports.GSWAP_ERROR_PHASE_BY_CODE = GSWAP_ERROR_PHASE_BY_CODE;
8351
6500
  exports.GSwap = GSwap;
8352
6501
  exports.GSwapSDKError = GSwapSDKError;
8353
- exports.GalaWalletSigner = GalaWalletSigner;
8354
6502
  exports.GdexStreamError = GdexStreamError;
8355
6503
  exports.GdexStreamService = GdexStreamService;
8356
- exports.INVALID_PRIVATE_KEY_REASONS = INVALID_PRIVATE_KEY_REASONS;
6504
+ exports.Leaderboard = Leaderboard;
6505
+ exports.MARKET_PRICE_BATCH_LIMIT = MARKET_PRICE_BATCH_LIMIT;
6506
+ exports.MARKET_PRICE_QUERY_BYTES = MARKET_PRICE_QUERY_BYTES;
6507
+ exports.Market = Market;
8357
6508
  exports.NOT_QUEUED_FINAL = NOT_QUEUED_FINAL;
8358
6509
  exports.PENDING_SWAPS_STORAGE_KEY = PENDING_SWAPS_STORAGE_KEY;
8359
6510
  exports.PENDING_SWAP_EXPIRY_MS = PENDING_SWAP_EXPIRY_MS;
8360
6511
  exports.PENDING_SWAP_FATES = PENDING_SWAP_FATES;
8361
6512
  exports.PENDING_SWAP_PRUNE_REASONS = PENDING_SWAP_PRUNE_REASONS;
6513
+ exports.PRICE_SERIES_TIMEFRAMES = PRICE_SERIES_TIMEFRAMES;
8362
6514
  exports.PendingSwapStore = PendingSwapStore;
8363
6515
  exports.Pools = Pools;
8364
6516
  exports.Positions = Positions;
8365
- exports.PrivateKeySigner = PrivateKeySigner;
8366
6517
  exports.Quoting = Quoting;
8367
6518
  exports.SHADOW_FAILURE_KINDS = SHADOW_FAILURE_KINDS;
8368
6519
  exports.SHADOW_SUBMIT_CODES = SHADOW_SUBMIT_CODES;
8369
- exports.SIGNING_FAILURE_REASONS = SIGNING_FAILURE_REASONS;
8370
6520
  exports.SUBMISSION_OUTCOME_UNKNOWN_REASONS = SUBMISSION_OUTCOME_UNKNOWN_REASONS;
8371
6521
  exports.SubmittedTransaction = SubmittedTransaction;
8372
6522
  exports.Swaps = Swaps;
@@ -8380,47 +6530,29 @@ exports.alignTickUpOrNaN = alignTickUpOrNaN;
8380
6530
  exports.assertCanonicalPair = assertCanonicalPair;
8381
6531
  exports.assertCanonicalV2Dto = assertCanonicalV2Dto;
8382
6532
  exports.assertTickRange = assertTickRange;
8383
- exports.assertUniqueKey = assertUniqueKey;
8384
6533
  exports.buildAddLiquidityDto = buildAddLiquidityDto;
8385
6534
  exports.buildCollectPositionFeesDto = buildCollectPositionFeesDto;
8386
6535
  exports.buildCreatePoolDto = buildCreatePoolDto;
8387
6536
  exports.buildDryRunWrapper = buildDryRunWrapper;
8388
- exports.buildEIP712Payload = buildEIP712Payload;
8389
6537
  exports.buildRemoveLiquidityDto = buildRemoveLiquidityDto;
8390
6538
  exports.buildRequestTradeDto = buildRequestTradeDto;
8391
- exports.calculatePersonalSignPrefix = calculatePersonalSignPrefix;
8392
- exports.canonicalDecimalString = canonicalDecimalString;
8393
6539
  exports.chainErrorKeyOf = chainErrorKeyOf;
8394
6540
  exports.classification = classification;
8395
6541
  exports.classifyFailure = classifyFailure;
8396
6542
  exports.classifyShadowSubmitError = classifyShadowSubmitError;
8397
6543
  exports.classifyShadowSubmitStatus = classifyShadowSubmitStatus;
8398
6544
  exports.classifySubmitEnvelope = classifySubmitEnvelope;
8399
- exports.compositeKeyOf = compositeKeyOf;
8400
6545
  exports.confirmAppliedTrade = confirmAppliedTrade;
8401
6546
  exports.confirmationStateOf = confirmationStateOf;
8402
- exports.createLazyPrivateKeySigner = createLazyPrivateKeySigner;
8403
- exports.createUniqueKey = createUniqueKey;
8404
- exports.eip1193ProviderFromEthers = eip1193ProviderFromEthers;
8405
- exports.eip712DomainFor = eip712DomainFor;
8406
- exports.ethAddressOfPrivateKey = ethAddressOfPrivateKey;
8407
- exports.ethereumAddressOfAccount = ethereumAddressOfAccount;
8408
- exports.fixpointPrefixFor = fixpointPrefixFor;
8409
6547
  exports.frameSlot0 = frameSlot0;
8410
- exports.generateEIP712Types = generateEIP712Types;
8411
6548
  exports.getObjectProperty = getObjectProperty;
8412
- exports.getPayloadToSign = getPayloadToSign;
8413
6549
  exports.getStringProperty = getStringProperty;
8414
6550
  exports.gswapErrorTemplates = gswapErrorTemplates;
8415
- exports.hashTypedData = hashTypedData;
8416
- exports.httpRequestorFromAxios = httpRequestorFromAxios;
8417
6551
  exports.isConfirmationAborted = isConfirmationAborted;
8418
6552
  exports.isConfirmationTimeout = isConfirmationTimeout;
8419
6553
  exports.isCurrentContractDexMessage = isCurrentContractDexMessage;
8420
6554
  exports.isDexFeeMethod = isDexFeeMethod;
8421
- exports.isFetchTransportFailure = isFetchTransportFailure;
8422
6555
  exports.isGSwapError = isGSwapError;
8423
- exports.isGSwapErrorLike = isGSwapErrorLike;
8424
6556
  exports.isGdexLiquidityEvent = isGdexLiquidityEvent;
8425
6557
  exports.isNoMarket = isNoMarket;
8426
6558
  exports.isPreSendError = isPreSendError;
@@ -8435,47 +6567,25 @@ exports.isTickInRange = isTickInRange;
8435
6567
  exports.isUninterpretedAnswer = isUninterpretedAnswer;
8436
6568
  exports.isUniqueKeyConsumed = isUniqueKeyConsumed;
8437
6569
  exports.isUnprovenAcknowledgement = isUnprovenAcknowledgement;
8438
- exports.isValidUniqueKey = isValidUniqueKey;
8439
- exports.isWalletUserRejection = isWalletUserRejection;
8440
- exports.isWriteView = isWriteView;
8441
6570
  exports.mayHaveBeenQueued = mayHaveBeenQueued;
8442
- exports.normalizePrivateKey = normalizePrivateKey;
8443
6571
  exports.notSentClassification = notSentClassification;
8444
6572
  exports.orderSymbols = orderSymbols;
8445
- exports.parseJson = parseJson;
8446
6573
  exports.parseTokenClassKey = parseTokenClassKey;
8447
6574
  exports.pendingSwapFateFor = pendingSwapFateFor;
8448
6575
  exports.pendingSwapFateOfOutcome = pendingSwapFateOfOutcome;
8449
- exports.personalSignPrefixFor = personalSignPrefixFor;
6576
+ exports.priceBatches = priceBatches;
8450
6577
  exports.queryTokenOf = queryTokenOf;
8451
6578
  exports.rawTokenOf = rawTokenOf;
8452
6579
  exports.readOrderedSymbols = readOrderedSymbols;
8453
6580
  exports.readShadowSubmitOutcome = readShadowSubmitOutcome;
8454
- exports.renderGSwapErrorTemplate = renderGSwapErrorTemplate;
8455
- exports.resolvePersonalSignChainDtoPayload = resolvePersonalSignChainDtoPayload;
8456
- exports.resolveUniqueKeyPrefix = resolveUniqueKeyPrefix;
8457
- exports.serialize = serialize;
8458
- exports.signChainDtoHash = signChainDtoHash;
8459
- exports.signChainDtoNative = signChainDtoNative;
8460
- exports.signChainDtoPersonalSign = signChainDtoPersonalSign;
8461
- exports.signNative = signNative;
8462
- exports.signPersonalMessage = signPersonalMessage;
8463
- exports.signRawObject = signRawObject;
8464
- exports.signSerializedNative = signSerializedNative;
8465
- exports.signTypedDataPayload = signTypedDataPayload;
8466
6581
  exports.sqrtPriceToTick = sqrtPriceToTick;
8467
6582
  exports.storageAdapterFromChromeStorage = storageAdapterFromChromeStorage;
8468
- exports.stripEip712DomainType = stripEip712DomainType;
8469
6583
  exports.swapRouteFromQuote = swapRouteFromQuote;
8470
6584
  exports.tickFromPrice = tickFromPrice;
8471
6585
  exports.tickToPrice = tickToPrice;
8472
6586
  exports.tickToSqrtPrice = tickToSqrtPrice;
8473
6587
  exports.toChainDto = toChainDto;
8474
- exports.toFailureView = toFailureView;
8475
- exports.tokenClassDollarKey = tokenClassDollarKey;
8476
6588
  exports.tradingSymbolOf = tradingSymbolOf;
8477
- exports.tryParseCompositeKey = tryParseCompositeKey;
8478
- exports.tryParseTokenClassKey = tryParseTokenClassKey;
8479
6589
  exports.validateFee = validateFee;
8480
6590
  exports.validateNumericAmount = validateNumericAmount;
8481
6591
  exports.validatePriceValues = validatePriceValues;
@@ -8483,7 +6593,5 @@ exports.validateTickRange = validateTickRange;
8483
6593
  exports.validateTickSpacing = validateTickSpacing;
8484
6594
  exports.validateTokenDecimals = validateTokenDecimals;
8485
6595
  exports.validateWalletAddress = validateWalletAddress;
8486
- exports.walletDeclineCode = walletDeclineCode;
8487
6596
  exports.webStorageAdapter = webStorageAdapter;
8488
- exports.withPrivateKey = withPrivateKey;
8489
6597
  //# sourceMappingURL=index.cjs.map