@gala-chain/gswap-sdk 1.0.0-rc.3 → 1.0.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.
package/dist/index.cjs CHANGED
@@ -1,2567 +1,2465 @@
1
- "use strict";
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
7
  var __getProtoOf = Object.getPrototypeOf;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
9
  var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
19
22
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- ALL_FEE_TIERS: () => ALL_FEE_TIERS,
34
- Assets: () => Assets,
35
- BrowserWalletSigner: () => BrowserWalletSigner,
36
- ChainGateway: () => ChainGateway,
37
- FEE_TIER: () => FEE_TIER,
38
- GC_MAX_TICK: () => GC_MAX_TICK,
39
- GC_MIN_TICK: () => GC_MIN_TICK,
40
- GSWAP_ENVIRONMENTS: () => GSWAP_ENVIRONMENTS,
41
- GSwap: () => GSwap,
42
- GSwapSDKError: () => GSwapSDKError,
43
- GalaWalletSigner: () => GalaWalletSigner,
44
- Pools: () => Pools,
45
- Positions: () => Positions,
46
- PrivateKeySigner: () => PrivateKeySigner,
47
- Quoting: () => Quoting,
48
- SubmittedTransaction: () => SubmittedTransaction,
49
- Swaps: () => Swaps,
50
- Symbols: () => Symbols,
51
- TICK_SPACING_BY_FEE: () => TICK_SPACING_BY_FEE,
52
- alignTickDown: () => alignTickDown,
53
- alignTickUp: () => alignTickUp,
54
- assertTickRange: () => assertTickRange,
55
- compositeKeyOf: () => compositeKeyOf,
56
- getObjectProperty: () => getObjectProperty,
57
- getStringProperty: () => getStringProperty,
58
- orderSymbols: () => orderSymbols,
59
- parseJson: () => parseJson,
60
- parseTokenClassKey: () => parseTokenClassKey,
61
- readOrderedSymbols: () => readOrderedSymbols,
62
- sqrtPriceToTick: () => sqrtPriceToTick,
63
- tickFromPrice: () => tickFromPrice,
64
- tickToSqrtPrice: () => tickToSqrtPrice,
65
- validateFee: () => validateFee,
66
- validateNumericAmount: () => validateNumericAmount,
67
- validatePriceValues: () => validatePriceValues,
68
- validateTickRange: () => validateTickRange,
69
- validateTickSpacing: () => validateTickSpacing,
70
- validateTokenDecimals: () => validateTokenDecimals,
71
- validateWalletAddress: () => validateWalletAddress
72
- });
73
- module.exports = __toCommonJS(index_exports);
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
74
27
 
75
- // src/utils/validation.ts
76
- var import_bignumber2 = __toESM(require("bignumber.js"), 1);
28
+ //#endregion
29
+ let bignumber_js = require("bignumber.js");
30
+ bignumber_js = __toESM(bignumber_js, 1);
31
+ let decimal_js = require("decimal.js");
32
+ let debug = require("debug");
33
+ debug = __toESM(debug, 1);
34
+ let _gala_chain_api = require("@gala-chain/api");
77
35
 
78
- // src/classes/gswap_sdk_error.ts
79
- var GSwapSDKError = class _GSwapSDKError extends Error {
80
- constructor(message, code, details, chainMessage, retryAfterMs) {
81
- super(message);
82
- this.code = code;
83
- this.details = details;
84
- this.name = "GSwapSDKError";
85
- this.chainMessage = chainMessage;
86
- this.retryAfterMs = retryAfterMs;
87
- }
88
- code;
89
- details;
90
- chainMessage;
91
- retryAfterMs;
92
- /** Create the standard missing-signer error. */
93
- static noSignerError() {
94
- return new _GSwapSDKError(
95
- "This method requires a signer. Please provide a signer to the GSwap constructor.",
96
- "NO_SIGNER"
97
- );
98
- }
99
- /** Create the error used when confirming a position write without a configured wallet address. */
100
- static noWalletAddressError() {
101
- return new _GSwapSDKError(
102
- "Cannot confirm this write: no walletAddress was provided to the GSwap constructor, so the resulting position cannot be looked up to confirm it landed on chain.",
103
- "NO_WALLET_ADDRESS"
104
- );
105
- }
106
- /** Create the error used when no pool can quote the requested pair. */
107
- static noPoolAvailableError(tokenIn, tokenOut, fee) {
108
- return new _GSwapSDKError("No pool is available for the requested pair.", "NO_POOL_AVAILABLE", {
109
- tokenIn,
110
- tokenOut,
111
- ...fee === void 0 ? {} : { fee }
112
- });
113
- }
114
- /** Create the error used when a pool lacks liquidity for a quote. */
115
- static insufficientLiquidityError(tokenIn, tokenOut, fee) {
116
- return new _GSwapSDKError(
117
- "The selected pool has insufficient liquidity for the requested quote.",
118
- "INSUFFICIENT_LIQUIDITY",
119
- { tokenIn, tokenOut, ...fee === void 0 ? {} : { fee } }
120
- );
121
- }
122
- /** Convert a chain-gateway bounce into a typed SDK error. */
123
- static fromGatewayBounce(code, message, status, retryAfterMs) {
124
- const details = { status, chainMessage: message };
125
- if (retryAfterMs !== void 0) details["retryAfterMs"] = retryAfterMs;
126
- const sdkMessage = code === "CHAIN_DISPATCH_FAILED" ? message : `Gateway rejected ${code}: ${message}`;
127
- return new _GSwapSDKError(sdkMessage, code, details, message, retryAfterMs);
128
- }
129
- /** Convert a GalaChain `Status: 0` response into a typed SDK error. */
130
- static fromChainError(errorKey, message, details) {
131
- return new _GSwapSDKError(
132
- `GalaChain error ${errorKey}: ${message}`,
133
- errorKey,
134
- { ...details, errorKey, message },
135
- message
136
- );
137
- }
138
- /** Create the error used when a token is not registered by the current DEX contract. */
139
- static unknownTokenError(token) {
140
- const tokenText = typeof token === "string" ? token : JSON.stringify(token);
141
- return new _GSwapSDKError(
142
- `Token ${tokenText} has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`,
143
- "UNKNOWN_TOKEN",
144
- { token }
145
- );
146
- }
147
- /** Create the error used when apply-results confirmation does not arrive in time. */
148
- static confirmationTimeoutError(uniqueKey, cause) {
149
- return new _GSwapSDKError(
150
- "Transaction confirmation timed out; the trade may still apply. Confirm the same uniqueKey again later instead of resubmitting.",
151
- "CONFIRMATION_TIMEOUT",
152
- { uniqueKey, ...cause === void 0 ? {} : { cause } }
153
- );
154
- }
155
- /** Convert an unexpected HTTP response into an SDK error. */
156
- static async fromErrorResponse(url, response) {
157
- const bodyText = await response.text();
158
- const bodyJson = parseJson(bodyText);
159
- const errorObject = getObjectProperty(bodyJson, "error");
160
- const errorKey = getStringProperty(errorObject, "ErrorKey");
161
- const message = getStringProperty(errorObject, "Message");
162
- if (errorKey !== void 0 && message !== void 0) {
163
- return new _GSwapSDKError(
164
- `GalaChain Error ${errorKey} from ${url}: ${message}`,
165
- errorKey,
166
- { message, errorKey, status: response.status, body: bodyJson, url },
167
- message
168
- );
169
- }
170
- return new _GSwapSDKError(`Unexpected HTTP Error ${response.status} from ${url}`, "HTTP_ERROR", {
171
- status: response.status,
172
- body: bodyJson ?? bodyText,
173
- url
174
- });
175
- }
36
+ //#region src/classes/gswap_sdk_error.ts
37
+ /** Error raised by the SDK for validation, gateway, chain, or transaction failures. */
38
+ var GSwapSDKError = class GSwapSDKError extends Error {
39
+ code;
40
+ details;
41
+ chainMessage;
42
+ retryAfterMs;
43
+ constructor(message, code, details, chainMessage, retryAfterMs) {
44
+ super(message);
45
+ this.code = code;
46
+ this.details = details;
47
+ this.name = "GSwapSDKError";
48
+ this.chainMessage = chainMessage;
49
+ this.retryAfterMs = retryAfterMs;
50
+ }
51
+ /** Create the standard missing-signer error. */
52
+ static noSignerError() {
53
+ return new GSwapSDKError("This method requires a signer. Please provide a signer to the GSwap constructor.", "NO_SIGNER");
54
+ }
55
+ /** Create the error used when confirming a position write without a configured wallet address. */
56
+ static noWalletAddressError() {
57
+ return new GSwapSDKError("Cannot confirm this write: no walletAddress was provided to the GSwap constructor, so the resulting position cannot be looked up to confirm it landed on chain.", "NO_WALLET_ADDRESS");
58
+ }
59
+ /** Create the error used when no pool can quote the requested pair. */
60
+ static noPoolAvailableError(tokenIn, tokenOut, fee) {
61
+ return new GSwapSDKError("No pool is available for the requested pair.", "NO_POOL_AVAILABLE", {
62
+ tokenIn,
63
+ tokenOut,
64
+ ...fee === void 0 ? {} : { fee }
65
+ });
66
+ }
67
+ /** Create the error used when a pool lacks liquidity for a quote. */
68
+ static insufficientLiquidityError(tokenIn, tokenOut, fee) {
69
+ return new GSwapSDKError("The selected pool has insufficient liquidity for the requested quote.", "INSUFFICIENT_LIQUIDITY", {
70
+ tokenIn,
71
+ tokenOut,
72
+ ...fee === void 0 ? {} : { fee }
73
+ });
74
+ }
75
+ /** Convert a chain-gateway bounce into a typed SDK error. */
76
+ static fromGatewayBounce(code, message, status, retryAfterMs) {
77
+ const details = {
78
+ status,
79
+ chainMessage: message
80
+ };
81
+ if (retryAfterMs !== void 0) details["retryAfterMs"] = retryAfterMs;
82
+ const sdkMessage = code === "CHAIN_DISPATCH_FAILED" ? message : `Gateway rejected ${code}: ${message}`;
83
+ return new GSwapSDKError(sdkMessage, code, details, message, retryAfterMs);
84
+ }
85
+ /** Convert a GalaChain `Status: 0` response into a typed SDK error. */
86
+ static fromChainError(errorKey, message, details) {
87
+ return new GSwapSDKError(`GalaChain error ${errorKey}: ${message}`, errorKey, {
88
+ ...details,
89
+ errorKey,
90
+ message
91
+ }, message);
92
+ }
93
+ /** Create the error used when a token is not registered by the current DEX contract. */
94
+ static unknownTokenError(token) {
95
+ const tokenText = typeof token === "string" ? token : JSON.stringify(token);
96
+ return new GSwapSDKError(`Token ${tokenText} has no trading symbol on the new DEX contract (no gcdex pool includes it yet).`, "UNKNOWN_TOKEN", { token });
97
+ }
98
+ /** Create the error used when apply-results confirmation does not arrive in time. */
99
+ static confirmationTimeoutError(uniqueKey, cause) {
100
+ return new GSwapSDKError("Transaction confirmation timed out; the trade may still apply. Confirm the same uniqueKey again later instead of resubmitting.", "CONFIRMATION_TIMEOUT", {
101
+ uniqueKey,
102
+ ...cause === void 0 ? {} : { cause }
103
+ });
104
+ }
105
+ /** Convert an unexpected HTTP response into an SDK error. */
106
+ static async fromErrorResponse(url, response) {
107
+ const bodyText = await response.text();
108
+ const bodyJson = parseJson(bodyText);
109
+ const errorObject = getObjectProperty(bodyJson, "error");
110
+ const errorKey = getStringProperty(errorObject, "ErrorKey");
111
+ const message = getStringProperty(errorObject, "Message");
112
+ if (errorKey !== void 0 && message !== void 0) return new GSwapSDKError(`GalaChain Error ${errorKey} from ${url}: ${message}`, errorKey, {
113
+ message,
114
+ errorKey,
115
+ status: response.status,
116
+ body: bodyJson,
117
+ url
118
+ }, message);
119
+ return new GSwapSDKError(`Unexpected HTTP Error ${response.status} from ${url}`, "HTTP_ERROR", {
120
+ status: response.status,
121
+ body: bodyJson ?? bodyText,
122
+ url
123
+ });
124
+ }
176
125
  };
126
+ /** Narrow an object property without trusting a cast at a network boundary. */
177
127
  function getObjectProperty(value, property) {
178
- if (typeof value !== "object" || value === null || !(property in value)) return void 0;
179
- const propertyValue = value[property];
180
- return typeof propertyValue === "object" && propertyValue !== null ? propertyValue : void 0;
128
+ if (typeof value !== "object" || value === null || !(property in value)) return void 0;
129
+ const propertyValue = value[property];
130
+ return typeof propertyValue === "object" && propertyValue !== null ? propertyValue : void 0;
181
131
  }
132
+ /** Read a string property from an unknown object. */
182
133
  function getStringProperty(value, property) {
183
- if (typeof value !== "object" || value === null || !(property in value)) return void 0;
184
- const propertyValue = value[property];
185
- return typeof propertyValue === "string" ? propertyValue : void 0;
134
+ if (typeof value !== "object" || value === null || !(property in value)) return void 0;
135
+ const propertyValue = value[property];
136
+ return typeof propertyValue === "string" ? propertyValue : void 0;
186
137
  }
138
+ /** Parse a response body, preserving non-JSON text for error reporting. */
187
139
  function parseJson(text) {
188
- try {
189
- return JSON.parse(text);
190
- } catch {
191
- return void 0;
192
- }
140
+ try {
141
+ return JSON.parse(text);
142
+ } catch {
143
+ return;
144
+ }
193
145
  }
194
146
 
195
- // src/types/fees.ts
196
- var FEE_TIER = /* @__PURE__ */ ((FEE_TIER2) => {
197
- FEE_TIER2[FEE_TIER2["PERCENT_00_00"] = 0] = "PERCENT_00_00";
198
- FEE_TIER2[FEE_TIER2["PERCENT_00_05"] = 500] = "PERCENT_00_05";
199
- FEE_TIER2[FEE_TIER2["PERCENT_00_30"] = 3e3] = "PERCENT_00_30";
200
- FEE_TIER2[FEE_TIER2["PERCENT_01_00"] = 1e4] = "PERCENT_01_00";
201
- return FEE_TIER2;
202
- })(FEE_TIER || {});
203
- var TICK_SPACING_BY_FEE = {
204
- [0 /* PERCENT_00_00 */]: 200,
205
- [500 /* PERCENT_00_05 */]: 10,
206
- [3e3 /* PERCENT_00_30 */]: 60,
207
- [1e4 /* PERCENT_01_00 */]: 200
147
+ //#endregion
148
+ //#region src/types/fees.ts
149
+ /**
150
+ * Fee tiers for pools.
151
+ */
152
+ let FEE_TIER = /* @__PURE__ */ function(FEE_TIER) {
153
+ /** No trading fee. */
154
+ FEE_TIER[FEE_TIER["PERCENT_00_00"] = 0] = "PERCENT_00_00";
155
+ /** 0.05% fee tier */
156
+ FEE_TIER[FEE_TIER["PERCENT_00_05"] = 500] = "PERCENT_00_05";
157
+ /** 0.3% fee tier */
158
+ FEE_TIER[FEE_TIER["PERCENT_00_30"] = 3e3] = "PERCENT_00_30";
159
+ /** 1.0% fee tier */
160
+ FEE_TIER[FEE_TIER["PERCENT_01_00"] = 1e4] = "PERCENT_01_00";
161
+ return FEE_TIER;
162
+ }({});
163
+ /** Tick spacing required by the current GalaChainDex contract for each fee tier. */
164
+ const TICK_SPACING_BY_FEE = {
165
+ [0]: 200,
166
+ [500]: 10,
167
+ [3e3]: 60,
168
+ [1e4]: 200
208
169
  };
209
- var ALL_FEE_TIERS = [
210
- 0 /* PERCENT_00_00 */,
211
- 500 /* PERCENT_00_05 */,
212
- 3e3 /* PERCENT_00_30 */,
213
- 1e4 /* PERCENT_01_00 */
170
+ /** All fee tiers supported by the current GalaChainDex contract. */
171
+ const ALL_FEE_TIERS = [
172
+ 0,
173
+ 500,
174
+ 3e3,
175
+ 1e4
214
176
  ];
215
177
 
216
- // src/utils/ticks.ts
217
- var import_bignumber = __toESM(require("bignumber.js"), 1);
218
- var import_decimal = require("decimal.js");
219
- var GC_MIN_TICK = -887272;
220
- var GC_MAX_TICK = 887272;
221
- var DexMath = import_bignumber.default.clone({
222
- DECIMAL_PLACES: 60,
223
- ROUNDING_MODE: import_bignumber.default.ROUND_DOWN
178
+ //#endregion
179
+ //#region src/utils/ticks.ts
180
+ /** Minimum tick supported by GalaChainDex. */
181
+ const GC_MIN_TICK = -887272;
182
+ /** Maximum tick supported by GalaChainDex. */
183
+ const GC_MAX_TICK = 887272;
184
+ const DexMath = bignumber_js.default.clone({
185
+ DECIMAL_PLACES: 60,
186
+ ROUNDING_MODE: bignumber_js.default.ROUND_DOWN
224
187
  });
225
- var DexDecimal = import_decimal.Decimal.clone({ precision: 60 });
188
+ const DexDecimal = decimal_js.Decimal.clone({ precision: 60 });
189
+ /** Convert a tick to the corresponding square-root price. */
226
190
  function tickToSqrtPrice(tick) {
227
- return new import_bignumber.default(new DexDecimal(1.0001).pow(tick / 2).toString());
191
+ return new bignumber_js.default(new DexDecimal(1.0001).pow(tick / 2).toString());
228
192
  }
193
+ /** Return the greatest tick whose square-root price is no greater than the input. */
229
194
  function sqrtPriceToTick(sqrtPrice) {
230
- let value;
231
- try {
232
- value = new DexMath(sqrtPrice);
233
- } catch {
234
- return Number.NaN;
235
- }
236
- if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return Number.NaN;
237
- const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);
238
- if (!Number.isFinite(approximate)) return Number.NaN;
239
- let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));
240
- while (tick < GC_MAX_TICK && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;
241
- while (tick > GC_MIN_TICK && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;
242
- return tick;
243
- }
195
+ let value;
196
+ try {
197
+ value = new DexMath(sqrtPrice);
198
+ } catch {
199
+ return NaN;
200
+ }
201
+ if (!value.isFinite() || value.isLessThanOrEqualTo(0)) return NaN;
202
+ const approximate = Math.log(value.toNumber() ** 2) / Math.log(1.0001);
203
+ if (!Number.isFinite(approximate)) return NaN;
204
+ let tick = Math.min(GC_MAX_TICK, Math.max(GC_MIN_TICK, Math.floor(approximate)));
205
+ while (tick < 887272 && tickToSqrtPrice(tick + 1).isLessThanOrEqualTo(value)) tick += 1;
206
+ while (tick > -887272 && tickToSqrtPrice(tick).isGreaterThan(value)) tick -= 1;
207
+ return tick;
208
+ }
209
+ /** Return the greatest integer tick whose token1/token0 price is no greater than `price`. */
244
210
  function tickFromPrice(price) {
245
- const priceText = typeof price === "string" ? price : typeof price === "number" ? price.toString() : import_bignumber.default.isBigNumber(price) ? price.toString() : "NaN";
246
- const value = new DexDecimal(priceText);
247
- if (!value.isFinite() || value.lessThanOrEqualTo(0)) return Number.NaN;
248
- if (!Number.isFinite(value.toNumber())) return Number.NaN;
249
- const tick = value.ln().dividedBy(new DexDecimal(1.0001).ln()).floor().toNumber();
250
- return Number.isFinite(tick) ? tick : Number.NaN;
251
- }
211
+ const priceText = typeof price === "string" ? price : typeof price === "number" ? price.toString() : bignumber_js.default.isBigNumber(price) ? price.toString() : "NaN";
212
+ const value = new DexDecimal(priceText);
213
+ if (!value.isFinite() || value.lessThanOrEqualTo(0)) return NaN;
214
+ if (!Number.isFinite(value.toNumber())) return NaN;
215
+ const tick = value.ln().dividedBy(new DexDecimal(1.0001).ln()).floor().toNumber();
216
+ return Number.isFinite(tick) ? tick : NaN;
217
+ }
218
+ /** Align a tick down to the nearest multiple of a positive spacing. */
252
219
  function alignTickDown(tick, spacing) {
253
- assertSpacing(spacing);
254
- return Math.floor(tick / spacing) * spacing;
220
+ assertSpacing(spacing);
221
+ return Math.floor(tick / spacing) * spacing;
255
222
  }
223
+ /** Align a tick up to the nearest multiple of a positive spacing. */
256
224
  function alignTickUp(tick, spacing) {
257
- assertSpacing(spacing);
258
- return Math.ceil(tick / spacing) * spacing;
225
+ assertSpacing(spacing);
226
+ return Math.ceil(tick / spacing) * spacing;
259
227
  }
228
+ /** Validate a position range against the global tick bounds and fee-tier spacing. */
260
229
  function assertTickRange(lower, upper, fee) {
261
- const spacing = TICK_SPACING_BY_FEE[fee];
262
- if (spacing === void 0) throw new RangeError(`Unsupported fee tier: ${fee}`);
263
- if (!Number.isInteger(lower) || !Number.isInteger(upper)) {
264
- throw new RangeError("Ticks must be integers");
265
- }
266
- if (lower < GC_MIN_TICK || upper > GC_MAX_TICK || lower >= upper) {
267
- throw new RangeError(
268
- `Tick range must satisfy ${GC_MIN_TICK} <= lower < upper <= ${GC_MAX_TICK}`
269
- );
270
- }
271
- if (lower % spacing !== 0 || upper % spacing !== 0) {
272
- throw new RangeError(`Ticks must be aligned to spacing ${spacing}`);
273
- }
230
+ const spacing = TICK_SPACING_BY_FEE[fee];
231
+ if (spacing === void 0) throw new RangeError(`Unsupported fee tier: ${fee}`);
232
+ if (!Number.isInteger(lower) || !Number.isInteger(upper)) throw new RangeError("Ticks must be integers");
233
+ if (lower < -887272 || upper > 887272 || lower >= upper) throw new RangeError(`Tick range must satisfy ${GC_MIN_TICK} <= lower < upper <= ${GC_MAX_TICK}`);
234
+ if (lower % spacing !== 0 || upper % spacing !== 0) throw new RangeError(`Ticks must be aligned to spacing ${spacing}`);
274
235
  }
275
236
  function assertSpacing(spacing) {
276
- if (!Number.isInteger(spacing) || spacing <= 0)
277
- throw new RangeError("Tick spacing must be positive");
237
+ if (!Number.isInteger(spacing) || spacing <= 0) throw new RangeError("Tick spacing must be positive");
278
238
  }
279
239
 
280
- // src/utils/validation.ts
240
+ //#endregion
241
+ //#region src/utils/validation.ts
281
242
  function validateNumericAmount(amount, parameterName, allowZero = false) {
282
- if (typeof amount === "number") {
283
- throw new GSwapSDKError(
284
- `Invalid ${parameterName}: use a decimal string or BigNumber, not a JavaScript number`,
285
- "VALIDATION_ERROR",
286
- { type: "INVALID_NUMERIC_AMOUNT", parameterName, value: amount, reason: "number_input" }
287
- );
288
- }
289
- let bnAmount;
290
- try {
291
- bnAmount = (0, import_bignumber2.default)(amount);
292
- } catch {
293
- bnAmount = (0, import_bignumber2.default)(NaN);
294
- }
295
- if (!bnAmount.isFinite()) {
296
- throw new GSwapSDKError(
297
- `Invalid ${parameterName}: must be a finite number`,
298
- "VALIDATION_ERROR",
299
- {
300
- type: "INVALID_NUMERIC_AMOUNT",
301
- parameterName,
302
- value: amount,
303
- reason: "not_finite"
304
- }
305
- );
306
- }
307
- if (!allowZero && bnAmount.isZero()) {
308
- throw new GSwapSDKError(`Invalid ${parameterName}: must be positive`, "VALIDATION_ERROR", {
309
- type: "INVALID_NUMERIC_AMOUNT",
310
- parameterName,
311
- value: amount,
312
- reason: "zero_not_allowed"
313
- });
314
- }
315
- if (bnAmount.isNegative()) {
316
- throw new GSwapSDKError(
317
- `Invalid ${parameterName}: must be ${allowZero ? "non-negative" : "positive"}`,
318
- "VALIDATION_ERROR",
319
- {
320
- type: "INVALID_NUMERIC_AMOUNT",
321
- parameterName,
322
- value: amount,
323
- reason: "negative"
324
- }
325
- );
326
- }
243
+ if (typeof amount === "number") throw new GSwapSDKError(`Invalid ${parameterName}: use a decimal string or BigNumber, not a JavaScript number`, "VALIDATION_ERROR", {
244
+ type: "INVALID_NUMERIC_AMOUNT",
245
+ parameterName,
246
+ value: amount,
247
+ reason: "number_input"
248
+ });
249
+ let bnAmount;
250
+ try {
251
+ bnAmount = (0, bignumber_js.default)(amount);
252
+ } catch {
253
+ bnAmount = (0, bignumber_js.default)(NaN);
254
+ }
255
+ if (!bnAmount.isFinite()) throw new GSwapSDKError(`Invalid ${parameterName}: must be a finite number`, "VALIDATION_ERROR", {
256
+ type: "INVALID_NUMERIC_AMOUNT",
257
+ parameterName,
258
+ value: amount,
259
+ reason: "not_finite"
260
+ });
261
+ if (!allowZero && bnAmount.isZero()) throw new GSwapSDKError(`Invalid ${parameterName}: must be positive`, "VALIDATION_ERROR", {
262
+ type: "INVALID_NUMERIC_AMOUNT",
263
+ parameterName,
264
+ value: amount,
265
+ reason: "zero_not_allowed"
266
+ });
267
+ if (bnAmount.isNegative()) throw new GSwapSDKError(`Invalid ${parameterName}: must be ${allowZero ? "non-negative" : "positive"}`, "VALIDATION_ERROR", {
268
+ type: "INVALID_NUMERIC_AMOUNT",
269
+ parameterName,
270
+ value: amount,
271
+ reason: "negative"
272
+ });
327
273
  }
328
274
  function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
329
- if ([spotPrice, lowerPrice, upperPrice].some((value) => typeof value === "number")) {
330
- throw new GSwapSDKError(
331
- "Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers",
332
- "VALIDATION_ERROR",
333
- { type: "INVALID_NUMERIC_AMOUNT", reason: "number_input" }
334
- );
335
- }
336
- const parse = (value) => {
337
- try {
338
- return (0, import_bignumber2.default)(value);
339
- } catch {
340
- return (0, import_bignumber2.default)(NaN);
341
- }
342
- };
343
- const bnSpotPrice = parse(spotPrice);
344
- const bnLowerPrice = parse(lowerPrice);
345
- let bnUpperPrice = parse(upperPrice);
346
- bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : (0, import_bignumber2.default)(1e18);
347
- if (!bnSpotPrice.isFinite() || !bnLowerPrice.isFinite() || !bnUpperPrice.isFinite() || !bnSpotPrice.isPositive() || !bnLowerPrice.isPositive() || !bnUpperPrice.isPositive()) {
348
- throw new GSwapSDKError(
349
- "Invalid price values: all prices must be finite and positive",
350
- "VALIDATION_ERROR",
351
- {
352
- type: "INVALID_PRICE_VALUES",
353
- spotPrice,
354
- lowerPrice,
355
- upperPrice
356
- }
357
- );
358
- }
359
- if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {
360
- throw new GSwapSDKError(
361
- "Invalid price range: lower price must be less than or equal to upper price",
362
- "VALIDATION_ERROR",
363
- {
364
- type: "INVALID_PRICE_RANGE",
365
- lowerPrice,
366
- upperPrice
367
- }
368
- );
369
- }
275
+ if ([
276
+ spotPrice,
277
+ lowerPrice,
278
+ upperPrice
279
+ ].some((value) => typeof value === "number")) throw new GSwapSDKError("Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers", "VALIDATION_ERROR", {
280
+ type: "INVALID_NUMERIC_AMOUNT",
281
+ reason: "number_input"
282
+ });
283
+ const parse = (value) => {
284
+ try {
285
+ return (0, bignumber_js.default)(value);
286
+ } catch {
287
+ return (0, bignumber_js.default)(NaN);
288
+ }
289
+ };
290
+ const bnSpotPrice = parse(spotPrice);
291
+ const bnLowerPrice = parse(lowerPrice);
292
+ let bnUpperPrice = parse(upperPrice);
293
+ bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : (0, bignumber_js.default)(0xde0b6b3a7640000);
294
+ if (!bnSpotPrice.isFinite() || !bnLowerPrice.isFinite() || !bnUpperPrice.isFinite() || !bnSpotPrice.isPositive() || !bnLowerPrice.isPositive() || !bnUpperPrice.isPositive()) throw new GSwapSDKError("Invalid price values: all prices must be finite and positive", "VALIDATION_ERROR", {
295
+ type: "INVALID_PRICE_VALUES",
296
+ spotPrice,
297
+ lowerPrice,
298
+ upperPrice
299
+ });
300
+ if (bnLowerPrice.isGreaterThan(bnUpperPrice)) throw new GSwapSDKError("Invalid price range: lower price must be less than or equal to upper price", "VALIDATION_ERROR", {
301
+ type: "INVALID_PRICE_RANGE",
302
+ lowerPrice,
303
+ upperPrice
304
+ });
370
305
  }
371
306
  function validateTokenDecimals(decimals, parameterName) {
372
- if (decimals < 0 || !Number.isInteger(decimals)) {
373
- throw new GSwapSDKError(
374
- `Invalid ${parameterName}: must be a non-negative integer`,
375
- "VALIDATION_ERROR",
376
- {
377
- type: "INVALID_TOKEN_DECIMALS",
378
- parameterName,
379
- value: decimals
380
- }
381
- );
382
- }
307
+ if (decimals < 0 || !Number.isInteger(decimals)) throw new GSwapSDKError(`Invalid ${parameterName}: must be a non-negative integer`, "VALIDATION_ERROR", {
308
+ type: "INVALID_TOKEN_DECIMALS",
309
+ parameterName,
310
+ value: decimals
311
+ });
383
312
  }
384
313
  function validateTickRange(tickLower, tickUpper) {
385
- if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {
386
- throw new GSwapSDKError("Invalid tick values: ticks must be integers", "VALIDATION_ERROR", {
387
- type: "INVALID_TICK_VALUES",
388
- tickLower,
389
- tickUpper
390
- });
391
- }
392
- if (tickLower >= tickUpper) {
393
- throw new GSwapSDKError(
394
- "Invalid tick range: tickLower must be less than tickUpper",
395
- "VALIDATION_ERROR",
396
- {
397
- type: "INVALID_TICK_RANGE",
398
- tickLower,
399
- tickUpper
400
- }
401
- );
402
- }
403
- if (tickLower < GC_MIN_TICK || tickUpper > GC_MAX_TICK) {
404
- throw new GSwapSDKError(
405
- `Invalid tick range: ticks must be between ${GC_MIN_TICK} and ${GC_MAX_TICK}`,
406
- "VALIDATION_ERROR",
407
- {
408
- type: "INVALID_TICK_BOUNDS",
409
- tickLower,
410
- tickUpper,
411
- minTick: GC_MIN_TICK,
412
- maxTick: GC_MAX_TICK
413
- }
414
- );
415
- }
314
+ if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) throw new GSwapSDKError("Invalid tick values: ticks must be integers", "VALIDATION_ERROR", {
315
+ type: "INVALID_TICK_VALUES",
316
+ tickLower,
317
+ tickUpper
318
+ });
319
+ if (tickLower >= tickUpper) throw new GSwapSDKError("Invalid tick range: tickLower must be less than tickUpper", "VALIDATION_ERROR", {
320
+ type: "INVALID_TICK_RANGE",
321
+ tickLower,
322
+ tickUpper
323
+ });
324
+ if (tickLower < -887272 || tickUpper > 887272) throw new GSwapSDKError(`Invalid tick range: ticks must be between ${GC_MIN_TICK} and ${GC_MAX_TICK}`, "VALIDATION_ERROR", {
325
+ type: "INVALID_TICK_BOUNDS",
326
+ tickLower,
327
+ tickUpper,
328
+ minTick: GC_MIN_TICK,
329
+ maxTick: GC_MAX_TICK
330
+ });
416
331
  }
417
332
  function validateFee(fee) {
418
- if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) {
419
- throw new GSwapSDKError(
420
- "Invalid fee tier: must be one of 0, 500, 3000, or 10000",
421
- "VALIDATION_ERROR",
422
- {
423
- type: "INVALID_FEE",
424
- value: fee
425
- }
426
- );
427
- }
333
+ if (!ALL_FEE_TIERS.some((tier) => Number(tier) === fee)) throw new GSwapSDKError("Invalid fee tier: must be one of 0, 500, 3000, or 10000", "VALIDATION_ERROR", {
334
+ type: "INVALID_FEE",
335
+ value: fee
336
+ });
428
337
  }
429
338
  function validateTickSpacing(tickSpacing) {
430
- if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {
431
- throw new GSwapSDKError(
432
- "Invalid tick spacing: must be a positive integer",
433
- "VALIDATION_ERROR",
434
- {
435
- type: "INVALID_TICK_SPACING",
436
- value: tickSpacing
437
- }
438
- );
439
- }
339
+ if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new GSwapSDKError("Invalid tick spacing: must be a positive integer", "VALIDATION_ERROR", {
340
+ type: "INVALID_TICK_SPACING",
341
+ value: tickSpacing
342
+ });
440
343
  }
441
344
  function validateWalletAddress(address) {
442
- if (address === void 0) {
443
- throw new GSwapSDKError(
444
- "Invalid wallet address: No wallet address provided",
445
- "VALIDATION_ERROR",
446
- {
447
- type: "MISSING_WALLET_ADDRESS",
448
- hint: "Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK"
449
- }
450
- );
451
- }
452
- if (!address || typeof address !== "string" || address.trim().length === 0) {
453
- throw new GSwapSDKError(
454
- "Invalid wallet address: must be a non-empty string",
455
- "VALIDATION_ERROR",
456
- {
457
- type: "INVALID_WALLET_ADDRESS",
458
- value: address
459
- }
460
- );
461
- }
345
+ if (address === void 0) throw new GSwapSDKError("Invalid wallet address: No wallet address provided", "VALIDATION_ERROR", {
346
+ type: "MISSING_WALLET_ADDRESS",
347
+ hint: "Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK"
348
+ });
349
+ if (!address || typeof address !== "string" || address.trim().length === 0) throw new GSwapSDKError("Invalid wallet address: must be a non-empty string", "VALIDATION_ERROR", {
350
+ type: "INVALID_WALLET_ADDRESS",
351
+ value: address
352
+ });
462
353
  }
463
354
 
464
- // src/classes/assets.ts
355
+ //#endregion
356
+ //#region src/classes/assets.ts
357
+ /**
358
+ * Service for handling user asset operations.
359
+ * Provides functionality to retrieve user token balances and asset information.
360
+ */
465
361
  var Assets = class {
466
- constructor(dexBackendBaseUrl, httpClient) {
467
- this.dexBackendBaseUrl = dexBackendBaseUrl;
468
- this.httpClient = httpClient;
469
- }
470
- dexBackendBaseUrl;
471
- httpClient;
472
- /**
473
- * Gets all token assets owned by a user with their balances.
474
- * @param ownerAddress - The wallet address to get assets for.
475
- * @param page - Page number for pagination (default: 1).
476
- * @param limit - Maximum number of assets to return per page (default: 10).
477
- * @returns User assets including token information and balances.
478
- * @example
479
- * ```typescript
480
- * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);
481
- * console.log(`User has ${assets.count} different tokens`);
482
- * assets.tokens.forEach(token => {
483
- * console.log(`${token.symbol}: ${token.quantity}`);
484
- * });
485
- * ```
486
- */
487
- async getUserAssets(ownerAddress, page = 1, limit = 10) {
488
- validateWalletAddress(ownerAddress);
489
- if (!Number.isInteger(page) || page < 1) {
490
- throw new GSwapSDKError("Invalid page: must be a positive integer", "VALIDATION_ERROR", {
491
- page
492
- });
493
- }
494
- if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
495
- throw new GSwapSDKError(
496
- "Invalid limit: must be an integer between 1 and 100",
497
- "VALIDATION_ERROR",
498
- { limit }
499
- );
500
- }
501
- const json = await this.httpClient.sendGetRequest(
502
- this.dexBackendBaseUrl,
503
- "/user/assets",
504
- "",
505
- { address: ownerAddress, page: page.toString(), limit: limit.toString() }
506
- );
507
- return parseUserAssets(json);
508
- }
362
+ dexBackendBaseUrl;
363
+ httpClient;
364
+ constructor(dexBackendBaseUrl, httpClient) {
365
+ this.dexBackendBaseUrl = dexBackendBaseUrl;
366
+ this.httpClient = httpClient;
367
+ }
368
+ /**
369
+ * Gets all token assets owned by a user with their balances.
370
+ * @param ownerAddress - The wallet address to get assets for.
371
+ * @param page - Page number for pagination (default: 1).
372
+ * @param limit - Maximum number of assets to return per page (default: 10).
373
+ * @returns User assets including token information and balances.
374
+ * @example
375
+ * ```typescript
376
+ * const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);
377
+ * console.log(`User has ${assets.count} different tokens`);
378
+ * assets.tokens.forEach(token => {
379
+ * console.log(`${token.symbol}: ${token.quantity}`);
380
+ * });
381
+ * ```
382
+ */
383
+ async getUserAssets(ownerAddress, page = 1, limit = 10) {
384
+ validateWalletAddress(ownerAddress);
385
+ if (!Number.isInteger(page) || page < 1) throw new GSwapSDKError("Invalid page: must be a positive integer", "VALIDATION_ERROR", { page });
386
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw new GSwapSDKError("Invalid limit: must be an integer between 1 and 100", "VALIDATION_ERROR", { limit });
387
+ return parseUserAssets(await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/user/assets", "", {
388
+ address: ownerAddress,
389
+ page: page.toString(),
390
+ limit: limit.toString()
391
+ }));
392
+ }
509
393
  };
510
394
  function parseUserAssets(value) {
511
- const data = getObjectProperty(value, "data");
512
- const tokens = data == null ? void 0 : data["token"];
513
- if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) {
514
- throw new GSwapSDKError(
515
- "Backend returned an invalid user assets response.",
516
- "INVALID_CHAIN_RESPONSE",
517
- {
518
- data: value
519
- }
520
- );
521
- }
522
- const count = data == null ? void 0 : data["count"];
523
- return {
524
- tokens: tokens.map((token) => ({ ...token, decimals: parseInt(token.decimals, 10) })),
525
- count: typeof count === "number" ? count : 0
526
- };
395
+ const data = getObjectProperty(value, "data");
396
+ const tokens = data === null || data === void 0 ? void 0 : data["token"];
397
+ if (!Array.isArray(tokens) || !tokens.every(isRawUserAsset)) throw new GSwapSDKError("Backend returned an invalid user assets response.", "INVALID_CHAIN_RESPONSE", { data: value });
398
+ const count = data === null || data === void 0 ? void 0 : data["count"];
399
+ return {
400
+ tokens: tokens.map((token) => ({
401
+ ...token,
402
+ decimals: parseInt(token.decimals, 10)
403
+ })),
404
+ count: typeof count === "number" ? count : 0
405
+ };
527
406
  }
528
407
  function isRawUserAsset(value) {
529
- if (typeof value !== "object" || value === null) return false;
530
- const entry = value;
531
- 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";
408
+ if (typeof value !== "object" || value === null) return false;
409
+ const entry = value;
410
+ 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";
532
411
  }
533
412
 
534
- // src/utils/transport.ts
413
+ //#endregion
414
+ //#region src/utils/transport.ts
535
415
  async function requestWithTimeout(requestor, url, options, timeoutMs) {
536
- const controller = new AbortController();
537
- const timer = setTimeout(() => controller.abort(), timeoutMs);
538
- const externalSignal = options.signal;
539
- const abortFromCaller = () => controller.abort();
540
- externalSignal == null ? void 0 : externalSignal.addEventListener("abort", abortFromCaller, { once: true });
541
- try {
542
- return await requestor(url, { ...options, signal: controller.signal });
543
- } catch (error) {
544
- if (controller.signal.aborted) {
545
- throw new GSwapSDKError(`Request timed out after ${timeoutMs} ms.`, "REQUEST_TIMEOUT", {
546
- url,
547
- timeoutMs,
548
- cause: error
549
- });
550
- }
551
- throw error;
552
- } finally {
553
- clearTimeout(timer);
554
- externalSignal == null ? void 0 : externalSignal.removeEventListener("abort", abortFromCaller);
555
- }
416
+ const controller = new AbortController();
417
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
418
+ const externalSignal = options.signal;
419
+ const abortFromCaller = () => controller.abort();
420
+ externalSignal === null || externalSignal === void 0 || externalSignal.addEventListener("abort", abortFromCaller, { once: true });
421
+ try {
422
+ return await requestor(url, {
423
+ ...options,
424
+ signal: controller.signal
425
+ });
426
+ } catch (error) {
427
+ if (controller.signal.aborted) throw new GSwapSDKError(`Request timed out after ${timeoutMs} ms.`, "REQUEST_TIMEOUT", {
428
+ url,
429
+ timeoutMs,
430
+ cause: error
431
+ });
432
+ throw error;
433
+ } finally {
434
+ clearTimeout(timer);
435
+ externalSignal === null || externalSignal === void 0 || externalSignal.removeEventListener("abort", abortFromCaller);
436
+ }
556
437
  }
557
438
  async function readResponseBody(response) {
558
- const text = await response.text();
559
- return parseJson(text) ?? text;
439
+ const text = await response.text();
440
+ return parseJson(text) ?? text;
560
441
  }
442
+ /** Read a case-insensitive response header from either supported header shape. */
561
443
  function readHeader(response, name) {
562
- var _a;
563
- const headers = response.headers;
564
- if (headers === void 0) return void 0;
565
- if (hasHeaderGetter(headers)) {
566
- const value2 = headers.get(name);
567
- return value2 === null || value2 === "" ? void 0 : value2;
568
- }
569
- const value = (_a = Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())) == null ? void 0 : _a[1];
570
- return value === void 0 || value === "" ? void 0 : value;
571
- }
444
+ var _Object$entries$find;
445
+ const headers = response.headers;
446
+ if (headers === void 0) return void 0;
447
+ if (hasHeaderGetter(headers)) {
448
+ const value = headers.get(name);
449
+ return value === null || value === "" ? void 0 : value;
450
+ }
451
+ 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];
452
+ return value === void 0 || value === "" ? void 0 : value;
453
+ }
454
+ /** Read a non-negative Retry-After header as milliseconds. */
572
455
  function readRetryAfter(response) {
573
- const raw = readHeader(response, "retry-after");
574
- if (raw === void 0) return void 0;
575
- const seconds = Number(raw);
576
- return Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : void 0;
456
+ const raw = readHeader(response, "retry-after");
457
+ if (raw === void 0) return void 0;
458
+ const seconds = Number(raw);
459
+ return Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : void 0;
577
460
  }
461
+ /** Read a non-negative integer block number header. */
578
462
  function readBlockNumberHeader(response, headerName = "x-block-number") {
579
- const raw = readHeader(response, headerName);
580
- if (raw === void 0) return void 0;
581
- const blockNumber = Number(raw);
582
- return Number.isInteger(blockNumber) && blockNumber >= 0 ? blockNumber : void 0;
463
+ const raw = readHeader(response, headerName);
464
+ if (raw === void 0) return void 0;
465
+ const blockNumber = Number(raw);
466
+ return Number.isInteger(blockNumber) && blockNumber >= 0 ? blockNumber : void 0;
583
467
  }
584
468
  function hasHeaderGetter(headers) {
585
- return "get" in headers && typeof headers.get === "function";
469
+ return "get" in headers && typeof headers.get === "function";
586
470
  }
587
471
 
588
- // src/classes/submitted_transaction.ts
472
+ //#endregion
473
+ //#region src/classes/submitted_transaction.ts
474
+ /** A submitted v2 transaction whose confirmation mode is explicit in the gateway response. */
589
475
  var SubmittedTransaction = class {
590
- method;
591
- uniqueKey;
592
- transactionId;
593
- blockNumber;
594
- mode;
595
- /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */
596
- result;
597
- backendBaseUrl;
598
- requestor;
599
- requestTimeoutMs;
600
- positionConfirmation;
601
- /** Construct a submitted transaction from a successful gateway response.
602
- *
603
- * @example
604
- * ```ts
605
- * const transaction = new SubmittedTransaction({
606
- * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',
607
- * transactionId: 'request-tx', result: undefined,
608
- * dexBackendBaseUrl: 'https://dex.example', httpRequestor,
609
- * });
610
- * ```
611
- */
612
- constructor(options) {
613
- this.method = options.method;
614
- this.uniqueKey = options.uniqueKey;
615
- this.transactionId = options.transactionId;
616
- this.blockNumber = options.blockNumber ?? null;
617
- this.mode = options.mode;
618
- this.result = options.result;
619
- this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\/$/u, "");
620
- this.requestor = options.httpRequestor;
621
- this.requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
622
- this.positionConfirmation = options.positionConfirmation;
623
- }
624
- /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.
625
- *
626
- * For RequestTrade, calling this method is required to learn the outcome: the queued
627
- * acknowledgement proves acceptance, not execution.
628
- *
629
- * @example
630
- * ```ts
631
- * const applied = await submitted.confirm({ initialDelayMs: 3_000 });
632
- * ```
633
- */
634
- async confirm(options) {
635
- if (this.method === "RequestTrade") {
636
- return this.confirmApplied(options);
637
- }
638
- return this.confirmPosition(options);
639
- }
640
- async confirmApplied(options) {
641
- const schedule = createConfirmationSchedule(options, 3e3);
642
- await schedule.waitForRead();
643
- const url = `${this.backendBaseUrl}/v1/chain/apply-results/${encodeURIComponent(this.uniqueKey)}?channel=asset&contract=dex-contract`;
644
- let lastError;
645
- while (true) {
646
- let response;
647
- let body;
648
- try {
649
- response = await requestWithTimeout(
650
- this.requestor,
651
- url,
652
- { method: "GET" },
653
- this.requestTimeoutMs
654
- );
655
- body = await readResponseBody(response);
656
- } catch (error) {
657
- lastError = error;
658
- if (!await schedule.waitForRead()) break;
659
- continue;
660
- }
661
- if (response.status === 200) {
662
- return this.readAppliedResult(response, body, url);
663
- }
664
- if (response.status === 404 || response.status === 429 || isTransient(response.status)) {
665
- if (response.status === 429) {
666
- const retryAfter = readRetryAfter(response);
667
- if (retryAfter !== void 0) {
668
- if (!await schedule.waitForRead(retryAfter)) break;
669
- continue;
670
- }
671
- }
672
- } else {
673
- throw new GSwapSDKError(bodyMessage(body), "CONFIRMATION_FAILED", {
674
- status: response.status,
675
- body,
676
- url
677
- });
678
- }
679
- if (!await schedule.waitForRead()) break;
680
- }
681
- throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);
682
- }
683
- readAppliedResult(response, body, url) {
684
- const record = asRecord(body);
685
- const status = record == null ? void 0 : record["Status"];
686
- const applyTransactionId = readHeader(response, "x-apply-transaction-id") ?? null;
687
- const blockNumber = readBlockNumberHeader(response, "x-apply-block-number") ?? null;
688
- if (status === 0) {
689
- throw GSwapSDKError.fromChainError(
690
- getStringProperty(record, "ErrorKey") ?? "CHAIN_ERROR",
691
- getStringProperty(record, "Message") ?? "The chain rejected this trade.",
692
- {
693
- uniqueKey: this.uniqueKey,
694
- applyTransactionId,
695
- blockNumber,
696
- status: response.status,
697
- body,
698
- url
699
- }
700
- );
701
- }
702
- if (status !== 1) throw malformedConfirmation(response, body, url);
703
- const result = parseTradeExecution(record == null ? void 0 : record["Data"]);
704
- if (result === void 0) throw malformedConfirmation(response, body, url);
705
- return {
706
- uniqueKey: this.uniqueKey,
707
- transactionId: applyTransactionId,
708
- blockNumber,
709
- requestTransactionId: this.transactionId,
710
- result
711
- };
712
- }
713
- /** Confirm a liquidity write against the position's observable effect.
714
- *
715
- * @returns The position after the write, or `null` for a confirmed full close.
716
- * @example
717
- * ```ts
718
- * const position = await submitted.confirm({ timeoutMs: 60_000 });
719
- * ```
720
- */
721
- async confirmPosition(options) {
722
- if (this.positionConfirmation === void 0) throw GSwapSDKError.noWalletAddressError();
723
- const schedule = createConfirmationSchedule(options, 0);
724
- await schedule.waitForRead();
725
- while (true) {
726
- const controller = new AbortController();
727
- const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
728
- try {
729
- const result = await this.positionConfirmation(controller.signal);
730
- if (result.confirmed) return result.position;
731
- } finally {
732
- clearTimeout(timer);
733
- }
734
- if (!await schedule.waitForRead()) break;
735
- }
736
- throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey);
737
- }
476
+ method;
477
+ uniqueKey;
478
+ transactionId;
479
+ blockNumber;
480
+ mode;
481
+ /** The synchronous gateway result, or `undefined` when `mode === 'queued'`. */
482
+ result;
483
+ backendBaseUrl;
484
+ requestor;
485
+ requestTimeoutMs;
486
+ positionConfirmation;
487
+ /** Construct a submitted transaction from a successful gateway response.
488
+ *
489
+ * @example
490
+ * ```ts
491
+ * const transaction = new SubmittedTransaction({
492
+ * method: 'RequestTrade', mode: 'queued', uniqueKey: 'swap-1',
493
+ * transactionId: 'request-tx', result: undefined,
494
+ * dexBackendBaseUrl: 'https://dex.example', httpRequestor,
495
+ * });
496
+ * ```
497
+ */
498
+ constructor(options) {
499
+ this.method = options.method;
500
+ this.uniqueKey = options.uniqueKey;
501
+ this.transactionId = options.transactionId;
502
+ this.blockNumber = options.blockNumber ?? null;
503
+ this.mode = options.mode;
504
+ this.result = options.result;
505
+ this.backendBaseUrl = options.dexBackendBaseUrl.replace(/\/$/u, "");
506
+ this.requestor = options.httpRequestor;
507
+ this.requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
508
+ this.positionConfirmation = options.positionConfirmation;
509
+ }
510
+ /** Confirm a queued RequestTrade or prove the affected position for a liquidity write.
511
+ *
512
+ * For RequestTrade, calling this method is required to learn the outcome: the queued
513
+ * acknowledgement proves acceptance, not execution.
514
+ *
515
+ * @example
516
+ * ```ts
517
+ * const applied = await submitted.confirm({ initialDelayMs: 3_000 });
518
+ * ```
519
+ */
520
+ async confirm(options) {
521
+ if (this.method === "RequestTrade") return this.confirmApplied(options);
522
+ return this.confirmPosition(options);
523
+ }
524
+ async confirmApplied(options) {
525
+ const schedule = createConfirmationSchedule(options, 3e3);
526
+ await schedule.waitForRead();
527
+ const url = `${this.backendBaseUrl}/v1/chain/apply-results/${encodeURIComponent(this.uniqueKey)}?channel=asset&contract=dex-contract`;
528
+ let lastError;
529
+ while (true) {
530
+ let response;
531
+ let body;
532
+ try {
533
+ response = await requestWithTimeout(this.requestor, url, { method: "GET" }, this.requestTimeoutMs);
534
+ body = await readResponseBody(response);
535
+ } catch (error) {
536
+ lastError = error;
537
+ if (!await schedule.waitForRead()) break;
538
+ continue;
539
+ }
540
+ if (response.status === 200) return this.readAppliedResult(response, body, url);
541
+ if (response.status === 404 || response.status === 429 || isTransient(response.status)) {
542
+ if (response.status === 429) {
543
+ const retryAfter = readRetryAfter(response);
544
+ if (retryAfter !== void 0) {
545
+ if (!await schedule.waitForRead(retryAfter)) break;
546
+ continue;
547
+ }
548
+ }
549
+ } else throw new GSwapSDKError(bodyMessage(body), "CONFIRMATION_FAILED", {
550
+ status: response.status,
551
+ body,
552
+ url
553
+ });
554
+ if (!await schedule.waitForRead()) break;
555
+ }
556
+ throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey, lastError);
557
+ }
558
+ readAppliedResult(response, body, url) {
559
+ const record = asRecord$1(body);
560
+ const status = record === null || record === void 0 ? void 0 : record["Status"];
561
+ const applyTransactionId = readHeader(response, "x-apply-transaction-id") ?? null;
562
+ const blockNumber = readBlockNumberHeader(response, "x-apply-block-number") ?? null;
563
+ if (status === 0) throw GSwapSDKError.fromChainError(getStringProperty(record, "ErrorKey") ?? "CHAIN_ERROR", getStringProperty(record, "Message") ?? "The chain rejected this trade.", {
564
+ uniqueKey: this.uniqueKey,
565
+ applyTransactionId,
566
+ blockNumber,
567
+ status: response.status,
568
+ body,
569
+ url
570
+ });
571
+ if (status !== 1) throw malformedConfirmation(response, body, url);
572
+ const result = parseTradeExecution(record === null || record === void 0 ? void 0 : record["Data"]);
573
+ if (result === void 0) throw malformedConfirmation(response, body, url);
574
+ return {
575
+ uniqueKey: this.uniqueKey,
576
+ transactionId: applyTransactionId,
577
+ blockNumber,
578
+ requestTransactionId: this.transactionId,
579
+ result
580
+ };
581
+ }
582
+ /** Confirm a liquidity write against the position's observable effect.
583
+ *
584
+ * @returns The position after the write, or `null` for a confirmed full close.
585
+ * @example
586
+ * ```ts
587
+ * const position = await submitted.confirm({ timeoutMs: 60_000 });
588
+ * ```
589
+ */
590
+ async confirmPosition(options) {
591
+ if (this.positionConfirmation === void 0) throw GSwapSDKError.noWalletAddressError();
592
+ const schedule = createConfirmationSchedule(options, 0);
593
+ await schedule.waitForRead();
594
+ while (true) {
595
+ const controller = new AbortController();
596
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
597
+ try {
598
+ const result = await this.positionConfirmation(controller.signal);
599
+ if (result.confirmed) return result.position;
600
+ } finally {
601
+ clearTimeout(timer);
602
+ }
603
+ if (!await schedule.waitForRead()) break;
604
+ }
605
+ throw GSwapSDKError.confirmationTimeoutError(this.uniqueKey);
606
+ }
738
607
  };
739
608
  function createConfirmationSchedule(options, defaultInitialDelayMs) {
740
- const timeoutMs = Math.max(0, (options == null ? void 0 : options.timeoutMs) ?? 6e4);
741
- const pollIntervalMs = Math.max(500, (options == null ? void 0 : options.pollIntervalMs) ?? 2e3);
742
- const initialDelayMs = Math.max(0, (options == null ? void 0 : options.initialDelayMs) ?? defaultInitialDelayMs);
743
- const deadline = Date.now() + timeoutMs;
744
- let firstRead = true;
745
- let attempt = 0;
746
- return {
747
- async waitForRead(retryAfterMs) {
748
- if (firstRead) {
749
- firstRead = false;
750
- const remaining = Math.max(0, deadline - Date.now());
751
- await delay(Math.min(initialDelayMs, remaining));
752
- return true;
753
- }
754
- const backoff = Math.min(8e3, pollIntervalMs * 2 ** Math.min(attempt, 5));
755
- attempt += 1;
756
- const waitMs = retryAfterMs === void 0 ? jitter(backoff) : retryAfterMs;
757
- if (Date.now() + waitMs > deadline) return false;
758
- await delay(waitMs);
759
- return true;
760
- }
761
- };
609
+ const timeoutMs = Math.max(0, (options === null || options === void 0 ? void 0 : options.timeoutMs) ?? 6e4);
610
+ const pollIntervalMs = Math.max(500, (options === null || options === void 0 ? void 0 : options.pollIntervalMs) ?? 2e3);
611
+ const initialDelayMs = Math.max(0, (options === null || options === void 0 ? void 0 : options.initialDelayMs) ?? defaultInitialDelayMs);
612
+ const deadline = Date.now() + timeoutMs;
613
+ let firstRead = true;
614
+ let attempt = 0;
615
+ return { async waitForRead(retryAfterMs) {
616
+ if (firstRead) {
617
+ firstRead = false;
618
+ const remaining = Math.max(0, deadline - Date.now());
619
+ await delay(Math.min(initialDelayMs, remaining));
620
+ return true;
621
+ }
622
+ const backoff = Math.min(8e3, pollIntervalMs * 2 ** Math.min(attempt, 5));
623
+ attempt += 1;
624
+ const waitMs = retryAfterMs === void 0 ? jitter(backoff) : retryAfterMs;
625
+ if (Date.now() + waitMs > deadline) return false;
626
+ await delay(waitMs);
627
+ return true;
628
+ } };
762
629
  }
763
630
  function parseTradeExecution(value) {
764
- const record = asRecord(value);
765
- if (record === void 0 || typeof record["token0"] !== "string" || typeof record["token1"] !== "string" || typeof record["fee"] !== "number") {
766
- return void 0;
767
- }
768
- const optionalFields = [
769
- "sell0Qty",
770
- "sell1Qty",
771
- "buy0Qty",
772
- "buy1Qty",
773
- "tradingFees",
774
- "protocolFees",
775
- "totalFees"
776
- ];
777
- for (const field of optionalFields) {
778
- if (field in record && typeof record[field] !== "string") return void 0;
779
- }
780
- return {
781
- token0: record["token0"],
782
- token1: record["token1"],
783
- fee: record["fee"],
784
- ...Object.fromEntries(
785
- optionalFields.flatMap(
786
- (field) => typeof record[field] === "string" ? [[field, record[field]]] : []
787
- )
788
- )
789
- };
631
+ const record = asRecord$1(value);
632
+ if (record === void 0 || typeof record["token0"] !== "string" || typeof record["token1"] !== "string" || typeof record["fee"] !== "number") return;
633
+ const optionalFields = [
634
+ "sell0Qty",
635
+ "sell1Qty",
636
+ "buy0Qty",
637
+ "buy1Qty",
638
+ "tradingFees",
639
+ "protocolFees",
640
+ "totalFees"
641
+ ];
642
+ for (const field of optionalFields) if (field in record && typeof record[field] !== "string") return void 0;
643
+ return {
644
+ token0: record["token0"],
645
+ token1: record["token1"],
646
+ fee: record["fee"],
647
+ ...Object.fromEntries(optionalFields.flatMap((field) => typeof record[field] === "string" ? [[field, record[field]]] : []))
648
+ };
790
649
  }
791
650
  function malformedConfirmation(response, body, url) {
792
- return new GSwapSDKError(
793
- "Transaction confirmation returned a malformed body",
794
- "CONFIRMATION_FAILED",
795
- { status: response.status, body, url }
796
- );
651
+ return new GSwapSDKError("Transaction confirmation returned a malformed body", "CONFIRMATION_FAILED", {
652
+ status: response.status,
653
+ body,
654
+ url
655
+ });
797
656
  }
798
657
  function isTransient(status) {
799
- return status === 500 || status === 502 || status === 503 || status === 504;
658
+ return status === 500 || status === 502 || status === 503 || status === 504;
800
659
  }
801
660
  function bodyMessage(body) {
802
- return getStringProperty(body, "message") ?? getStringProperty(body, "Message") ?? getStringProperty(getObjectProperty(body, "error"), "message") ?? getStringProperty(getObjectProperty(body, "error"), "Message") ?? (typeof body === "string" ? body : "Transaction confirmation failed");
661
+ return getStringProperty(body, "message") ?? getStringProperty(body, "Message") ?? getStringProperty(getObjectProperty(body, "error"), "message") ?? getStringProperty(getObjectProperty(body, "error"), "Message") ?? (typeof body === "string" ? body : "Transaction confirmation failed");
803
662
  }
804
- function asRecord(value) {
805
- return typeof value === "object" && value !== null ? value : void 0;
663
+ function asRecord$1(value) {
664
+ return typeof value === "object" && value !== null ? value : void 0;
806
665
  }
807
666
  function delay(milliseconds) {
808
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
667
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
809
668
  }
810
669
  function jitter(milliseconds) {
811
- return Math.max(0, Math.round(milliseconds * (0.9 + Math.random() * 0.2)));
670
+ return Math.max(0, Math.round(milliseconds * (.9 + Math.random() * .2)));
812
671
  }
813
672
 
814
- // src/classes/gateway.ts
673
+ //#endregion
674
+ //#region src/classes/gateway.ts
675
+ /** Thin client for backend-routed v2 writes: synchronous liquidity writes and queued RequestTrade. */
815
676
  var ChainGateway = class {
816
- requestor;
817
- walletAddress;
818
- chainCallTimeoutMs;
819
- requestTimeoutMs;
820
- dexBackendBaseUrl;
821
- /** Create a chain gateway client. */
822
- constructor(options) {
823
- this.dexBackendBaseUrl = trimTrailingSlash(options.dexBackendBaseUrl);
824
- this.requestor = options.httpRequestor ?? fetch.bind(globalThis);
825
- this.walletAddress = options.walletAddress;
826
- this.chainCallTimeoutMs = options.chainCallTimeoutMs ?? 3e4;
827
- this.requestTimeoutMs = this.chainCallTimeoutMs;
828
- }
829
- async submit(method, signedBody, options) {
830
- if (method === "Trade") {
831
- throw new GSwapSDKError(
832
- "The synchronous Trade method was removed; swaps are queued through RequestTrade.",
833
- "METHOD_NOT_SUPPORTED",
834
- { method }
835
- );
836
- }
837
- const url = `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;
838
- const headers = { "content-type": "application/json" };
839
- const walletAddress = (options == null ? void 0 : options.walletAddress) ?? this.walletAddress;
840
- if (walletAddress !== void 0) headers["X-Wallet-Address"] = walletAddress;
841
- let response;
842
- try {
843
- response = await requestWithTimeout(
844
- this.requestor,
845
- url,
846
- {
847
- method: "POST",
848
- headers,
849
- body: JSON.stringify(signedBody)
850
- },
851
- this.chainCallTimeoutMs
852
- );
853
- } catch (error) {
854
- if (error instanceof GSwapSDKError && error.code === "REQUEST_TIMEOUT") {
855
- throw new GSwapSDKError(
856
- "The submission outcome is unknown because the gateway request timed out. Confirm before retrying.",
857
- "SUBMISSION_OUTCOME_UNKNOWN",
858
- { uniqueKey: getStringProperty(signedBody, "uniqueKey") ?? "", cause: error }
859
- );
860
- }
861
- throw error;
862
- }
863
- const body = await readResponseBody(response);
864
- if (!response.ok) {
865
- throw gatewayError(response, body, url);
866
- }
867
- const envelope = asRecord2(body);
868
- const data = asRecord2((envelope == null ? void 0 : envelope["data"]) ?? (envelope == null ? void 0 : envelope["Data"]));
869
- if (data === void 0) {
870
- throw invalidGatewayResponse(response, body, url, "Expected a data object.");
871
- }
872
- const transactionId = getStringProperty(data, "transactionId");
873
- const mode = getStringProperty(data, "mode");
874
- const rawTransactionId = data["transactionId"];
875
- const bodyBlockNumber = data["blockNumber"];
876
- const invalidModeMessage = 'Gateway response must contain data.mode="sync" with data.result, or data.mode="queued".';
877
- if (mode !== "sync" && mode !== "queued") {
878
- throw invalidGatewayResponse(response, body, url, invalidModeMessage);
879
- }
880
- if ("transactionId" in data && typeof rawTransactionId !== "string" || bodyBlockNumber !== void 0 && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber)) {
881
- throw invalidGatewayResponse(response, body, url, invalidModeMessage);
882
- }
883
- if (method === "RequestTrade" && mode === "sync") {
884
- throw invalidGatewayResponse(
885
- response,
886
- body,
887
- url,
888
- "The gateway executed RequestTrade synchronously, which this SDK refuses; RequestTrade must be queued."
889
- );
890
- }
891
- if (method === "RequestTrade" && mode === "queued") {
892
- const signedUniqueKey = getStringProperty(signedBody, "uniqueKey");
893
- if ("uniqueKey" in data && (typeof data["uniqueKey"] !== "string" || data["uniqueKey"] !== signedUniqueKey)) {
894
- throw invalidGatewayResponse(
895
- response,
896
- body,
897
- url,
898
- "Gateway response data.uniqueKey must match the signed RequestTrade uniqueKey."
899
- );
900
- }
901
- } else if (mode === "queued" || !("result" in data)) {
902
- throw invalidGatewayResponse(response, body, url, invalidModeMessage);
903
- }
904
- if (mode === "sync") {
905
- const embeddedResult = asRecord2(data["result"]);
906
- if (embeddedResult !== void 0) {
907
- const resultStatus = embeddedResult["Status"];
908
- if (resultStatus !== void 0 && resultStatus !== 1) {
909
- throw GSwapSDKError.fromChainError(
910
- getStringProperty(embeddedResult, "ErrorKey") ?? "CHAIN_ERROR",
911
- getStringProperty(embeddedResult, "Message") ?? "The chain rejected this write.",
912
- { status: response.status, body, url }
913
- );
914
- }
915
- }
916
- }
917
- const uniqueKey = getStringProperty(signedBody, "uniqueKey") ?? "";
918
- const headerTransactionId = readHeader(response, "x-transaction-id");
919
- const resolvedTransactionId = transactionId === void 0 || transactionId === "" ? headerTransactionId : transactionId;
920
- const blockNumber = bodyBlockNumber === null || bodyBlockNumber === void 0 ? readBlockNumberHeader(response) : isBlockNumber(bodyBlockNumber) ? bodyBlockNumber : void 0;
921
- return new SubmittedTransaction({
922
- method,
923
- uniqueKey,
924
- transactionId: resolvedTransactionId === void 0 || resolvedTransactionId === "" ? null : resolvedTransactionId,
925
- blockNumber: blockNumber ?? null,
926
- mode,
927
- result: mode === "queued" ? void 0 : data["result"],
928
- dexBackendBaseUrl: this.dexBackendBaseUrl,
929
- httpRequestor: this.requestor,
930
- requestTimeoutMs: this.chainCallTimeoutMs,
931
- ...(options == null ? void 0 : options.positionConfirmation) === void 0 ? {} : { positionConfirmation: options.positionConfirmation }
932
- });
933
- }
934
- /** Expose the requestor for sibling read services that share this gateway transport. */
935
- get httpRequestor() {
936
- return this.requestor;
937
- }
677
+ requestor;
678
+ walletAddress;
679
+ chainCallTimeoutMs;
680
+ requestTimeoutMs;
681
+ dexBackendBaseUrl;
682
+ /** Create a chain gateway client. */
683
+ constructor(options) {
684
+ this.dexBackendBaseUrl = trimTrailingSlash$1(options.dexBackendBaseUrl);
685
+ this.requestor = options.httpRequestor ?? fetch.bind(globalThis);
686
+ this.walletAddress = options.walletAddress;
687
+ this.chainCallTimeoutMs = options.chainCallTimeoutMs ?? 3e4;
688
+ this.requestTimeoutMs = this.chainCallTimeoutMs;
689
+ }
690
+ async submit(method, signedBody, options) {
691
+ if (method === "Trade") throw new GSwapSDKError("The synchronous Trade method was removed; swaps are queued through RequestTrade.", "METHOD_NOT_SUPPORTED", { method });
692
+ const url = `${this.dexBackendBaseUrl}/v1/chain/asset/dex-contract/${method}`;
693
+ const headers = { "content-type": "application/json" };
694
+ const walletAddress = (options === null || options === void 0 ? void 0 : options.walletAddress) ?? this.walletAddress;
695
+ if (walletAddress !== void 0) headers["X-Wallet-Address"] = walletAddress;
696
+ let response;
697
+ try {
698
+ response = await requestWithTimeout(this.requestor, url, {
699
+ method: "POST",
700
+ headers,
701
+ body: JSON.stringify(signedBody)
702
+ }, this.chainCallTimeoutMs);
703
+ } catch (error) {
704
+ if (error instanceof GSwapSDKError && error.code === "REQUEST_TIMEOUT") throw new GSwapSDKError("The submission outcome is unknown because the gateway request timed out. Confirm before retrying.", "SUBMISSION_OUTCOME_UNKNOWN", {
705
+ uniqueKey: getStringProperty(signedBody, "uniqueKey") ?? "",
706
+ cause: error
707
+ });
708
+ throw error;
709
+ }
710
+ const body = await readResponseBody(response);
711
+ if (!response.ok) throw gatewayError(response, body, url);
712
+ const envelope = asRecord(body);
713
+ const data = asRecord((envelope === null || envelope === void 0 ? void 0 : envelope["data"]) ?? (envelope === null || envelope === void 0 ? void 0 : envelope["Data"]));
714
+ if (data === void 0) throw invalidGatewayResponse(response, body, url, "Expected a data object.");
715
+ const transactionId = getStringProperty(data, "transactionId");
716
+ const mode = getStringProperty(data, "mode");
717
+ const rawTransactionId = data["transactionId"];
718
+ const bodyBlockNumber = data["blockNumber"];
719
+ const invalidModeMessage = "Gateway response must contain data.mode=\"sync\" with data.result, or data.mode=\"queued\".";
720
+ if (mode !== "sync" && mode !== "queued") throw invalidGatewayResponse(response, body, url, invalidModeMessage);
721
+ if ("transactionId" in data && typeof rawTransactionId !== "string" || bodyBlockNumber !== void 0 && bodyBlockNumber !== null && !isBlockNumber(bodyBlockNumber)) throw invalidGatewayResponse(response, body, url, invalidModeMessage);
722
+ if (method === "RequestTrade" && mode === "sync") throw invalidGatewayResponse(response, body, url, "The gateway executed RequestTrade synchronously, which this SDK refuses; RequestTrade must be queued.");
723
+ if (method === "RequestTrade" && mode === "queued") {
724
+ const signedUniqueKey = getStringProperty(signedBody, "uniqueKey");
725
+ if ("uniqueKey" in data && (typeof data["uniqueKey"] !== "string" || data["uniqueKey"] !== signedUniqueKey)) throw invalidGatewayResponse(response, body, url, "Gateway response data.uniqueKey must match the signed RequestTrade uniqueKey.");
726
+ } else if (mode === "queued" || !("result" in data)) throw invalidGatewayResponse(response, body, url, invalidModeMessage);
727
+ if (mode === "sync") {
728
+ const embeddedResult = asRecord(data["result"]);
729
+ if (embeddedResult !== void 0) {
730
+ const resultStatus = embeddedResult["Status"];
731
+ if (resultStatus !== void 0 && resultStatus !== 1) throw GSwapSDKError.fromChainError(getStringProperty(embeddedResult, "ErrorKey") ?? "CHAIN_ERROR", getStringProperty(embeddedResult, "Message") ?? "The chain rejected this write.", {
732
+ status: response.status,
733
+ body,
734
+ url
735
+ });
736
+ }
737
+ }
738
+ const uniqueKey = getStringProperty(signedBody, "uniqueKey") ?? "";
739
+ const headerTransactionId = readHeader(response, "x-transaction-id");
740
+ const resolvedTransactionId = transactionId === void 0 || transactionId === "" ? headerTransactionId : transactionId;
741
+ const blockNumber = bodyBlockNumber === null || bodyBlockNumber === void 0 ? readBlockNumberHeader(response) : isBlockNumber(bodyBlockNumber) ? bodyBlockNumber : void 0;
742
+ return new SubmittedTransaction({
743
+ method,
744
+ uniqueKey,
745
+ transactionId: resolvedTransactionId === void 0 || resolvedTransactionId === "" ? null : resolvedTransactionId,
746
+ blockNumber: blockNumber ?? null,
747
+ mode,
748
+ result: mode === "queued" ? void 0 : data["result"],
749
+ dexBackendBaseUrl: this.dexBackendBaseUrl,
750
+ httpRequestor: this.requestor,
751
+ requestTimeoutMs: this.chainCallTimeoutMs,
752
+ ...(options === null || options === void 0 ? void 0 : options.positionConfirmation) === void 0 ? {} : { positionConfirmation: options.positionConfirmation }
753
+ });
754
+ }
755
+ /** Expose the requestor for sibling read services that share this gateway transport. */
756
+ get httpRequestor() {
757
+ return this.requestor;
758
+ }
938
759
  };
939
- function trimTrailingSlash(value) {
940
- return value.replace(/\/$/u, "");
760
+ function trimTrailingSlash$1(value) {
761
+ return value.replace(/\/$/u, "");
941
762
  }
942
763
  function invalidGatewayResponse(response, body, url, message) {
943
- return new GSwapSDKError(message, "INVALID_GATEWAY_RESPONSE", {
944
- status: response.status,
945
- body,
946
- url
947
- });
764
+ return new GSwapSDKError(message, "INVALID_GATEWAY_RESPONSE", {
765
+ status: response.status,
766
+ body,
767
+ url
768
+ });
948
769
  }
949
770
  function gatewayError(response, body, url) {
950
- const object = asRecord2(body);
951
- const nested = getObjectProperty(body, "error");
952
- const code = getStringProperty(object, "code") ?? getStringProperty(nested, "code") ?? getStringProperty(nested, "ErrorKey") ?? "HTTP_ERROR";
953
- const message = getStringProperty(object, "message") ?? getStringProperty(nested, "message") ?? getStringProperty(nested, "Message") ?? (typeof body === "string" ? body : `Gateway request failed with HTTP ${response.status}`);
954
- const retryAfterMs = response.status === 429 ? readRetryAfter(response) : void 0;
955
- if (code === "HTTP_ERROR") {
956
- return new GSwapSDKError(message, code, { status: response.status, body, url });
957
- }
958
- return GSwapSDKError.fromGatewayBounce(code, message, response.status, retryAfterMs);
959
- }
960
- function asRecord2(value) {
961
- return typeof value === "object" && value !== null ? value : void 0;
771
+ const object = asRecord(body);
772
+ const nested = getObjectProperty(body, "error");
773
+ const code = getStringProperty(object, "code") ?? getStringProperty(nested, "code") ?? getStringProperty(nested, "ErrorKey") ?? "HTTP_ERROR";
774
+ const message = getStringProperty(object, "message") ?? getStringProperty(nested, "message") ?? getStringProperty(nested, "Message") ?? (typeof body === "string" ? body : `Gateway request failed with HTTP ${response.status}`);
775
+ const retryAfterMs = response.status === 429 ? readRetryAfter(response) : void 0;
776
+ if (code === "HTTP_ERROR") return new GSwapSDKError(message, code, {
777
+ status: response.status,
778
+ body,
779
+ url
780
+ });
781
+ return GSwapSDKError.fromGatewayBounce(code, message, response.status, retryAfterMs);
782
+ }
783
+ function asRecord(value) {
784
+ return typeof value === "object" && value !== null ? value : void 0;
962
785
  }
963
786
  function isBlockNumber(value) {
964
- return typeof value === "number" && Number.isInteger(value) && value >= 0;
787
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
965
788
  }
966
789
 
967
- // src/utils/debug.ts
968
- var import_debug = __toESM(require("debug"), 1);
969
- var debugLog = (0, import_debug.default)("GSWAP_SDK");
790
+ //#endregion
791
+ //#region src/utils/debug.ts
792
+ const debugLog = (0, debug.default)("GSWAP_SDK");
970
793
 
971
- // src/version.ts
972
- var SDK_VERSION = true ? "1.0.0-rc.3" : "1.0.0-rc.3";
794
+ //#endregion
795
+ //#region src/version.ts
796
+ /** Package version embedded by the bundler, with a source-test fallback. */
797
+ const SDK_VERSION = "1.0.0";
973
798
 
974
- // src/classes/http_client.ts
799
+ //#endregion
800
+ //#region src/classes/http_client.ts
975
801
  var HttpClient = class {
976
- /** Create an HTTP client around fetch or an injected requestor. */
977
- constructor(httpRequestor = fetch, timeoutMs = 3e4) {
978
- this.httpRequestor = httpRequestor;
979
- this.timeoutMs = timeoutMs;
980
- }
981
- httpRequestor;
982
- timeoutMs;
983
- async sendRequest(method, baseUrl, basePath, endpoint, body, options) {
984
- const url = `${baseUrl}${basePath}${endpoint}`;
985
- debugLog(`Sending request to ${url} with body:`, body);
986
- const response = await requestWithTimeout(
987
- this.httpRequestor,
988
- url,
989
- {
990
- method,
991
- headers: {
992
- "Content-Type": "application/json",
993
- "User-Agent": `GalaChain-SDK/${SDK_VERSION}`
994
- },
995
- ...body ? { body: JSON.stringify(body) } : {},
996
- ...(options == null ? void 0 : options.signal) === void 0 ? {} : { signal: options.signal }
997
- },
998
- this.timeoutMs
999
- );
1000
- if (!response.ok) {
1001
- throw await GSwapSDKError.fromErrorResponse(url, response);
1002
- }
1003
- const json = await readResponseBody(response);
1004
- debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);
1005
- return json;
1006
- }
1007
- /** Send a JSON POST request and decode its response. */
1008
- async sendPostRequest(baseUrl, basePath, endpoint, body) {
1009
- return this.sendRequest("POST", baseUrl, basePath, endpoint, body);
1010
- }
1011
- /** Send a GET request with URL-encoded query parameters and decode its response. */
1012
- async sendGetRequest(baseUrl, basePath, endpoint, params, options) {
1013
- const searchParams = params ? new URLSearchParams(params) : void 0;
1014
- const endpointWithParams = searchParams ? `${endpoint}?${searchParams.toString()}` : endpoint;
1015
- return this.sendRequest("GET", baseUrl, basePath, endpointWithParams, void 0, options);
1016
- }
802
+ httpRequestor;
803
+ timeoutMs;
804
+ /** Create an HTTP client around fetch or an injected requestor. */
805
+ constructor(httpRequestor = fetch, timeoutMs = 3e4) {
806
+ this.httpRequestor = httpRequestor;
807
+ this.timeoutMs = timeoutMs;
808
+ }
809
+ async sendRequest(method, baseUrl, basePath, endpoint, body, options) {
810
+ const url = `${baseUrl}${basePath}${endpoint}`;
811
+ debugLog(`Sending request to ${url} with body:`, body);
812
+ const response = await requestWithTimeout(this.httpRequestor, url, {
813
+ method,
814
+ headers: {
815
+ "Content-Type": "application/json",
816
+ "User-Agent": `GalaChain-SDK/${SDK_VERSION}`
817
+ },
818
+ ...body ? { body: JSON.stringify(body) } : {},
819
+ ...(options === null || options === void 0 ? void 0 : options.signal) === void 0 ? {} : { signal: options.signal }
820
+ }, this.timeoutMs);
821
+ if (!response.ok) throw await GSwapSDKError.fromErrorResponse(url, response);
822
+ const json = await readResponseBody(response);
823
+ debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);
824
+ return json;
825
+ }
826
+ /** Send a JSON POST request and decode its response. */
827
+ async sendPostRequest(baseUrl, basePath, endpoint, body) {
828
+ return this.sendRequest("POST", baseUrl, basePath, endpoint, body);
829
+ }
830
+ /** Send a GET request with URL-encoded query parameters and decode its response. */
831
+ async sendGetRequest(baseUrl, basePath, endpoint, params, options) {
832
+ const searchParams = params ? new URLSearchParams(params) : void 0;
833
+ const endpointWithParams = searchParams ? `${endpoint}?${searchParams.toString()}` : endpoint;
834
+ return this.sendRequest("GET", baseUrl, basePath, endpointWithParams, void 0, options);
835
+ }
1017
836
  };
1018
837
 
1019
- // src/utils/ordering.ts
838
+ //#endregion
839
+ //#region src/utils/ordering.ts
840
+ /** Return two trading symbols in the contract's plain-string order. */
1020
841
  function orderSymbols(a, b) {
1021
- return a < b ? [a, b] : [b, a];
1022
- }
842
+ return a < b ? [a, b] : [b, a];
843
+ }
844
+ /** Read an ordered symbol pair from a tuple or object returned by a boundary helper.
845
+ *
846
+ * @example
847
+ * ```ts
848
+ * const pair = readOrderedSymbols(['GALA', 'GUSDC']);
849
+ * console.log(pair.token0);
850
+ * ```
851
+ */
1023
852
  function readOrderedSymbols(value) {
1024
- if (Array.isArray(value) && value.length >= 2) {
1025
- const token0 = value[0];
1026
- const token1 = value[1];
1027
- if (typeof token0 === "string" && typeof token1 === "string") return { token0, token1 };
1028
- }
1029
- if (typeof value === "object" && value !== null) {
1030
- const record = value;
1031
- const token0 = record["token0"];
1032
- const token1 = record["token1"];
1033
- if (typeof token0 === "string" && typeof token1 === "string") return { token0, token1 };
1034
- }
1035
- throw new GSwapSDKError("Unable to order trading symbols.", "VALIDATION_ERROR", { value });
1036
- }
853
+ if (Array.isArray(value) && value.length >= 2) {
854
+ const token0 = value[0];
855
+ const token1 = value[1];
856
+ if (typeof token0 === "string" && typeof token1 === "string") return {
857
+ token0,
858
+ token1
859
+ };
860
+ }
861
+ if (typeof value === "object" && value !== null) {
862
+ const record = value;
863
+ const token0 = record["token0"];
864
+ const token1 = record["token1"];
865
+ if (typeof token0 === "string" && typeof token1 === "string") return {
866
+ token0,
867
+ token1
868
+ };
869
+ }
870
+ throw new GSwapSDKError("Unable to order trading symbols.", "VALIDATION_ERROR", { value });
871
+ }
872
+ /** Return the `$`-joined composite key used by GalaChain object identities. */
1037
873
  function compositeKeyOf(token) {
1038
- return [token.collection, token.category, token.type, token.additionalKey].join("$");
1039
- }
874
+ return [
875
+ token.collection,
876
+ token.category,
877
+ token.type,
878
+ token.additionalKey
879
+ ].join("$");
880
+ }
881
+ /**
882
+ * Parse a pipe- or dollar-separated token class key.
883
+ *
884
+ * The LAST three segments are always `category`, `type` and `additionalKey`; everything before
885
+ * them is the `collection`. Parsing from the right is required because real collections contain
886
+ * the `$` delimiter themselves (for example `$GMUSIC`), so a plain left-to-right `split('$')`
887
+ * shifts every field. Nothing here says anything about the token's symbol: a class key carries
888
+ * no symbol, which must come from the token class or trading-symbol registry.
889
+ *
890
+ * @example
891
+ * ```ts
892
+ * parseTokenClassKey('$GMUSIC$Unit$none$none').collection; // '$GMUSIC'
893
+ * ```
894
+ */
1040
895
  function parseTokenClassKey(tokenClassKey) {
1041
- if (typeof tokenClassKey === "object") {
1042
- return {
1043
- collection: tokenClassKey.collection,
1044
- category: tokenClassKey.category,
1045
- type: tokenClassKey.type,
1046
- additionalKey: tokenClassKey.additionalKey
1047
- };
1048
- }
1049
- const parts = tokenClassKey.includes("|") ? tokenClassKey.split("|") : tokenClassKey.split("$");
1050
- if (parts.length !== 4 || parts.some((part) => part.length === 0)) {
1051
- throw new GSwapSDKError(
1052
- "Invalid token class key: expected four non-empty parts",
1053
- "VALIDATION_ERROR",
1054
- {
1055
- tokenClassKey
1056
- }
1057
- );
1058
- }
1059
- const [collection, category, type, additionalKey] = parts;
1060
- return {
1061
- collection,
1062
- category,
1063
- type,
1064
- additionalKey
1065
- };
896
+ if (typeof tokenClassKey === "object") return {
897
+ collection: tokenClassKey.collection,
898
+ category: tokenClassKey.category,
899
+ type: tokenClassKey.type,
900
+ additionalKey: tokenClassKey.additionalKey
901
+ };
902
+ const delimiter = tokenClassKey.includes("|") ? "|" : "$";
903
+ const segments = tokenClassKey.split(delimiter);
904
+ const tail = segments.slice(-3);
905
+ const collection = segments.slice(0, -3).join(delimiter);
906
+ if (segments.length < 4 || collection.length === 0 || tail.some((part) => part.length === 0)) throw new GSwapSDKError("Invalid token class key: expected a collection followed by category, type and additionalKey", "VALIDATION_ERROR", { tokenClassKey });
907
+ const [category, type, additionalKey] = tail;
908
+ return {
909
+ collection,
910
+ category,
911
+ type,
912
+ additionalKey
913
+ };
1066
914
  }
1067
915
 
1068
- // src/classes/pools.ts
916
+ //#endregion
917
+ //#region src/classes/pools.ts
918
+ /** Read-only pool and current-price access for the current GalaChainDex contract. */
1069
919
  var Pools = class {
1070
- /**
1071
- * Creates a pool service.
1072
- *
1073
- * @example
1074
- * ```ts
1075
- * const pools = new Pools(gateway, symbols);
1076
- * ```
1077
- */
1078
- constructor(gateway, symbols) {
1079
- this.gateway = gateway;
1080
- this.symbols = symbols;
1081
- this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs ?? 3e4);
1082
- }
1083
- gateway;
1084
- symbols;
1085
- http;
1086
- /**
1087
- * Fetches every current-contract pool from the swap backend.
1088
- *
1089
- * @example
1090
- * ```ts
1091
- * const pools = await service.getPools();
1092
- * console.log(pools.length);
1093
- * ```
1094
- */
1095
- async getPools(options) {
1096
- const response = await this.http.sendGetRequest(
1097
- this.gateway.dexBackendBaseUrl,
1098
- "/v2/trade",
1099
- "/pools",
1100
- void 0,
1101
- (options == null ? void 0 : options.signal) === void 0 ? void 0 : { signal: options.signal }
1102
- );
1103
- if (!Array.isArray(response.data) || !response.data.every(isPoolListInfo)) {
1104
- throw new GSwapSDKError("Backend returned an invalid pool list.", "INVALID_CHAIN_RESPONSE", {
1105
- data: response.data
1106
- });
1107
- }
1108
- return response.data;
1109
- }
1110
- /**
1111
- * Fetches one pool from the backend, preserving whether the request order was flipped.
1112
- *
1113
- * @example
1114
- * ```ts
1115
- * const pool = await service.getPool('GUSDC', 'GALA', 3000);
1116
- * console.log(pool.flippedFromRequest);
1117
- * ```
1118
- */
1119
- async getPool(token0, token1, fee) {
1120
- validateFee(fee);
1121
- return this.getBackend("/pool", await this.backendParams(token0, token1, fee));
1122
- }
1123
- /**
1124
- * Fetches the current sqrt price, price, and tick for one pool.
1125
- *
1126
- * @example
1127
- * ```ts
1128
- * const slot0 = await service.getSlot0('GALA', 'GUSDC', 3000);
1129
- * console.log(slot0.tick);
1130
- * ```
1131
- */
1132
- async getSlot0(token0, token1, fee) {
1133
- validateFee(fee);
1134
- return this.getBackend("/slot0", await this.backendParams(token0, token1, fee));
1135
- }
1136
- /**
1137
- * Fetches the complete chain composite pool snapshot, in canonical symbol order.
1138
- *
1139
- * @example
1140
- * ```ts
1141
- * const composite = await service.getCompositePool('GALA', 'GUSDC', 3000);
1142
- * console.log(composite.positions?.length ?? 0);
1143
- * ```
1144
- */
1145
- async getCompositePool(token0, token1, fee) {
1146
- validateFee(fee);
1147
- const first = await resolveSymbol(this.symbols, token0);
1148
- const second = await resolveSymbol(this.symbols, token1);
1149
- const ordered = readOrderedSymbols(orderSymbols(first, second));
1150
- return this.getBackend("/composite-pool", {
1151
- token0: ordered.token0,
1152
- token1: ordered.token1,
1153
- fee: String(fee)
1154
- });
1155
- }
1156
- async backendParams(token0, token1, fee) {
1157
- return {
1158
- token0: await resolveSymbol(this.symbols, token0),
1159
- token1: await resolveSymbol(this.symbols, token1),
1160
- fee: String(fee)
1161
- };
1162
- }
1163
- async getBackend(endpoint, params) {
1164
- try {
1165
- const response = await this.http.sendGetRequest(
1166
- this.gateway.dexBackendBaseUrl,
1167
- "/v2/trade",
1168
- endpoint,
1169
- params
1170
- );
1171
- return response.data;
1172
- } catch (error) {
1173
- if (error instanceof GSwapSDKError) throw error;
1174
- throw new GSwapSDKError("Pool request failed.", "HTTP_ERROR", { cause: error });
1175
- }
1176
- }
920
+ gateway;
921
+ symbols;
922
+ /**
923
+ * Creates a pool service.
924
+ *
925
+ * @example
926
+ * ```ts
927
+ * const pools = new Pools(gateway, symbols);
928
+ * ```
929
+ */
930
+ constructor(gateway, symbols) {
931
+ this.gateway = gateway;
932
+ this.symbols = symbols;
933
+ this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs ?? 3e4);
934
+ }
935
+ http;
936
+ /**
937
+ * Fetches every current-contract pool from the swap backend.
938
+ *
939
+ * @example
940
+ * ```ts
941
+ * const pools = await service.getPools();
942
+ * console.log(pools.length);
943
+ * ```
944
+ */
945
+ async getPools(options) {
946
+ const response = await this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", "/pools", void 0, (options === null || options === void 0 ? void 0 : options.signal) === void 0 ? void 0 : { signal: options.signal });
947
+ if (!Array.isArray(response.data) || !response.data.every(isPoolListInfo)) throw new GSwapSDKError("Backend returned an invalid pool list.", "INVALID_CHAIN_RESPONSE", { data: response.data });
948
+ return response.data;
949
+ }
950
+ /**
951
+ * Fetches one pool from the backend, preserving whether the request order was flipped.
952
+ *
953
+ * @example
954
+ * ```ts
955
+ * const pool = await service.getPool('GUSDC', 'GALA', 3000);
956
+ * console.log(pool.flippedFromRequest);
957
+ * ```
958
+ */
959
+ async getPool(token0, token1, fee) {
960
+ validateFee(fee);
961
+ return this.getBackend("/pool", await this.backendParams(token0, token1, fee));
962
+ }
963
+ /**
964
+ * Fetches the current sqrt price, price, and tick for one pool.
965
+ *
966
+ * @example
967
+ * ```ts
968
+ * const slot0 = await service.getSlot0('GALA', 'GUSDC', 3000);
969
+ * console.log(slot0.tick);
970
+ * ```
971
+ */
972
+ async getSlot0(token0, token1, fee) {
973
+ validateFee(fee);
974
+ return this.getBackend("/slot0", await this.backendParams(token0, token1, fee));
975
+ }
976
+ /**
977
+ * Fetches the complete chain composite pool snapshot, in canonical symbol order.
978
+ *
979
+ * @example
980
+ * ```ts
981
+ * const composite = await service.getCompositePool('GALA', 'GUSDC', 3000);
982
+ * console.log(composite.positions?.length ?? 0);
983
+ * ```
984
+ */
985
+ async getCompositePool(token0, token1, fee) {
986
+ validateFee(fee);
987
+ const first = await resolveSymbol$2(this.symbols, token0);
988
+ const second = await resolveSymbol$2(this.symbols, token1);
989
+ const ordered = readOrderedSymbols(orderSymbols(first, second));
990
+ return this.getBackend("/composite-pool", {
991
+ token0: ordered.token0,
992
+ token1: ordered.token1,
993
+ fee: String(fee)
994
+ });
995
+ }
996
+ async backendParams(token0, token1, fee) {
997
+ return {
998
+ token0: await resolveSymbol$2(this.symbols, token0),
999
+ token1: await resolveSymbol$2(this.symbols, token1),
1000
+ fee: String(fee)
1001
+ };
1002
+ }
1003
+ async getBackend(endpoint, params) {
1004
+ try {
1005
+ return (await this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", endpoint, params)).data;
1006
+ } catch (error) {
1007
+ if (error instanceof GSwapSDKError) throw error;
1008
+ throw new GSwapSDKError("Pool request failed.", "HTTP_ERROR", { cause: error });
1009
+ }
1010
+ }
1177
1011
  };
1178
- async function resolveSymbol(symbols, token) {
1179
- const resolved = await symbols.resolve(token);
1180
- if (resolved.symbol.length > 0) return resolved.symbol;
1181
- throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", {
1182
- token
1183
- });
1012
+ async function resolveSymbol$2(symbols, token) {
1013
+ const resolved = await symbols.resolve(token);
1014
+ if (resolved.symbol.length > 0) return resolved.symbol;
1015
+ throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", { token });
1184
1016
  }
1185
1017
  function isPoolListInfo(value) {
1186
- if (typeof value !== "object" || value === null) return false;
1187
- const row = value;
1188
- const requiredNumbers = ["fee", "tickSpacing", "protocolFees", "tradingFees"];
1189
- const optionalStrings = [
1190
- "token0CompositeKey",
1191
- "token1CompositeKey",
1192
- "creator",
1193
- "price",
1194
- "sqrtPrice",
1195
- "token0Tvl",
1196
- "token1Tvl"
1197
- ];
1198
- const optionalNumbers = [
1199
- "tick",
1200
- "tvlUsd",
1201
- "volume1d",
1202
- "volume7d",
1203
- "volume30d",
1204
- "trades1d",
1205
- "fee24h",
1206
- "apr1d",
1207
- "token0Price",
1208
- "token1Price"
1209
- ];
1210
- return row["contractVersion"] === "v2" && typeof row["token0"] === "string" && typeof row["token1"] === "string" && typeof row["poolName"] === "string" && typeof row["poolRef"] === "string" && requiredNumbers.every((key) => isFiniteNumber(row[key])) && optionalStrings.every((key) => isOptionalString(row[key])) && optionalNumbers.every((key) => isOptionalNumber(row[key]));
1018
+ if (typeof value !== "object" || value === null) return false;
1019
+ const row = value;
1020
+ return row["contractVersion"] === "v2" && typeof row["token0"] === "string" && typeof row["token1"] === "string" && typeof row["poolName"] === "string" && typeof row["poolRef"] === "string" && [
1021
+ "fee",
1022
+ "tickSpacing",
1023
+ "protocolFees",
1024
+ "tradingFees"
1025
+ ].every((key) => isFiniteNumber(row[key])) && [
1026
+ "token0CompositeKey",
1027
+ "token1CompositeKey",
1028
+ "creator",
1029
+ "price",
1030
+ "sqrtPrice",
1031
+ "token0Tvl",
1032
+ "token1Tvl"
1033
+ ].every((key) => isOptionalString(row[key])) && [
1034
+ "tick",
1035
+ "tvlUsd",
1036
+ "volume1d",
1037
+ "volume7d",
1038
+ "volume30d",
1039
+ "trades1d",
1040
+ "fee24h",
1041
+ "apr1d",
1042
+ "token0Price",
1043
+ "token1Price"
1044
+ ].every((key) => isOptionalNumber(row[key]));
1211
1045
  }
1212
1046
  function isFiniteNumber(value) {
1213
- return typeof value === "number" && Number.isFinite(value);
1047
+ return typeof value === "number" && Number.isFinite(value);
1214
1048
  }
1215
1049
  function isOptionalString(value) {
1216
- return value === void 0 || typeof value === "string";
1050
+ return value === void 0 || typeof value === "string";
1217
1051
  }
1218
1052
  function isOptionalNumber(value) {
1219
- return value === void 0 || isFiniteNumber(value);
1053
+ return value === void 0 || isFiniteNumber(value);
1220
1054
  }
1221
1055
 
1222
- // src/classes/positions.ts
1223
- var import_bignumber3 = __toESM(require("bignumber.js"), 1);
1056
+ //#endregion
1057
+ //#region src/classes/positions.ts
1058
+ /**
1059
+ * Manages current-contract concentrated-liquidity positions.
1060
+ *
1061
+ * @example
1062
+ * ```typescript
1063
+ * const positions = gSwap.positions;
1064
+ * const mine = await positions.getUserPositions('client|012345678901234567890123');
1065
+ * console.log(mine.length);
1066
+ * ```
1067
+ */
1224
1068
  var Positions = class {
1225
- constructor(gateway, symbols, signer, walletAddress) {
1226
- this.gateway = gateway;
1227
- this.symbols = symbols;
1228
- this.signer = signer;
1229
- this.walletAddress = walletAddress;
1230
- this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs ?? 3e4);
1231
- }
1232
- gateway;
1233
- symbols;
1234
- signer;
1235
- walletAddress;
1236
- http;
1237
- /**
1238
- * Gets all current-contract positions owned by an address.
1239
- *
1240
- * @param owner - GalaChain owner identity.
1241
- * @returns Enriched positions from the v2 trade backend.
1242
- * @example
1243
- * ```typescript
1244
- * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');
1245
- * ```
1246
- */
1247
- async getUserPositions(owner) {
1248
- const response = await this.get("/positions", { user: owner });
1249
- return response.data.map((position) => this.mapPosition(position));
1250
- }
1251
- /**
1252
- * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.
1253
- * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.
1254
- *
1255
- * @param args - Pair, owner, fee, and position tick range.
1256
- * @returns The position, or `null` when the backend returns 404.
1257
- * @example
1258
- * ```typescript
1259
- * const position = await gSwap.positions.getPosition({
1260
- * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',
1261
- * fee: 3000, tickLower: -19200, tickUpper: 12000,
1262
- * });
1263
- * ```
1264
- */
1265
- async getPosition(args, signal) {
1266
- const pair = await this.symbols.orderPair(args.token0, args.token1);
1267
- const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1268
- const response = await this.getNullable(
1269
- "/position",
1270
- {
1271
- token0: pair.token0.symbol,
1272
- token1: pair.token1.symbol,
1273
- fee: `${args.fee}`,
1274
- owner: args.owner,
1275
- tickLower: `${ticks.tickLower}`,
1276
- tickUpper: `${ticks.tickUpper}`
1277
- },
1278
- signal
1279
- );
1280
- return response === null ? null : this.mapPosition(response.data);
1281
- }
1282
- /**
1283
- * Estimates the other token amount and resulting liquidity for a deposit.
1284
- *
1285
- * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.
1286
- * @returns Backend liquidity estimate.
1287
- * @example
1288
- * ```typescript
1289
- * const estimate = await gSwap.positions.estimateAddLiquidity({
1290
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1291
- * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,
1292
- * });
1293
- * ```
1294
- */
1295
- async estimateAddLiquidity(args) {
1296
- validateNumericAmount(args.amount, "amount");
1297
- const response = await this.get("/add-liq-estimate", {
1298
- token0: this.requestToken(args.token0),
1299
- token1: this.requestToken(args.token1),
1300
- fee: `${args.fee}`,
1301
- tickLower: `${args.tickLower}`,
1302
- tickUpper: `${args.tickUpper}`,
1303
- amount: new import_bignumber3.default(args.amount).toFixed(),
1304
- amountIsToken0: String(args.amountIsToken0)
1305
- });
1306
- return response.data;
1307
- }
1308
- /**
1309
- * Estimates token amounts released by burning liquidity.
1310
- *
1311
- * @param args - Pair, tick range, fee tier, and liquidity quantity.
1312
- * @returns Estimated token0 and token1 quantities.
1313
- * @example
1314
- * ```typescript
1315
- * const estimate = await gSwap.positions.estimateRemoveLiquidity({
1316
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1317
- * tickLower: -19200, tickUpper: 12000, liquidity: '1000',
1318
- * });
1319
- * ```
1320
- */
1321
- async estimateRemoveLiquidity(args) {
1322
- validateNumericAmount(args.liquidity, "liquidity");
1323
- const response = await this.get("/remove-liq-estimate", {
1324
- token0: this.requestToken(args.token0),
1325
- token1: this.requestToken(args.token1),
1326
- fee: `${args.fee}`,
1327
- tickLower: `${args.tickLower}`,
1328
- tickUpper: `${args.tickUpper}`,
1329
- liquidity: new import_bignumber3.default(args.liquidity).toFixed()
1330
- });
1331
- return response.data;
1332
- }
1333
- /**
1334
- * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.
1335
- *
1336
- * @param args - Pair, fee, range, deposit amount, and caller-side token index.
1337
- * @returns The synchronously submitted transaction.
1338
- * @example
1339
- * ```typescript
1340
- * const tx = await gSwap.positions.addLiquidityByTicks({
1341
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1342
- * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,
1343
- * });
1344
- * await tx.confirm();
1345
- * ```
1346
- */
1347
- async addLiquidityByTicks(args) {
1348
- validateFee(args.fee);
1349
- const pair = await this.symbols.orderPair(args.token0, args.token1);
1350
- const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1351
- assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1352
- validateNumericAmount(args.amount, "amount");
1353
- const amount = new import_bignumber3.default(args.amount).toFixed();
1354
- const dto = {
1355
- token0: pair.token0.symbol,
1356
- token1: pair.token1.symbol,
1357
- fee: args.fee,
1358
- tickLower: ticks.tickLower,
1359
- tickUpper: ticks.tickUpper,
1360
- uniqueKey: this.uniqueKey(),
1361
- ...pair.flipped !== args.amountIsToken0 ? { depositQuantityToken0: amount } : { depositQuantityToken1: amount }
1362
- };
1363
- return this.submit("AddLiquidity", dto, {
1364
- kind: "add",
1365
- identity: {
1366
- token0: pair.token0.symbol,
1367
- token1: pair.token1.symbol,
1368
- fee: args.fee,
1369
- tickLower: ticks.tickLower,
1370
- tickUpper: ticks.tickUpper
1371
- }
1372
- });
1373
- }
1374
- /**
1375
- * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.
1376
- * The resulting range is therefore no narrower than the requested price interval.
1377
- *
1378
- * @param args - Pair, fee, price range, deposit amount, and caller-side token index.
1379
- * @returns The synchronously submitted transaction.
1380
- * @example
1381
- * ```typescript
1382
- * const tx = await gSwap.positions.addLiquidityByPrice({
1383
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1384
- * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,
1385
- * });
1386
- * ```
1387
- */
1388
- async addLiquidityByPrice(args) {
1389
- validateFee(args.fee);
1390
- this.rejectNumber(args.minPrice, "minPrice");
1391
- this.rejectNumber(args.maxPrice, "maxPrice");
1392
- const minPrice = new import_bignumber3.default(args.minPrice);
1393
- const maxPrice = new import_bignumber3.default(args.maxPrice);
1394
- if (!minPrice.isFinite() || !maxPrice.isFinite() || minPrice.isLessThanOrEqualTo(0) || maxPrice.isLessThanOrEqualTo(0)) {
1395
- throw new GSwapSDKError("Price bounds must be finite and positive.", "VALIDATION_ERROR");
1396
- }
1397
- if (minPrice.isGreaterThan(maxPrice)) {
1398
- throw new GSwapSDKError(
1399
- "minPrice must be less than or equal to maxPrice.",
1400
- "VALIDATION_ERROR"
1401
- );
1402
- }
1403
- const spacing = this.tickSpacing(args.fee);
1404
- const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);
1405
- const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);
1406
- return this.addLiquidityByTicks({
1407
- token0: args.token0,
1408
- token1: args.token1,
1409
- fee: args.fee,
1410
- tickLower,
1411
- tickUpper,
1412
- amount: args.amount,
1413
- amountIsToken0: args.amountIsToken0
1414
- });
1415
- }
1416
- /**
1417
- * Removes liquidity by withdrawing at most one canonical token quantity.
1418
- * Omitting both amounts closes the position and sweeps all accrued fees.
1419
- *
1420
- * @param args - Pair, fee, range, and optional caller-side withdrawal amount.
1421
- * @returns The synchronously submitted transaction.
1422
- * @example
1423
- * ```typescript
1424
- * const tx = await gSwap.positions.removeLiquidity({
1425
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1426
- * tickLower: -19200, tickUpper: 12000,
1427
- * });
1428
- * ```
1429
- */
1430
- async removeLiquidity(args) {
1431
- validateFee(args.fee);
1432
- const pair = await this.symbols.orderPair(args.token0, args.token1);
1433
- const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1434
- assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1435
- if (args.amount0 !== void 0 && args.amount1 !== void 0) {
1436
- throw new GSwapSDKError("Provide at most one of amount0 or amount1.", "VALIDATION_ERROR");
1437
- }
1438
- if (args.amount0 !== void 0) validateNumericAmount(args.amount0, "amount0");
1439
- if (args.amount1 !== void 0) validateNumericAmount(args.amount1, "amount1");
1440
- const withdrawal = args.amount0 !== void 0 ? pair.flipped ? { withdrawalQuantityToken1: new import_bignumber3.default(args.amount0).toFixed() } : { withdrawalQuantityToken0: new import_bignumber3.default(args.amount0).toFixed() } : args.amount1 !== void 0 ? pair.flipped ? { withdrawalQuantityToken0: new import_bignumber3.default(args.amount1).toFixed() } : { withdrawalQuantityToken1: new import_bignumber3.default(args.amount1).toFixed() } : {};
1441
- const dto = {
1442
- token0: pair.token0.symbol,
1443
- token1: pair.token1.symbol,
1444
- fee: args.fee,
1445
- tickLower: ticks.tickLower,
1446
- tickUpper: ticks.tickUpper,
1447
- uniqueKey: this.uniqueKey(),
1448
- ...withdrawal
1449
- };
1450
- const isFullClose = args.amount0 === void 0 && args.amount1 === void 0;
1451
- return this.submit("RemoveLiquidity", dto, {
1452
- kind: isFullClose ? "removeFull" : "removePartial",
1453
- identity: {
1454
- token0: pair.token0.symbol,
1455
- token1: pair.token1.symbol,
1456
- fee: args.fee,
1457
- tickLower: ticks.tickLower,
1458
- tickUpper: ticks.tickUpper
1459
- }
1460
- });
1461
- }
1462
- /**
1463
- * Collects all accrued fees for a position; the contract does not support partial collection.
1464
- *
1465
- * @param args - Pair, fee, and tick range identifying the position.
1466
- * @returns The synchronously submitted transaction.
1467
- * @example
1468
- * ```typescript
1469
- * const tx = await gSwap.positions.collectPositionFees({
1470
- * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1471
- * tickLower: -19200, tickUpper: 12000,
1472
- * });
1473
- * ```
1474
- */
1475
- async collectPositionFees(args) {
1476
- validateFee(args.fee);
1477
- const pair = await this.symbols.orderPair(args.token0, args.token1);
1478
- const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1479
- assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1480
- const dto = {
1481
- token0: pair.token0.symbol,
1482
- token1: pair.token1.symbol,
1483
- fee: args.fee,
1484
- tickLower: ticks.tickLower,
1485
- tickUpper: ticks.tickUpper,
1486
- uniqueKey: this.uniqueKey()
1487
- };
1488
- return this.submit("CollectPositionFees", dto, {
1489
- kind: "collect",
1490
- identity: {
1491
- token0: pair.token0.symbol,
1492
- token1: pair.token1.symbol,
1493
- fee: args.fee,
1494
- tickLower: ticks.tickLower,
1495
- tickUpper: ticks.tickUpper
1496
- }
1497
- });
1498
- }
1499
- /**
1500
- * Creates a pool, resolving registered trading symbols and falling back to class collections.
1501
- * Reversed symbol order inverts the supplied starting price or square-root price.
1502
- *
1503
- * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.
1504
- * @returns The synchronously submitted transaction.
1505
- * @example
1506
- * ```typescript
1507
- * const tx = await gSwap.positions.createPool({
1508
- * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,
1509
- * startingPrice: '0.15',
1510
- * });
1511
- * ```
1512
- */
1513
- async createPool(args) {
1514
- var _a, _b;
1515
- const hasPrice = args.startingPrice !== void 0;
1516
- const hasSqrtPrice = args.startingSqrtPrice !== void 0;
1517
- if (hasPrice === hasSqrtPrice) {
1518
- throw new GSwapSDKError(
1519
- "Provide exactly one of startingPrice or startingSqrtPrice.",
1520
- "VALIDATION_ERROR"
1521
- );
1522
- }
1523
- validateFee(args.fee);
1524
- const [tokenA, tokenB] = await Promise.all([
1525
- this.resolveCreateToken(args.token0),
1526
- this.resolveCreateToken(args.token1)
1527
- ]);
1528
- const flipped = tokenA.symbol > tokenB.symbol;
1529
- const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];
1530
- const sourcePriceInput = hasPrice ? args.startingPrice : args.startingSqrtPrice;
1531
- this.rejectNumber(sourcePriceInput, hasPrice ? "startingPrice" : "startingSqrtPrice");
1532
- const sourcePrice = new import_bignumber3.default(sourcePriceInput);
1533
- if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) {
1534
- throw new GSwapSDKError("Starting price must be finite and positive.", "VALIDATION_ERROR");
1535
- }
1536
- const canonicalPrice = flipped ? new import_bignumber3.default(1).dividedBy(sourcePrice) : sourcePrice;
1537
- const dto = {
1538
- token0Key: token0.classKey,
1539
- token1Key: token1.classKey,
1540
- token0Symbol: token0.symbol,
1541
- token1Symbol: token1.symbol,
1542
- fee: args.fee,
1543
- uniqueKey: this.uniqueKey(),
1544
- ...hasPrice ? { startingPrice: canonicalPrice.toFixed() } : { startingSqrtPrice: canonicalPrice.toFixed() },
1545
- ...args.isPrivate === void 0 ? {} : { isPrivate: args.isPrivate },
1546
- ...args.privateAccess === void 0 ? {} : { privateAccess: args.privateAccess }
1547
- };
1548
- const transaction = await this.submit("CreatePool", dto, {
1549
- kind: "createPool",
1550
- token0: token0.symbol,
1551
- token1: token1.symbol,
1552
- fee: args.fee
1553
- });
1554
- (_b = (_a = this.symbols).invalidate) == null ? void 0 : _b.call(_a);
1555
- return transaction;
1556
- }
1557
- async submit(method, dto, confirmation) {
1558
- if (this.signer === void 0) throw GSwapSDKError.noSignerError();
1559
- const signed = await this.signer.signObject(method, dto);
1560
- const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
1561
- const owner = this.walletAddress;
1562
- const positionConfirmation = this.buildPositionConfirmation(confirmation, owner);
1563
- const options = {
1564
- ...submitOptions,
1565
- ...positionConfirmation === void 0 ? {} : { positionConfirmation }
1566
- };
1567
- return this.gateway.submit(method, signed, options);
1568
- }
1569
- /**
1570
- * Builds a confirmation closure that proves the write's own effect, not just that a
1571
- * position row exists (true before most of these writes run too, for any operation on a
1572
- * pre-existing position — existence alone would false-confirm before the write executes,
1573
- * and would never confirm a full close, whose whole point is that the position stops
1574
- * existing).
1575
- *
1576
- * The "before" state is captured lazily, on the confirmation closure's own first poll —
1577
- * not eagerly here in `submit()` — so confirming a write never adds an extra round-trip to
1578
- * the write itself; the cost of establishing the baseline is paid by `confirm()`, only if
1579
- * and when the caller actually asks to confirm.
1580
- */
1581
- buildPositionConfirmation(confirmation, owner) {
1582
- if (confirmation === void 0) return void 0;
1583
- if (confirmation.kind === "createPool") {
1584
- const { token0, token1, fee } = confirmation;
1585
- return async (signal) => {
1586
- const pool = await this.getNullable(
1587
- "/pool",
1588
- { token0, token1, fee: `${fee}` },
1589
- signal
1590
- );
1591
- return pool === null ? { confirmed: false } : { confirmed: true, position: null };
1592
- };
1593
- }
1594
- if (owner === void 0) return void 0;
1595
- const { kind, identity } = confirmation;
1596
- let baseline;
1597
- return async (signal) => {
1598
- const current = await this.getPosition({ ...identity, owner }, signal);
1599
- if (baseline === void 0) {
1600
- baseline = {
1601
- liquidity: new import_bignumber3.default((current == null ? void 0 : current.liquidity) ?? 0),
1602
- fees: new import_bignumber3.default((current == null ? void 0 : current.fees0) ?? 0).plus(new import_bignumber3.default((current == null ? void 0 : current.fees1) ?? 0))
1603
- };
1604
- return kind === "removeFull" && current === null ? { confirmed: true, position: null } : { confirmed: false };
1605
- }
1606
- switch (kind) {
1607
- case "add":
1608
- return current !== null && new import_bignumber3.default(current.liquidity).isGreaterThan(baseline.liquidity) ? { confirmed: true, position: current } : { confirmed: false };
1609
- case "removePartial":
1610
- return current !== null && new import_bignumber3.default(current.liquidity).isLessThan(baseline.liquidity) ? { confirmed: true, position: current } : { confirmed: false };
1611
- case "removeFull":
1612
- return current === null ? { confirmed: true, position: null } : { confirmed: false };
1613
- case "collect": {
1614
- if (current === null) return { confirmed: false };
1615
- const currentFees = new import_bignumber3.default(current.fees0 ?? 0).plus(
1616
- new import_bignumber3.default(current.fees1 ?? 0)
1617
- );
1618
- if (currentFees.isLessThan(baseline.fees)) return { confirmed: true, position: current };
1619
- if (baseline.fees.isZero() && currentFees.isZero())
1620
- return { confirmed: true, position: current };
1621
- return { confirmed: false };
1622
- }
1623
- }
1624
- };
1625
- }
1626
- async get(endpoint, params, signal) {
1627
- return this.http.sendGetRequest(
1628
- this.gateway.dexBackendBaseUrl,
1629
- "/v2/trade",
1630
- endpoint,
1631
- params,
1632
- signal === void 0 ? void 0 : { signal }
1633
- );
1634
- }
1635
- async getNullable(endpoint, params, signal) {
1636
- try {
1637
- return await this.get(endpoint, params, signal);
1638
- } catch (error) {
1639
- if (this.isNotFound(error)) return null;
1640
- throw error;
1641
- }
1642
- }
1643
- isNotFound(error) {
1644
- if (!(error instanceof GSwapSDKError) || error.details === void 0) return false;
1645
- return error.details["status"] === 404;
1646
- }
1647
- mapPosition(position) {
1648
- return {
1649
- token0Symbol: position.token0Symbol,
1650
- token1Symbol: position.token1Symbol,
1651
- ...position.token0CompositeKey === void 0 ? {} : { token0CompositeKey: position.token0CompositeKey },
1652
- ...position.token1CompositeKey === void 0 ? {} : { token1CompositeKey: position.token1CompositeKey },
1653
- fee: position.fee,
1654
- tickLower: position.tickLower,
1655
- tickUpper: position.tickUpper,
1656
- liquidity: position.liquidity,
1657
- amount0: position.amount0,
1658
- amount1: position.amount1,
1659
- inRange: position.inRange,
1660
- ...position.currentTick === void 0 ? {} : { currentTick: position.currentTick },
1661
- ...position.sqrtPrice === void 0 ? {} : { sqrtPrice: position.sqrtPrice },
1662
- pool: position.poolRef ?? position.pool ?? "",
1663
- owner: position.owner,
1664
- ...position.fees0 === void 0 ? {} : { fees0: position.fees0 },
1665
- ...position.fees1 === void 0 ? {} : { fees1: position.fees1 }
1666
- };
1667
- }
1668
- requestToken(ref) {
1669
- return typeof ref === "string" ? ref : compositeKeyOf(ref);
1670
- }
1671
- canonicalTicks(tickLower, tickUpper, flipped) {
1672
- return flipped ? { tickLower: -tickUpper, tickUpper: -tickLower } : { tickLower, tickUpper };
1673
- }
1674
- tickSpacing(fee) {
1675
- const spacing = TICK_SPACING_BY_FEE[fee];
1676
- if (spacing === void 0) {
1677
- throw new GSwapSDKError(`Unsupported fee tier: ${fee}.`, "VALIDATION_ERROR");
1678
- }
1679
- return spacing;
1680
- }
1681
- rejectNumber(value, parameterName) {
1682
- if (typeof value === "number") {
1683
- throw new GSwapSDKError(
1684
- `Invalid ${parameterName}: use a decimal string or BigNumber, not a JavaScript number`,
1685
- "VALIDATION_ERROR"
1686
- );
1687
- }
1688
- }
1689
- uniqueKey() {
1690
- return `gswap-sdk-${globalThis.crypto.randomUUID()}`;
1691
- }
1692
- async resolveCreateToken(ref) {
1693
- try {
1694
- const lookupRef = typeof ref === "object" ? compositeKeyOf(ref) : ref;
1695
- const resolved = await this.symbols.resolve(lookupRef);
1696
- const suppliedClassKey = this.tryParseClassKey(ref);
1697
- return {
1698
- symbol: resolved.symbol,
1699
- classKey: suppliedClassKey ?? parseTokenClassKey({
1700
- collection: resolved.collection,
1701
- category: resolved.category,
1702
- type: resolved.type,
1703
- additionalKey: resolved.additionalKey
1704
- })
1705
- };
1706
- } catch (error) {
1707
- if (!(error instanceof GSwapSDKError) || error.code !== "UNKNOWN_TOKEN") {
1708
- throw error;
1709
- }
1710
- let classKey;
1711
- try {
1712
- classKey = parseTokenClassKey(ref);
1713
- } catch {
1714
- throw error;
1715
- }
1716
- return { symbol: classKey.collection, classKey };
1717
- }
1718
- }
1719
- tryParseClassKey(ref) {
1720
- try {
1721
- return parseTokenClassKey(ref);
1722
- } catch {
1723
- return void 0;
1724
- }
1725
- }
1069
+ gateway;
1070
+ symbols;
1071
+ signer;
1072
+ walletAddress;
1073
+ constructor(gateway, symbols, signer, walletAddress) {
1074
+ this.gateway = gateway;
1075
+ this.symbols = symbols;
1076
+ this.signer = signer;
1077
+ this.walletAddress = walletAddress;
1078
+ this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs ?? 3e4);
1079
+ }
1080
+ http;
1081
+ /**
1082
+ * Gets all current-contract positions owned by an address.
1083
+ *
1084
+ * @param owner - GalaChain owner identity.
1085
+ * @returns Enriched positions from the v2 trade backend.
1086
+ * @example
1087
+ * ```typescript
1088
+ * const positions = await gSwap.positions.getUserPositions('client|012345678901234567890123');
1089
+ * ```
1090
+ */
1091
+ async getUserPositions(owner) {
1092
+ return (await this.get("/positions", { user: owner })).data.map((position) => this.mapPosition(position));
1093
+ }
1094
+ /**
1095
+ * Gets one position, normalizing a caller-supplied reversed pair to canonical symbol order.
1096
+ * Reversed pairs also invert the price axis, so `[lower, upper]` becomes `[-upper, -lower]`.
1097
+ *
1098
+ * @param args - Pair, owner, fee, and position tick range.
1099
+ * @returns The position, or `null` when the backend returns 404.
1100
+ * @example
1101
+ * ```typescript
1102
+ * const position = await gSwap.positions.getPosition({
1103
+ * token0: 'GALA', token1: 'GUSDC', owner: 'client|012345678901234567890123',
1104
+ * fee: 3000, tickLower: -19200, tickUpper: 12000,
1105
+ * });
1106
+ * ```
1107
+ */
1108
+ async getPosition(args, signal) {
1109
+ const pair = await this.symbols.orderPair(args.token0, args.token1);
1110
+ const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1111
+ const response = await this.getNullable("/position", {
1112
+ token0: pair.token0.symbol,
1113
+ token1: pair.token1.symbol,
1114
+ fee: `${args.fee}`,
1115
+ owner: args.owner,
1116
+ tickLower: `${ticks.tickLower}`,
1117
+ tickUpper: `${ticks.tickUpper}`
1118
+ }, signal);
1119
+ return response === null ? null : this.mapPosition(response.data);
1120
+ }
1121
+ /**
1122
+ * Estimates the other token amount and resulting liquidity for a deposit.
1123
+ *
1124
+ * @param args - Pair, tick range, deposit amount, and the amount's caller-side token index.
1125
+ * @returns Backend liquidity estimate.
1126
+ * @example
1127
+ * ```typescript
1128
+ * const estimate = await gSwap.positions.estimateAddLiquidity({
1129
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1130
+ * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,
1131
+ * });
1132
+ * ```
1133
+ */
1134
+ async estimateAddLiquidity(args) {
1135
+ validateNumericAmount(args.amount, "amount");
1136
+ return (await this.get("/add-liq-estimate", {
1137
+ token0: this.requestToken(args.token0),
1138
+ token1: this.requestToken(args.token1),
1139
+ fee: `${args.fee}`,
1140
+ tickLower: `${args.tickLower}`,
1141
+ tickUpper: `${args.tickUpper}`,
1142
+ amount: new bignumber_js.default(args.amount).toFixed(),
1143
+ amountIsToken0: String(args.amountIsToken0)
1144
+ })).data;
1145
+ }
1146
+ /**
1147
+ * Estimates token amounts released by burning liquidity.
1148
+ *
1149
+ * @param args - Pair, tick range, fee tier, and liquidity quantity.
1150
+ * @returns Estimated token0 and token1 quantities.
1151
+ * @example
1152
+ * ```typescript
1153
+ * const estimate = await gSwap.positions.estimateRemoveLiquidity({
1154
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1155
+ * tickLower: -19200, tickUpper: 12000, liquidity: '1000',
1156
+ * });
1157
+ * ```
1158
+ */
1159
+ async estimateRemoveLiquidity(args) {
1160
+ validateNumericAmount(args.liquidity, "liquidity");
1161
+ return (await this.get("/remove-liq-estimate", {
1162
+ token0: this.requestToken(args.token0),
1163
+ token1: this.requestToken(args.token1),
1164
+ fee: `${args.fee}`,
1165
+ tickLower: `${args.tickLower}`,
1166
+ tickUpper: `${args.tickUpper}`,
1167
+ liquidity: new bignumber_js.default(args.liquidity).toFixed()
1168
+ })).data;
1169
+ }
1170
+ /**
1171
+ * Adds liquidity using an explicit tick range. Exactly one canonical deposit field is emitted.
1172
+ *
1173
+ * @param args - Pair, fee, range, deposit amount, and caller-side token index.
1174
+ * @returns The synchronously submitted transaction.
1175
+ * @example
1176
+ * ```typescript
1177
+ * const tx = await gSwap.positions.addLiquidityByTicks({
1178
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1179
+ * tickLower: -19200, tickUpper: 12000, amount: '100', amountIsToken0: true,
1180
+ * });
1181
+ * await tx.confirm();
1182
+ * ```
1183
+ */
1184
+ async addLiquidityByTicks(args) {
1185
+ validateFee(args.fee);
1186
+ const pair = await this.symbols.orderPair(args.token0, args.token1);
1187
+ const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1188
+ assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1189
+ validateNumericAmount(args.amount, "amount");
1190
+ const amount = new bignumber_js.default(args.amount).toFixed();
1191
+ const dto = {
1192
+ token0: pair.token0.symbol,
1193
+ token1: pair.token1.symbol,
1194
+ fee: args.fee,
1195
+ tickLower: ticks.tickLower,
1196
+ tickUpper: ticks.tickUpper,
1197
+ uniqueKey: this.uniqueKey(),
1198
+ ...pair.flipped !== args.amountIsToken0 ? { depositQuantityToken0: amount } : { depositQuantityToken1: amount }
1199
+ };
1200
+ return this.submit("AddLiquidity", dto, {
1201
+ kind: "add",
1202
+ identity: {
1203
+ token0: pair.token0.symbol,
1204
+ token1: pair.token1.symbol,
1205
+ fee: args.fee,
1206
+ tickLower: ticks.tickLower,
1207
+ tickUpper: ticks.tickUpper
1208
+ }
1209
+ });
1210
+ }
1211
+ /**
1212
+ * Adds liquidity from prices, flooring the lower tick and ceiling the upper tick to fee spacing.
1213
+ * The resulting range is therefore no narrower than the requested price interval.
1214
+ *
1215
+ * @param args - Pair, fee, price range, deposit amount, and caller-side token index.
1216
+ * @returns The synchronously submitted transaction.
1217
+ * @example
1218
+ * ```typescript
1219
+ * const tx = await gSwap.positions.addLiquidityByPrice({
1220
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1221
+ * minPrice: '0.14', maxPrice: '0.16', amount: '100', amountIsToken0: true,
1222
+ * });
1223
+ * ```
1224
+ */
1225
+ async addLiquidityByPrice(args) {
1226
+ validateFee(args.fee);
1227
+ this.rejectNumber(args.minPrice, "minPrice");
1228
+ this.rejectNumber(args.maxPrice, "maxPrice");
1229
+ const minPrice = new bignumber_js.default(args.minPrice);
1230
+ const maxPrice = new bignumber_js.default(args.maxPrice);
1231
+ if (!minPrice.isFinite() || !maxPrice.isFinite() || minPrice.isLessThanOrEqualTo(0) || maxPrice.isLessThanOrEqualTo(0)) throw new GSwapSDKError("Price bounds must be finite and positive.", "VALIDATION_ERROR");
1232
+ if (minPrice.isGreaterThan(maxPrice)) throw new GSwapSDKError("minPrice must be less than or equal to maxPrice.", "VALIDATION_ERROR");
1233
+ const spacing = this.tickSpacing(args.fee);
1234
+ const tickLower = alignTickDown(tickFromPrice(minPrice), spacing);
1235
+ const tickUpper = alignTickUp(tickFromPrice(maxPrice), spacing);
1236
+ return this.addLiquidityByTicks({
1237
+ token0: args.token0,
1238
+ token1: args.token1,
1239
+ fee: args.fee,
1240
+ tickLower,
1241
+ tickUpper,
1242
+ amount: args.amount,
1243
+ amountIsToken0: args.amountIsToken0
1244
+ });
1245
+ }
1246
+ /**
1247
+ * Removes liquidity by withdrawing at most one canonical token quantity.
1248
+ * Omitting both amounts closes the position and sweeps all accrued fees.
1249
+ *
1250
+ * @param args - Pair, fee, range, and optional caller-side withdrawal amount.
1251
+ * @returns The synchronously submitted transaction.
1252
+ * @example
1253
+ * ```typescript
1254
+ * const tx = await gSwap.positions.removeLiquidity({
1255
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1256
+ * tickLower: -19200, tickUpper: 12000,
1257
+ * });
1258
+ * ```
1259
+ */
1260
+ async removeLiquidity(args) {
1261
+ validateFee(args.fee);
1262
+ const pair = await this.symbols.orderPair(args.token0, args.token1);
1263
+ const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1264
+ assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1265
+ if (args.amount0 !== void 0 && args.amount1 !== void 0) throw new GSwapSDKError("Provide at most one of amount0 or amount1.", "VALIDATION_ERROR");
1266
+ if (args.amount0 !== void 0) validateNumericAmount(args.amount0, "amount0");
1267
+ if (args.amount1 !== void 0) validateNumericAmount(args.amount1, "amount1");
1268
+ const withdrawal = args.amount0 !== void 0 ? pair.flipped ? { withdrawalQuantityToken1: new bignumber_js.default(args.amount0).toFixed() } : { withdrawalQuantityToken0: new bignumber_js.default(args.amount0).toFixed() } : args.amount1 !== void 0 ? pair.flipped ? { withdrawalQuantityToken0: new bignumber_js.default(args.amount1).toFixed() } : { withdrawalQuantityToken1: new bignumber_js.default(args.amount1).toFixed() } : {};
1269
+ const dto = {
1270
+ token0: pair.token0.symbol,
1271
+ token1: pair.token1.symbol,
1272
+ fee: args.fee,
1273
+ tickLower: ticks.tickLower,
1274
+ tickUpper: ticks.tickUpper,
1275
+ uniqueKey: this.uniqueKey(),
1276
+ ...withdrawal
1277
+ };
1278
+ const isFullClose = args.amount0 === void 0 && args.amount1 === void 0;
1279
+ return this.submit("RemoveLiquidity", dto, {
1280
+ kind: isFullClose ? "removeFull" : "removePartial",
1281
+ identity: {
1282
+ token0: pair.token0.symbol,
1283
+ token1: pair.token1.symbol,
1284
+ fee: args.fee,
1285
+ tickLower: ticks.tickLower,
1286
+ tickUpper: ticks.tickUpper
1287
+ }
1288
+ });
1289
+ }
1290
+ /**
1291
+ * Collects all accrued fees for a position; the contract does not support partial collection.
1292
+ *
1293
+ * @param args - Pair, fee, and tick range identifying the position.
1294
+ * @returns The synchronously submitted transaction.
1295
+ * @example
1296
+ * ```typescript
1297
+ * const tx = await gSwap.positions.collectPositionFees({
1298
+ * token0: 'GALA', token1: 'GUSDC', fee: 3000,
1299
+ * tickLower: -19200, tickUpper: 12000,
1300
+ * });
1301
+ * ```
1302
+ */
1303
+ async collectPositionFees(args) {
1304
+ validateFee(args.fee);
1305
+ const pair = await this.symbols.orderPair(args.token0, args.token1);
1306
+ const ticks = this.canonicalTicks(args.tickLower, args.tickUpper, pair.flipped);
1307
+ assertTickRange(ticks.tickLower, ticks.tickUpper, args.fee);
1308
+ const dto = {
1309
+ token0: pair.token0.symbol,
1310
+ token1: pair.token1.symbol,
1311
+ fee: args.fee,
1312
+ tickLower: ticks.tickLower,
1313
+ tickUpper: ticks.tickUpper,
1314
+ uniqueKey: this.uniqueKey()
1315
+ };
1316
+ return this.submit("CollectPositionFees", dto, {
1317
+ kind: "collect",
1318
+ identity: {
1319
+ token0: pair.token0.symbol,
1320
+ token1: pair.token1.symbol,
1321
+ fee: args.fee,
1322
+ tickLower: ticks.tickLower,
1323
+ tickUpper: ticks.tickUpper
1324
+ }
1325
+ });
1326
+ }
1327
+ /**
1328
+ * Creates a pool, resolving registered trading symbols.
1329
+ * Reversed symbol order inverts the supplied starting price or square-root price.
1330
+ *
1331
+ * A token class key carries no symbol, so for a token being proposed into the v2
1332
+ * trading-symbol registry for the first time (no existing pool has registered it yet) the
1333
+ * caller MUST pass `token0Symbol`/`token1Symbol` (the token class's symbol, from the token
1334
+ * list or FetchTokenClasses). The SDK never derives a symbol from the key, and throws a
1335
+ * VALIDATION_ERROR when an unregistered token has none. For an already-registered token a
1336
+ * supplied symbol must match the registered one.
1337
+ *
1338
+ * @param args - Token class keys or references, fee, exactly one starting price field, and privacy options.
1339
+ * @returns The synchronously submitted transaction.
1340
+ * @example
1341
+ * ```typescript
1342
+ * const tx = await gSwap.positions.createPool({
1343
+ * token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000,
1344
+ * startingPrice: '0.15',
1345
+ * });
1346
+ * ```
1347
+ */
1348
+ async createPool(args) {
1349
+ var _this$symbols$invalid, _this$symbols;
1350
+ const hasPrice = args.startingPrice !== void 0;
1351
+ if (hasPrice === (args.startingSqrtPrice !== void 0)) throw new GSwapSDKError("Provide exactly one of startingPrice or startingSqrtPrice.", "VALIDATION_ERROR");
1352
+ validateFee(args.fee);
1353
+ const [tokenA, tokenB] = await Promise.all([this.resolveCreateToken(args.token0, args.token0Symbol), this.resolveCreateToken(args.token1, args.token1Symbol)]);
1354
+ const flipped = tokenA.symbol > tokenB.symbol;
1355
+ const [token0, token1] = flipped ? [tokenB, tokenA] : [tokenA, tokenB];
1356
+ const sourcePriceInput = hasPrice ? args.startingPrice : args.startingSqrtPrice;
1357
+ this.rejectNumber(sourcePriceInput, hasPrice ? "startingPrice" : "startingSqrtPrice");
1358
+ const sourcePrice = new bignumber_js.default(sourcePriceInput);
1359
+ if (!sourcePrice.isFinite() || sourcePrice.isLessThanOrEqualTo(0)) throw new GSwapSDKError("Starting price must be finite and positive.", "VALIDATION_ERROR");
1360
+ const canonicalPrice = flipped ? new bignumber_js.default(1).dividedBy(sourcePrice) : sourcePrice;
1361
+ const dto = {
1362
+ token0Key: token0.classKey,
1363
+ token1Key: token1.classKey,
1364
+ token0Symbol: token0.symbol,
1365
+ token1Symbol: token1.symbol,
1366
+ fee: args.fee,
1367
+ uniqueKey: this.uniqueKey(),
1368
+ ...hasPrice ? { startingPrice: canonicalPrice.toFixed() } : { startingSqrtPrice: canonicalPrice.toFixed() },
1369
+ ...args.isPrivate === void 0 ? {} : { isPrivate: args.isPrivate },
1370
+ ...args.privateAccess === void 0 ? {} : { privateAccess: args.privateAccess }
1371
+ };
1372
+ const transaction = await this.submit("CreatePool", dto, {
1373
+ kind: "createPool",
1374
+ token0: token0.symbol,
1375
+ token1: token1.symbol,
1376
+ fee: args.fee
1377
+ });
1378
+ (_this$symbols$invalid = (_this$symbols = this.symbols).invalidate) === null || _this$symbols$invalid === void 0 || _this$symbols$invalid.call(_this$symbols);
1379
+ return transaction;
1380
+ }
1381
+ async submit(method, dto, confirmation) {
1382
+ if (this.signer === void 0) throw GSwapSDKError.noSignerError();
1383
+ const signed = await this.signer.signObject(method, dto);
1384
+ const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
1385
+ const owner = this.walletAddress;
1386
+ const positionConfirmation = this.buildPositionConfirmation(confirmation, owner);
1387
+ const options = {
1388
+ ...submitOptions,
1389
+ ...positionConfirmation === void 0 ? {} : { positionConfirmation }
1390
+ };
1391
+ return this.gateway.submit(method, signed, options);
1392
+ }
1393
+ /**
1394
+ * Builds a confirmation closure that proves the write's own effect, not just that a
1395
+ * position row exists (true before most of these writes run too, for any operation on a
1396
+ * pre-existing position — existence alone would false-confirm before the write executes,
1397
+ * and would never confirm a full close, whose whole point is that the position stops
1398
+ * existing).
1399
+ *
1400
+ * The "before" state is captured lazily, on the confirmation closure's own first poll —
1401
+ * not eagerly here in `submit()` — so confirming a write never adds an extra round-trip to
1402
+ * the write itself; the cost of establishing the baseline is paid by `confirm()`, only if
1403
+ * and when the caller actually asks to confirm.
1404
+ */
1405
+ buildPositionConfirmation(confirmation, owner) {
1406
+ if (confirmation === void 0) return void 0;
1407
+ if (confirmation.kind === "createPool") {
1408
+ const { token0, token1, fee } = confirmation;
1409
+ return async (signal) => {
1410
+ return await this.getNullable("/pool", {
1411
+ token0,
1412
+ token1,
1413
+ fee: `${fee}`
1414
+ }, signal) === null ? { confirmed: false } : {
1415
+ confirmed: true,
1416
+ position: null
1417
+ };
1418
+ };
1419
+ }
1420
+ if (owner === void 0) return void 0;
1421
+ const { kind, identity } = confirmation;
1422
+ let baseline;
1423
+ return async (signal) => {
1424
+ const current = await this.getPosition({
1425
+ ...identity,
1426
+ owner
1427
+ }, signal);
1428
+ if (baseline === void 0) {
1429
+ baseline = {
1430
+ liquidity: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.liquidity) ?? 0),
1431
+ fees: new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees0) ?? 0).plus(new bignumber_js.default((current === null || current === void 0 ? void 0 : current.fees1) ?? 0))
1432
+ };
1433
+ return kind === "removeFull" && current === null ? {
1434
+ confirmed: true,
1435
+ position: null
1436
+ } : { confirmed: false };
1437
+ }
1438
+ switch (kind) {
1439
+ case "add": return current !== null && new bignumber_js.default(current.liquidity).isGreaterThan(baseline.liquidity) ? {
1440
+ confirmed: true,
1441
+ position: current
1442
+ } : { confirmed: false };
1443
+ case "removePartial": return current !== null && new bignumber_js.default(current.liquidity).isLessThan(baseline.liquidity) ? {
1444
+ confirmed: true,
1445
+ position: current
1446
+ } : { confirmed: false };
1447
+ case "removeFull": return current === null ? {
1448
+ confirmed: true,
1449
+ position: null
1450
+ } : { confirmed: false };
1451
+ case "collect": {
1452
+ if (current === null) return { confirmed: false };
1453
+ const currentFees = new bignumber_js.default(current.fees0 ?? 0).plus(new bignumber_js.default(current.fees1 ?? 0));
1454
+ if (currentFees.isLessThan(baseline.fees)) return {
1455
+ confirmed: true,
1456
+ position: current
1457
+ };
1458
+ if (baseline.fees.isZero() && currentFees.isZero()) return {
1459
+ confirmed: true,
1460
+ position: current
1461
+ };
1462
+ return { confirmed: false };
1463
+ }
1464
+ }
1465
+ };
1466
+ }
1467
+ async get(endpoint, params, signal) {
1468
+ return this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", endpoint, params, signal === void 0 ? void 0 : { signal });
1469
+ }
1470
+ async getNullable(endpoint, params, signal) {
1471
+ try {
1472
+ return await this.get(endpoint, params, signal);
1473
+ } catch (error) {
1474
+ if (this.isNotFound(error)) return null;
1475
+ throw error;
1476
+ }
1477
+ }
1478
+ isNotFound(error) {
1479
+ if (!(error instanceof GSwapSDKError) || error.details === void 0) return false;
1480
+ return error.details["status"] === 404;
1481
+ }
1482
+ mapPosition(position) {
1483
+ return {
1484
+ token0Symbol: position.token0Symbol,
1485
+ token1Symbol: position.token1Symbol,
1486
+ ...position.token0CompositeKey === void 0 ? {} : { token0CompositeKey: position.token0CompositeKey },
1487
+ ...position.token1CompositeKey === void 0 ? {} : { token1CompositeKey: position.token1CompositeKey },
1488
+ fee: position.fee,
1489
+ tickLower: position.tickLower,
1490
+ tickUpper: position.tickUpper,
1491
+ liquidity: position.liquidity,
1492
+ amount0: position.amount0,
1493
+ amount1: position.amount1,
1494
+ inRange: position.inRange,
1495
+ ...position.currentTick === void 0 ? {} : { currentTick: position.currentTick },
1496
+ ...position.sqrtPrice === void 0 ? {} : { sqrtPrice: position.sqrtPrice },
1497
+ pool: position.poolRef ?? position.pool ?? "",
1498
+ owner: position.owner,
1499
+ ...position.fees0 === void 0 ? {} : { fees0: position.fees0 },
1500
+ ...position.fees1 === void 0 ? {} : { fees1: position.fees1 }
1501
+ };
1502
+ }
1503
+ requestToken(ref) {
1504
+ return typeof ref === "string" ? ref : compositeKeyOf(ref);
1505
+ }
1506
+ canonicalTicks(tickLower, tickUpper, flipped) {
1507
+ return flipped ? {
1508
+ tickLower: -tickUpper,
1509
+ tickUpper: -tickLower
1510
+ } : {
1511
+ tickLower,
1512
+ tickUpper
1513
+ };
1514
+ }
1515
+ tickSpacing(fee) {
1516
+ const spacing = TICK_SPACING_BY_FEE[fee];
1517
+ if (spacing === void 0) throw new GSwapSDKError(`Unsupported fee tier: ${fee}.`, "VALIDATION_ERROR");
1518
+ return spacing;
1519
+ }
1520
+ rejectNumber(value, parameterName) {
1521
+ if (typeof value === "number") throw new GSwapSDKError(`Invalid ${parameterName}: use a decimal string or BigNumber, not a JavaScript number`, "VALIDATION_ERROR");
1522
+ }
1523
+ uniqueKey() {
1524
+ return `gswap-sdk-${globalThis.crypto.randomUUID()}`;
1525
+ }
1526
+ async resolveCreateToken(ref, symbolOverride) {
1527
+ try {
1528
+ const lookupRef = typeof ref === "object" ? compositeKeyOf(ref) : ref;
1529
+ const resolved = await this.symbols.resolve(lookupRef);
1530
+ if (symbolOverride !== void 0 && symbolOverride !== "" && symbolOverride !== resolved.symbol) throw new GSwapSDKError(`Supplied symbol ${symbolOverride} disagrees with the registered trading symbol ${resolved.symbol}.`, "VALIDATION_ERROR", {
1531
+ token: ref,
1532
+ suppliedSymbol: symbolOverride,
1533
+ registeredSymbol: resolved.symbol
1534
+ });
1535
+ const suppliedClassKey = this.tryParseClassKey(ref);
1536
+ return {
1537
+ symbol: resolved.symbol,
1538
+ classKey: suppliedClassKey ?? parseTokenClassKey({
1539
+ collection: resolved.collection,
1540
+ category: resolved.category,
1541
+ type: resolved.type,
1542
+ additionalKey: resolved.additionalKey
1543
+ })
1544
+ };
1545
+ } catch (error) {
1546
+ if (!(error instanceof GSwapSDKError) || error.code !== "UNKNOWN_TOKEN") throw error;
1547
+ let classKey;
1548
+ try {
1549
+ classKey = parseTokenClassKey(ref);
1550
+ } catch {
1551
+ throw error;
1552
+ }
1553
+ if (symbolOverride === void 0 || symbolOverride === "") throw new GSwapSDKError("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.", "VALIDATION_ERROR", { token: ref });
1554
+ if (!/^[A-Za-z0-9]+$/u.test(symbolOverride)) throw new GSwapSDKError("Invalid trading symbol: must be ASCII letters and digits only.", "VALIDATION_ERROR", { symbol: symbolOverride });
1555
+ return {
1556
+ symbol: symbolOverride,
1557
+ classKey
1558
+ };
1559
+ }
1560
+ }
1561
+ tryParseClassKey(ref) {
1562
+ try {
1563
+ return parseTokenClassKey(ref);
1564
+ } catch {
1565
+ return;
1566
+ }
1567
+ }
1726
1568
  };
1727
1569
 
1728
- // src/classes/quoting.ts
1729
- var import_bignumber4 = __toESM(require("bignumber.js"), 1);
1570
+ //#endregion
1571
+ //#region src/classes/quoting.ts
1572
+ /** Read-only quote service backed by the v2 offline quote engine. */
1730
1573
  var Quoting = class {
1731
- /**
1732
- * Creates a quote service.
1733
- *
1734
- * @example
1735
- * ```ts
1736
- * const quoting = new Quoting('https://swap-backend.stage.defi.ovh.gala.com', http, symbols);
1737
- * ```
1738
- */
1739
- constructor(dexBackendBaseUrl, http, symbols) {
1740
- this.dexBackendBaseUrl = dexBackendBaseUrl;
1741
- this.http = http;
1742
- this.symbols = symbols;
1743
- }
1744
- dexBackendBaseUrl;
1745
- http;
1746
- symbols;
1747
- /**
1748
- * Quotes the output for a positive exact-input amount.
1749
- *
1750
- * @example
1751
- * ```ts
1752
- * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');
1753
- * console.log(quote.amountOut);
1754
- * ```
1755
- */
1756
- async quoteExactInput(tokenIn, tokenOut, amountIn, fee) {
1757
- validateNumericAmount(amountIn, "amountIn");
1758
- return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString(amountIn) }, fee);
1759
- }
1760
- /**
1761
- * Quotes the input for a positive exact-output amount.
1762
- *
1763
- * @example
1764
- * ```ts
1765
- * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);
1766
- * console.log(quote.amountIn);
1767
- * ```
1768
- */
1769
- async quoteExactOutput(tokenIn, tokenOut, amountOut, fee) {
1770
- validateNumericAmount(amountOut, "amountOut");
1771
- return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString(amountOut) }, fee);
1772
- }
1773
- async quote(tokenIn, tokenOut, amount, fee) {
1774
- validateOptionalFee(fee);
1775
- const tokenInSymbol = await resolveSymbol2(this.symbols, tokenIn);
1776
- const tokenOutSymbol = await resolveSymbol2(this.symbols, tokenOut);
1777
- const params = {
1778
- tokenIn: tokenInSymbol,
1779
- tokenOut: tokenOutSymbol,
1780
- ...amount
1781
- };
1782
- if (fee !== void 0) params["fee"] = String(fee);
1783
- try {
1784
- const response = await this.http.sendGetRequest(
1785
- this.dexBackendBaseUrl,
1786
- "/v2/trade",
1787
- "/quote",
1788
- params
1789
- );
1790
- return mapQuote(response.data);
1791
- } catch (error) {
1792
- throw mapQuoteError(error, tokenIn, tokenOut, fee);
1793
- }
1794
- }
1574
+ dexBackendBaseUrl;
1575
+ http;
1576
+ symbols;
1577
+ /**
1578
+ * Creates a quote service.
1579
+ *
1580
+ * @example
1581
+ * ```ts
1582
+ * const quoting = new Quoting('https://swap-backend.stage.defi.ovh.gala.com', http, symbols);
1583
+ * ```
1584
+ */
1585
+ constructor(dexBackendBaseUrl, http, symbols) {
1586
+ this.dexBackendBaseUrl = dexBackendBaseUrl;
1587
+ this.http = http;
1588
+ this.symbols = symbols;
1589
+ }
1590
+ /**
1591
+ * Quotes the output for a positive exact-input amount.
1592
+ *
1593
+ * @example
1594
+ * ```ts
1595
+ * const quote = await quoting.quoteExactInput('GALA', 'GUSDC', '100');
1596
+ * console.log(quote.amountOut);
1597
+ * ```
1598
+ */
1599
+ async quoteExactInput(tokenIn, tokenOut, amountIn, fee) {
1600
+ validateNumericAmount(amountIn, "amountIn");
1601
+ return this.quote(tokenIn, tokenOut, { amountIn: toDecimalString$1(amountIn) }, fee);
1602
+ }
1603
+ /**
1604
+ * Quotes the input for a positive exact-output amount.
1605
+ *
1606
+ * @example
1607
+ * ```ts
1608
+ * const quote = await quoting.quoteExactOutput('GALA', 'GUSDC', '10', 3000);
1609
+ * console.log(quote.amountIn);
1610
+ * ```
1611
+ */
1612
+ async quoteExactOutput(tokenIn, tokenOut, amountOut, fee) {
1613
+ validateNumericAmount(amountOut, "amountOut");
1614
+ return this.quote(tokenIn, tokenOut, { amountOut: toDecimalString$1(amountOut) }, fee);
1615
+ }
1616
+ async quote(tokenIn, tokenOut, amount, fee) {
1617
+ validateOptionalFee(fee);
1618
+ const params = {
1619
+ tokenIn: await resolveSymbol$1(this.symbols, tokenIn),
1620
+ tokenOut: await resolveSymbol$1(this.symbols, tokenOut),
1621
+ ...amount
1622
+ };
1623
+ if (fee !== void 0) params["fee"] = String(fee);
1624
+ try {
1625
+ return mapQuote((await this.http.sendGetRequest(this.dexBackendBaseUrl, "/v2/trade", "/quote", params)).data);
1626
+ } catch (error) {
1627
+ throw mapQuoteError(error, tokenIn, tokenOut, fee);
1628
+ }
1629
+ }
1795
1630
  };
1796
1631
  function mapQuote(value) {
1797
- if (!isQuoteWire(value)) {
1798
- throw new GSwapSDKError("Backend returned an invalid quote.", "INVALID_CHAIN_RESPONSE", {
1799
- data: value
1800
- });
1801
- }
1802
- const wire = value;
1803
- const currentPrice = wire.currentPrice !== void 0 ? new import_bignumber4.default(wire.currentPrice) : orientPrice(wire.currentSqrtPrice, wire.tokenInIsToken0);
1804
- const newPrice = wire.newPrice !== void 0 ? new import_bignumber4.default(wire.newPrice) : orientPrice(wire.newSqrtPrice, wire.tokenInIsToken0);
1805
- const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);
1806
- return {
1807
- contractVersion: wire.contractVersion,
1808
- fee: wire.fee,
1809
- amountIn: wire.amountIn,
1810
- amountOut: wire.amountOut,
1811
- ...wire.currentSqrtPrice === void 0 ? {} : { currentSqrtPrice: wire.currentSqrtPrice },
1812
- ...wire.newSqrtPrice === void 0 ? {} : { newSqrtPrice: wire.newSqrtPrice },
1813
- feeTier: wire.fee,
1814
- newTick: wire.newTick,
1815
- tradingFees: wire.tradingFees,
1816
- protocolFees: wire.protocolFees,
1817
- totalFees: wire.totalFees,
1818
- feeTokenSymbol: wire.feeTokenSymbol,
1819
- token0Symbol: wire.token0Symbol,
1820
- token1Symbol: wire.token1Symbol,
1821
- tokenInIsToken0: wire.tokenInIsToken0,
1822
- currentPrice,
1823
- newPrice,
1824
- priceImpact
1825
- };
1826
- }
1827
- var HighPrecision = import_bignumber4.default.clone({ DECIMAL_PLACES: 60 });
1632
+ if (!isQuoteWire(value)) throw new GSwapSDKError("Backend returned an invalid quote.", "INVALID_CHAIN_RESPONSE", { data: value });
1633
+ const wire = value;
1634
+ const currentPrice = wire.currentPrice !== void 0 ? new bignumber_js.default(wire.currentPrice) : orientPrice(wire.currentSqrtPrice, wire.tokenInIsToken0);
1635
+ const newPrice = wire.newPrice !== void 0 ? new bignumber_js.default(wire.newPrice) : orientPrice(wire.newSqrtPrice, wire.tokenInIsToken0);
1636
+ const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);
1637
+ return {
1638
+ contractVersion: wire.contractVersion,
1639
+ fee: wire.fee,
1640
+ amountIn: wire.amountIn,
1641
+ amountOut: wire.amountOut,
1642
+ ...wire.currentSqrtPrice === void 0 ? {} : { currentSqrtPrice: wire.currentSqrtPrice },
1643
+ ...wire.newSqrtPrice === void 0 ? {} : { newSqrtPrice: wire.newSqrtPrice },
1644
+ feeTier: wire.fee,
1645
+ newTick: wire.newTick,
1646
+ tradingFees: wire.tradingFees,
1647
+ protocolFees: wire.protocolFees,
1648
+ totalFees: wire.totalFees,
1649
+ feeTokenSymbol: wire.feeTokenSymbol,
1650
+ token0Symbol: wire.token0Symbol,
1651
+ token1Symbol: wire.token1Symbol,
1652
+ tokenInIsToken0: wire.tokenInIsToken0,
1653
+ currentPrice,
1654
+ newPrice,
1655
+ priceImpact
1656
+ };
1657
+ }
1658
+ const HighPrecision = bignumber_js.default.clone({ DECIMAL_PLACES: 60 });
1828
1659
  function orientPrice(sqrtPrice, tokenInIsToken0) {
1829
- const poolPrice = new HighPrecision(sqrtPrice).pow(2);
1830
- return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);
1660
+ const poolPrice = new HighPrecision(sqrtPrice).pow(2);
1661
+ return tokenInIsToken0 ? poolPrice : new HighPrecision(1).dividedBy(poolPrice);
1831
1662
  }
1832
1663
  function isQuoteWire(value) {
1833
- if (typeof value !== "object" || value === null) return false;
1834
- const wire = value;
1835
- const requiredStrings = [
1836
- "amountIn",
1837
- "amountOut",
1838
- "tradingFees",
1839
- "protocolFees",
1840
- "totalFees",
1841
- "feeTokenSymbol",
1842
- "token0Symbol",
1843
- "token1Symbol"
1844
- ];
1845
- return wire["contractVersion"] === "v2" && typeof wire["fee"] === "number" && Number.isFinite(wire["fee"]) && requiredStrings.every((key) => typeof wire[key] === "string") && typeof wire["newTick"] === "number" && Number.isInteger(wire["newTick"]) && typeof wire["tokenInIsToken0"] === "boolean" && optionalPositiveDecimal(wire["currentSqrtPrice"]) && optionalPositiveDecimal(wire["newSqrtPrice"]) && optionalPositiveDecimal(wire["currentPrice"]) && optionalPositiveDecimal(wire["newPrice"]) && (wire["currentSqrtPrice"] !== void 0 || wire["currentPrice"] !== void 0) && (wire["newSqrtPrice"] !== void 0 || wire["newPrice"] !== void 0);
1664
+ if (typeof value !== "object" || value === null) return false;
1665
+ const wire = value;
1666
+ return wire["contractVersion"] === "v2" && typeof wire["fee"] === "number" && Number.isFinite(wire["fee"]) && [
1667
+ "amountIn",
1668
+ "amountOut",
1669
+ "tradingFees",
1670
+ "protocolFees",
1671
+ "totalFees",
1672
+ "feeTokenSymbol",
1673
+ "token0Symbol",
1674
+ "token1Symbol"
1675
+ ].every((key) => typeof wire[key] === "string") && typeof wire["newTick"] === "number" && Number.isInteger(wire["newTick"]) && typeof wire["tokenInIsToken0"] === "boolean" && optionalPositiveDecimal(wire["currentSqrtPrice"]) && optionalPositiveDecimal(wire["newSqrtPrice"]) && optionalPositiveDecimal(wire["currentPrice"]) && optionalPositiveDecimal(wire["newPrice"]) && (wire["currentSqrtPrice"] !== void 0 || wire["currentPrice"] !== void 0) && (wire["newSqrtPrice"] !== void 0 || wire["newPrice"] !== void 0);
1846
1676
  }
1847
1677
  function optionalPositiveDecimal(value) {
1848
- if (value === void 0) return true;
1849
- if (typeof value !== "string") return false;
1850
- try {
1851
- const decimal = new import_bignumber4.default(value);
1852
- return decimal.isFinite() && decimal.isGreaterThan(0);
1853
- } catch {
1854
- return false;
1855
- }
1678
+ if (value === void 0) return true;
1679
+ if (typeof value !== "string") return false;
1680
+ try {
1681
+ const decimal = new bignumber_js.default(value);
1682
+ return decimal.isFinite() && decimal.isGreaterThan(0);
1683
+ } catch {
1684
+ return false;
1685
+ }
1856
1686
  }
1857
1687
  function mapQuoteError(error, tokenIn, tokenOut, fee) {
1858
- if (error instanceof GSwapSDKError) {
1859
- const status = readStatus(error.details);
1860
- const message = readMessage(error.details) ?? error.message;
1861
- if (status === 404 || /no pool|no pools|pool does not exist/iu.test(message)) {
1862
- return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee);
1863
- }
1864
- if (status === 400 && /insufficient liquidity/iu.test(message)) {
1865
- return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee);
1866
- }
1867
- return error;
1868
- }
1869
- return new GSwapSDKError("Quote request failed.", "HTTP_ERROR", {
1870
- cause: error,
1871
- tokenIn,
1872
- tokenOut,
1873
- fee
1874
- });
1688
+ if (error instanceof GSwapSDKError) {
1689
+ const status = readStatus(error.details);
1690
+ const message = readMessage(error.details) ?? error.message;
1691
+ if (status === 404 || /no pool|no pools|pool does not exist/iu.test(message)) return GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut, fee);
1692
+ if (status === 400 && /insufficient liquidity/iu.test(message)) return GSwapSDKError.insufficientLiquidityError(tokenIn, tokenOut, fee);
1693
+ return error;
1694
+ }
1695
+ return new GSwapSDKError("Quote request failed.", "HTTP_ERROR", {
1696
+ cause: error,
1697
+ tokenIn,
1698
+ tokenOut,
1699
+ fee
1700
+ });
1875
1701
  }
1876
1702
  function readStatus(details) {
1877
- const status = details == null ? void 0 : details["status"];
1878
- return typeof status === "number" ? status : void 0;
1703
+ const status = details === null || details === void 0 ? void 0 : details["status"];
1704
+ return typeof status === "number" ? status : void 0;
1879
1705
  }
1880
1706
  function readMessage(details) {
1881
- const direct = details == null ? void 0 : details["message"];
1882
- if (typeof direct === "string") return direct;
1883
- const body = details == null ? void 0 : details["body"];
1884
- if (typeof body !== "object" || body === null || Array.isArray(body)) return void 0;
1885
- const message = body["message"];
1886
- return typeof message === "string" ? message : void 0;
1707
+ const direct = details === null || details === void 0 ? void 0 : details["message"];
1708
+ if (typeof direct === "string") return direct;
1709
+ const body = details === null || details === void 0 ? void 0 : details["body"];
1710
+ if (typeof body !== "object" || body === null || Array.isArray(body)) return void 0;
1711
+ const message = body["message"];
1712
+ return typeof message === "string" ? message : void 0;
1887
1713
  }
1888
1714
  function validateOptionalFee(fee) {
1889
- if (fee !== void 0 && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) {
1890
- throw new GSwapSDKError(`Invalid fee tier: ${fee}`, "VALIDATION_ERROR", { fee });
1891
- }
1715
+ if (fee !== void 0 && !ALL_FEE_TIERS.some((tier) => Number(tier) === Number(fee))) throw new GSwapSDKError(`Invalid fee tier: ${fee}`, "VALIDATION_ERROR", { fee });
1892
1716
  }
1893
- function toDecimalString(amount) {
1894
- return new import_bignumber4.default(amount).toFixed();
1717
+ function toDecimalString$1(amount) {
1718
+ return new bignumber_js.default(amount).toFixed();
1895
1719
  }
1896
- async function resolveSymbol2(symbols, token) {
1897
- const resolved = await symbols.resolve(token);
1898
- if (resolved.symbol.length > 0) return resolved.symbol;
1899
- throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", {
1900
- token
1901
- });
1720
+ async function resolveSymbol$1(symbols, token) {
1721
+ const resolved = await symbols.resolve(token);
1722
+ if (resolved.symbol.length > 0) return resolved.symbol;
1723
+ throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", { token });
1902
1724
  }
1903
1725
 
1904
- // src/classes/symbols.ts
1905
- var SYMBOL_CACHE_TTL_MS = 6e4;
1726
+ //#endregion
1727
+ //#region src/classes/symbols.ts
1728
+ const SYMBOL_CACHE_TTL_MS = 6e4;
1729
+ /** Symbol registry client for the current GalaChainDex contract. */
1906
1730
  var Symbols = class {
1907
- /** Create a symbol service backed by the swap backend. */
1908
- constructor(gateway) {
1909
- this.gateway = gateway;
1910
- this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs);
1911
- }
1912
- gateway;
1913
- cachedSymbols;
1914
- cachedAt = 0;
1915
- refreshInFlight;
1916
- http;
1917
- /** List all registered GalaChainDex trading symbols, cached for 60 seconds. */
1918
- async list() {
1919
- if (this.cachedSymbols !== void 0 && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) {
1920
- return this.cachedSymbols;
1921
- }
1922
- if (this.refreshInFlight !== void 0) return this.refreshInFlight;
1923
- this.refreshInFlight = this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", "/symbols").then((response) => parseSymbols(response.data)).then((symbols) => {
1924
- this.cachedSymbols = symbols;
1925
- this.cachedAt = Date.now();
1926
- return symbols;
1927
- }).finally(() => {
1928
- this.refreshInFlight = void 0;
1929
- });
1930
- return this.refreshInFlight;
1931
- }
1932
- /** Invalidate the cached symbol registry after a write changes registration state.
1933
- *
1934
- * @example
1935
- * ```ts
1936
- * gSwap.symbols.invalidate();
1937
- * ```
1938
- */
1939
- invalidate() {
1940
- this.cachedSymbols = void 0;
1941
- this.cachedAt = 0;
1942
- }
1943
- /** Force one registry refresh, bypassing the cache.
1944
- *
1945
- * @example
1946
- * ```ts
1947
- * const symbols = await gSwap.symbols.refresh();
1948
- * ```
1949
- */
1950
- async refresh() {
1951
- this.invalidate();
1952
- this.refreshInFlight = void 0;
1953
- return this.list();
1954
- }
1955
- /** Resolve a symbol or token class key to its registered symbol metadata. */
1956
- async resolve(ref) {
1957
- let symbols = await this.list();
1958
- const composite = typeof ref === "string" ? isCompositeKey(ref) ? compositeKeyOf(parseTokenClassKey(ref)) : void 0 : compositeKeyOf(ref);
1959
- const resolved = symbols.find(
1960
- (entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite
1961
- );
1962
- if (resolved === void 0) {
1963
- symbols = await this.refresh();
1964
- const refreshed = symbols.find(
1965
- (entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite
1966
- );
1967
- if (refreshed === void 0) throw GSwapSDKError.unknownTokenError(ref);
1968
- return refreshed;
1969
- }
1970
- return resolved;
1971
- }
1972
- /** Resolve and put two token references in canonical trading-symbol order. */
1973
- async orderPair(a, b) {
1974
- const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);
1975
- const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);
1976
- return {
1977
- token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,
1978
- token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,
1979
- flipped: token0Symbol !== resolvedA.symbol
1980
- };
1981
- }
1731
+ gateway;
1732
+ cachedSymbols;
1733
+ cachedAt = 0;
1734
+ refreshInFlight;
1735
+ http;
1736
+ /** Create a symbol service backed by the swap backend. */
1737
+ constructor(gateway) {
1738
+ this.gateway = gateway;
1739
+ this.http = new HttpClient(gateway.httpRequestor, gateway.requestTimeoutMs);
1740
+ }
1741
+ /** List all registered GalaChainDex trading symbols, cached for 60 seconds. */
1742
+ async list() {
1743
+ if (this.cachedSymbols !== void 0 && Date.now() - this.cachedAt < SYMBOL_CACHE_TTL_MS) return this.cachedSymbols;
1744
+ if (this.refreshInFlight !== void 0) return this.refreshInFlight;
1745
+ this.refreshInFlight = this.http.sendGetRequest(this.gateway.dexBackendBaseUrl, "/v2/trade", "/symbols").then((response) => parseSymbols(response.data)).then((symbols) => {
1746
+ this.cachedSymbols = symbols;
1747
+ this.cachedAt = Date.now();
1748
+ return symbols;
1749
+ }).finally(() => {
1750
+ this.refreshInFlight = void 0;
1751
+ });
1752
+ return this.refreshInFlight;
1753
+ }
1754
+ /** Invalidate the cached symbol registry after a write changes registration state.
1755
+ *
1756
+ * @example
1757
+ * ```ts
1758
+ * gSwap.symbols.invalidate();
1759
+ * ```
1760
+ */
1761
+ invalidate() {
1762
+ this.cachedSymbols = void 0;
1763
+ this.cachedAt = 0;
1764
+ }
1765
+ /** Force one registry refresh, bypassing the cache.
1766
+ *
1767
+ * @example
1768
+ * ```ts
1769
+ * const symbols = await gSwap.symbols.refresh();
1770
+ * ```
1771
+ */
1772
+ async refresh() {
1773
+ this.invalidate();
1774
+ this.refreshInFlight = void 0;
1775
+ return this.list();
1776
+ }
1777
+ /** Resolve a symbol or token class key to its registered symbol metadata. */
1778
+ async resolve(ref) {
1779
+ let symbols = await this.list();
1780
+ const composite = typeof ref === "string" ? isCompositeKey(ref) ? compositeKeyOf(parseTokenClassKey(ref)) : void 0 : compositeKeyOf(ref);
1781
+ const resolved = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite);
1782
+ if (resolved === void 0) {
1783
+ symbols = await this.refresh();
1784
+ const refreshed = symbols.find((entry) => entry.symbol === ref || composite !== void 0 && compositeKeyOf(entry) === composite);
1785
+ if (refreshed === void 0) throw GSwapSDKError.unknownTokenError(ref);
1786
+ return refreshed;
1787
+ }
1788
+ return resolved;
1789
+ }
1790
+ /** Resolve and put two token references in canonical trading-symbol order. */
1791
+ async orderPair(a, b) {
1792
+ const [resolvedA, resolvedB] = await Promise.all([this.resolve(a), this.resolve(b)]);
1793
+ const [token0Symbol, token1Symbol] = orderSymbols(resolvedA.symbol, resolvedB.symbol);
1794
+ return {
1795
+ token0: token0Symbol === resolvedA.symbol ? resolvedA : resolvedB,
1796
+ token1: token1Symbol === resolvedB.symbol ? resolvedB : resolvedA,
1797
+ flipped: token0Symbol !== resolvedA.symbol
1798
+ };
1799
+ }
1982
1800
  };
1983
1801
  function parseSymbols(value) {
1984
- if (!Array.isArray(value) || !value.every(isTradingSymbol)) {
1985
- throw new GSwapSDKError("Backend returned an invalid symbol list.", "INVALID_CHAIN_RESPONSE", {
1986
- data: value
1987
- });
1988
- }
1989
- return value;
1802
+ if (!Array.isArray(value) || !value.every(isTradingSymbol)) throw new GSwapSDKError("Backend returned an invalid symbol list.", "INVALID_CHAIN_RESPONSE", { data: value });
1803
+ return value;
1990
1804
  }
1991
1805
  function isTradingSymbol(value) {
1992
- if (typeof value !== "object" || value === null) return false;
1993
- const entry = value;
1994
- return typeof entry["symbol"] === "string" && typeof entry["collection"] === "string" && typeof entry["category"] === "string" && typeof entry["type"] === "string" && typeof entry["additionalKey"] === "string" && typeof entry["decimals"] === "number" && Number.isInteger(entry["decimals"]) && entry["decimals"] >= 0;
1806
+ if (typeof value !== "object" || value === null) return false;
1807
+ const entry = value;
1808
+ return typeof entry["symbol"] === "string" && typeof entry["collection"] === "string" && typeof entry["category"] === "string" && typeof entry["type"] === "string" && typeof entry["additionalKey"] === "string" && typeof entry["decimals"] === "number" && Number.isInteger(entry["decimals"]) && entry["decimals"] >= 0;
1995
1809
  }
1996
1810
  function isCompositeKey(ref) {
1997
- return ref.includes("|") || ref.includes("$");
1811
+ return ref.includes("|") || ref.includes("$");
1998
1812
  }
1999
1813
 
2000
- // src/classes/swaps.ts
2001
- var import_bignumber5 = __toESM(require("bignumber.js"), 1);
2002
- var UNIQUE_KEY_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/u;
1814
+ //#endregion
1815
+ //#region src/classes/swaps.ts
1816
+ /** The swap backend's apply-results key constraint (`apply-results.dto.ts`). */
1817
+ const UNIQUE_KEY_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/u;
1818
+ /** Executes queued current-contract RequestTrade operations through the Chain Gateway. */
2003
1819
  var Swaps = class {
2004
- /**
2005
- * Creates a swap service.
2006
- *
2007
- * @example
2008
- * ```ts
2009
- * const swaps = new Swaps(gateway, symbols, signer, 'client|alice');
2010
- * ```
2011
- */
2012
- constructor(gateway, symbols, signer, walletAddress) {
2013
- this.gateway = gateway;
2014
- this.symbols = symbols;
2015
- this.signer = signer;
2016
- this.walletAddress = walletAddress;
2017
- }
2018
- gateway;
2019
- symbols;
2020
- signer;
2021
- walletAddress;
2022
- /**
2023
- * Signs and submits an exact-input or exact-output RequestTrade DTO. The returned transaction
2024
- * is QUEUED; call `await tx.confirm()` to obtain the executed trade or chain rejection.
2025
- *
2026
- * @example
2027
- * ```ts
2028
- * const submitted = await swaps.swap('GALA', 'GUSDC', 3000, {
2029
- * exactIn: '100',
2030
- * amountOutMinimum: '14',
2031
- * });
2032
- * ```
2033
- */
2034
- async swap(tokenIn, tokenOut, fee, amount) {
2035
- validateFee(fee);
2036
- const dto = await this.buildRequestTradeDto(tokenIn, tokenOut, fee, amount);
2037
- if (this.signer === void 0) throw GSwapSDKError.noSignerError();
2038
- const signedDto = await this.signer.signObject("RequestTrade", dto);
2039
- const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
2040
- return this.gateway.submit("RequestTrade", signedDto, submitOptions);
2041
- }
2042
- /**
2043
- * Confirm a swap by its durable `uniqueKey` without resubmitting it. This is the recovery
2044
- * path after a `CONFIRMATION_TIMEOUT`, a `SUBMISSION_OUTCOME_UNKNOWN`, a `409` replay
2045
- * conflict, or a process restart: it reads the same apply-results record that
2046
- * `SubmittedTransaction.confirm()` reads (retained for 7 days) and resolves the applied trade
2047
- * or throws the chain's rejection. The first read happens immediately unless
2048
- * `initialDelayMs` is given.
2049
- *
2050
- * @example
2051
- * ```ts
2052
- * const applied = await swaps.confirmSwap('gswap-sdk-2f1c…');
2053
- * ```
2054
- */
2055
- async confirmSwap(uniqueKey, options) {
2056
- if (!UNIQUE_KEY_PATTERN.test(uniqueKey)) {
2057
- throw new GSwapSDKError(
2058
- 'uniqueKey must be 1-128 characters of A-Z, a-z, 0-9, ".", "_", ":" or "-".',
2059
- "VALIDATION_ERROR",
2060
- { uniqueKey }
2061
- );
2062
- }
2063
- const transaction = new SubmittedTransaction({
2064
- method: "RequestTrade",
2065
- uniqueKey,
2066
- transactionId: null,
2067
- mode: "queued",
2068
- result: void 0,
2069
- dexBackendBaseUrl: this.gateway.dexBackendBaseUrl,
2070
- httpRequestor: this.gateway.httpRequestor,
2071
- requestTimeoutMs: this.gateway.requestTimeoutMs
2072
- });
2073
- return transaction.confirm({ initialDelayMs: 0, ...options });
2074
- }
2075
- async buildRequestTradeDto(tokenIn, tokenOut, fee, amount) {
2076
- const tokenInSymbol = await resolveSymbol3(this.symbols, tokenIn);
2077
- const tokenOutSymbol = await resolveSymbol3(this.symbols, tokenOut);
2078
- const ordered = readOrderedSymbols(orderSymbols(tokenInSymbol, tokenOutSymbol));
2079
- const tokenInIsToken0 = tokenInSymbol === ordered.token0;
2080
- const dto = {
2081
- token0: ordered.token0,
2082
- token1: ordered.token1,
2083
- fee,
2084
- uniqueKey: `gswap-sdk-${globalThis.crypto.randomUUID()}`
2085
- };
2086
- if ("exactIn" in amount) {
2087
- const exactIn = amount.exactIn;
2088
- if (exactIn === void 0) {
2089
- throw new GSwapSDKError("exactIn is required for an exact-input swap.", "VALIDATION_ERROR");
2090
- }
2091
- validateNumericAmount(exactIn, "exactIn");
2092
- dto[tokenInIsToken0 ? "sell0Qty" : "sell1Qty"] = toDecimalString2(exactIn);
2093
- if (amount.amountOutMinimum !== void 0) {
2094
- validateNumericAmount(amount.amountOutMinimum, "amountOutMinimum", true);
2095
- dto["amountOutMinimum"] = toDecimalString2(amount.amountOutMinimum);
2096
- }
2097
- } else {
2098
- const exactOut = amount.exactOut;
2099
- if (exactOut === void 0) {
2100
- throw new GSwapSDKError(
2101
- "exactOut is required for an exact-output swap.",
2102
- "VALIDATION_ERROR"
2103
- );
2104
- }
2105
- validateNumericAmount(exactOut, "exactOut");
2106
- dto[tokenInIsToken0 ? "buy1Qty" : "buy0Qty"] = toDecimalString2(exactOut);
2107
- if (amount.amountInMaximum !== void 0) {
2108
- validateNumericAmount(amount.amountInMaximum, "amountInMaximum", true);
2109
- dto["amountInMaximum"] = toDecimalString2(amount.amountInMaximum);
2110
- }
2111
- }
2112
- return dto;
2113
- }
1820
+ gateway;
1821
+ symbols;
1822
+ signer;
1823
+ walletAddress;
1824
+ /**
1825
+ * Creates a swap service.
1826
+ *
1827
+ * @example
1828
+ * ```ts
1829
+ * const swaps = new Swaps(gateway, symbols, signer, 'client|alice');
1830
+ * ```
1831
+ */
1832
+ constructor(gateway, symbols, signer, walletAddress) {
1833
+ this.gateway = gateway;
1834
+ this.symbols = symbols;
1835
+ this.signer = signer;
1836
+ this.walletAddress = walletAddress;
1837
+ }
1838
+ /**
1839
+ * Signs and submits an exact-input or exact-output RequestTrade DTO. The returned transaction
1840
+ * is QUEUED; call `await tx.confirm()` to obtain the executed trade or chain rejection.
1841
+ *
1842
+ * @example
1843
+ * ```ts
1844
+ * const submitted = await swaps.swap('GALA', 'GUSDC', 3000, {
1845
+ * exactIn: '100',
1846
+ * amountOutMinimum: '14',
1847
+ * });
1848
+ * ```
1849
+ */
1850
+ async swap(tokenIn, tokenOut, fee, amount) {
1851
+ validateFee(fee);
1852
+ const dto = await this.buildRequestTradeDto(tokenIn, tokenOut, fee, amount);
1853
+ if (this.signer === void 0) throw GSwapSDKError.noSignerError();
1854
+ const signedDto = await this.signer.signObject("RequestTrade", dto);
1855
+ const submitOptions = this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress };
1856
+ return this.gateway.submit("RequestTrade", signedDto, submitOptions);
1857
+ }
1858
+ /**
1859
+ * Confirm a swap by its durable `uniqueKey` without resubmitting it. This is the recovery
1860
+ * path after a `CONFIRMATION_TIMEOUT`, a `SUBMISSION_OUTCOME_UNKNOWN`, a `409` replay
1861
+ * conflict, or a process restart: it reads the same apply-results record that
1862
+ * `SubmittedTransaction.confirm()` reads (retained for 7 days) and resolves the applied trade
1863
+ * or throws the chain's rejection. The first read happens immediately unless
1864
+ * `initialDelayMs` is given.
1865
+ *
1866
+ * @example
1867
+ * ```ts
1868
+ * const applied = await swaps.confirmSwap('gswap-sdk-2f1c…');
1869
+ * ```
1870
+ */
1871
+ async confirmSwap(uniqueKey, options) {
1872
+ if (!UNIQUE_KEY_PATTERN.test(uniqueKey)) throw new GSwapSDKError("uniqueKey must be 1-128 characters of A-Z, a-z, 0-9, \".\", \"_\", \":\" or \"-\".", "VALIDATION_ERROR", { uniqueKey });
1873
+ return new SubmittedTransaction({
1874
+ method: "RequestTrade",
1875
+ uniqueKey,
1876
+ transactionId: null,
1877
+ mode: "queued",
1878
+ result: void 0,
1879
+ dexBackendBaseUrl: this.gateway.dexBackendBaseUrl,
1880
+ httpRequestor: this.gateway.httpRequestor,
1881
+ requestTimeoutMs: this.gateway.requestTimeoutMs
1882
+ }).confirm({
1883
+ initialDelayMs: 0,
1884
+ ...options
1885
+ });
1886
+ }
1887
+ async buildRequestTradeDto(tokenIn, tokenOut, fee, amount) {
1888
+ const tokenInSymbol = await resolveSymbol(this.symbols, tokenIn);
1889
+ const tokenOutSymbol = await resolveSymbol(this.symbols, tokenOut);
1890
+ const ordered = readOrderedSymbols(orderSymbols(tokenInSymbol, tokenOutSymbol));
1891
+ const tokenInIsToken0 = tokenInSymbol === ordered.token0;
1892
+ const dto = {
1893
+ token0: ordered.token0,
1894
+ token1: ordered.token1,
1895
+ fee,
1896
+ uniqueKey: `gswap-sdk-${globalThis.crypto.randomUUID()}`
1897
+ };
1898
+ if ("exactIn" in amount) {
1899
+ const exactIn = amount.exactIn;
1900
+ if (exactIn === void 0) throw new GSwapSDKError("exactIn is required for an exact-input swap.", "VALIDATION_ERROR");
1901
+ validateNumericAmount(exactIn, "exactIn");
1902
+ dto[tokenInIsToken0 ? "sell0Qty" : "sell1Qty"] = toDecimalString(exactIn);
1903
+ if (amount.amountOutMinimum !== void 0) {
1904
+ validateNumericAmount(amount.amountOutMinimum, "amountOutMinimum", true);
1905
+ dto["amountOutMinimum"] = toDecimalString(amount.amountOutMinimum);
1906
+ }
1907
+ } else {
1908
+ const exactOut = amount.exactOut;
1909
+ if (exactOut === void 0) throw new GSwapSDKError("exactOut is required for an exact-output swap.", "VALIDATION_ERROR");
1910
+ validateNumericAmount(exactOut, "exactOut");
1911
+ dto[tokenInIsToken0 ? "buy1Qty" : "buy0Qty"] = toDecimalString(exactOut);
1912
+ if (amount.amountInMaximum !== void 0) {
1913
+ validateNumericAmount(amount.amountInMaximum, "amountInMaximum", true);
1914
+ dto["amountInMaximum"] = toDecimalString(amount.amountInMaximum);
1915
+ }
1916
+ }
1917
+ return dto;
1918
+ }
2114
1919
  };
2115
- function toDecimalString2(amount) {
2116
- return new import_bignumber5.default(amount).toFixed();
1920
+ function toDecimalString(amount) {
1921
+ return new bignumber_js.default(amount).toFixed();
2117
1922
  }
2118
- async function resolveSymbol3(symbols, token) {
2119
- const resolved = await symbols.resolve(token);
2120
- if (resolved.symbol.length > 0) return resolved.symbol;
2121
- throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", {
2122
- token
2123
- });
1923
+ async function resolveSymbol(symbols, token) {
1924
+ const resolved = await symbols.resolve(token);
1925
+ if (resolved.symbol.length > 0) return resolved.symbol;
1926
+ throw new GSwapSDKError("Token could not be resolved to a trading symbol.", "SYMBOL_NOT_FOUND", { token });
2124
1927
  }
2125
1928
 
2126
- // src/types/env.ts
2127
- var GSWAP_ENVIRONMENTS = {
2128
- prod: {
2129
- dexBackendBaseUrl: "https://dex-backend-prod1.defi.gala.com"
2130
- },
2131
- stage: {
2132
- dexBackendBaseUrl: "https://swap-backend.stage.defi.ovh.gala.com"
2133
- }
1929
+ //#endregion
1930
+ //#region src/types/env.ts
1931
+ /** Built-in GalaSwap deployment environments. */
1932
+ const GSWAP_ENVIRONMENTS = {
1933
+ prod: { dexBackendBaseUrl: "https://dex-backend-prod1.defi.gala.com" },
1934
+ stage: { dexBackendBaseUrl: "https://swap-backend.stage.defi.ovh.gala.com" }
2134
1935
  };
2135
1936
 
2136
- // src/classes/gswap.ts
1937
+ //#endregion
1938
+ //#region src/classes/gswap.ts
1939
+ /** Main entry point for the current GalaChainDex SDK. */
2137
1940
  var GSwap = class {
2138
- dexBackendBaseUrl;
2139
- chainCallTimeoutMs;
2140
- signer;
2141
- walletAddress;
2142
- gateway;
2143
- symbols;
2144
- quoting;
2145
- pools;
2146
- positions;
2147
- swaps;
2148
- assets;
2149
- /**
2150
- * Create an SDK client for prod or stage.
2151
- *
2152
- * @example
2153
- * ```typescript
2154
- * const gSwap = new GSwap({ env: 'stage' });
2155
- * const symbols = await gSwap.symbols.list();
2156
- * ```
2157
- */
2158
- constructor(options) {
2159
- const environment = GSWAP_ENVIRONMENTS[(options == null ? void 0 : options.env) ?? "prod"];
2160
- this.dexBackendBaseUrl = trimTrailingSlash2(
2161
- (options == null ? void 0 : options.dexBackendBaseUrl) ?? environment.dexBackendBaseUrl
2162
- );
2163
- this.chainCallTimeoutMs = (options == null ? void 0 : options.chainCallTimeoutMs) ?? 3e4;
2164
- this.signer = options == null ? void 0 : options.signer;
2165
- this.walletAddress = options == null ? void 0 : options.walletAddress;
2166
- const httpClient = new HttpClient(options == null ? void 0 : options.httpRequestor, this.chainCallTimeoutMs);
2167
- this.gateway = new ChainGateway({
2168
- dexBackendBaseUrl: this.dexBackendBaseUrl,
2169
- chainCallTimeoutMs: this.chainCallTimeoutMs,
2170
- ...(options == null ? void 0 : options.httpRequestor) === void 0 ? {} : { httpRequestor: options.httpRequestor },
2171
- ...this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress }
2172
- });
2173
- this.symbols = new Symbols(this.gateway);
2174
- this.quoting = new Quoting(this.dexBackendBaseUrl, httpClient, this.symbols);
2175
- this.pools = new Pools(this.gateway, this.symbols);
2176
- this.positions = new Positions(this.gateway, this.symbols, this.signer, this.walletAddress);
2177
- this.swaps = new Swaps(this.gateway, this.symbols, this.signer, this.walletAddress);
2178
- this.assets = new Assets(this.dexBackendBaseUrl, httpClient);
2179
- }
1941
+ dexBackendBaseUrl;
1942
+ chainCallTimeoutMs;
1943
+ signer;
1944
+ walletAddress;
1945
+ gateway;
1946
+ symbols;
1947
+ quoting;
1948
+ pools;
1949
+ positions;
1950
+ swaps;
1951
+ assets;
1952
+ /**
1953
+ * Create an SDK client for prod or stage.
1954
+ *
1955
+ * @example
1956
+ * ```typescript
1957
+ * const gSwap = new GSwap({ env: 'stage' });
1958
+ * const symbols = await gSwap.symbols.list();
1959
+ * ```
1960
+ */
1961
+ constructor(options) {
1962
+ const environment = GSWAP_ENVIRONMENTS[(options === null || options === void 0 ? void 0 : options.env) ?? "prod"];
1963
+ this.dexBackendBaseUrl = trimTrailingSlash((options === null || options === void 0 ? void 0 : options.dexBackendBaseUrl) ?? environment.dexBackendBaseUrl);
1964
+ this.chainCallTimeoutMs = (options === null || options === void 0 ? void 0 : options.chainCallTimeoutMs) ?? 3e4;
1965
+ this.signer = options === null || options === void 0 ? void 0 : options.signer;
1966
+ this.walletAddress = options === null || options === void 0 ? void 0 : options.walletAddress;
1967
+ const httpClient = new HttpClient(options === null || options === void 0 ? void 0 : options.httpRequestor, this.chainCallTimeoutMs);
1968
+ this.gateway = new ChainGateway({
1969
+ dexBackendBaseUrl: this.dexBackendBaseUrl,
1970
+ chainCallTimeoutMs: this.chainCallTimeoutMs,
1971
+ ...(options === null || options === void 0 ? void 0 : options.httpRequestor) === void 0 ? {} : { httpRequestor: options.httpRequestor },
1972
+ ...this.walletAddress === void 0 ? {} : { walletAddress: this.walletAddress }
1973
+ });
1974
+ this.symbols = new Symbols(this.gateway);
1975
+ this.quoting = new Quoting(this.dexBackendBaseUrl, httpClient, this.symbols);
1976
+ this.pools = new Pools(this.gateway, this.symbols);
1977
+ this.positions = new Positions(this.gateway, this.symbols, this.signer, this.walletAddress);
1978
+ this.swaps = new Swaps(this.gateway, this.symbols, this.signer, this.walletAddress);
1979
+ this.assets = new Assets(this.dexBackendBaseUrl, httpClient);
1980
+ }
2180
1981
  };
2181
- function trimTrailingSlash2(value) {
2182
- return value.replace(/\/$/u, "");
1982
+ function trimTrailingSlash(value) {
1983
+ return value.replace(/\/$/u, "");
2183
1984
  }
2184
1985
 
2185
- // src/classes/signers.ts
2186
- var import_api = require("@gala-chain/api");
2187
-
2188
- // src/utils/eip712.ts
1986
+ //#endregion
1987
+ //#region src/utils/eip712.ts
1988
+ /**
1989
+ * Derives the EIP-712 `types` for a DTO from its runtime shape.
1990
+ *
1991
+ * The generated `types` travel with the signed payload and are what BOTH sides hash, so they
1992
+ * must enumerate EVERY field the chain-side DTO will carry. GalaChain refuses any signature
1993
+ * whose `types` leave a DTO field uncovered (`assertNoUnsignedFields`, the fix for the
1994
+ * 2026-08-18 unsigned-field-injection drain); when that happens signature recovery fails
1995
+ * outright and the chain reports "Missing signerPublicKey or signerAddress field in dto".
1996
+ */
2189
1997
  function generateEIP712Types(typeName, params) {
2190
- const types = {};
2191
- types[typeName] = [];
2192
- function fieldsFor(name) {
2193
- const fields = types[name];
2194
- if (!fields) throw new Error(`Missing EIP-712 type definition for ${name}`);
2195
- return fields;
2196
- }
2197
- function addField(name, fieldValue, parentTypeName, onlyGetType = false) {
2198
- if (Array.isArray(fieldValue)) {
2199
- const type = fieldValue.length > 0 ? addField(name, fieldValue[0], parentTypeName, true) : "string";
2200
- if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: (type ?? name) + "[]" });
2201
- } else if (typeof fieldValue === "object" && fieldValue !== null) {
2202
- if (types[name]) {
2203
- throw new Error("Name collisions not yet supported");
2204
- }
2205
- types[name] = [];
2206
- Object.entries(fieldValue).forEach(([key, value]) => {
2207
- addField(key, value, name);
2208
- });
2209
- if (!onlyGetType) fieldsFor(parentTypeName).push({ name, type: name });
2210
- } else {
2211
- let eipType;
2212
- switch (typeof fieldValue) {
2213
- case "string":
2214
- eipType = "string";
2215
- break;
2216
- case "number":
2217
- eipType = "int256";
2218
- break;
2219
- case "boolean":
2220
- eipType = "bool";
2221
- break;
2222
- case "bigint":
2223
- case "symbol":
2224
- case "undefined":
2225
- case "function":
2226
- case "object":
2227
- throw new Error(
2228
- `Unsupported type, ${typeof fieldValue}, value: ${Object.prototype.toString.call(fieldValue)}`
2229
- );
2230
- }
2231
- if (onlyGetType) {
2232
- return eipType;
2233
- }
2234
- fieldsFor(parentTypeName).push({ name, type: eipType });
2235
- }
2236
- return void 0;
2237
- }
2238
- Object.entries(params).forEach(([key, value]) => {
2239
- addField(key, value, typeName);
2240
- });
2241
- return types;
2242
- }
2243
- var EIP712_DOMAIN = { name: "ethereum", chainId: 1 };
2244
- var EIP712_CAPABLE_METHODS = /* @__PURE__ */ new Set([
2245
- "RequestTrade",
2246
- "AddLiquidity",
2247
- "RemoveLiquidity",
2248
- "CollectPositionFees"
1998
+ const types = {};
1999
+ types[typeName] = [];
2000
+ function fieldsFor(name) {
2001
+ const fields = types[name];
2002
+ /* c8 ignore next */
2003
+ if (!fields) throw new Error(`Missing EIP-712 type definition for ${name}`);
2004
+ return fields;
2005
+ }
2006
+ function addField(name, fieldValue, parentTypeName, onlyGetType = false) {
2007
+ if (Array.isArray(fieldValue)) {
2008
+ const type = fieldValue.length > 0 ? addField(name, fieldValue[0], parentTypeName, true) : "string";
2009
+ if (!onlyGetType) fieldsFor(parentTypeName).push({
2010
+ name,
2011
+ type: (type ?? name) + "[]"
2012
+ });
2013
+ } else if (typeof fieldValue === "object" && fieldValue !== null) {
2014
+ if (types[name]) throw new Error("Name collisions not yet supported");
2015
+ types[name] = [];
2016
+ Object.entries(fieldValue).forEach(([key, value]) => {
2017
+ addField(key, value, name);
2018
+ });
2019
+ if (!onlyGetType) fieldsFor(parentTypeName).push({
2020
+ name,
2021
+ type: name
2022
+ });
2023
+ } else {
2024
+ let eipType;
2025
+ switch (typeof fieldValue) {
2026
+ case "string":
2027
+ eipType = "string";
2028
+ break;
2029
+ case "number":
2030
+ eipType = "int256";
2031
+ break;
2032
+ case "boolean":
2033
+ eipType = "bool";
2034
+ break;
2035
+ case "bigint":
2036
+ case "symbol":
2037
+ case "undefined":
2038
+ case "function":
2039
+ case "object": throw new Error(`Unsupported type, ${typeof fieldValue}, value: ${Object.prototype.toString.call(fieldValue)}`);
2040
+ }
2041
+ if (onlyGetType) return eipType;
2042
+ fieldsFor(parentTypeName).push({
2043
+ name,
2044
+ type: eipType
2045
+ });
2046
+ }
2047
+ }
2048
+ Object.entries(params).forEach(([key, value]) => {
2049
+ addField(key, value, typeName);
2050
+ });
2051
+ return types;
2052
+ }
2053
+ /** Matches every genuine-EIP-712 probe that has actually recovered `client|` on stage. */
2054
+ const EIP712_DOMAIN = {
2055
+ name: "ethereum",
2056
+ chainId: 1
2057
+ };
2058
+ /**
2059
+ * The four v2 operations proven to recover the signer correctly via genuine EIP-712: `RequestTrade`
2060
+ * never had the problem (one numeric field). `AddLiquidity`/`RemoveLiquidity`/
2061
+ * `CollectPositionFees` each need their `types` completed with a handful of fields their real
2062
+ * server-side DTO always carries — see the `complete*Fields` functions below. `CreatePool` is a
2063
+ * genuinely different, unsolved problem (nested `TokenClassKey` structs, not a flat
2064
+ * missing-field gap) and is NOT in this set — callers must keep using `personal-sign` for it.
2065
+ */
2066
+ const EIP712_CAPABLE_METHODS = /* @__PURE__ */ new Set([
2067
+ "RequestTrade",
2068
+ "AddLiquidity",
2069
+ "RemoveLiquidity",
2070
+ "CollectPositionFees"
2249
2071
  ]);
2072
+ /**
2073
+ * Every `complete*Fields` function below shares the same two live-proven rules:
2074
+ * 1. Numeric completeness fields MUST be JS `number`, never numeric strings —
2075
+ * `generateEIP712Types` infers a field's Solidity type from `typeof`, and declaring one as
2076
+ * EIP-712 `string` instead of `int256` breaks recovery identically to omitting the field
2077
+ * entirely (verified live on AddLiquidity: `amount0Min: '0'` fails with the exact same
2078
+ * "Missing signerPublicKey" error as `amount0Min` being absent; `amount0Min: 0` succeeds).
2079
+ * 2. `positionId` has no such constraint — an empty string works, and does not target an
2080
+ * existing position (`positionId: ''` created a fresh position on AddLiquidity, not an add
2081
+ * to position id `''`; on RemoveLiquidity/CollectPositionFees the real position is still
2082
+ * resolved from `token0`/`token1`/`fee`/`tickLower`/`tickUpper`, not from this field).
2083
+ */
2250
2084
  function numericOr0(dto, field) {
2251
- return typeof dto[field] === "number" ? dto[field] : 0;
2252
- }
2085
+ return typeof dto[field] === "number" ? dto[field] : 0;
2086
+ }
2087
+ /**
2088
+ * `AddLiquidity`'s real server-side DTO always carries `amount0Desired`/`amount0Min`/
2089
+ * `amount1Desired`/`amount1Min`/`positionId` once reconstructed, regardless of which deposit
2090
+ * convention the caller used (`Positions.addLiquidityByTicks` only ever sends
2091
+ * `depositQuantityToken0`/`depositQuantityToken1`). Proven empirically by bisection: none of the
2092
+ * five alone fixes recovery, all five together does (live 201, tx `407d9b24...`, block
2093
+ * `2429022`).
2094
+ */
2253
2095
  function completeAddLiquidityFields(dto) {
2254
- return {
2255
- ...dto,
2256
- amount0Desired: numericOr0(dto, "amount0Desired"),
2257
- amount0Min: numericOr0(dto, "amount0Min"),
2258
- amount1Desired: numericOr0(dto, "amount1Desired"),
2259
- amount1Min: numericOr0(dto, "amount1Min"),
2260
- positionId: dto["positionId"] ?? ""
2261
- };
2262
- }
2096
+ return {
2097
+ ...dto,
2098
+ amount0Desired: numericOr0(dto, "amount0Desired"),
2099
+ amount0Min: numericOr0(dto, "amount0Min"),
2100
+ amount1Desired: numericOr0(dto, "amount1Desired"),
2101
+ amount1Min: numericOr0(dto, "amount1Min"),
2102
+ positionId: dto["positionId"] ?? ""
2103
+ };
2104
+ }
2105
+ /**
2106
+ * `RemoveLiquidity`'s real server-side DTO always carries `amount`/`amount0Min`/`amount1Min`/
2107
+ * `positionId` — `Positions.removeLiquidity` only ever sends a `withdrawalQuantityTokenX` (or
2108
+ * neither, for a full close). Proven empirically: every subset of these four fails, all four
2109
+ * together succeeds (live, random-signer probe — recovery confirmed by the response moving from
2110
+ * "Missing signerPublicKey" to a genuine position-not-found 404).
2111
+ */
2263
2112
  function completeRemoveLiquidityFields(dto) {
2264
- return {
2265
- ...dto,
2266
- amount: numericOr0(dto, "amount"),
2267
- amount0Min: numericOr0(dto, "amount0Min"),
2268
- amount1Min: numericOr0(dto, "amount1Min"),
2269
- positionId: dto["positionId"] ?? ""
2270
- };
2271
- }
2113
+ return {
2114
+ ...dto,
2115
+ amount: numericOr0(dto, "amount"),
2116
+ amount0Min: numericOr0(dto, "amount0Min"),
2117
+ amount1Min: numericOr0(dto, "amount1Min"),
2118
+ positionId: dto["positionId"] ?? ""
2119
+ };
2120
+ }
2121
+ /**
2122
+ * `CollectPositionFees`'s real server-side DTO always carries `amount0Requested`/
2123
+ * `amount1Requested`/`positionId` — `Positions.collectPositionFees` sends only the five identity
2124
+ * fields. Proven empirically the same way as `completeRemoveLiquidityFields`.
2125
+ */
2272
2126
  function completeCollectPositionFeesFields(dto) {
2273
- return {
2274
- ...dto,
2275
- amount0Requested: numericOr0(dto, "amount0Requested"),
2276
- amount1Requested: numericOr0(dto, "amount1Requested"),
2277
- positionId: dto["positionId"] ?? ""
2278
- };
2279
- }
2280
- var EIP712_FIELD_COMPLETERS = {
2281
- AddLiquidity: completeAddLiquidityFields,
2282
- RemoveLiquidity: completeRemoveLiquidityFields,
2283
- CollectPositionFees: completeCollectPositionFeesFields
2127
+ return {
2128
+ ...dto,
2129
+ amount0Requested: numericOr0(dto, "amount0Requested"),
2130
+ amount1Requested: numericOr0(dto, "amount1Requested"),
2131
+ positionId: dto["positionId"] ?? ""
2132
+ };
2133
+ }
2134
+ const EIP712_FIELD_COMPLETERS = {
2135
+ AddLiquidity: completeAddLiquidityFields,
2136
+ RemoveLiquidity: completeRemoveLiquidityFields,
2137
+ CollectPositionFees: completeCollectPositionFeesFields
2284
2138
  };
2139
+ /**
2140
+ * Completes a DTO's fields for EIP-712 signing (a no-op for methods with no known gap, e.g.
2141
+ * `RequestTrade`) and derives its `types`. Exported separately from the signing call itself so tests
2142
+ * can assert on the exact payload without needing a live provider.
2143
+ */
2285
2144
  function buildEIP712Payload(methodName, dto) {
2286
- const completer = EIP712_FIELD_COMPLETERS[methodName];
2287
- const completedDto = completer ? completer(dto) : dto;
2288
- const types = generateEIP712Types(methodName, completedDto);
2289
- return { completedDto, types };
2145
+ const completer = EIP712_FIELD_COMPLETERS[methodName];
2146
+ const completedDto = completer ? completer(dto) : dto;
2147
+ return {
2148
+ completedDto,
2149
+ types: generateEIP712Types(methodName, completedDto)
2150
+ };
2290
2151
  }
2291
2152
 
2292
- // src/classes/signers.ts
2293
- var ETHEREUM_SIGNED_MESSAGE = String.fromCharCode(25) + "Ethereum Signed Message:\n";
2153
+ //#endregion
2154
+ //#region src/classes/signers.ts
2155
+ const ETHEREUM_SIGNED_MESSAGE = String.fromCharCode(25) + "Ethereum Signed Message:\n";
2156
+ /** The EIP-191 header for `dto`'s canonical JSON (UTF-8 byte length; any `prefix` on it is ignored). */
2294
2157
  function personalSignPrefixFor(dto) {
2295
- const withoutPrefix = { ...dto };
2296
- delete withoutPrefix["prefix"];
2297
- const message = (0, import_api.serialize)(withoutPrefix);
2298
- return ETHEREUM_SIGNED_MESSAGE + String(new TextEncoder().encode(message).length);
2158
+ const withoutPrefix = { ...dto };
2159
+ delete withoutPrefix["prefix"];
2160
+ const message = (0, _gala_chain_api.serialize)(withoutPrefix);
2161
+ return ETHEREUM_SIGNED_MESSAGE + String(new TextEncoder().encode(message).length);
2299
2162
  }
2300
2163
  function getWalletProvider() {
2301
- var _a;
2302
- const globalObject = globalThis;
2303
- const wallet = (_a = globalObject.window) == null ? void 0 : _a.gala;
2304
- if (!wallet) {
2305
- throw new GSwapSDKError(
2306
- "Gala wallet is not available. Please ensure the Gala wallet is connected.",
2307
- "GALA_WALLET_NOT_AVAILABLE"
2308
- );
2309
- }
2310
- return wallet;
2164
+ var _globalObject$window;
2165
+ const wallet = (_globalObject$window = globalThis.window) === null || _globalObject$window === void 0 ? void 0 : _globalObject$window.gala;
2166
+ if (!wallet) throw new GSwapSDKError("Gala wallet is not available. Please ensure the Gala wallet is connected.", "GALA_WALLET_NOT_AVAILABLE");
2167
+ return wallet;
2311
2168
  }
2312
2169
  function getNativeSignature(value) {
2313
- if (typeof value !== "string") {
2314
- throw new GSwapSDKError("Wallet returned an invalid signature.", "INVALID_SIGNATURE");
2315
- }
2316
- if (!/^[0-9a-fA-F]{130}$/u.test(value)) {
2317
- throw new GSwapSDKError("Wallet returned an invalid native signature.", "INVALID_SIGNATURE");
2318
- }
2319
- return value;
2170
+ if (typeof value !== "string") throw new GSwapSDKError("Wallet returned an invalid signature.", "INVALID_SIGNATURE");
2171
+ if (!/^[0-9a-fA-F]{130}$/u.test(value)) throw new GSwapSDKError("Wallet returned an invalid native signature.", "INVALID_SIGNATURE");
2172
+ return value;
2320
2173
  }
2321
2174
  function getPersonalSignature(value) {
2322
- if (typeof value !== "string" || !/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) {
2323
- throw new GSwapSDKError(
2324
- "Wallet returned an invalid personal-sign signature.",
2325
- "INVALID_SIGNATURE"
2326
- );
2327
- }
2328
- return value;
2175
+ if (typeof value !== "string" || !/^(?:0x)?[0-9a-fA-F]{130}$/u.test(value)) throw new GSwapSDKError("Wallet returned an invalid personal-sign signature.", "INVALID_SIGNATURE");
2176
+ return value;
2329
2177
  }
2330
2178
  function normalizeEthereumAccount(address, allowGalaPrefix) {
2331
- const normalized = allowGalaPrefix && address.startsWith("eth|") ? address.slice(4) : address;
2332
- if (!/^0x[0-9a-fA-F]{40}$/u.test(normalized)) {
2333
- throw new GSwapSDKError(
2334
- "Wallet address must be the selected Ethereum account in 0x-prefixed form.",
2335
- "VALIDATION_ERROR",
2336
- { type: "INVALID_WALLET_ADDRESS", value: address }
2337
- );
2338
- }
2339
- return `0x${normalized.slice(2).toLowerCase()}`;
2179
+ const normalized = allowGalaPrefix && address.startsWith("eth|") ? address.slice(4) : address;
2180
+ if (!/^0x[0-9a-fA-F]{40}$/u.test(normalized)) throw new GSwapSDKError("Wallet address must be the selected Ethereum account in 0x-prefixed form.", "VALIDATION_ERROR", {
2181
+ type: "INVALID_WALLET_ADDRESS",
2182
+ value: address
2183
+ });
2184
+ return `0x${normalized.slice(2).toLowerCase()}`;
2340
2185
  }
2341
2186
  function getErrorMessage(error) {
2342
- if (error instanceof Error) {
2343
- return error.message;
2344
- }
2345
- if (typeof error === "string") {
2346
- return error;
2347
- }
2348
- if (typeof error === "object" && error !== null && "message" in error) {
2349
- const message = error.message;
2350
- return typeof message === "string" ? message : "";
2351
- }
2352
- return "";
2187
+ if (error instanceof Error) return error.message;
2188
+ if (typeof error === "string") return error;
2189
+ if (typeof error === "object" && error !== null && "message" in error) {
2190
+ const message = error.message;
2191
+ return typeof message === "string" ? message : "";
2192
+ }
2193
+ return "";
2353
2194
  }
2354
2195
  function isUnsupportedNativeSchemeError(error) {
2355
- return /unsupported|unknown scheme/i.test(getErrorMessage(error));
2196
+ return /unsupported|unknown scheme/i.test(getErrorMessage(error));
2356
2197
  }
2357
2198
  function personalSign(provider, dto, walletAddress, methodName) {
2358
- const prefix = personalSignPrefixFor(dto);
2359
- const payload = { ...dto, prefix };
2360
- const params = methodName !== void 0 ? [(0, import_api.serialize)(payload), walletAddress, methodName] : [(0, import_api.serialize)(dto), walletAddress];
2361
- return provider.request({ method: methodName !== void 0 ? "gala_signChainDto" : "personal_sign", params }).then((value) => ({ ...payload, signature: getPersonalSignature(value) }));
2362
- }
2199
+ const prefix = personalSignPrefixFor(dto);
2200
+ const payload = {
2201
+ ...dto,
2202
+ prefix
2203
+ };
2204
+ const params = methodName !== void 0 ? [
2205
+ (0, _gala_chain_api.serialize)(payload),
2206
+ walletAddress,
2207
+ methodName
2208
+ ] : [(0, _gala_chain_api.serialize)(dto), walletAddress];
2209
+ return provider.request({
2210
+ method: methodName !== void 0 ? "gala_signChainDto" : "personal_sign",
2211
+ params
2212
+ }).then((value) => ({
2213
+ ...payload,
2214
+ signature: getPersonalSignature(value)
2215
+ }));
2216
+ }
2217
+ /**
2218
+ * Signs a DTO via genuine EIP-712 (`eth_signTypedData_v4`) — correctly resolves the `client|`
2219
+ * identity, unlike `personal_sign`, for the operations in `EIP712_CAPABLE_METHODS`.
2220
+ *
2221
+ * Constructs the raw JSON-RPC payload by hand (`{domain, types: {...types, EIP712Domain},
2222
+ * primaryType, message}`) rather than depending on ethers.js, matching exactly what
2223
+ * `ethers.TypedDataEncoder.getPayload`/`Wallet.signTypedData` produce internally — verified
2224
+ * byte-for-byte equivalent (same recovered address from the same signature against both
2225
+ * constructions) before this shipped, since gswap-sdk deliberately has no ethers dependency.
2226
+ */
2363
2227
  function signEIP712(provider, methodName, dto, walletAddress) {
2364
- const { completedDto, types } = buildEIP712Payload(methodName, dto);
2365
- const prefix = personalSignPrefixFor(completedDto);
2366
- const message = { ...completedDto, prefix };
2367
- const eip712Domain = [
2368
- { name: "name", type: "string" },
2369
- { name: "chainId", type: "uint256" }
2370
- ];
2371
- const payload = {
2372
- domain: EIP712_DOMAIN,
2373
- types: { ...types, EIP712Domain: eip712Domain },
2374
- primaryType: methodName,
2375
- message
2376
- };
2377
- return provider.request({
2378
- method: "eth_signTypedData_v4",
2379
- params: [walletAddress, JSON.stringify(payload)]
2380
- }).then((value) => ({
2381
- ...message,
2382
- types,
2383
- domain: EIP712_DOMAIN,
2384
- signature: getPersonalSignature(value)
2385
- }));
2386
- }
2228
+ const { completedDto, types } = buildEIP712Payload(methodName, dto);
2229
+ const prefix = personalSignPrefixFor(completedDto);
2230
+ const message = {
2231
+ ...completedDto,
2232
+ prefix
2233
+ };
2234
+ const eip712Domain = [{
2235
+ name: "name",
2236
+ type: "string"
2237
+ }, {
2238
+ name: "chainId",
2239
+ type: "uint256"
2240
+ }];
2241
+ const payload = {
2242
+ domain: EIP712_DOMAIN,
2243
+ types: {
2244
+ ...types,
2245
+ EIP712Domain: eip712Domain
2246
+ },
2247
+ primaryType: methodName,
2248
+ message
2249
+ };
2250
+ return provider.request({
2251
+ method: "eth_signTypedData_v4",
2252
+ params: [walletAddress, JSON.stringify(payload)]
2253
+ }).then((value) => ({
2254
+ ...message,
2255
+ types,
2256
+ domain: EIP712_DOMAIN,
2257
+ signature: getPersonalSignature(value)
2258
+ }));
2259
+ }
2260
+ /**
2261
+ * A GalaChain native signer backed by a secp256k1 private key.
2262
+ *
2263
+ * Native signing produces the bare GalaChain signature format, without a personal-sign prefix
2264
+ * or EIP-712 metadata. The private-key identity is recovered by the chain.
2265
+ */
2387
2266
  var PrivateKeySigner = class {
2388
- keyBuffer;
2389
- /**
2390
- * Creates a native signer from a hex or base64 secp256k1 private key.
2391
- *
2392
- * @example
2393
- * ```typescript
2394
- * const signer = new PrivateKeySigner('1'.padStart(64, '0'));
2395
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2396
- * ```
2397
- */
2398
- constructor(privateKey) {
2399
- this.keyBuffer = import_api.signatures.normalizePrivateKey(privateKey);
2400
- }
2401
- /**
2402
- * Signs the DTO with GalaChain native signing.
2403
- *
2404
- * @example
2405
- * ```typescript
2406
- * const signed = await signer.signObject('RequestTrade', {
2407
- * token0: 'GALA',
2408
- * token1: 'GUSDC',
2409
- * fee: 3000,
2410
- * });
2411
- * ```
2412
- */
2413
- signObject(_methodName, dto) {
2414
- const signature = import_api.signatures.getSignature(dto, this.keyBuffer);
2415
- return Promise.resolve({ ...dto, signature });
2416
- }
2267
+ keyBuffer;
2268
+ /**
2269
+ * Creates a native signer from a hex or base64 secp256k1 private key.
2270
+ *
2271
+ * @example
2272
+ * ```typescript
2273
+ * const signer = new PrivateKeySigner('1'.padStart(64, '0'));
2274
+ * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2275
+ * ```
2276
+ */
2277
+ constructor(privateKey) {
2278
+ this.keyBuffer = _gala_chain_api.signatures.normalizePrivateKey(privateKey);
2279
+ }
2280
+ /**
2281
+ * Signs the DTO with GalaChain native signing.
2282
+ *
2283
+ * @example
2284
+ * ```typescript
2285
+ * const signed = await signer.signObject('RequestTrade', {
2286
+ * token0: 'GALA',
2287
+ * token1: 'GUSDC',
2288
+ * fee: 3000,
2289
+ * });
2290
+ * ```
2291
+ */
2292
+ signObject(_methodName, dto) {
2293
+ const signature = _gala_chain_api.signatures.getSignature(dto, this.keyBuffer);
2294
+ return Promise.resolve({
2295
+ ...dto,
2296
+ signature
2297
+ });
2298
+ }
2417
2299
  };
2300
+ /**
2301
+ * A Gala Wallet signer using native GalaChain signing, with an opt-in personal-sign mode and
2302
+ * automatic fallback for older wallets.
2303
+ *
2304
+ * The selected Ethereum account is passed to Gala Wallet. Personal-sign resolves the bare
2305
+ * `eth|` identity; the legacy EIP-712 `eth_signTypedData` path is not used. The fallback calls
2306
+ * `gala_signChainDto([serialize({ ...dto, prefix }), walletAddress, methodName])`.
2307
+ */
2418
2308
  var GalaWalletSigner = class {
2419
- /** The wallet address supplied to Gala Wallet for each signing request. */
2420
- walletAddress;
2421
- /** The scheme currently used, including any automatic native-to-personal fallback. */
2422
- effectiveScheme;
2423
- /**
2424
- * Creates a Gala Wallet signer.
2425
- *
2426
- * @example
2427
- * ```typescript
2428
- * const signer = new GalaWalletSigner('0x0123456789012345678901234567890123456789');
2429
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2430
- * ```
2431
- *
2432
- * @param walletAddress - The selected Ethereum account (`0x` plus 40 hex digits); Gala Wallet's
2433
- * `eth|0x...` form is also accepted and normalized.
2434
- * @param options - Select native signing or personal-sign explicitly.
2435
- */
2436
- constructor(walletAddress, options = {}) {
2437
- this.walletAddress = normalizeEthereumAccount(walletAddress, true);
2438
- this.effectiveScheme = options.scheme ?? "native";
2439
- }
2440
- /**
2441
- * Signs a DTO through `gala_signChainDto`.
2442
- *
2443
- * @example
2444
- * ```typescript
2445
- * const signed = await signer.signObject('AddLiquidity', {
2446
- * token0: 'GALA',
2447
- * token1: 'GUSDC',
2448
- * tickLower: -60,
2449
- * tickUpper: 60,
2450
- * });
2451
- * ```
2452
- */
2453
- async signObject(methodName, dto) {
2454
- const wallet = getWalletProvider();
2455
- if (this.effectiveScheme === "personal-sign") {
2456
- return personalSign(wallet, dto, this.walletAddress, methodName);
2457
- }
2458
- try {
2459
- const signature = await wallet.request({
2460
- method: "gala_signChainDto",
2461
- params: [(0, import_api.serialize)(dto), this.walletAddress, methodName, "native"]
2462
- });
2463
- return { ...dto, signature: getNativeSignature(signature) };
2464
- } catch (error) {
2465
- if (!isUnsupportedNativeSchemeError(error)) {
2466
- throw error;
2467
- }
2468
- this.effectiveScheme = "personal-sign";
2469
- return personalSign(wallet, dto, this.walletAddress, methodName);
2470
- }
2471
- }
2309
+ /** The wallet address supplied to Gala Wallet for each signing request. */
2310
+ walletAddress;
2311
+ /** The scheme currently used, including any automatic native-to-personal fallback. */
2312
+ effectiveScheme;
2313
+ /**
2314
+ * Creates a Gala Wallet signer.
2315
+ *
2316
+ * @example
2317
+ * ```typescript
2318
+ * const signer = new GalaWalletSigner('0x0123456789012345678901234567890123456789');
2319
+ * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2320
+ * ```
2321
+ *
2322
+ * @param walletAddress - The selected Ethereum account (`0x` plus 40 hex digits); Gala Wallet's
2323
+ * `eth|0x...` form is also accepted and normalized.
2324
+ * @param options - Select native signing or personal-sign explicitly.
2325
+ */
2326
+ constructor(walletAddress, options = {}) {
2327
+ this.walletAddress = normalizeEthereumAccount(walletAddress, true);
2328
+ this.effectiveScheme = options.scheme ?? "native";
2329
+ }
2330
+ /**
2331
+ * Signs a DTO through `gala_signChainDto`.
2332
+ *
2333
+ * @example
2334
+ * ```typescript
2335
+ * const signed = await signer.signObject('AddLiquidity', {
2336
+ * token0: 'GALA',
2337
+ * token1: 'GUSDC',
2338
+ * tickLower: -60,
2339
+ * tickUpper: 60,
2340
+ * });
2341
+ * ```
2342
+ */
2343
+ async signObject(methodName, dto) {
2344
+ const wallet = getWalletProvider();
2345
+ if (this.effectiveScheme === "personal-sign") return personalSign(wallet, dto, this.walletAddress, methodName);
2346
+ try {
2347
+ const signature = await wallet.request({
2348
+ method: "gala_signChainDto",
2349
+ params: [
2350
+ (0, _gala_chain_api.serialize)(dto),
2351
+ this.walletAddress,
2352
+ methodName,
2353
+ "native"
2354
+ ]
2355
+ });
2356
+ return {
2357
+ ...dto,
2358
+ signature: getNativeSignature(signature)
2359
+ };
2360
+ } catch (error) {
2361
+ if (!isUnsupportedNativeSchemeError(error)) throw error;
2362
+ this.effectiveScheme = "personal-sign";
2363
+ return personalSign(wallet, dto, this.walletAddress, methodName);
2364
+ }
2365
+ }
2472
2366
  };
2367
+ /**
2368
+ * A personal-sign signer for MetaMask and other EIP-1193 browser wallets.
2369
+ *
2370
+ * The chain recovers this signature using the EIP-191 wrap applied by the wallet to
2371
+ * `personal_sign`. This is the browser-wallet path used by the v2 frontend and resolves the
2372
+ * bare `eth|` identity.
2373
+ */
2473
2374
  var BrowserWalletSigner = class {
2474
- /**
2475
- * Creates a browser-wallet signer.
2476
- *
2477
- * Defaults to `personal_sign` — unchanged from every existing integration, since it only ever
2478
- * resolves the bare `eth|` identity and changing that silently would be a real behavior
2479
- * break for anyone already depending on it. Pass `{ scheme: 'eip712' }` to correctly resolve
2480
- * a registered `client|` alias instead, for `RequestTrade`/`AddLiquidity`/`RemoveLiquidity`/
2481
- * `CollectPositionFees` (`EIP712_CAPABLE_METHODS`) — `CreatePool` and any other method still
2482
- * falls back to `personal_sign` even in `'eip712'` mode, since its EIP-712 signing is a
2483
- * separate, unsolved chain-side problem.
2484
- *
2485
- * @example
2486
- * ```typescript
2487
- * const signer = new BrowserWalletSigner(window.ethereum, '0x0123456789012345678901234567890123456789');
2488
- * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2489
- * ```
2490
- * @example
2491
- * ```typescript
2492
- * // Correctly resolves a registered client| alias instead of the bare eth| address.
2493
- * const signer = new BrowserWalletSigner(window.ethereum, walletAddress, { scheme: 'eip712' });
2494
- * ```
2495
- */
2496
- constructor(provider, walletAddress, options = {}) {
2497
- this.provider = provider;
2498
- this.walletAddress = normalizeEthereumAccount(walletAddress, false);
2499
- this.scheme = options.scheme ?? "personal-sign";
2500
- }
2501
- provider;
2502
- walletAddress;
2503
- scheme;
2504
- /**
2505
- * Signs the DTO with `eth_signTypedData_v4` (when constructed with `{ scheme: 'eip712' }` and
2506
- * `methodName` is in `EIP712_CAPABLE_METHODS`) or the EIP-1193 `personal_sign` method
2507
- * (otherwise — the default).
2508
- *
2509
- * @example
2510
- * ```typescript
2511
- * const signed = await signer.signObject('RequestTrade', {
2512
- * token0: 'GALA',
2513
- * token1: 'GUSDC',
2514
- * fee: 3000,
2515
- * });
2516
- * ```
2517
- */
2518
- signObject(methodName, dto) {
2519
- if (this.scheme === "eip712" && EIP712_CAPABLE_METHODS.has(methodName)) {
2520
- return signEIP712(this.provider, methodName, dto, this.walletAddress);
2521
- }
2522
- return personalSign(this.provider, dto, this.walletAddress);
2523
- }
2375
+ provider;
2376
+ /**
2377
+ * Creates a browser-wallet signer.
2378
+ *
2379
+ * Defaults to `personal_sign` — unchanged from every existing integration, since it only ever
2380
+ * resolves the bare `eth|` identity and changing that silently would be a real behavior
2381
+ * break for anyone already depending on it. Pass `{ scheme: 'eip712' }` to correctly resolve
2382
+ * a registered `client|` alias instead, for `RequestTrade`/`AddLiquidity`/`RemoveLiquidity`/
2383
+ * `CollectPositionFees` (`EIP712_CAPABLE_METHODS`) — `CreatePool` and any other method still
2384
+ * falls back to `personal_sign` even in `'eip712'` mode, since its EIP-712 signing is a
2385
+ * separate, unsolved chain-side problem.
2386
+ *
2387
+ * @example
2388
+ * ```typescript
2389
+ * const signer = new BrowserWalletSigner(window.ethereum, '0x0123456789012345678901234567890123456789');
2390
+ * const signed = await signer.signObject('RequestTrade', { token0: 'GALA', token1: 'GUSDC' });
2391
+ * ```
2392
+ * @example
2393
+ * ```typescript
2394
+ * // Correctly resolves a registered client| alias instead of the bare eth| address.
2395
+ * const signer = new BrowserWalletSigner(window.ethereum, walletAddress, { scheme: 'eip712' });
2396
+ * ```
2397
+ */
2398
+ constructor(provider, walletAddress, options = {}) {
2399
+ this.provider = provider;
2400
+ this.walletAddress = normalizeEthereumAccount(walletAddress, false);
2401
+ this.scheme = options.scheme ?? "personal-sign";
2402
+ }
2403
+ walletAddress;
2404
+ scheme;
2405
+ /**
2406
+ * Signs the DTO with `eth_signTypedData_v4` (when constructed with `{ scheme: 'eip712' }` and
2407
+ * `methodName` is in `EIP712_CAPABLE_METHODS`) or the EIP-1193 `personal_sign` method
2408
+ * (otherwise — the default).
2409
+ *
2410
+ * @example
2411
+ * ```typescript
2412
+ * const signed = await signer.signObject('RequestTrade', {
2413
+ * token0: 'GALA',
2414
+ * token1: 'GUSDC',
2415
+ * fee: 3000,
2416
+ * });
2417
+ * ```
2418
+ */
2419
+ signObject(methodName, dto) {
2420
+ if (this.scheme === "eip712" && EIP712_CAPABLE_METHODS.has(methodName)) return signEIP712(this.provider, methodName, dto, this.walletAddress);
2421
+ return personalSign(this.provider, dto, this.walletAddress);
2422
+ }
2524
2423
  };
2525
- // Annotate the CommonJS export names for ESM import in node:
2526
- 0 && (module.exports = {
2527
- ALL_FEE_TIERS,
2528
- Assets,
2529
- BrowserWalletSigner,
2530
- ChainGateway,
2531
- FEE_TIER,
2532
- GC_MAX_TICK,
2533
- GC_MIN_TICK,
2534
- GSWAP_ENVIRONMENTS,
2535
- GSwap,
2536
- GSwapSDKError,
2537
- GalaWalletSigner,
2538
- Pools,
2539
- Positions,
2540
- PrivateKeySigner,
2541
- Quoting,
2542
- SubmittedTransaction,
2543
- Swaps,
2544
- Symbols,
2545
- TICK_SPACING_BY_FEE,
2546
- alignTickDown,
2547
- alignTickUp,
2548
- assertTickRange,
2549
- compositeKeyOf,
2550
- getObjectProperty,
2551
- getStringProperty,
2552
- orderSymbols,
2553
- parseJson,
2554
- parseTokenClassKey,
2555
- readOrderedSymbols,
2556
- sqrtPriceToTick,
2557
- tickFromPrice,
2558
- tickToSqrtPrice,
2559
- validateFee,
2560
- validateNumericAmount,
2561
- validatePriceValues,
2562
- validateTickRange,
2563
- validateTickSpacing,
2564
- validateTokenDecimals,
2565
- validateWalletAddress
2566
- });
2424
+
2425
+ //#endregion
2426
+ exports.ALL_FEE_TIERS = ALL_FEE_TIERS;
2427
+ exports.Assets = Assets;
2428
+ exports.BrowserWalletSigner = BrowserWalletSigner;
2429
+ exports.ChainGateway = ChainGateway;
2430
+ exports.FEE_TIER = FEE_TIER;
2431
+ exports.GC_MAX_TICK = GC_MAX_TICK;
2432
+ exports.GC_MIN_TICK = GC_MIN_TICK;
2433
+ exports.GSWAP_ENVIRONMENTS = GSWAP_ENVIRONMENTS;
2434
+ exports.GSwap = GSwap;
2435
+ exports.GSwapSDKError = GSwapSDKError;
2436
+ exports.GalaWalletSigner = GalaWalletSigner;
2437
+ exports.Pools = Pools;
2438
+ exports.Positions = Positions;
2439
+ exports.PrivateKeySigner = PrivateKeySigner;
2440
+ exports.Quoting = Quoting;
2441
+ exports.SubmittedTransaction = SubmittedTransaction;
2442
+ exports.Swaps = Swaps;
2443
+ exports.Symbols = Symbols;
2444
+ exports.TICK_SPACING_BY_FEE = TICK_SPACING_BY_FEE;
2445
+ exports.alignTickDown = alignTickDown;
2446
+ exports.alignTickUp = alignTickUp;
2447
+ exports.assertTickRange = assertTickRange;
2448
+ exports.compositeKeyOf = compositeKeyOf;
2449
+ exports.getObjectProperty = getObjectProperty;
2450
+ exports.getStringProperty = getStringProperty;
2451
+ exports.orderSymbols = orderSymbols;
2452
+ exports.parseJson = parseJson;
2453
+ exports.parseTokenClassKey = parseTokenClassKey;
2454
+ exports.readOrderedSymbols = readOrderedSymbols;
2455
+ exports.sqrtPriceToTick = sqrtPriceToTick;
2456
+ exports.tickFromPrice = tickFromPrice;
2457
+ exports.tickToSqrtPrice = tickToSqrtPrice;
2458
+ exports.validateFee = validateFee;
2459
+ exports.validateNumericAmount = validateNumericAmount;
2460
+ exports.validatePriceValues = validatePriceValues;
2461
+ exports.validateTickRange = validateTickRange;
2462
+ exports.validateTickSpacing = validateTickSpacing;
2463
+ exports.validateTokenDecimals = validateTokenDecimals;
2464
+ exports.validateWalletAddress = validateWalletAddress;
2567
2465
  //# sourceMappingURL=index.cjs.map