@gala-chain/gswap-sdk 0.0.0-preview
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/LICENSE.txt +201 -0
- package/README.md +47 -0
- package/dist/browser/index.js +25 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/index.d.cts +921 -0
- package/dist/index.d.ts +921 -0
- package/dist/index.js +1812 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1753 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +89 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1753 @@
|
|
|
1
|
+
// src/utils/validation.ts
|
|
2
|
+
import BigNumber from "bignumber.js";
|
|
3
|
+
|
|
4
|
+
// src/classes/gswap_sdk_error.ts
|
|
5
|
+
var GSwapSDKError = class _GSwapSDKError extends Error {
|
|
6
|
+
constructor(message, code, details) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = "GSwapSDKError";
|
|
11
|
+
}
|
|
12
|
+
static noSignerError() {
|
|
13
|
+
return new _GSwapSDKError(
|
|
14
|
+
"This method requires a signer. Please provide a signer to the GSwap constructor.",
|
|
15
|
+
"NO_SIGNER"
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
static async fromErrorResponse(url, response) {
|
|
19
|
+
const bodyText = await response.text();
|
|
20
|
+
const bodyJson = (() => {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(bodyText);
|
|
23
|
+
} catch {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
const errorKey = typeof bodyJson === "object" && bodyJson && "error" in bodyJson && typeof bodyJson.error === "object" && bodyJson.error && "ErrorKey" in bodyJson.error && typeof bodyJson.error.ErrorKey === "string" ? bodyJson.error.ErrorKey : void 0;
|
|
28
|
+
const message = typeof bodyJson === "object" && bodyJson && "error" in bodyJson && typeof bodyJson.error === "object" && bodyJson.error && "Message" in bodyJson.error && typeof bodyJson.error.Message === "string" ? bodyJson.error.Message : void 0;
|
|
29
|
+
if (errorKey && message) {
|
|
30
|
+
return new _GSwapSDKError(`GalaChain Error ${errorKey} from ${url}: ${message}`, errorKey, {
|
|
31
|
+
message,
|
|
32
|
+
errorKey,
|
|
33
|
+
status: response.status,
|
|
34
|
+
body: bodyJson,
|
|
35
|
+
url
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return new _GSwapSDKError(`Unexpected HTTP Error ${response.status} from ${url}`, "HTTP_ERROR", {
|
|
39
|
+
status: response.status,
|
|
40
|
+
body: bodyJson ?? bodyText,
|
|
41
|
+
url
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
static incorrectTokenOrderingError(specifiedToken0, specifiedToken1) {
|
|
45
|
+
return new _GSwapSDKError(
|
|
46
|
+
"Token ordering is incorrect. token0 should sort below token1.",
|
|
47
|
+
"INCORRECT_TOKEN_ORDERING",
|
|
48
|
+
{
|
|
49
|
+
specifiedToken0,
|
|
50
|
+
specifiedToken1
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
static transactionWaitTimeoutError(txId) {
|
|
55
|
+
return new _GSwapSDKError("Transaction wait timed out.", "TRANSACTION_WAIT_TIMEOUT", {
|
|
56
|
+
txId
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
static transactionWaitFailedError(txId, detail) {
|
|
60
|
+
return new _GSwapSDKError("Transaction wait failed.", "TRANSACTION_WAIT_FAILED", {
|
|
61
|
+
txId,
|
|
62
|
+
...detail
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
static socketConnectionRequiredError() {
|
|
66
|
+
return new _GSwapSDKError(
|
|
67
|
+
"This method requires a socket connection. Did you call connectSocket()?",
|
|
68
|
+
"SOCKET_CONNECTION_REQUIRED"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
static noPoolAvailableError(tokenIn, tokenOut, fee) {
|
|
72
|
+
const message = fee !== void 0 ? `No pool available for the specified token pair at fee tier ${fee}` : "No pools available for the specified token pair";
|
|
73
|
+
return new _GSwapSDKError(message, "NO_POOL_AVAILABLE", {
|
|
74
|
+
tokenIn,
|
|
75
|
+
tokenOut,
|
|
76
|
+
fee
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/utils/validation.ts
|
|
82
|
+
function validateNumericAmount(amount, parameterName, allowZero = false) {
|
|
83
|
+
const bnAmount = BigNumber(amount);
|
|
84
|
+
if (!bnAmount.isFinite()) {
|
|
85
|
+
throw new GSwapSDKError(
|
|
86
|
+
`Invalid ${parameterName}: must be a finite number`,
|
|
87
|
+
"VALIDATION_ERROR",
|
|
88
|
+
{
|
|
89
|
+
type: "INVALID_NUMERIC_AMOUNT",
|
|
90
|
+
parameterName,
|
|
91
|
+
value: amount,
|
|
92
|
+
reason: "not_finite"
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!allowZero && bnAmount.isZero()) {
|
|
97
|
+
throw new GSwapSDKError(`Invalid ${parameterName}: must be positive`, "VALIDATION_ERROR", {
|
|
98
|
+
type: "INVALID_NUMERIC_AMOUNT",
|
|
99
|
+
parameterName,
|
|
100
|
+
value: amount,
|
|
101
|
+
reason: "zero_not_allowed"
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (bnAmount.isNegative()) {
|
|
105
|
+
throw new GSwapSDKError(
|
|
106
|
+
`Invalid ${parameterName}: must be ${allowZero ? "non-negative" : "positive"}`,
|
|
107
|
+
"VALIDATION_ERROR",
|
|
108
|
+
{
|
|
109
|
+
type: "INVALID_NUMERIC_AMOUNT",
|
|
110
|
+
parameterName,
|
|
111
|
+
value: amount,
|
|
112
|
+
reason: "negative"
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function validatePriceValues(spotPrice, lowerPrice, upperPrice) {
|
|
118
|
+
const bnSpotPrice = BigNumber(spotPrice);
|
|
119
|
+
const bnLowerPrice = BigNumber(lowerPrice);
|
|
120
|
+
let bnUpperPrice = BigNumber(upperPrice);
|
|
121
|
+
bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber(1e18);
|
|
122
|
+
if (!bnSpotPrice.isFinite() || !bnLowerPrice.isFinite() || !bnUpperPrice.isFinite() || !bnSpotPrice.isPositive() || !bnLowerPrice.isPositive() || !bnUpperPrice.isPositive()) {
|
|
123
|
+
throw new GSwapSDKError(
|
|
124
|
+
"Invalid price values: all prices must be finite and positive",
|
|
125
|
+
"VALIDATION_ERROR",
|
|
126
|
+
{
|
|
127
|
+
type: "INVALID_PRICE_VALUES",
|
|
128
|
+
spotPrice,
|
|
129
|
+
lowerPrice,
|
|
130
|
+
upperPrice
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (bnLowerPrice.isGreaterThan(bnUpperPrice)) {
|
|
135
|
+
throw new GSwapSDKError(
|
|
136
|
+
"Invalid price range: lower price must be less than or equal to upper price",
|
|
137
|
+
"VALIDATION_ERROR",
|
|
138
|
+
{
|
|
139
|
+
type: "INVALID_PRICE_RANGE",
|
|
140
|
+
lowerPrice,
|
|
141
|
+
upperPrice
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function validateTokenDecimals(decimals, parameterName) {
|
|
147
|
+
if (decimals < 0 || !Number.isInteger(decimals)) {
|
|
148
|
+
throw new GSwapSDKError(
|
|
149
|
+
`Invalid ${parameterName}: must be a non-negative integer`,
|
|
150
|
+
"VALIDATION_ERROR",
|
|
151
|
+
{
|
|
152
|
+
type: "INVALID_TOKEN_DECIMALS",
|
|
153
|
+
parameterName,
|
|
154
|
+
value: decimals
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function validateTickRange(tickLower, tickUpper) {
|
|
160
|
+
if (!Number.isInteger(tickLower) || !Number.isInteger(tickUpper)) {
|
|
161
|
+
throw new GSwapSDKError("Invalid tick values: ticks must be integers", "VALIDATION_ERROR", {
|
|
162
|
+
type: "INVALID_TICK_VALUES",
|
|
163
|
+
tickLower,
|
|
164
|
+
tickUpper
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (tickLower >= tickUpper) {
|
|
168
|
+
throw new GSwapSDKError(
|
|
169
|
+
"Invalid tick range: tickLower must be less than tickUpper",
|
|
170
|
+
"VALIDATION_ERROR",
|
|
171
|
+
{
|
|
172
|
+
type: "INVALID_TICK_RANGE",
|
|
173
|
+
tickLower,
|
|
174
|
+
tickUpper
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (tickLower < -886800 || tickUpper > 886800) {
|
|
179
|
+
throw new GSwapSDKError(
|
|
180
|
+
"Invalid tick range: ticks must be between -886800 and 886800",
|
|
181
|
+
"VALIDATION_ERROR",
|
|
182
|
+
{
|
|
183
|
+
type: "INVALID_TICK_BOUNDS",
|
|
184
|
+
tickLower,
|
|
185
|
+
tickUpper,
|
|
186
|
+
minTick: -886800,
|
|
187
|
+
maxTick: 886800
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function validateFee(fee) {
|
|
193
|
+
if (!Number.isInteger(fee) || fee < 0) {
|
|
194
|
+
throw new GSwapSDKError("Invalid fee: must be a non-negative integer", "VALIDATION_ERROR", {
|
|
195
|
+
type: "INVALID_FEE",
|
|
196
|
+
value: fee
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function validateTickSpacing(tickSpacing) {
|
|
201
|
+
if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {
|
|
202
|
+
throw new GSwapSDKError(
|
|
203
|
+
"Invalid tick spacing: must be a positive integer",
|
|
204
|
+
"VALIDATION_ERROR",
|
|
205
|
+
{
|
|
206
|
+
type: "INVALID_TICK_SPACING",
|
|
207
|
+
value: tickSpacing
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function validateWalletAddress(address) {
|
|
213
|
+
if (address === void 0) {
|
|
214
|
+
throw new GSwapSDKError(
|
|
215
|
+
"Invalid wallet address: No wallet address provided",
|
|
216
|
+
"VALIDATION_ERROR",
|
|
217
|
+
{
|
|
218
|
+
type: "MISSING_WALLET_ADDRESS",
|
|
219
|
+
hint: "Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK"
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
if (!address || typeof address !== "string" || address.trim().length === 0) {
|
|
224
|
+
throw new GSwapSDKError(
|
|
225
|
+
"Invalid wallet address: must be a non-empty string",
|
|
226
|
+
"VALIDATION_ERROR",
|
|
227
|
+
{
|
|
228
|
+
type: "INVALID_WALLET_ADDRESS",
|
|
229
|
+
value: address
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/classes/assets.ts
|
|
236
|
+
var Assets = class {
|
|
237
|
+
constructor(dexBackendBaseUrl, httpClient) {
|
|
238
|
+
this.dexBackendBaseUrl = dexBackendBaseUrl;
|
|
239
|
+
this.httpClient = httpClient;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Gets all token assets owned by a user with their balances.
|
|
243
|
+
* @param ownerAddress - The wallet address to get assets for.
|
|
244
|
+
* @param page - Page number for pagination (default: 1).
|
|
245
|
+
* @param limit - Maximum number of assets to return per page (default: 10).
|
|
246
|
+
* @returns User assets including token information and balances.
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* const assets = await assetsService.getUserAssets('eth|123...abc', 1, 20);
|
|
250
|
+
* console.log(`User has ${assets.count} different tokens`);
|
|
251
|
+
* assets.tokens.forEach(token => {
|
|
252
|
+
* console.log(`${token.symbol}: ${token.quantity}`);
|
|
253
|
+
* });
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
async getUserAssets(ownerAddress, page = 1, limit = 10) {
|
|
257
|
+
validateWalletAddress(ownerAddress);
|
|
258
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
259
|
+
throw new Error("Invalid page: must be a positive integer");
|
|
260
|
+
}
|
|
261
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
262
|
+
throw new Error("Invalid limit: must be an integer between 1 and 100");
|
|
263
|
+
}
|
|
264
|
+
const json = await this.httpClient.sendGetRequest(this.dexBackendBaseUrl, "/user/assets", "", {
|
|
265
|
+
address: ownerAddress,
|
|
266
|
+
page: page.toString(),
|
|
267
|
+
limit: limit.toString()
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
tokens: json.data.token.map((token) => ({
|
|
271
|
+
...token,
|
|
272
|
+
decimals: parseInt(token.decimals, 10)
|
|
273
|
+
})) || [],
|
|
274
|
+
count: json.data.count || 0
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// src/classes/bundler.ts
|
|
280
|
+
import crypto from "crypto";
|
|
281
|
+
|
|
282
|
+
// src/utils/debug.ts
|
|
283
|
+
import debug from "debug";
|
|
284
|
+
var debugLog = debug("GALASWAP_DEX");
|
|
285
|
+
|
|
286
|
+
// src/classes/event_socket_client.ts
|
|
287
|
+
import { EventEmitter } from "events";
|
|
288
|
+
import { io } from "socket.io-client";
|
|
289
|
+
var TradeEventEmitter = class extends EventEmitter {
|
|
290
|
+
};
|
|
291
|
+
var EventSocketClient = class extends TradeEventEmitter {
|
|
292
|
+
socket = null;
|
|
293
|
+
bundlerUrl;
|
|
294
|
+
constructor(bundlerUrl) {
|
|
295
|
+
super();
|
|
296
|
+
this.bundlerUrl = bundlerUrl;
|
|
297
|
+
}
|
|
298
|
+
connect() {
|
|
299
|
+
return new Promise((resolve, reject) => {
|
|
300
|
+
var _a;
|
|
301
|
+
if ((_a = this.socket) == null ? void 0 : _a.connected) {
|
|
302
|
+
resolve();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this.socket = io(this.bundlerUrl, {
|
|
306
|
+
transports: ["websocket"],
|
|
307
|
+
autoConnect: true
|
|
308
|
+
});
|
|
309
|
+
this.socket.on("connect", () => {
|
|
310
|
+
console.log("Connected to bundler socket:", this.bundlerUrl);
|
|
311
|
+
this.emit("connect");
|
|
312
|
+
resolve();
|
|
313
|
+
});
|
|
314
|
+
this.socket.on("connect_error", (error) => {
|
|
315
|
+
console.error("Failed to connect to bundler socket:", error);
|
|
316
|
+
this.emit("error", error);
|
|
317
|
+
reject(error);
|
|
318
|
+
});
|
|
319
|
+
this.socket.on("disconnect", (reason) => {
|
|
320
|
+
console.log("Disconnected from bundler socket:", reason);
|
|
321
|
+
this.emit("disconnect", reason);
|
|
322
|
+
});
|
|
323
|
+
this.socket.onAny((eventName, ...args) => {
|
|
324
|
+
if (typeof eventName === "string") {
|
|
325
|
+
const [responseData] = args;
|
|
326
|
+
this.emit("transaction", eventName, responseData);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
disconnect() {
|
|
332
|
+
if (this.socket) {
|
|
333
|
+
this.socket.disconnect();
|
|
334
|
+
this.socket = null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
isConnected() {
|
|
338
|
+
var _a;
|
|
339
|
+
return ((_a = this.socket) == null ? void 0 : _a.connected) ?? false;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// src/classes/tx_waiter.ts
|
|
344
|
+
var TransactionWaiter = class {
|
|
345
|
+
enabled = false;
|
|
346
|
+
promiseInfoForTxId = /* @__PURE__ */ new Map();
|
|
347
|
+
setEnabled(enabled) {
|
|
348
|
+
this.enabled = enabled;
|
|
349
|
+
if (!enabled) {
|
|
350
|
+
for (const [txId, promiseInfo] of this.promiseInfoForTxId.entries()) {
|
|
351
|
+
clearTimeout(promiseInfo.timeoutId);
|
|
352
|
+
promiseInfo.reject(
|
|
353
|
+
GSwapSDKError.transactionWaitFailedError(txId, {
|
|
354
|
+
message: "Transaction waiter disabled"
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
this.promiseInfoForTxId.clear();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
registerTxId(txId, timeoutMs) {
|
|
362
|
+
if (this.promiseInfoForTxId.has(txId)) {
|
|
363
|
+
throw new GSwapSDKError(
|
|
364
|
+
`Transaction ID is already registered`,
|
|
365
|
+
"TRANSACTION_ID_ALREADY_REGISTERED",
|
|
366
|
+
{ txId }
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
if (!this.enabled) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
let resolve;
|
|
373
|
+
let reject;
|
|
374
|
+
const promise = new Promise((res, rej) => {
|
|
375
|
+
resolve = res;
|
|
376
|
+
reject = rej;
|
|
377
|
+
});
|
|
378
|
+
const timeoutId = setTimeout(() => {
|
|
379
|
+
const promiseInfo = this.promiseInfoForTxId.get(txId);
|
|
380
|
+
if (promiseInfo) {
|
|
381
|
+
if (promiseInfo.waited) {
|
|
382
|
+
promiseInfo.reject(GSwapSDKError.transactionWaitTimeoutError(txId));
|
|
383
|
+
} else {
|
|
384
|
+
promiseInfo.resolve();
|
|
385
|
+
}
|
|
386
|
+
this.promiseInfoForTxId.delete(txId);
|
|
387
|
+
}
|
|
388
|
+
}, timeoutMs);
|
|
389
|
+
this.promiseInfoForTxId.set(txId, {
|
|
390
|
+
promise,
|
|
391
|
+
resolve,
|
|
392
|
+
reject,
|
|
393
|
+
timeoutId,
|
|
394
|
+
waited: false
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
wait(txId) {
|
|
398
|
+
const promise = this.promiseInfoForTxId.get(txId);
|
|
399
|
+
if (!promise) {
|
|
400
|
+
throw new GSwapSDKError(
|
|
401
|
+
`Transaction ID is not registered for waiting`,
|
|
402
|
+
"TRANSACTION_ID_NOT_REGISTERED",
|
|
403
|
+
{
|
|
404
|
+
txId
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
promise.waited = true;
|
|
409
|
+
return promise.promise;
|
|
410
|
+
}
|
|
411
|
+
notifySuccess(txId) {
|
|
412
|
+
const promiseInfo = this.promiseInfoForTxId.get(txId);
|
|
413
|
+
if (!promiseInfo) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
clearTimeout(promiseInfo.timeoutId);
|
|
417
|
+
promiseInfo.resolve();
|
|
418
|
+
this.promiseInfoForTxId.delete(txId);
|
|
419
|
+
}
|
|
420
|
+
notifyFailure(txId, detail) {
|
|
421
|
+
const promiseInfo = this.promiseInfoForTxId.get(txId);
|
|
422
|
+
if (!promiseInfo) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
clearTimeout(promiseInfo.timeoutId);
|
|
426
|
+
if (promiseInfo.waited) {
|
|
427
|
+
promiseInfo.reject(GSwapSDKError.transactionWaitFailedError(txId, detail));
|
|
428
|
+
} else {
|
|
429
|
+
promiseInfo.resolve();
|
|
430
|
+
}
|
|
431
|
+
this.promiseInfoForTxId.delete(txId);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// src/classes/events.ts
|
|
436
|
+
var Events = class _Events {
|
|
437
|
+
globalSocketClient;
|
|
438
|
+
globalWaitHelper = new TransactionWaiter();
|
|
439
|
+
connectionPromise;
|
|
440
|
+
static instance = new _Events();
|
|
441
|
+
static tradeEventEmitterConstructor = EventSocketClient;
|
|
442
|
+
/**
|
|
443
|
+
* Establishes a global socket connection for real-time event streaming.
|
|
444
|
+
* This connection is shared across all service instances.
|
|
445
|
+
* @param bundlerBaseUrl - Optional bundler base URL. If not provided, uses default.
|
|
446
|
+
* @returns The connected EventSocketClient.
|
|
447
|
+
* @example
|
|
448
|
+
* ```typescript
|
|
449
|
+
* await eventsService.connectEventSocket();
|
|
450
|
+
*
|
|
451
|
+
* // Socket is now available for transaction updates
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
async connectEventSocket(bundlerBaseUrl) {
|
|
455
|
+
var _a;
|
|
456
|
+
if (this.connectionPromise) {
|
|
457
|
+
return this.connectionPromise;
|
|
458
|
+
}
|
|
459
|
+
if ((_a = this.globalSocketClient) == null ? void 0 : _a.isConnected()) {
|
|
460
|
+
return this.globalSocketClient;
|
|
461
|
+
}
|
|
462
|
+
const url = bundlerBaseUrl ?? "https://bundle-backend-test1.defi.gala.com";
|
|
463
|
+
this.connectionPromise = (async () => {
|
|
464
|
+
const client = new _Events.tradeEventEmitterConstructor(url);
|
|
465
|
+
await client.connect();
|
|
466
|
+
if (!this.globalWaitHelper) {
|
|
467
|
+
this.globalWaitHelper = new TransactionWaiter();
|
|
468
|
+
}
|
|
469
|
+
client.on("transaction", this.internalHandleSocketMessage.bind(this));
|
|
470
|
+
return client;
|
|
471
|
+
})();
|
|
472
|
+
this.globalSocketClient = await this.connectionPromise;
|
|
473
|
+
this.connectionPromise = void 0;
|
|
474
|
+
this.globalWaitHelper.setEnabled(true);
|
|
475
|
+
return this.globalSocketClient;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Disconnects the global socket connection and cleans up resources.
|
|
479
|
+
*/
|
|
480
|
+
disconnectEventSocket() {
|
|
481
|
+
if (this.globalSocketClient) {
|
|
482
|
+
this.globalSocketClient.off("transaction", this.internalHandleSocketMessage.bind(this));
|
|
483
|
+
this.globalSocketClient.disconnect();
|
|
484
|
+
this.globalSocketClient = void 0;
|
|
485
|
+
this.globalWaitHelper.setEnabled(false);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Checks if the global socket connection is active.
|
|
490
|
+
* @returns True if connected, false otherwise.
|
|
491
|
+
*/
|
|
492
|
+
eventSocketConnected() {
|
|
493
|
+
var _a;
|
|
494
|
+
return ((_a = this.globalSocketClient) == null ? void 0 : _a.isConnected()) ?? false;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Registers a transaction ID for waiting and timeout handling.
|
|
498
|
+
* @param txId - The transaction ID to register.
|
|
499
|
+
* @param timeoutMs - Timeout in milliseconds.
|
|
500
|
+
*/
|
|
501
|
+
registerTxId(txId, timeoutMs) {
|
|
502
|
+
this.globalWaitHelper.registerTxId(txId, timeoutMs);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Waits for a transaction to complete.
|
|
506
|
+
* @param txId - The transaction ID to wait for.
|
|
507
|
+
* @returns Promise that resolves when the transaction completes.
|
|
508
|
+
*/
|
|
509
|
+
async wait(txId) {
|
|
510
|
+
if (!this.eventSocketConnected()) {
|
|
511
|
+
throw GSwapSDKError.socketConnectionRequiredError();
|
|
512
|
+
}
|
|
513
|
+
await this.globalWaitHelper.wait(txId);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Internal handler for socket messages.
|
|
517
|
+
* @param response - The bundler response.
|
|
518
|
+
* @param txId - The transaction ID.
|
|
519
|
+
*/
|
|
520
|
+
internalHandleSocketMessage(txId, response) {
|
|
521
|
+
if (response.status === "PROCESSED") {
|
|
522
|
+
this.globalWaitHelper.notifySuccess(txId);
|
|
523
|
+
} else if (response.status === "FAILED") {
|
|
524
|
+
this.globalWaitHelper.notifyFailure(txId, {
|
|
525
|
+
error: response.error,
|
|
526
|
+
status: response.status,
|
|
527
|
+
data: response.data
|
|
528
|
+
});
|
|
529
|
+
} else if (response.status === "PENDING") {
|
|
530
|
+
} else {
|
|
531
|
+
debugLog(`Unknown response status for transaction ${txId}:`, response.status);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// src/classes/pending_transaction.ts
|
|
537
|
+
var PendingTransaction = class {
|
|
538
|
+
constructor(transactionId, message, error, waitDelegate) {
|
|
539
|
+
this.transactionId = transactionId;
|
|
540
|
+
this.message = message;
|
|
541
|
+
this.error = error;
|
|
542
|
+
this.waitDelegate = waitDelegate;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Waits for the transaction to be confirmed.
|
|
546
|
+
* This should be called immediately after receiving the PendingTransaction
|
|
547
|
+
* to ensure proper event handling. If you delay calling this method and the
|
|
548
|
+
* transaction confirms before you call this method, an error will be thrown.
|
|
549
|
+
*
|
|
550
|
+
* @returns A promise that resolves when the transaction is confirmed.
|
|
551
|
+
*/
|
|
552
|
+
wait() {
|
|
553
|
+
return this.waitDelegate();
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// src/classes/bundler.ts
|
|
558
|
+
function randomUUID() {
|
|
559
|
+
if (globalThis.crypto) {
|
|
560
|
+
return globalThis.crypto.randomUUID();
|
|
561
|
+
}
|
|
562
|
+
return crypto.randomUUID();
|
|
563
|
+
}
|
|
564
|
+
var Bundler = class {
|
|
565
|
+
constructor(bundlerBaseUrl, bundlingAPIBasePath, transactionWaitTimeoutMs, signer, httpClient) {
|
|
566
|
+
this.bundlerBaseUrl = bundlerBaseUrl;
|
|
567
|
+
this.bundlingAPIBasePath = bundlingAPIBasePath;
|
|
568
|
+
this.transactionWaitTimeoutMs = transactionWaitTimeoutMs;
|
|
569
|
+
this.signer = signer;
|
|
570
|
+
this.httpClient = httpClient;
|
|
571
|
+
}
|
|
572
|
+
async signObject(methodName, toSign) {
|
|
573
|
+
if (!this.signer) {
|
|
574
|
+
throw GSwapSDKError.noSignerError();
|
|
575
|
+
}
|
|
576
|
+
const withUniqueKey = {
|
|
577
|
+
...toSign,
|
|
578
|
+
uniqueKey: toSign.uniqueKey ?? `galaswap - operation - ${randomUUID()}`
|
|
579
|
+
};
|
|
580
|
+
debugLog("Signing object for method", methodName, withUniqueKey);
|
|
581
|
+
return this.signer.signObject(methodName, withUniqueKey);
|
|
582
|
+
}
|
|
583
|
+
async sendBundlerRequest(method, body, stringsInstructions) {
|
|
584
|
+
if (!this.hasSigner()) {
|
|
585
|
+
throw GSwapSDKError.noSignerError();
|
|
586
|
+
}
|
|
587
|
+
const requestBody = {
|
|
588
|
+
method,
|
|
589
|
+
signedDto: await this.signObject(method, body),
|
|
590
|
+
stringsInstructions
|
|
591
|
+
};
|
|
592
|
+
debugLog("Sending bundler request", method, requestBody);
|
|
593
|
+
const response = await this.httpClient.sendPostRequest(
|
|
594
|
+
this.bundlerBaseUrl,
|
|
595
|
+
this.bundlingAPIBasePath,
|
|
596
|
+
"",
|
|
597
|
+
requestBody
|
|
598
|
+
);
|
|
599
|
+
debugLog("Received bundler response", method, response);
|
|
600
|
+
Events.instance.registerTxId(response.data, this.transactionWaitTimeoutMs);
|
|
601
|
+
const transaction = new PendingTransaction(
|
|
602
|
+
response.data,
|
|
603
|
+
response.message,
|
|
604
|
+
response.error,
|
|
605
|
+
() => {
|
|
606
|
+
return Events.instance.wait(response.data);
|
|
607
|
+
}
|
|
608
|
+
);
|
|
609
|
+
return transaction;
|
|
610
|
+
}
|
|
611
|
+
hasSigner() {
|
|
612
|
+
return this.signer !== void 0;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
// src/classes/http_client.ts
|
|
617
|
+
var HttpClient = class {
|
|
618
|
+
constructor(httpRequestor = fetch) {
|
|
619
|
+
this.httpRequestor = httpRequestor;
|
|
620
|
+
}
|
|
621
|
+
async sendRequest(method, baseUrl, basePath, endpoint, body) {
|
|
622
|
+
const url = `${baseUrl}${basePath}${endpoint}`;
|
|
623
|
+
debugLog(`Sending request to ${url} with body:`, body);
|
|
624
|
+
const response = await this.httpRequestor(url, {
|
|
625
|
+
method,
|
|
626
|
+
headers: {
|
|
627
|
+
"Content-Type": "application/json",
|
|
628
|
+
"User-Agent": "GalaChain-SDK/0.0"
|
|
629
|
+
},
|
|
630
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
631
|
+
});
|
|
632
|
+
if (!response.ok) {
|
|
633
|
+
throw await GSwapSDKError.fromErrorResponse(url, response);
|
|
634
|
+
}
|
|
635
|
+
const json = await response.json();
|
|
636
|
+
debugLog(`Response from ${baseUrl}${basePath}${endpoint}:`, json);
|
|
637
|
+
return json;
|
|
638
|
+
}
|
|
639
|
+
async sendPostRequest(baseUrl, basePath, endpoint, body) {
|
|
640
|
+
return this.sendRequest("POST", baseUrl, basePath, endpoint, body);
|
|
641
|
+
}
|
|
642
|
+
async sendGetRequest(baseUrl, basePath, endpoint, params) {
|
|
643
|
+
const searchParams = params ? new URLSearchParams(params) : void 0;
|
|
644
|
+
const endpointWithParams = searchParams ? `${endpoint}?${searchParams.toString()}` : endpoint;
|
|
645
|
+
return this.sendRequest("GET", baseUrl, basePath, endpointWithParams, void 0);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
// src/classes/pools.ts
|
|
650
|
+
import BigNumber2 from "bignumber.js";
|
|
651
|
+
|
|
652
|
+
// src/utils/token.ts
|
|
653
|
+
function stringifyTokenClassKey(tokenClassKey, separator = "|") {
|
|
654
|
+
if (typeof tokenClassKey === "string") {
|
|
655
|
+
return tokenClassKey;
|
|
656
|
+
}
|
|
657
|
+
return `${tokenClassKey.collection}${separator}${tokenClassKey.category}${separator}${tokenClassKey.type}${separator}${tokenClassKey.additionalKey}`;
|
|
658
|
+
}
|
|
659
|
+
function parseTokenClassKey(tokenClassKey) {
|
|
660
|
+
if (typeof tokenClassKey === "object") {
|
|
661
|
+
return {
|
|
662
|
+
collection: tokenClassKey.collection,
|
|
663
|
+
category: tokenClassKey.category,
|
|
664
|
+
type: tokenClassKey.type,
|
|
665
|
+
additionalKey: tokenClassKey.additionalKey
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
const [collection, category, type, additionalKey] = tokenClassKey.split("|");
|
|
669
|
+
if (!collection || !category || !type || !additionalKey) {
|
|
670
|
+
throw new GSwapSDKError(`Invalid token class key`, "INVALID_TOKEN_CLASS_KEY", {
|
|
671
|
+
tokenClassKey
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
collection,
|
|
676
|
+
category,
|
|
677
|
+
type,
|
|
678
|
+
additionalKey
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/utils/token_ordering.ts
|
|
683
|
+
function compareTokens(first, second) {
|
|
684
|
+
return stringifyTokenClassKey(first).localeCompare(stringifyTokenClassKey(second));
|
|
685
|
+
}
|
|
686
|
+
function getTokenOrdering(first, second, assertCorrectness, token1Data, token2Data) {
|
|
687
|
+
const zeroForOne = compareTokens(first, second) < 0;
|
|
688
|
+
if (zeroForOne) {
|
|
689
|
+
return {
|
|
690
|
+
token0: first,
|
|
691
|
+
token1: second,
|
|
692
|
+
zeroForOne,
|
|
693
|
+
token0Attributes: token1Data,
|
|
694
|
+
token1Attributes: token2Data
|
|
695
|
+
};
|
|
696
|
+
} else {
|
|
697
|
+
if (assertCorrectness) {
|
|
698
|
+
throw GSwapSDKError.incorrectTokenOrderingError(first, second);
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
token0: second,
|
|
702
|
+
token1: first,
|
|
703
|
+
zeroForOne,
|
|
704
|
+
token0Attributes: token2Data,
|
|
705
|
+
token1Attributes: token1Data
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/classes/pools.ts
|
|
711
|
+
var Pools = class {
|
|
712
|
+
constructor(gatewayBaseUrl, dexContractBasePath, httpClient) {
|
|
713
|
+
this.gatewayBaseUrl = gatewayBaseUrl;
|
|
714
|
+
this.dexContractBasePath = dexContractBasePath;
|
|
715
|
+
this.httpClient = httpClient;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Gets pool data for a specific token pair and fee tier.
|
|
719
|
+
*/
|
|
720
|
+
async getPoolData(token0, token1, fee) {
|
|
721
|
+
validateFee(fee);
|
|
722
|
+
const token0Class = parseTokenClassKey(token0);
|
|
723
|
+
const token1Class = parseTokenClassKey(token1);
|
|
724
|
+
const ordering = getTokenOrdering(token0Class, token1Class, false);
|
|
725
|
+
const responseBody = await this.httpClient.sendPostRequest(this.gatewayBaseUrl, this.dexContractBasePath, "/GetPoolData", {
|
|
726
|
+
token0: ordering.token0,
|
|
727
|
+
token1: ordering.token1,
|
|
728
|
+
fee
|
|
729
|
+
});
|
|
730
|
+
const rawData = responseBody.Data;
|
|
731
|
+
return {
|
|
732
|
+
bitmap: rawData.bitmap,
|
|
733
|
+
fee: rawData.fee,
|
|
734
|
+
feeGrowthGlobal0: BigNumber2(rawData.feeGrowthGlobal0),
|
|
735
|
+
feeGrowthGlobal1: BigNumber2(rawData.feeGrowthGlobal1),
|
|
736
|
+
grossPoolLiquidity: BigNumber2(rawData.grossPoolLiquidity),
|
|
737
|
+
liquidity: BigNumber2(rawData.liquidity),
|
|
738
|
+
maxLiquidityPerTick: BigNumber2(rawData.maxLiquidityPerTick),
|
|
739
|
+
protocolFees: rawData.protocolFees,
|
|
740
|
+
protocolFeesToken0: BigNumber2(rawData.protocolFeesToken0),
|
|
741
|
+
protocolFeesToken1: BigNumber2(rawData.protocolFeesToken1),
|
|
742
|
+
sqrtPrice: BigNumber2(rawData.sqrtPrice),
|
|
743
|
+
tickSpacing: rawData.tickSpacing,
|
|
744
|
+
token0: rawData.token0,
|
|
745
|
+
token0ClassKey: rawData.token0ClassKey,
|
|
746
|
+
token1: rawData.token1,
|
|
747
|
+
token1ClassKey: rawData.token1ClassKey
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Calculates the nearest valid tick value for a given price.
|
|
752
|
+
*/
|
|
753
|
+
calculateTicksForPrice(price, tickSpacing) {
|
|
754
|
+
validateNumericAmount(price, "price", true);
|
|
755
|
+
validateTickSpacing(tickSpacing);
|
|
756
|
+
const priceNumber = BigNumber2(price).toNumber();
|
|
757
|
+
if (priceNumber === 0) {
|
|
758
|
+
return -886800;
|
|
759
|
+
}
|
|
760
|
+
if (priceNumber === Infinity) {
|
|
761
|
+
return 886800;
|
|
762
|
+
}
|
|
763
|
+
const uncoercedTicks = Math.round(Math.log(priceNumber) / Math.log(1.0001));
|
|
764
|
+
const ticks = Math.floor(uncoercedTicks / tickSpacing) * tickSpacing;
|
|
765
|
+
return Math.min(Math.max(ticks, -886800), 886800);
|
|
766
|
+
}
|
|
767
|
+
calculatePriceForTicks(tick) {
|
|
768
|
+
if (tick === -886800) {
|
|
769
|
+
return BigNumber2("0");
|
|
770
|
+
} else if (tick === 886800) {
|
|
771
|
+
return BigNumber2(Infinity);
|
|
772
|
+
} else {
|
|
773
|
+
const price = Math.pow(1.0001, tick);
|
|
774
|
+
return BigNumber2(price);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Calculates the current spot price of a pool based on sqrt price.
|
|
779
|
+
* Price is defined as the amount of outToken you would receive for 1 inToken.
|
|
780
|
+
*/
|
|
781
|
+
calculateSpotPrice(inToken, outToken, poolSqrtPrice) {
|
|
782
|
+
validateNumericAmount(poolSqrtPrice, "poolSqrtPrice");
|
|
783
|
+
const ordering = getTokenOrdering(inToken, outToken, false);
|
|
784
|
+
const poolPrice = BigNumber2(poolSqrtPrice).pow(2);
|
|
785
|
+
if (ordering.zeroForOne) {
|
|
786
|
+
return poolPrice;
|
|
787
|
+
} else {
|
|
788
|
+
return BigNumber2(1).div(poolPrice);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
// src/classes/positions.ts
|
|
794
|
+
import BigNumber3 from "bignumber.js";
|
|
795
|
+
var Positions = class {
|
|
796
|
+
constructor(gatewayBaseUrl, dexContractBasePath, bundlerService, poolService, httpClient, options) {
|
|
797
|
+
this.gatewayBaseUrl = gatewayBaseUrl;
|
|
798
|
+
this.dexContractBasePath = dexContractBasePath;
|
|
799
|
+
this.options = options;
|
|
800
|
+
this.httpClient = httpClient;
|
|
801
|
+
this.bundlerService = bundlerService;
|
|
802
|
+
this.poolService = poolService;
|
|
803
|
+
}
|
|
804
|
+
httpClient;
|
|
805
|
+
bundlerService;
|
|
806
|
+
poolService;
|
|
807
|
+
/**
|
|
808
|
+
* Get all liquidity positions for a specific wallet address.
|
|
809
|
+
* @param ownerAddress - The wallet address to get positions for.
|
|
810
|
+
* @param limit - Maximum number of positions to return.
|
|
811
|
+
* @param bookmark - Pagination bookmark for retrieving additional results. If you call this function and it returns a bookmark that is not an empty string, you can pass that bookmark as this parameter in a subsequent call to fetch the next page.
|
|
812
|
+
* @returns User positions and pagination bookmark
|
|
813
|
+
* @example
|
|
814
|
+
* ```typescript
|
|
815
|
+
* const positions = await gSwap.positions.getUserPositions('eth|123...abc');
|
|
816
|
+
* console.log(positions);
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
819
|
+
async getUserPositions(ownerAddress, limit, bookmark) {
|
|
820
|
+
const results = await this.sendUserPositionsRequest("/GetUserPositions", {
|
|
821
|
+
user: ownerAddress,
|
|
822
|
+
limit,
|
|
823
|
+
bookmark
|
|
824
|
+
});
|
|
825
|
+
return {
|
|
826
|
+
bookmark: results.nextBookMark,
|
|
827
|
+
positions: results.positions
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Gets detailed information about a specific liquidity position.
|
|
832
|
+
* @param ownerAddress - The wallet address that owns the position.
|
|
833
|
+
* @param position - Position parameters including tokens, fee, and tick range.
|
|
834
|
+
* @param position.token0ClassKey - The first token in the position.
|
|
835
|
+
* @param position.token1ClassKey - The second token in the position.
|
|
836
|
+
* @param position.fee - The pool fee tier.
|
|
837
|
+
* @param position.tickLower - The lower tick of the position range.
|
|
838
|
+
* @param position.tickUpper - The upper tick of the position range.
|
|
839
|
+
* @returns Detailed position information.
|
|
840
|
+
* @example
|
|
841
|
+
* ```typescript
|
|
842
|
+
* const position = await gSwap.positions.getPosition('eth|123...abc', {
|
|
843
|
+
* token0ClassKey: 'GALA|Unit|none|none',
|
|
844
|
+
* token1ClassKey: 'GUSDC|Unit|none|none',
|
|
845
|
+
* fee: 500,
|
|
846
|
+
* tickLower: -6000,
|
|
847
|
+
* tickUpper: 6000
|
|
848
|
+
* });
|
|
849
|
+
* console.log('Position:', position);
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
async getPosition(ownerAddress, position) {
|
|
853
|
+
const result = await this.sendPositionRequest("/GetPositions", {
|
|
854
|
+
owner: ownerAddress,
|
|
855
|
+
token0: parseTokenClassKey(position.token0ClassKey),
|
|
856
|
+
token1: parseTokenClassKey(position.token1ClassKey),
|
|
857
|
+
fee: position.fee,
|
|
858
|
+
tickLower: position.tickLower,
|
|
859
|
+
tickUpper: position.tickUpper
|
|
860
|
+
});
|
|
861
|
+
return result;
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Gets detailed information about a liquidity position by its ID.
|
|
865
|
+
* @param ownerAddress - The wallet address that owns the position.
|
|
866
|
+
* @param positionId - The unique identifier of the position.
|
|
867
|
+
* @returns Detailed position information, or undefined if not found.
|
|
868
|
+
* @example
|
|
869
|
+
* ```typescript
|
|
870
|
+
* const position = await gSwap.positions.getPositionById('eth|123...abc', 'position-uuid-123');
|
|
871
|
+
* if (position) {
|
|
872
|
+
* console.log('Position found:', position);
|
|
873
|
+
* } else {
|
|
874
|
+
* console.log('Position not found');
|
|
875
|
+
* }
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
async getPositionById(ownerAddress, positionId) {
|
|
879
|
+
const userPositions = await this.getUserPositions(ownerAddress);
|
|
880
|
+
const position = userPositions.positions.find((pos) => pos.positionId === positionId);
|
|
881
|
+
if (!position) {
|
|
882
|
+
return void 0;
|
|
883
|
+
}
|
|
884
|
+
return this.getPosition(ownerAddress, position);
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Creates a new position or adds liquidity to a position, using a specific tick range. Consider using `addLiquidityByPrice()` instead unless you want to use ticks directly.
|
|
888
|
+
* @param args - Parameters for adding liquidity.
|
|
889
|
+
* @param args.walletAddress - The wallet address adding liquidity.
|
|
890
|
+
* @param args.positionId - The position identifier. If you're creating a new position, this should be an empty string.
|
|
891
|
+
* @param args.token0 - The first token in the pair.
|
|
892
|
+
* @param args.token1 - The second token in the pair.
|
|
893
|
+
* @param args.fee - The pool fee tier.
|
|
894
|
+
* @param args.tickLower - The lower tick of the position range.
|
|
895
|
+
* @param args.tickUpper - The upper tick of the position range.
|
|
896
|
+
* @param args.amount0Desired - Desired (also maximum) amount of token0 to add.
|
|
897
|
+
* @param args.amount1Desired - Desired (also maximum) amount of token1 to add.
|
|
898
|
+
* @param args.amount0Min - Minimum amount of token0 to add (slippage protection).
|
|
899
|
+
* @param args.amount1Min - Minimum amount of token1 to add (slippage protection).
|
|
900
|
+
* @returns Pending transaction.
|
|
901
|
+
* @example
|
|
902
|
+
* ```typescript
|
|
903
|
+
* const result = await gSwap.positions.addLiquidityByTicks({
|
|
904
|
+
* walletAddress: 'eth|123...abc',
|
|
905
|
+
* positionId: '',
|
|
906
|
+
* token0: 'GALA|Unit|none|none',
|
|
907
|
+
* token1: 'GUSDC|Unit|none|none',
|
|
908
|
+
* fee: 500,
|
|
909
|
+
* tickSpacing: 10,
|
|
910
|
+
* tickLower: -6000,
|
|
911
|
+
* tickUpper: 6000,
|
|
912
|
+
* amount0Desired: '100',
|
|
913
|
+
* amount1Desired: '50',
|
|
914
|
+
* amount0Min: '95',
|
|
915
|
+
* amount1Min: '47.5'
|
|
916
|
+
* });
|
|
917
|
+
* console.log('Liquidity added:', result);
|
|
918
|
+
* ```
|
|
919
|
+
*/
|
|
920
|
+
async addLiquidityByTicks(args) {
|
|
921
|
+
var _a, _b, _c, _d, _e;
|
|
922
|
+
const walletAddress = args.walletAddress ?? ((_a = this.options) == null ? void 0 : _a.walletAddress);
|
|
923
|
+
validateWalletAddress(walletAddress);
|
|
924
|
+
validateFee(args.fee);
|
|
925
|
+
validateTickRange(args.tickLower, args.tickUpper);
|
|
926
|
+
validateNumericAmount(args.amount0Desired, "amount0Desired");
|
|
927
|
+
validateNumericAmount(args.amount1Desired, "amount1Desired");
|
|
928
|
+
validateNumericAmount(args.amount0Min, "amount0Min", true);
|
|
929
|
+
validateNumericAmount(args.amount1Min, "amount1Min", true);
|
|
930
|
+
const token0TokenClassKey = parseTokenClassKey(args.token0);
|
|
931
|
+
const token1TokenClassKey = parseTokenClassKey(args.token1);
|
|
932
|
+
const ordering = getTokenOrdering(
|
|
933
|
+
token0TokenClassKey,
|
|
934
|
+
token1TokenClassKey,
|
|
935
|
+
true,
|
|
936
|
+
[args.amount0Desired, args.amount0Min],
|
|
937
|
+
[args.amount1Desired, args.amount1Min]
|
|
938
|
+
);
|
|
939
|
+
const toSign = {
|
|
940
|
+
token0: ordering.token0,
|
|
941
|
+
token1: ordering.token1,
|
|
942
|
+
fee: args.fee,
|
|
943
|
+
owner: args.walletAddress,
|
|
944
|
+
tickLower: args.tickLower,
|
|
945
|
+
tickUpper: args.tickUpper,
|
|
946
|
+
amount0Desired: (_b = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _b[0],
|
|
947
|
+
amount1Desired: (_c = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _c[0],
|
|
948
|
+
amount0Min: (_d = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _d[1],
|
|
949
|
+
amount1Min: (_e = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _e[1],
|
|
950
|
+
positionId: args.positionId
|
|
951
|
+
};
|
|
952
|
+
const token0StringKey = stringifyTokenClassKey(ordering.token0, "$");
|
|
953
|
+
const token1StringKey = stringifyTokenClassKey(ordering.token1, "$");
|
|
954
|
+
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${args.fee}`;
|
|
955
|
+
const userPositionString = `$userPosition$${args.walletAddress}`;
|
|
956
|
+
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${args.walletAddress}`;
|
|
957
|
+
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${args.walletAddress}`;
|
|
958
|
+
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
|
|
959
|
+
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
|
|
960
|
+
const stringsInstructions = [
|
|
961
|
+
poolString,
|
|
962
|
+
userPositionString,
|
|
963
|
+
tokenBalance0,
|
|
964
|
+
tokenBalance1,
|
|
965
|
+
tokenBalance0Pool,
|
|
966
|
+
tokenBalance1Pool
|
|
967
|
+
];
|
|
968
|
+
return this.bundlerService.sendBundlerRequest("AddLiquidity", toSign, stringsInstructions);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Creates a new position or adds liquidity to a position, using a specified price range. Note that this method automatically converts your minPrice and maxPrice to ticks, rounding down if necessary.
|
|
972
|
+
* @param args - Parameters for adding liquidity.
|
|
973
|
+
* @param args.walletAddress - The wallet address adding liquidity.
|
|
974
|
+
* @param args.positionId - The position identifier. This should be an empty string if you are creating a new position.
|
|
975
|
+
* @param args.token0 - The first token in the pair.
|
|
976
|
+
* @param args.token1 - The second token in the pair.
|
|
977
|
+
* @param args.fee - The pool fee tier.
|
|
978
|
+
* @param args.tickSpacing - The tick spacing for the pool.
|
|
979
|
+
* @param args.minPrice - The minimum price for the position range.
|
|
980
|
+
* @param args.maxPrice - The maximum price for the position range.
|
|
981
|
+
* @param args.amount0Desired - Desired (also maximum) amount of token0 to add.
|
|
982
|
+
* @param args.amount1Desired - Desired (also maximum) amount of token1 to add.
|
|
983
|
+
* @param args.amount0Min - Minimum amount of token0 to add (slippage protection).
|
|
984
|
+
* @param args.amount1Min - Minimum amount of token1 to add (slippage protection).
|
|
985
|
+
* @returns Pending transaction.
|
|
986
|
+
* @example
|
|
987
|
+
* ```typescript
|
|
988
|
+
* const result = await gSwap.positions.addLiquidityByPrice({
|
|
989
|
+
* walletAddress: 'eth|123...abc',
|
|
990
|
+
* positionId: '',
|
|
991
|
+
* token0: 'GALA|Unit|none|none',
|
|
992
|
+
* token1: 'GUSDC|Unit|none|none',
|
|
993
|
+
* fee: 500,
|
|
994
|
+
* tickSpacing: 10,
|
|
995
|
+
* minPrice: '0.45',
|
|
996
|
+
* maxPrice: '0.55',
|
|
997
|
+
* amount0Desired: '100',
|
|
998
|
+
* amount1Desired: '50',
|
|
999
|
+
* amount0Min: '95',
|
|
1000
|
+
* amount1Min: '47.5'
|
|
1001
|
+
* });
|
|
1002
|
+
* console.log('Liquidity added with price range:', result);
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
1005
|
+
async addLiquidityByPrice(args) {
|
|
1006
|
+
var _a, _b, _c, _d, _e;
|
|
1007
|
+
const walletAddress = args.walletAddress ?? ((_a = this.options) == null ? void 0 : _a.walletAddress);
|
|
1008
|
+
validateWalletAddress(walletAddress);
|
|
1009
|
+
validateFee(args.fee);
|
|
1010
|
+
validateTickSpacing(args.tickSpacing);
|
|
1011
|
+
validateNumericAmount(args.minPrice, "minPrice", true);
|
|
1012
|
+
validateNumericAmount(args.maxPrice, "maxPrice");
|
|
1013
|
+
validateNumericAmount(args.amount0Desired, "amount0Desired");
|
|
1014
|
+
validateNumericAmount(args.amount1Desired, "amount1Desired");
|
|
1015
|
+
validateNumericAmount(args.amount0Min, "amount0Min", true);
|
|
1016
|
+
validateNumericAmount(args.amount1Min, "amount1Min", true);
|
|
1017
|
+
if (BigNumber3(args.minPrice).isGreaterThan(BigNumber3(args.maxPrice))) {
|
|
1018
|
+
throw new Error("Invalid price range: minPrice must be less than or equal to maxPrice");
|
|
1019
|
+
}
|
|
1020
|
+
const token0TokenClassKey = parseTokenClassKey(args.token0);
|
|
1021
|
+
const token1TokenClassKey = parseTokenClassKey(args.token1);
|
|
1022
|
+
const ordering = getTokenOrdering(
|
|
1023
|
+
token0TokenClassKey,
|
|
1024
|
+
token1TokenClassKey,
|
|
1025
|
+
true,
|
|
1026
|
+
[args.amount0Desired, args.amount0Min],
|
|
1027
|
+
[args.amount1Desired, args.amount1Min]
|
|
1028
|
+
);
|
|
1029
|
+
const minPriceTicks = this.poolService.calculateTicksForPrice(args.minPrice, args.tickSpacing);
|
|
1030
|
+
const maxPriceTicks = this.poolService.calculateTicksForPrice(args.maxPrice, args.tickSpacing);
|
|
1031
|
+
const tickLower = ordering.zeroForOne ? minPriceTicks : maxPriceTicks * -1;
|
|
1032
|
+
const tickUpper = ordering.zeroForOne ? maxPriceTicks : minPriceTicks * -1;
|
|
1033
|
+
const toSign = {
|
|
1034
|
+
token0: ordering.token0,
|
|
1035
|
+
token1: ordering.token1,
|
|
1036
|
+
fee: args.fee,
|
|
1037
|
+
owner: args.walletAddress,
|
|
1038
|
+
tickLower,
|
|
1039
|
+
tickUpper,
|
|
1040
|
+
amount0Desired: (_b = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _b[0],
|
|
1041
|
+
amount1Desired: (_c = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _c[0],
|
|
1042
|
+
amount0Min: (_d = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _d[1],
|
|
1043
|
+
amount1Min: (_e = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _e[1],
|
|
1044
|
+
positionId: args.positionId
|
|
1045
|
+
};
|
|
1046
|
+
const token0StringKey = stringifyTokenClassKey(ordering.token0, "$");
|
|
1047
|
+
const token1StringKey = stringifyTokenClassKey(ordering.token1, "$");
|
|
1048
|
+
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${args.fee}`;
|
|
1049
|
+
const userPositionString = `$userPosition$${args.walletAddress}`;
|
|
1050
|
+
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${args.walletAddress}`;
|
|
1051
|
+
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${args.walletAddress}`;
|
|
1052
|
+
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
|
|
1053
|
+
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
|
|
1054
|
+
const stringsInstructions = [
|
|
1055
|
+
poolString,
|
|
1056
|
+
userPositionString,
|
|
1057
|
+
tokenBalance0,
|
|
1058
|
+
tokenBalance1,
|
|
1059
|
+
tokenBalance0Pool,
|
|
1060
|
+
tokenBalance1Pool
|
|
1061
|
+
];
|
|
1062
|
+
return this.bundlerService.sendBundlerRequest("AddLiquidity", toSign, stringsInstructions);
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Removes liquidity from a position.
|
|
1066
|
+
* @param args - Parameters for removing liquidity.
|
|
1067
|
+
* @param args.walletAddress - The wallet address removing liquidity.
|
|
1068
|
+
* @param args.positionId - The position identifier.
|
|
1069
|
+
* @param args.token0 - The first token in the pair.
|
|
1070
|
+
* @param args.token1 - The second token in the pair.
|
|
1071
|
+
* @param args.fee - The pool fee tier.
|
|
1072
|
+
* @param args.tickLower - The lower tick of the position range.
|
|
1073
|
+
* @param args.tickUpper - The upper tick of the position range.
|
|
1074
|
+
* @param args.amount - The amount of liquidity to remove.
|
|
1075
|
+
* @param args.amount0Min - Minimum amount of token0 to receive (slippage protection, optional).
|
|
1076
|
+
* @param args.amount1Min - Minimum amount of token1 to receive (slippage protection, optional).
|
|
1077
|
+
* @returns Pending transaction.
|
|
1078
|
+
* @example
|
|
1079
|
+
* ```typescript
|
|
1080
|
+
* // Remove 50% of liquidity from a position
|
|
1081
|
+
* const result = await gSwap.positions.removeLiquidity({
|
|
1082
|
+
* walletAddress: 'eth|123...abc',
|
|
1083
|
+
* positionId: 'position-123',
|
|
1084
|
+
* token0: 'GALA|Unit|none|none',
|
|
1085
|
+
* token1: 'GUSDC|Unit|none|none',
|
|
1086
|
+
* fee: 500,
|
|
1087
|
+
* tickLower: -6000,
|
|
1088
|
+
* tickUpper: 6000,
|
|
1089
|
+
* amount: '50000000000000000000', // 50% of position liquidity
|
|
1090
|
+
* amount0Min: '45',
|
|
1091
|
+
* amount1Min: '22'
|
|
1092
|
+
* });
|
|
1093
|
+
* console.log('Liquidity removed:', result);
|
|
1094
|
+
* ```
|
|
1095
|
+
*/
|
|
1096
|
+
async removeLiquidity(args) {
|
|
1097
|
+
var _a, _b, _c;
|
|
1098
|
+
const walletAddress = args.walletAddress ?? ((_a = this.options) == null ? void 0 : _a.walletAddress);
|
|
1099
|
+
validateWalletAddress(walletAddress);
|
|
1100
|
+
validateFee(args.fee);
|
|
1101
|
+
validateTickRange(args.tickLower, args.tickUpper);
|
|
1102
|
+
validateNumericAmount(args.amount, "amount");
|
|
1103
|
+
if (args.amount0Min !== void 0) {
|
|
1104
|
+
validateNumericAmount(args.amount0Min, "amount0Min", true);
|
|
1105
|
+
}
|
|
1106
|
+
if (args.amount1Min !== void 0) {
|
|
1107
|
+
validateNumericAmount(args.amount1Min, "amount1Min", true);
|
|
1108
|
+
}
|
|
1109
|
+
const token0TokenClassKey = parseTokenClassKey(args.token0);
|
|
1110
|
+
const token1TokenClassKey = parseTokenClassKey(args.token1);
|
|
1111
|
+
const ordering = getTokenOrdering(
|
|
1112
|
+
token0TokenClassKey,
|
|
1113
|
+
token1TokenClassKey,
|
|
1114
|
+
true,
|
|
1115
|
+
[args.amount0Min ?? 0],
|
|
1116
|
+
[args.amount1Min ?? 0]
|
|
1117
|
+
);
|
|
1118
|
+
const toSign = {
|
|
1119
|
+
token0: ordering.token0,
|
|
1120
|
+
token1: ordering.token1,
|
|
1121
|
+
fee: args.fee,
|
|
1122
|
+
tickLower: args.tickLower,
|
|
1123
|
+
tickUpper: args.tickUpper,
|
|
1124
|
+
amount: args.amount.toString(),
|
|
1125
|
+
amount0Min: ((_b = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _b[0]) || "0",
|
|
1126
|
+
amount1Min: ((_c = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _c[0]) || "0",
|
|
1127
|
+
positionId: args.positionId
|
|
1128
|
+
};
|
|
1129
|
+
const token0StringKey = stringifyTokenClassKey(ordering.token0, "$");
|
|
1130
|
+
const token1StringKey = stringifyTokenClassKey(ordering.token1, "$");
|
|
1131
|
+
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${args.fee}`;
|
|
1132
|
+
const userPositionString = `$userPosition$${args.walletAddress}`;
|
|
1133
|
+
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${args.walletAddress}`;
|
|
1134
|
+
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${args.walletAddress}`;
|
|
1135
|
+
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
|
|
1136
|
+
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
|
|
1137
|
+
const stringsInstructions = [
|
|
1138
|
+
poolString,
|
|
1139
|
+
userPositionString,
|
|
1140
|
+
tokenBalance0,
|
|
1141
|
+
tokenBalance1,
|
|
1142
|
+
tokenBalance0Pool,
|
|
1143
|
+
tokenBalance1Pool
|
|
1144
|
+
];
|
|
1145
|
+
return this.bundlerService.sendBundlerRequest("RemoveLiquidity", toSign, stringsInstructions);
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Collects accumulated fees from a liquidity position.
|
|
1149
|
+
* @param args - Parameters for collecting fees.
|
|
1150
|
+
* @param args.walletAddress - The wallet address collecting fees.
|
|
1151
|
+
* @param args.positionId - The position identifier.
|
|
1152
|
+
* @param args.token0 - The first token in the pair.
|
|
1153
|
+
* @param args.token1 - The second token in the pair.
|
|
1154
|
+
* @param args.fee - The pool fee tier.
|
|
1155
|
+
* @param args.tickLower - The lower tick of the position range.
|
|
1156
|
+
* @param args.tickUpper - The upper tick of the position range.
|
|
1157
|
+
* @param args.amount0Requested - Desired amount of token0 fees to collect.
|
|
1158
|
+
* @param args.amount1Requested - Desired amount of token1 fees to collect.
|
|
1159
|
+
* @returns Pending transaction.
|
|
1160
|
+
* @example
|
|
1161
|
+
* ```typescript
|
|
1162
|
+
* // Collect all accumulated fees from a position
|
|
1163
|
+
* const result = await gSwap.positions.collectPositionFees({
|
|
1164
|
+
* walletAddress: 'eth|123...abc',
|
|
1165
|
+
* positionId: 'position-123',
|
|
1166
|
+
* token0: 'GALA|Unit|none|none',
|
|
1167
|
+
* token1: 'GUSDC|Unit|none|none',
|
|
1168
|
+
* fee: 500,
|
|
1169
|
+
* tickLower: -6000,
|
|
1170
|
+
* tickUpper: 6000,
|
|
1171
|
+
* amount0Requested: '1000000000000000000', // Max fees available
|
|
1172
|
+
* amount1Requested: '500000000' // Max fees available
|
|
1173
|
+
* });
|
|
1174
|
+
* console.log('Fees collected:', result);
|
|
1175
|
+
* ```
|
|
1176
|
+
*/
|
|
1177
|
+
async collectPositionFees(args) {
|
|
1178
|
+
var _a, _b, _c;
|
|
1179
|
+
const walletAddress = args.walletAddress ?? ((_a = this.options) == null ? void 0 : _a.walletAddress);
|
|
1180
|
+
validateWalletAddress(walletAddress);
|
|
1181
|
+
validateFee(args.fee);
|
|
1182
|
+
validateTickRange(args.tickLower, args.tickUpper);
|
|
1183
|
+
validateNumericAmount(args.amount0Requested, "amount0Requested", true);
|
|
1184
|
+
validateNumericAmount(args.amount1Requested, "amount1Requested", true);
|
|
1185
|
+
const token0TokenClassKey = parseTokenClassKey(args.token0);
|
|
1186
|
+
const token1TokenClassKey = parseTokenClassKey(args.token1);
|
|
1187
|
+
const ordering = getTokenOrdering(
|
|
1188
|
+
token0TokenClassKey,
|
|
1189
|
+
token1TokenClassKey,
|
|
1190
|
+
true,
|
|
1191
|
+
[args.amount0Requested],
|
|
1192
|
+
[args.amount1Requested]
|
|
1193
|
+
);
|
|
1194
|
+
const toSign = {
|
|
1195
|
+
token0: ordering.token0,
|
|
1196
|
+
token1: ordering.token1,
|
|
1197
|
+
fee: args.fee,
|
|
1198
|
+
amount0Requested: (_b = ordering == null ? void 0 : ordering.token0Attributes) == null ? void 0 : _b[0],
|
|
1199
|
+
amount1Requested: (_c = ordering == null ? void 0 : ordering.token1Attributes) == null ? void 0 : _c[0],
|
|
1200
|
+
tickLower: args.tickLower,
|
|
1201
|
+
tickUpper: args.tickUpper,
|
|
1202
|
+
positionId: args.positionId
|
|
1203
|
+
};
|
|
1204
|
+
const token0StringKey = stringifyTokenClassKey(ordering.token0, "$");
|
|
1205
|
+
const token1StringKey = stringifyTokenClassKey(ordering.token1, "$");
|
|
1206
|
+
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${args.fee}`;
|
|
1207
|
+
const userPositionString = `$userPosition$${args.walletAddress}`;
|
|
1208
|
+
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${args.walletAddress}`;
|
|
1209
|
+
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${args.walletAddress}`;
|
|
1210
|
+
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
|
|
1211
|
+
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
|
|
1212
|
+
const stringsInstructions = [
|
|
1213
|
+
poolString,
|
|
1214
|
+
userPositionString,
|
|
1215
|
+
tokenBalance0,
|
|
1216
|
+
tokenBalance1,
|
|
1217
|
+
tokenBalance0Pool,
|
|
1218
|
+
tokenBalance1Pool
|
|
1219
|
+
];
|
|
1220
|
+
return this.bundlerService.sendBundlerRequest(
|
|
1221
|
+
"CollectPositionFees",
|
|
1222
|
+
toSign,
|
|
1223
|
+
stringsInstructions
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
calculateOptimalPositionSize(tokenAmount, spotPrice, lowerPrice, upperPrice, tokenDecimals, otherTokenDecimals) {
|
|
1227
|
+
validateNumericAmount(tokenAmount, "tokenAmount");
|
|
1228
|
+
validatePriceValues(spotPrice, lowerPrice, upperPrice);
|
|
1229
|
+
validateTokenDecimals(tokenDecimals, "tokenDecimals");
|
|
1230
|
+
validateTokenDecimals(otherTokenDecimals, "otherTokenDecimals");
|
|
1231
|
+
const bnTokenAmount = BigNumber3(tokenAmount);
|
|
1232
|
+
const bnSpotPrice = BigNumber3(spotPrice);
|
|
1233
|
+
const bnLowerPrice = BigNumber3(lowerPrice);
|
|
1234
|
+
let bnUpperPrice = BigNumber3(upperPrice);
|
|
1235
|
+
bnUpperPrice = bnUpperPrice.isFinite() ? bnUpperPrice : BigNumber3(1e18);
|
|
1236
|
+
const liquidityAmount = bnTokenAmount.times(10 ** (tokenDecimals - otherTokenDecimals)).times(bnSpotPrice.sqrt()).times(bnUpperPrice.sqrt()).div(bnUpperPrice.sqrt().minus(bnSpotPrice.sqrt()));
|
|
1237
|
+
const yAmount = BigNumber3(liquidityAmount).times(bnSpotPrice.sqrt().minus(bnLowerPrice.sqrt()));
|
|
1238
|
+
return yAmount.div(BigNumber3(10).pow(tokenDecimals - otherTokenDecimals));
|
|
1239
|
+
}
|
|
1240
|
+
async sendUserPositionsRequest(endpoint, body) {
|
|
1241
|
+
const responseBody = await this.httpClient.sendPostRequest(this.gatewayBaseUrl, this.dexContractBasePath, endpoint, body);
|
|
1242
|
+
return {
|
|
1243
|
+
nextBookMark: responseBody.Data.nextBookMark,
|
|
1244
|
+
positions: responseBody.Data.positions.map((position) => ({
|
|
1245
|
+
...position,
|
|
1246
|
+
liquidity: BigNumber3(position.liquidity)
|
|
1247
|
+
}))
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
async sendPositionRequest(endpoint, body) {
|
|
1251
|
+
const responseBody = await this.httpClient.sendPostRequest(this.gatewayBaseUrl, this.dexContractBasePath, endpoint, body);
|
|
1252
|
+
return {
|
|
1253
|
+
...responseBody.Data,
|
|
1254
|
+
feeGrowthInside0Last: BigNumber3(responseBody.Data.feeGrowthInside0Last),
|
|
1255
|
+
feeGrowthInside1Last: BigNumber3(responseBody.Data.feeGrowthInside1Last),
|
|
1256
|
+
liquidity: BigNumber3(responseBody.Data.liquidity),
|
|
1257
|
+
tokensOwed0: BigNumber3(responseBody.Data.tokensOwed0),
|
|
1258
|
+
tokensOwed1: BigNumber3(responseBody.Data.tokensOwed1)
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
// src/classes/quoting.ts
|
|
1264
|
+
import BigNumber4 from "bignumber.js";
|
|
1265
|
+
|
|
1266
|
+
// src/types/fees.ts
|
|
1267
|
+
var FEE_TIER = /* @__PURE__ */ ((FEE_TIER2) => {
|
|
1268
|
+
FEE_TIER2[FEE_TIER2["PERCENT_00_05"] = 500] = "PERCENT_00_05";
|
|
1269
|
+
FEE_TIER2[FEE_TIER2["PERCENT_00_30"] = 3e3] = "PERCENT_00_30";
|
|
1270
|
+
FEE_TIER2[FEE_TIER2["PERCENT_01_00"] = 1e4] = "PERCENT_01_00";
|
|
1271
|
+
return FEE_TIER2;
|
|
1272
|
+
})(FEE_TIER || {});
|
|
1273
|
+
|
|
1274
|
+
// src/classes/quoting.ts
|
|
1275
|
+
var Quoting = class {
|
|
1276
|
+
constructor(gatewayBaseUrl, dexContractBasePath, httpClient) {
|
|
1277
|
+
this.gatewayBaseUrl = gatewayBaseUrl;
|
|
1278
|
+
this.dexContractBasePath = dexContractBasePath;
|
|
1279
|
+
this.httpClient = httpClient ?? new HttpClient();
|
|
1280
|
+
}
|
|
1281
|
+
httpClient;
|
|
1282
|
+
/**
|
|
1283
|
+
* Gets a quote for an exact amount of token being sold.
|
|
1284
|
+
* @param tokenIn - The input token to sell.
|
|
1285
|
+
* @param tokenOut - The output token to buy.
|
|
1286
|
+
* @param amountIn - The exact amount of input tokens you want to sell.
|
|
1287
|
+
* @param fee - The pool fee tier. If not specified, will check all available fee tiers and return the best quote.
|
|
1288
|
+
* @returns The expected number of tokens you will receive (buy) when/if you execute the swap.
|
|
1289
|
+
*/
|
|
1290
|
+
async quoteExactInput(tokenIn, tokenOut, amountIn, fee) {
|
|
1291
|
+
validateNumericAmount(amountIn, "amountIn");
|
|
1292
|
+
if (fee !== void 0) {
|
|
1293
|
+
const result = await this.getSingleQuoteExactInput(tokenIn, tokenOut, fee, amountIn);
|
|
1294
|
+
return result;
|
|
1295
|
+
}
|
|
1296
|
+
const allFees = [500 /* PERCENT_00_05 */, 3e3 /* PERCENT_00_30 */, 1e4 /* PERCENT_01_00 */];
|
|
1297
|
+
const quotePromises = allFees.map(async (feeTier) => {
|
|
1298
|
+
try {
|
|
1299
|
+
return await this.getSingleQuoteExactInput(tokenIn, tokenOut, feeTier, amountIn);
|
|
1300
|
+
} catch (err) {
|
|
1301
|
+
if (err instanceof GSwapSDKError && (err.code === "CONFLICT" || err.code === "OBJECT_NOT_FOUND")) {
|
|
1302
|
+
return void 0;
|
|
1303
|
+
}
|
|
1304
|
+
throw err;
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
const results = await Promise.all(quotePromises);
|
|
1308
|
+
const quotes = results.filter((quote) => quote !== void 0);
|
|
1309
|
+
if (quotes.length === 0) {
|
|
1310
|
+
throw GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut);
|
|
1311
|
+
}
|
|
1312
|
+
return quotes.reduce(
|
|
1313
|
+
(best, current) => current.outTokenAmount.isGreaterThan(best.outTokenAmount) ? current : best
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Gets a quote for an exact amount of tokens being bought.
|
|
1318
|
+
* @param tokenIn - The input token sell.
|
|
1319
|
+
* @param tokenOut - The output token to buy.
|
|
1320
|
+
* @param amountOut - The exact amount of output tokens you want to buy.
|
|
1321
|
+
* @param fee - The pool fee tier. If not specified, will check all available fee tiers and return the best quote.
|
|
1322
|
+
* @returns The expected number of tokens you will need to sell (input) to receive the specified amount of output tokens.
|
|
1323
|
+
*/
|
|
1324
|
+
async quoteExactOutput(tokenIn, tokenOut, amountOut, fee) {
|
|
1325
|
+
validateNumericAmount(amountOut, "amountOut");
|
|
1326
|
+
if (fee !== void 0) {
|
|
1327
|
+
const result = await this.getSingleQuoteExactOutput(tokenIn, tokenOut, amountOut, fee);
|
|
1328
|
+
return result;
|
|
1329
|
+
}
|
|
1330
|
+
const allFees = [500 /* PERCENT_00_05 */, 3e3 /* PERCENT_00_30 */, 1e4 /* PERCENT_01_00 */];
|
|
1331
|
+
const quotePromises = allFees.map(async (feeTier) => {
|
|
1332
|
+
try {
|
|
1333
|
+
return await this.getSingleQuoteExactOutput(tokenIn, tokenOut, amountOut, feeTier);
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
if (err instanceof GSwapSDKError && (err.code === "CONFLICT" || err.code === "OBJECT_NOT_FOUND")) {
|
|
1336
|
+
return void 0;
|
|
1337
|
+
}
|
|
1338
|
+
throw err;
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
const results = await Promise.all(quotePromises);
|
|
1342
|
+
const quotes = results.filter((quote) => quote !== void 0);
|
|
1343
|
+
if (quotes.length === 0) {
|
|
1344
|
+
throw GSwapSDKError.noPoolAvailableError(tokenIn, tokenOut);
|
|
1345
|
+
}
|
|
1346
|
+
return quotes.reduce(
|
|
1347
|
+
(best, current) => current.inTokenAmount.isLessThan(best.inTokenAmount) ? current : best
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
async getSingleQuote(tokenIn, tokenOut, fee, amount, isExactInput) {
|
|
1351
|
+
const tokenInClass = parseTokenClassKey(tokenIn);
|
|
1352
|
+
const tokenOutClass = parseTokenClassKey(tokenOut);
|
|
1353
|
+
const ordering = getTokenOrdering(tokenInClass, tokenOutClass, false);
|
|
1354
|
+
const formattedAmount = isExactInput ? amount.toString() : BigNumber4(amount).multipliedBy(-1).toString();
|
|
1355
|
+
const response = await this.sendQuoteRequest("/QuoteExactAmount", {
|
|
1356
|
+
...ordering,
|
|
1357
|
+
fee,
|
|
1358
|
+
amount: formattedAmount
|
|
1359
|
+
});
|
|
1360
|
+
const tokenInAmount = ordering.zeroForOne ? response.amount0 : response.amount1;
|
|
1361
|
+
const tokenOutAmount = ordering.zeroForOne ? response.amount1 : response.amount0;
|
|
1362
|
+
let currentPrice = response.currentSqrtPrice.pow(2);
|
|
1363
|
+
let newPrice = response.newSqrtPrice.pow(2);
|
|
1364
|
+
if (!ordering.zeroForOne) {
|
|
1365
|
+
currentPrice = BigNumber4(1).dividedBy(currentPrice);
|
|
1366
|
+
newPrice = BigNumber4(1).dividedBy(newPrice);
|
|
1367
|
+
}
|
|
1368
|
+
const priceImpact = newPrice.minus(currentPrice).dividedBy(currentPrice);
|
|
1369
|
+
return {
|
|
1370
|
+
amount0: response.amount0,
|
|
1371
|
+
amount1: response.amount1,
|
|
1372
|
+
currentPoolSqrtPrice: response.currentSqrtPrice,
|
|
1373
|
+
newPoolSqrtPrice: response.newSqrtPrice,
|
|
1374
|
+
currentPrice,
|
|
1375
|
+
newPrice,
|
|
1376
|
+
inTokenAmount: tokenInAmount.abs(),
|
|
1377
|
+
outTokenAmount: tokenOutAmount.abs(),
|
|
1378
|
+
priceImpact,
|
|
1379
|
+
feeTier: fee
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
async getSingleQuoteExactInput(tokenIn, tokenOut, fee, amountIn) {
|
|
1383
|
+
return this.getSingleQuote(tokenIn, tokenOut, fee, amountIn, true);
|
|
1384
|
+
}
|
|
1385
|
+
async getSingleQuoteExactOutput(tokenIn, tokenOut, amountOut, fee) {
|
|
1386
|
+
return this.getSingleQuote(tokenIn, tokenOut, fee, amountOut, false);
|
|
1387
|
+
}
|
|
1388
|
+
async sendQuoteRequest(endpoint, body) {
|
|
1389
|
+
const response = await this.httpClient.sendPostRequest(
|
|
1390
|
+
this.gatewayBaseUrl,
|
|
1391
|
+
this.dexContractBasePath,
|
|
1392
|
+
endpoint,
|
|
1393
|
+
body
|
|
1394
|
+
);
|
|
1395
|
+
const responseBody = response;
|
|
1396
|
+
return {
|
|
1397
|
+
amount0: BigNumber4(responseBody.Data.amount0),
|
|
1398
|
+
amount1: BigNumber4(responseBody.Data.amount1),
|
|
1399
|
+
currentSqrtPrice: BigNumber4(responseBody.Data.currentSqrtPrice),
|
|
1400
|
+
newSqrtPrice: BigNumber4(responseBody.Data.newSqrtPrice)
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
// src/classes/swaps.ts
|
|
1406
|
+
import BigNumber5 from "bignumber.js";
|
|
1407
|
+
var MIN_SQRT_PRICE_LIMIT = "0.000000000000000000094212147";
|
|
1408
|
+
var MAX_SQRT_PRICE_LIMIT = "18446050999999999999";
|
|
1409
|
+
var Swaps = class {
|
|
1410
|
+
constructor(bundlerService, options) {
|
|
1411
|
+
this.bundlerService = bundlerService;
|
|
1412
|
+
this.options = options;
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* Executes a token swap transaction.
|
|
1416
|
+
* @param walletAddress - The wallet address executing the swap.
|
|
1417
|
+
* @param tokenIn - The input token to sell.
|
|
1418
|
+
* @param tokenOut - The output token to buy.
|
|
1419
|
+
* @param fee - The pool fee tier.
|
|
1420
|
+
* @param amount - Swap parameters specifying either exact input or exact output.
|
|
1421
|
+
* @param amount.exactIn - For exact input swaps, the exact amount of input tokens to sell.
|
|
1422
|
+
* @param amount.amountOutMinimum - For exact input swaps, the minimum amount of output tokens to buy (slippage protection).
|
|
1423
|
+
* @param amount.exactOut - For exact output swaps, the exact amount of output tokens to buy.
|
|
1424
|
+
* @param amount.amountInMaximum - For exact output swaps, the maximum amount of input tokens to sell (slippage protection).
|
|
1425
|
+
* @returns Pending transaction.
|
|
1426
|
+
* @example
|
|
1427
|
+
* ```typescript
|
|
1428
|
+
* // Exact input swap: sell 100 GALA for USDC
|
|
1429
|
+
* const result = await swapsService.swap(
|
|
1430
|
+
* 'GALA|Unit|none|none',
|
|
1431
|
+
* 'GUSDC|Unit|none|none',
|
|
1432
|
+
* 500,
|
|
1433
|
+
* { exactIn: '100', amountOutMinimum: '45' },
|
|
1434
|
+
* 'eth|123...abc', // your wallet address
|
|
1435
|
+
* );
|
|
1436
|
+
* console.log('Swap successful:', result);
|
|
1437
|
+
* ```
|
|
1438
|
+
*/
|
|
1439
|
+
async swap(tokenIn, tokenOut, fee, amount, walletAddress) {
|
|
1440
|
+
var _a, _b;
|
|
1441
|
+
walletAddress = walletAddress ?? ((_a = this.options) == null ? void 0 : _a.walletAddress);
|
|
1442
|
+
validateWalletAddress(walletAddress);
|
|
1443
|
+
validateFee(fee);
|
|
1444
|
+
if ("exactIn" in amount) {
|
|
1445
|
+
validateNumericAmount(amount.exactIn, "exactIn");
|
|
1446
|
+
if (amount.amountOutMinimum !== void 0) {
|
|
1447
|
+
validateNumericAmount(amount.amountOutMinimum, "amountOutMinimum", true);
|
|
1448
|
+
}
|
|
1449
|
+
} else {
|
|
1450
|
+
validateNumericAmount(amount.exactOut, "exactOut");
|
|
1451
|
+
if (amount.amountInMaximum !== void 0) {
|
|
1452
|
+
validateNumericAmount(amount.amountInMaximum, "amountInMaximum");
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
const ordering = getTokenOrdering(tokenIn, tokenOut, false);
|
|
1456
|
+
const zeroForOne = stringifyTokenClassKey(tokenIn) === stringifyTokenClassKey(ordering.token0);
|
|
1457
|
+
const rawAmount = "exactIn" in amount ? amount.exactIn.toString() : BigNumber5(amount.exactOut).multipliedBy(-1).toString();
|
|
1458
|
+
const rawAmountOutMinimum = "exactIn" in amount ? ((_b = amount.amountOutMinimum) == null ? void 0 : _b.toString()) ? BigNumber5(amount.amountOutMinimum).multipliedBy(-1).toString() : void 0 : BigNumber5(amount.exactOut ?? 0).multipliedBy(-1).toString();
|
|
1459
|
+
const rawAmountInMaximum = "exactIn" in amount ? amount.exactIn.toString() : amount.amountInMaximum ? amount.amountInMaximum.toString() : void 0;
|
|
1460
|
+
const toSign = {
|
|
1461
|
+
token0: parseTokenClassKey(ordering.token0),
|
|
1462
|
+
token1: parseTokenClassKey(ordering.token1),
|
|
1463
|
+
fee,
|
|
1464
|
+
amount: rawAmount,
|
|
1465
|
+
zeroForOne,
|
|
1466
|
+
sqrtPriceLimit: ordering.zeroForOne ? MIN_SQRT_PRICE_LIMIT : MAX_SQRT_PRICE_LIMIT,
|
|
1467
|
+
recipient: walletAddress,
|
|
1468
|
+
amountOutMinimum: rawAmountOutMinimum,
|
|
1469
|
+
amountInMaximum: rawAmountInMaximum
|
|
1470
|
+
};
|
|
1471
|
+
const token0StringKey = stringifyTokenClassKey(ordering.token0, "$");
|
|
1472
|
+
const token1StringKey = stringifyTokenClassKey(ordering.token1, "$");
|
|
1473
|
+
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${fee}`;
|
|
1474
|
+
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${walletAddress}`;
|
|
1475
|
+
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${walletAddress}`;
|
|
1476
|
+
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
|
|
1477
|
+
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
|
|
1478
|
+
const stringsInstructions = [
|
|
1479
|
+
poolString,
|
|
1480
|
+
tokenBalance0,
|
|
1481
|
+
tokenBalance1,
|
|
1482
|
+
tokenBalance0Pool,
|
|
1483
|
+
tokenBalance1Pool
|
|
1484
|
+
];
|
|
1485
|
+
return this.bundlerService.sendBundlerRequest("Swap", toSign, stringsInstructions);
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
|
|
1489
|
+
// src/classes/gswap.ts
|
|
1490
|
+
var GSwap = class {
|
|
1491
|
+
gatewayBaseUrl;
|
|
1492
|
+
dexContractBasePath;
|
|
1493
|
+
tokenContractBasePath;
|
|
1494
|
+
bundlerBaseUrl;
|
|
1495
|
+
bundlingAPIBasePath;
|
|
1496
|
+
dexBackendBaseUrl;
|
|
1497
|
+
transactionWaitTimeoutMs;
|
|
1498
|
+
signer;
|
|
1499
|
+
/**
|
|
1500
|
+
* Quoting functionality for price discovery and trade estimation.
|
|
1501
|
+
* Use this to get quotes for token swaps without executing transactions.
|
|
1502
|
+
*
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```typescript
|
|
1505
|
+
* // Get the best quote across all fee tiers
|
|
1506
|
+
* const quote = await gSwap.quoting.quoteExactInput(tokenA, tokenB, amount);
|
|
1507
|
+
* ```
|
|
1508
|
+
*/
|
|
1509
|
+
quoting;
|
|
1510
|
+
/**
|
|
1511
|
+
* Position management operations for liquidity positions.
|
|
1512
|
+
* Use this to manage liquidity positions including creation, modification, and fee collection.
|
|
1513
|
+
*
|
|
1514
|
+
* @example
|
|
1515
|
+
* ```typescript
|
|
1516
|
+
* // Get all user positions
|
|
1517
|
+
* const positions = await gSwap.positions.getUserPositions('eth|123...abc');
|
|
1518
|
+
*
|
|
1519
|
+
* // Add liquidity to a position using price range
|
|
1520
|
+
* const result = await gSwap.positions.addLiquidityByPrice({
|
|
1521
|
+
* walletAddress: 'eth|123...abc',
|
|
1522
|
+
* positionId: '',
|
|
1523
|
+
* token0: 'GALA|Unit|none|none',
|
|
1524
|
+
* token1: 'GUSDC|Unit|none|none',
|
|
1525
|
+
* fee: 500,
|
|
1526
|
+
* tickSpacing: 10,
|
|
1527
|
+
* minPrice: '0.45',
|
|
1528
|
+
* maxPrice: '0.55',
|
|
1529
|
+
* amount0Desired: '100',
|
|
1530
|
+
* amount1Desired: '50',
|
|
1531
|
+
* amount0Min: '95',
|
|
1532
|
+
* amount1Min: '47.5'
|
|
1533
|
+
* });
|
|
1534
|
+
* ```
|
|
1535
|
+
*/
|
|
1536
|
+
positions;
|
|
1537
|
+
/**
|
|
1538
|
+
* Token swap operations for trading tokens.
|
|
1539
|
+
* Use this to execute token swaps on the DEX.
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* ```typescript
|
|
1543
|
+
* // Execute an exact input swap: sell 100 GALA for USDC
|
|
1544
|
+
* const result = await gSwap.swaps.swap(
|
|
1545
|
+
* 'GALA|Unit|none|none',
|
|
1546
|
+
* 'GUSDC|Unit|none|none',
|
|
1547
|
+
* 500,
|
|
1548
|
+
* { exactIn: '100', amountOutMinimum: '45' },
|
|
1549
|
+
* 'eth|123...abc', // your wallet address
|
|
1550
|
+
* );
|
|
1551
|
+
* ```
|
|
1552
|
+
*/
|
|
1553
|
+
swaps;
|
|
1554
|
+
/**
|
|
1555
|
+
* User asset management operations.
|
|
1556
|
+
* Use this to retrieve user token balances and asset information.
|
|
1557
|
+
*
|
|
1558
|
+
* @example
|
|
1559
|
+
* ```typescript
|
|
1560
|
+
* // Get user assets with pagination
|
|
1561
|
+
* const assets = await gSwap.assets.getUserAssets('eth|123...abc', 1, 20);
|
|
1562
|
+
* console.log(`User has ${assets.count} different tokens`);
|
|
1563
|
+
* ```
|
|
1564
|
+
*/
|
|
1565
|
+
assets;
|
|
1566
|
+
/**
|
|
1567
|
+
* Event management operations for real-time socket connections.
|
|
1568
|
+
* Use this to manage event streaming and transaction status updates.
|
|
1569
|
+
*
|
|
1570
|
+
* @example
|
|
1571
|
+
* ```typescript
|
|
1572
|
+
* // Connect to event socket for transaction updates
|
|
1573
|
+
* await GSwap.events.connectEventSocket();
|
|
1574
|
+
*
|
|
1575
|
+
* // Check if socket is connected
|
|
1576
|
+
* const isConnected = GSwap.events.eventSocketConnected();
|
|
1577
|
+
* ```
|
|
1578
|
+
*/
|
|
1579
|
+
static events = Events.instance;
|
|
1580
|
+
httpClient;
|
|
1581
|
+
httpRequestor;
|
|
1582
|
+
bundler;
|
|
1583
|
+
pools;
|
|
1584
|
+
/**
|
|
1585
|
+
* Creates a new SDK instance.
|
|
1586
|
+
* @param options - Customization options.
|
|
1587
|
+
* @param options.signer - The signer to use for authenticated operations. Required if you use any functionality that creates transactions (such as swapping). Not required for readonly operations.
|
|
1588
|
+
* @param options.gatewayBaseUrl - Base URL for the GalaChain Gateway API.
|
|
1589
|
+
* @param options.dexContractBasePath - Base path for DEX contract API endpoints, within the GalaChain Gateway API.
|
|
1590
|
+
* @param options.tokenContractBasePath - Base path for token contract API endpoints, within the GalaChain Gateway API.
|
|
1591
|
+
* @param options.bundlerBaseUrl - Base URL for the DEX transaction bundling API.
|
|
1592
|
+
* @param options.bundlingAPIBasePath - Base path for transaction bundling API endpoints.
|
|
1593
|
+
* @param options.dexBackendBaseUrl - Base URL for the DEX backend API (for user assets and other data).
|
|
1594
|
+
* @param options.httpRequestor - Custom HTTP requestor to use for API calls. Defaults to the global `fetch` function.
|
|
1595
|
+
* @param options.transactionWaitTimeoutMs - Timeout in milliseconds for waiting for transactions to complete. Defaults to 300,000 milliseconds (five minutes).
|
|
1596
|
+
* @param options.walletAddress - Optional default wallet address for operations that require a wallet address (e.x. swapping). If not provided, you must specify the wallet address in each method call.
|
|
1597
|
+
*/
|
|
1598
|
+
constructor(options) {
|
|
1599
|
+
var _a;
|
|
1600
|
+
this.gatewayBaseUrl = ((_a = options == null ? void 0 : options.gatewayBaseUrl) == null ? void 0 : _a.replace(/\/$/, "")) ?? "https://galachain-gateway-chain-platform-stage-chain-platform-eks.stage.galachain.com";
|
|
1601
|
+
this.dexContractBasePath = (options == null ? void 0 : options.dexContractBasePath) ?? "/api/asset/dexv3-contract";
|
|
1602
|
+
this.tokenContractBasePath = (options == null ? void 0 : options.tokenContractBasePath) ?? "/api/asset/token-contract";
|
|
1603
|
+
this.bundlerBaseUrl = (options == null ? void 0 : options.bundlerBaseUrl) ?? "https://bundle-backend-test1.defi.gala.com";
|
|
1604
|
+
this.bundlingAPIBasePath = (options == null ? void 0 : options.bundlingAPIBasePath) ?? "/bundle";
|
|
1605
|
+
this.dexBackendBaseUrl = (options == null ? void 0 : options.dexBackendBaseUrl) ?? "https://dex-backend-dev1.defi.gala.com";
|
|
1606
|
+
this.signer = options == null ? void 0 : options.signer;
|
|
1607
|
+
this.transactionWaitTimeoutMs = (options == null ? void 0 : options.transactionWaitTimeoutMs) ?? 3e5;
|
|
1608
|
+
this.httpRequestor = (options == null ? void 0 : options.httpRequestor) ?? fetch.bind(globalThis);
|
|
1609
|
+
this.httpClient = new HttpClient(this.httpRequestor);
|
|
1610
|
+
this.bundler = new Bundler(
|
|
1611
|
+
this.bundlerBaseUrl,
|
|
1612
|
+
this.bundlingAPIBasePath,
|
|
1613
|
+
this.transactionWaitTimeoutMs,
|
|
1614
|
+
this.signer,
|
|
1615
|
+
this.httpClient
|
|
1616
|
+
);
|
|
1617
|
+
this.pools = new Pools(this.gatewayBaseUrl, this.dexContractBasePath, this.httpClient);
|
|
1618
|
+
this.quoting = new Quoting(this.gatewayBaseUrl, this.dexContractBasePath, this.httpClient);
|
|
1619
|
+
this.positions = new Positions(
|
|
1620
|
+
this.gatewayBaseUrl,
|
|
1621
|
+
this.dexContractBasePath,
|
|
1622
|
+
this.bundler,
|
|
1623
|
+
this.pools,
|
|
1624
|
+
this.httpClient,
|
|
1625
|
+
{ walletAddress: options == null ? void 0 : options.walletAddress }
|
|
1626
|
+
);
|
|
1627
|
+
this.swaps = new Swaps(this.bundler, { walletAddress: options == null ? void 0 : options.walletAddress });
|
|
1628
|
+
this.assets = new Assets(this.dexBackendBaseUrl, this.httpClient);
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
// src/classes/signers.ts
|
|
1633
|
+
import { signatures } from "@gala-chain/api";
|
|
1634
|
+
import { calculatePersonalSignPrefix } from "@gala-chain/connect";
|
|
1635
|
+
var PrivateKeySigner = class {
|
|
1636
|
+
keyBuffer;
|
|
1637
|
+
constructor(privateKey) {
|
|
1638
|
+
this.keyBuffer = signatures.normalizePrivateKey(privateKey);
|
|
1639
|
+
}
|
|
1640
|
+
async signObject(_methodName, obj) {
|
|
1641
|
+
const signature = signatures.getSignature(obj, this.keyBuffer);
|
|
1642
|
+
return { ...obj, signature };
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
var GalaWalletSigner = class _GalaWalletSigner {
|
|
1646
|
+
constructor(walletAddress) {
|
|
1647
|
+
this.walletAddress = walletAddress;
|
|
1648
|
+
}
|
|
1649
|
+
async signObject(methodName, obj) {
|
|
1650
|
+
const globalGala = global.gala;
|
|
1651
|
+
if (!globalGala) {
|
|
1652
|
+
throw new GSwapSDKError(
|
|
1653
|
+
"Gala wallet is not available. Please ensure the Gala wallet is connected.",
|
|
1654
|
+
"GALA_WALLET_NOT_AVAILABLE"
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1657
|
+
const domain = { name: "ethereum", chainId: 1 };
|
|
1658
|
+
const types = _GalaWalletSigner.generateEIP712Types(methodName, obj);
|
|
1659
|
+
const signRequest = {
|
|
1660
|
+
domain,
|
|
1661
|
+
types,
|
|
1662
|
+
Primary_type: methodName,
|
|
1663
|
+
message: {
|
|
1664
|
+
...obj,
|
|
1665
|
+
prefix: calculatePersonalSignPrefix(obj)
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
await globalGala.setAddress(this.walletAddress);
|
|
1669
|
+
const signature = await globalGala.request({
|
|
1670
|
+
method: "eth_signTypedData",
|
|
1671
|
+
params: [JSON.stringify(signRequest), this.walletAddress]
|
|
1672
|
+
});
|
|
1673
|
+
return { ...obj, domain, types, signature };
|
|
1674
|
+
}
|
|
1675
|
+
static generateEIP712Types(typeName, params) {
|
|
1676
|
+
const types = {};
|
|
1677
|
+
types[typeName] = [];
|
|
1678
|
+
function addField(name, fieldValue, parentTypeName, onlyGetType = false) {
|
|
1679
|
+
if (fieldValue === void 0) {
|
|
1680
|
+
} else if (Array.isArray(fieldValue)) {
|
|
1681
|
+
const type = addField(name, fieldValue[0], parentTypeName, true);
|
|
1682
|
+
if (!onlyGetType) types[parentTypeName].push({ name, type: (type ?? name) + "[]" });
|
|
1683
|
+
} else if (typeof fieldValue === "object" && fieldValue !== null) {
|
|
1684
|
+
if (types[name]) {
|
|
1685
|
+
throw new GSwapSDKError(
|
|
1686
|
+
"Name collisions not yet supported in EIP712 type generation",
|
|
1687
|
+
"EIP712_NAME_COLLISION",
|
|
1688
|
+
{ name }
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
types[name] = [];
|
|
1692
|
+
Object.entries(fieldValue).forEach(([key, value]) => {
|
|
1693
|
+
addField(key, value, name);
|
|
1694
|
+
});
|
|
1695
|
+
if (!onlyGetType) types[parentTypeName].push({ name, type: name });
|
|
1696
|
+
} else {
|
|
1697
|
+
let eipType;
|
|
1698
|
+
switch (typeof fieldValue) {
|
|
1699
|
+
case "string":
|
|
1700
|
+
eipType = "string";
|
|
1701
|
+
break;
|
|
1702
|
+
case "number":
|
|
1703
|
+
eipType = "int256";
|
|
1704
|
+
break;
|
|
1705
|
+
case "boolean":
|
|
1706
|
+
eipType = "bool";
|
|
1707
|
+
break;
|
|
1708
|
+
default:
|
|
1709
|
+
throw new GSwapSDKError(
|
|
1710
|
+
`Unsupported type for EIP712 signing: ${typeof fieldValue}`,
|
|
1711
|
+
"EIP712_UNSUPPORTED_TYPE",
|
|
1712
|
+
{ type: typeof fieldValue, value: fieldValue }
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
if (onlyGetType) {
|
|
1716
|
+
return eipType;
|
|
1717
|
+
} else {
|
|
1718
|
+
types[parentTypeName].push({ name, type: eipType });
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1723
|
+
addField(key, value, typeName);
|
|
1724
|
+
});
|
|
1725
|
+
return types;
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
export {
|
|
1729
|
+
Assets,
|
|
1730
|
+
Bundler,
|
|
1731
|
+
EventSocketClient,
|
|
1732
|
+
Events,
|
|
1733
|
+
FEE_TIER,
|
|
1734
|
+
GSwap,
|
|
1735
|
+
GSwapSDKError,
|
|
1736
|
+
GalaWalletSigner,
|
|
1737
|
+
PendingTransaction,
|
|
1738
|
+
Pools,
|
|
1739
|
+
Positions,
|
|
1740
|
+
PrivateKeySigner,
|
|
1741
|
+
Quoting,
|
|
1742
|
+
Swaps,
|
|
1743
|
+
TradeEventEmitter,
|
|
1744
|
+
compareTokens,
|
|
1745
|
+
validateFee,
|
|
1746
|
+
validateNumericAmount,
|
|
1747
|
+
validatePriceValues,
|
|
1748
|
+
validateTickRange,
|
|
1749
|
+
validateTickSpacing,
|
|
1750
|
+
validateTokenDecimals,
|
|
1751
|
+
validateWalletAddress
|
|
1752
|
+
};
|
|
1753
|
+
//# sourceMappingURL=index.mjs.map
|