@cetusprotocol/aggregator-sdk 0.3.21 → 0.3.23
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/bun.lockb +0 -0
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +161 -47
- package/dist/index.mjs +161 -48
- package/dist/src/client.d.ts +7 -2
- package/dist/src/transaction/haedal_pmm.d.ts +2 -4
- package/package.json +1 -1
- package/src/api.ts +2 -2
- package/src/client.ts +230 -58
- package/src/transaction/haedal_pmm.ts +33 -24
- package/src/transaction/index.ts +9 -4
- package/src/transaction/swap.ts +2 -7
- package/tests/router.test.ts +25 -11
package/src/client.ts
CHANGED
|
@@ -43,7 +43,10 @@ import { Bluefin } from "./transaction/bluefin"
|
|
|
43
43
|
import { HaedalPmm } from "./transaction/haedal_pmm"
|
|
44
44
|
import { Alphafi } from "./transaction/alphafi"
|
|
45
45
|
import { CoinUtils } from "./types/CoinAssist"
|
|
46
|
-
|
|
46
|
+
import {
|
|
47
|
+
SuiPriceServiceConnection,
|
|
48
|
+
SuiPythClient,
|
|
49
|
+
} from "@pythnetwork/pyth-sui-js"
|
|
47
50
|
|
|
48
51
|
export const CETUS = "CETUS"
|
|
49
52
|
export const DEEPBOOKV2 = "DEEPBOOK"
|
|
@@ -116,6 +119,12 @@ export interface SwapInPoolsParams {
|
|
|
116
119
|
pools: string[]
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
interface PythConfig {
|
|
123
|
+
connections: SuiPriceServiceConnection[]
|
|
124
|
+
wormholeStateId: string
|
|
125
|
+
pythStateId: string
|
|
126
|
+
}
|
|
127
|
+
|
|
119
128
|
export interface SwapInPoolsResult {
|
|
120
129
|
isExceed: boolean
|
|
121
130
|
routeData?: RouterData
|
|
@@ -124,13 +133,13 @@ export interface SwapInPoolsResult {
|
|
|
124
133
|
function isBuilderRouterSwapParams(
|
|
125
134
|
params: BuildRouterSwapParams | BuildRouterSwapParamsV2
|
|
126
135
|
): params is BuildRouterSwapParams {
|
|
127
|
-
return Array.isArray((params as BuildRouterSwapParams).routers)
|
|
136
|
+
return Array.isArray((params as BuildRouterSwapParams).routers)
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
function isBuilderFastRouterSwapParams(
|
|
131
140
|
params: BuildFastRouterSwapParams | BuildFastRouterSwapParamsV2
|
|
132
141
|
): params is BuildFastRouterSwapParams {
|
|
133
|
-
return Array.isArray((params as BuildFastRouterSwapParams).routers)
|
|
142
|
+
return Array.isArray((params as BuildFastRouterSwapParams).routers)
|
|
134
143
|
}
|
|
135
144
|
|
|
136
145
|
export class AggregatorClient {
|
|
@@ -140,6 +149,38 @@ export class AggregatorClient {
|
|
|
140
149
|
public env: Env
|
|
141
150
|
private allCoins: Map<string, CoinAsset[]>
|
|
142
151
|
|
|
152
|
+
private pythConnections: SuiPriceServiceConnection[]
|
|
153
|
+
private pythClient: SuiPythClient
|
|
154
|
+
|
|
155
|
+
private static readonly CONFIG: Record<Env, PythConfig> = {
|
|
156
|
+
[Env.Testnet]: {
|
|
157
|
+
connections: [
|
|
158
|
+
new SuiPriceServiceConnection("https://hermes-beta.pyth.network"),
|
|
159
|
+
],
|
|
160
|
+
wormholeStateId:
|
|
161
|
+
"0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
|
|
162
|
+
pythStateId:
|
|
163
|
+
"0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
|
|
164
|
+
},
|
|
165
|
+
[Env.Mainnet]: {
|
|
166
|
+
connections: [
|
|
167
|
+
new SuiPriceServiceConnection(
|
|
168
|
+
"https://cetus.liquify.com/api=X9LTVPQD7Y3R5N2A/hermes",
|
|
169
|
+
{
|
|
170
|
+
timeout: 3000,
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
new SuiPriceServiceConnection("https://hermes.pyth.network", {
|
|
174
|
+
timeout: 3000,
|
|
175
|
+
}),
|
|
176
|
+
],
|
|
177
|
+
wormholeStateId:
|
|
178
|
+
"0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
|
|
179
|
+
pythStateId:
|
|
180
|
+
"0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
|
|
143
184
|
constructor(
|
|
144
185
|
endpoint?: string,
|
|
145
186
|
signer?: string,
|
|
@@ -151,6 +192,14 @@ export class AggregatorClient {
|
|
|
151
192
|
this.signer = signer || ""
|
|
152
193
|
this.env = env || Env.Mainnet
|
|
153
194
|
this.allCoins = new Map<string, CoinAsset[]>()
|
|
195
|
+
|
|
196
|
+
const config = AggregatorClient.CONFIG[this.env]
|
|
197
|
+
this.pythConnections = config.connections
|
|
198
|
+
this.pythClient = new SuiPythClient(
|
|
199
|
+
this.client,
|
|
200
|
+
config.pythStateId,
|
|
201
|
+
config.wormholeStateId
|
|
202
|
+
)
|
|
154
203
|
}
|
|
155
204
|
|
|
156
205
|
async getCoins(
|
|
@@ -205,6 +254,7 @@ export class AggregatorClient {
|
|
|
205
254
|
inputCoin: TransactionObjectArgument,
|
|
206
255
|
routers: Router[],
|
|
207
256
|
amountOutLimit: BN,
|
|
257
|
+
pythPriceIDs: Map<string, string>,
|
|
208
258
|
partner?: string,
|
|
209
259
|
deepbookv3DeepFee?: TransactionObjectArgument,
|
|
210
260
|
packages?: Map<string, string>
|
|
@@ -223,16 +273,31 @@ export class AggregatorClient {
|
|
|
223
273
|
}
|
|
224
274
|
let nextCoin = inputCoins[i] as TransactionObjectArgument
|
|
225
275
|
for (const path of routers[i].path) {
|
|
226
|
-
const dex = this.newDex(path.provider, partner)
|
|
227
|
-
nextCoin = await dex.swap(
|
|
276
|
+
const dex = this.newDex(path.provider, pythPriceIDs, partner)
|
|
277
|
+
nextCoin = await dex.swap(
|
|
278
|
+
this,
|
|
279
|
+
txb,
|
|
280
|
+
path,
|
|
281
|
+
nextCoin,
|
|
282
|
+
packages,
|
|
283
|
+
deepbookv3DeepFee
|
|
284
|
+
)
|
|
228
285
|
}
|
|
229
286
|
|
|
230
287
|
outputCoins.push(nextCoin)
|
|
231
288
|
}
|
|
232
289
|
|
|
233
|
-
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
290
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
291
|
+
this.publishedAtV2(),
|
|
292
|
+
packages
|
|
293
|
+
)
|
|
234
294
|
|
|
235
|
-
this.transferOrDestoryCoin(
|
|
295
|
+
this.transferOrDestoryCoin(
|
|
296
|
+
txb,
|
|
297
|
+
inputCoin,
|
|
298
|
+
inputCoinType,
|
|
299
|
+
this.publishedAtV2()
|
|
300
|
+
)
|
|
236
301
|
const mergedTargetCointhis = this.checkCoinThresholdAndMergeCoin(
|
|
237
302
|
txb,
|
|
238
303
|
outputCoins,
|
|
@@ -255,7 +320,10 @@ export class AggregatorClient {
|
|
|
255
320
|
const targetCoins = []
|
|
256
321
|
const dex = new Cetus(this.env, partner)
|
|
257
322
|
|
|
258
|
-
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
323
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
324
|
+
this.publishedAtV2(),
|
|
325
|
+
packages
|
|
326
|
+
)
|
|
259
327
|
|
|
260
328
|
for (let i = 0; i < routers.length; i++) {
|
|
261
329
|
const router = routers[i]
|
|
@@ -280,7 +348,12 @@ export class AggregatorClient {
|
|
|
280
348
|
if (j === 0) {
|
|
281
349
|
inputCoin = repayResult
|
|
282
350
|
} else {
|
|
283
|
-
this.transferOrDestoryCoin(
|
|
351
|
+
this.transferOrDestoryCoin(
|
|
352
|
+
txb,
|
|
353
|
+
repayResult,
|
|
354
|
+
path.from,
|
|
355
|
+
aggregatorV2PublishedAt
|
|
356
|
+
)
|
|
284
357
|
}
|
|
285
358
|
if (j === router.path.length - 1) {
|
|
286
359
|
targetCoins.push(nextRepayCoin)
|
|
@@ -288,7 +361,12 @@ export class AggregatorClient {
|
|
|
288
361
|
}
|
|
289
362
|
}
|
|
290
363
|
const inputCoinType = routers[0].path[0].from
|
|
291
|
-
this.transferOrDestoryCoin(
|
|
364
|
+
this.transferOrDestoryCoin(
|
|
365
|
+
txb,
|
|
366
|
+
inputCoin,
|
|
367
|
+
inputCoinType,
|
|
368
|
+
aggregatorV2PublishedAt
|
|
369
|
+
)
|
|
292
370
|
if (targetCoins.length > 1) {
|
|
293
371
|
const vec = txb.makeMoveVec({ elements: targetCoins.slice(1) })
|
|
294
372
|
txb.moveCall({
|
|
@@ -317,19 +395,13 @@ export class AggregatorClient {
|
|
|
317
395
|
async routerSwap(
|
|
318
396
|
params: BuildRouterSwapParams | BuildRouterSwapParamsV2
|
|
319
397
|
): Promise<TransactionObjectArgument> {
|
|
320
|
-
const {
|
|
321
|
-
|
|
322
|
-
inputCoin,
|
|
323
|
-
slippage,
|
|
324
|
-
txb,
|
|
325
|
-
partner,
|
|
326
|
-
deepbookv3DeepFee,
|
|
327
|
-
} = params
|
|
398
|
+
const { routers, inputCoin, slippage, txb, partner, deepbookv3DeepFee } =
|
|
399
|
+
params
|
|
328
400
|
|
|
329
401
|
const routerData = Array.isArray(routers) ? routers : routers.routes
|
|
330
|
-
const byAmountIn = isBuilderRouterSwapParams(params)
|
|
331
|
-
|
|
332
|
-
|
|
402
|
+
const byAmountIn = isBuilderRouterSwapParams(params)
|
|
403
|
+
? params.byAmountIn
|
|
404
|
+
: params.routers.byAmountIn
|
|
333
405
|
|
|
334
406
|
const amountIn = routerData.reduce(
|
|
335
407
|
(acc, router) => acc.add(router.amountIn),
|
|
@@ -346,11 +418,21 @@ export class AggregatorClient {
|
|
|
346
418
|
slippage
|
|
347
419
|
)
|
|
348
420
|
|
|
349
|
-
const packages = isBuilderRouterSwapParams(params)
|
|
421
|
+
const packages = isBuilderRouterSwapParams(params)
|
|
422
|
+
? undefined
|
|
423
|
+
: params.routers.packages
|
|
350
424
|
|
|
351
|
-
|
|
425
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
426
|
+
this.publishedAtV2(),
|
|
427
|
+
packages
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
const priceIDs = findPythPriceIDs(routerData)
|
|
352
431
|
|
|
353
|
-
const
|
|
432
|
+
const priceInfoObjectIds =
|
|
433
|
+
priceIDs.length > 0
|
|
434
|
+
? await this.updatePythPriceIDs(priceIDs, txb)
|
|
435
|
+
: new Map<string, string>()
|
|
354
436
|
|
|
355
437
|
if (byAmountIn) {
|
|
356
438
|
const targetCoin = await this.expectInputSwap(
|
|
@@ -358,9 +440,10 @@ export class AggregatorClient {
|
|
|
358
440
|
inputCoin,
|
|
359
441
|
routerData,
|
|
360
442
|
amountLimit,
|
|
443
|
+
priceInfoObjectIds,
|
|
361
444
|
partner,
|
|
362
445
|
deepbookv3DeepFee,
|
|
363
|
-
packages
|
|
446
|
+
packages
|
|
364
447
|
)
|
|
365
448
|
return targetCoin
|
|
366
449
|
}
|
|
@@ -369,7 +452,12 @@ export class AggregatorClient {
|
|
|
369
452
|
const splitedInputCoins = txb.splitCoins(inputCoin, [
|
|
370
453
|
amountLimit.toString(),
|
|
371
454
|
])
|
|
372
|
-
this.transferOrDestoryCoin(
|
|
455
|
+
this.transferOrDestoryCoin(
|
|
456
|
+
txb,
|
|
457
|
+
inputCoin,
|
|
458
|
+
routerData[0].path[0].from,
|
|
459
|
+
aggregatorV2PublishedAt
|
|
460
|
+
)
|
|
373
461
|
const targetCoin = await this.expectOutputSwap(
|
|
374
462
|
txb,
|
|
375
463
|
splitedInputCoins[0],
|
|
@@ -381,7 +469,9 @@ export class AggregatorClient {
|
|
|
381
469
|
|
|
382
470
|
// auto build input coin
|
|
383
471
|
// auto merge, transfer or destory target coin.
|
|
384
|
-
async fastRouterSwap(
|
|
472
|
+
async fastRouterSwap(
|
|
473
|
+
params: BuildFastRouterSwapParams | BuildFastRouterSwapParamsV2
|
|
474
|
+
) {
|
|
385
475
|
const {
|
|
386
476
|
routers,
|
|
387
477
|
slippage,
|
|
@@ -395,7 +485,8 @@ export class AggregatorClient {
|
|
|
395
485
|
const fromCoinType = routerData[0].path[0].from
|
|
396
486
|
let fromCoins = await this.getCoins(fromCoinType, refreshAllCoins)
|
|
397
487
|
|
|
398
|
-
const targetCoinType =
|
|
488
|
+
const targetCoinType =
|
|
489
|
+
routerData[0].path[routerData[0].path.length - 1].target
|
|
399
490
|
const amountIn = routerData.reduce(
|
|
400
491
|
(acc, router) => acc.add(router.amountIn),
|
|
401
492
|
new BN(0)
|
|
@@ -405,7 +496,9 @@ export class AggregatorClient {
|
|
|
405
496
|
new BN(0)
|
|
406
497
|
)
|
|
407
498
|
|
|
408
|
-
const byAmountIn = isBuilderFastRouterSwapParams(params)
|
|
499
|
+
const byAmountIn = isBuilderFastRouterSwapParams(params)
|
|
500
|
+
? params.byAmountIn
|
|
501
|
+
: params.routers.byAmountIn
|
|
409
502
|
const amountLimit = CalculateAmountLimit(
|
|
410
503
|
byAmountIn ? amountOut : amountIn,
|
|
411
504
|
byAmountIn,
|
|
@@ -430,23 +523,25 @@ export class AggregatorClient {
|
|
|
430
523
|
).targetCoin
|
|
431
524
|
}
|
|
432
525
|
|
|
433
|
-
const routerSwapParams = isBuilderFastRouterSwapParams(params)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
526
|
+
const routerSwapParams = isBuilderFastRouterSwapParams(params)
|
|
527
|
+
? {
|
|
528
|
+
routers: routerData,
|
|
529
|
+
inputCoin: buildFromCoinRes.targetCoin,
|
|
530
|
+
slippage,
|
|
531
|
+
byAmountIn,
|
|
532
|
+
txb,
|
|
533
|
+
partner,
|
|
534
|
+
deepbookv3DeepFee: deepCoin,
|
|
535
|
+
}
|
|
536
|
+
: {
|
|
537
|
+
routers: params.routers,
|
|
538
|
+
inputCoin: buildFromCoinRes.targetCoin,
|
|
539
|
+
slippage,
|
|
540
|
+
byAmountIn,
|
|
541
|
+
txb,
|
|
542
|
+
partner,
|
|
543
|
+
deepbookv3DeepFee: deepCoin,
|
|
544
|
+
}
|
|
450
545
|
|
|
451
546
|
const targetCoin = await this.routerSwap(routerSwapParams)
|
|
452
547
|
|
|
@@ -460,10 +555,15 @@ export class AggregatorClient {
|
|
|
460
555
|
BigInt(0),
|
|
461
556
|
targetCoinType
|
|
462
557
|
)
|
|
463
|
-
|
|
464
|
-
const packages = isBuilderFastRouterSwapParams(params)
|
|
465
|
-
|
|
466
|
-
|
|
558
|
+
|
|
559
|
+
const packages = isBuilderFastRouterSwapParams(params)
|
|
560
|
+
? undefined
|
|
561
|
+
: params.routers.packages
|
|
562
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
563
|
+
this.publishedAtV2(),
|
|
564
|
+
packages
|
|
565
|
+
)
|
|
566
|
+
|
|
467
567
|
txb.mergeCoins(targetCoinRes.targetCoin, [targetCoin])
|
|
468
568
|
if (targetCoinRes.isMintZeroCoin) {
|
|
469
569
|
this.transferOrDestoryCoin(
|
|
@@ -481,7 +581,8 @@ export class AggregatorClient {
|
|
|
481
581
|
if (this.env === Env.Mainnet) {
|
|
482
582
|
// return "0x3fb42ddf908af45f9fc3c59eab227888ff24ba2e137b3b55bf80920fd47e11af" // version 6
|
|
483
583
|
// return "0x4069913c4953297b7f08f67f6722e3b04aa5ab2976b4e1b8a456b81590b34ab4"
|
|
484
|
-
return "0xf9c6f78322ed667909e05f6b42b2f5a67af6297503c905335e02a15148e9440d"
|
|
584
|
+
// return "0xf9c6f78322ed667909e05f6b42b2f5a67af6297503c905335e02a15148e9440d"
|
|
585
|
+
return "0x2485feb9d42c7c3bcb8ecde555ad40f1b073d9fb4faf354fa2d30a0b183a23ce"
|
|
485
586
|
// return "0x803db8dfcc86fc1afbc7d2212bd14ec9690978ddebea0d590e01147d6b17aa06" // pre
|
|
486
587
|
} else {
|
|
487
588
|
// return "0x0ed287d6c3fe4962d0994ffddc1d19a15fba6a81533f3f0dcc2bbcedebce0637" // version 2
|
|
@@ -498,7 +599,7 @@ export class AggregatorClient {
|
|
|
498
599
|
// return "0x3b6d71bdeb8ce5b06febfd3cfc29ecd60d50da729477c8b8038ecdae34541b91" // version 5, add bluefin
|
|
499
600
|
// return "0x81ade554cb24a7564ca43a4bfb7381b08d9e5c5f375162c95215b696ab903502" // version 6, force upgrade scallop
|
|
500
601
|
// return "0x347dd58bbd11cd82c8b386b344729717c04a998da73386e82a239cc196d5706b" // version 7
|
|
501
|
-
return "0xf2fcea41dc217385019828375764fa06d9bd25e8e4726ba1962680849fb8d613"
|
|
602
|
+
return "0xf2fcea41dc217385019828375764fa06d9bd25e8e4726ba1962680849fb8d613" // version 8
|
|
502
603
|
} else {
|
|
503
604
|
return "0xabb6a81c8a216828e317719e06125de5bb2cb0fe8f9916ff8c023ca5be224c78"
|
|
504
605
|
}
|
|
@@ -551,7 +652,11 @@ export class AggregatorClient {
|
|
|
551
652
|
return targetCoin
|
|
552
653
|
}
|
|
553
654
|
|
|
554
|
-
newDex(
|
|
655
|
+
newDex(
|
|
656
|
+
provider: string,
|
|
657
|
+
pythPriceIDs: Map<string, string>,
|
|
658
|
+
partner?: string
|
|
659
|
+
): Dex {
|
|
555
660
|
switch (provider) {
|
|
556
661
|
case CETUS:
|
|
557
662
|
return new Cetus(this.env, partner)
|
|
@@ -588,7 +693,7 @@ export class AggregatorClient {
|
|
|
588
693
|
case BLUEFIN:
|
|
589
694
|
return new Bluefin(this.env)
|
|
590
695
|
case HAEDALPMM:
|
|
591
|
-
return new HaedalPmm(this.env,
|
|
696
|
+
return new HaedalPmm(this.env, pythPriceIDs)
|
|
592
697
|
case ALPHAFI:
|
|
593
698
|
return new Alphafi(this.env)
|
|
594
699
|
default:
|
|
@@ -634,9 +739,74 @@ export class AggregatorClient {
|
|
|
634
739
|
}
|
|
635
740
|
return null
|
|
636
741
|
}
|
|
742
|
+
|
|
743
|
+
async updatePythPriceIDs(
|
|
744
|
+
priceIDs: string[],
|
|
745
|
+
txb: Transaction
|
|
746
|
+
): Promise<Map<string, string>> {
|
|
747
|
+
let priceUpdateData: Buffer[] | null = null
|
|
748
|
+
let lastError: Error | null = null
|
|
749
|
+
|
|
750
|
+
for (const connection of this.pythConnections) {
|
|
751
|
+
try {
|
|
752
|
+
priceUpdateData = await connection.getPriceFeedsUpdateData(priceIDs)
|
|
753
|
+
break
|
|
754
|
+
} catch (e) {
|
|
755
|
+
lastError = e as Error
|
|
756
|
+
console.log("Error: ", e)
|
|
757
|
+
continue
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (priceUpdateData == null) {
|
|
762
|
+
throw new Error(
|
|
763
|
+
`No pyth price seeds update data found: ${lastError?.message}`
|
|
764
|
+
)
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
let priceInfoObjectIds = []
|
|
768
|
+
try {
|
|
769
|
+
priceInfoObjectIds = await this.pythClient.updatePriceFeeds(
|
|
770
|
+
txb,
|
|
771
|
+
priceUpdateData,
|
|
772
|
+
priceIDs
|
|
773
|
+
)
|
|
774
|
+
} catch (e) {
|
|
775
|
+
throw new Error(`Failed to update price feeds: ${e}`)
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
let priceInfoObjectIdsMap = new Map<string, string>()
|
|
779
|
+
for (let i = 0; i < priceIDs.length; i++) {
|
|
780
|
+
priceInfoObjectIdsMap.set(priceIDs[i], priceInfoObjectIds[i])
|
|
781
|
+
}
|
|
782
|
+
return priceInfoObjectIdsMap
|
|
783
|
+
}
|
|
637
784
|
}
|
|
638
785
|
|
|
639
|
-
export function
|
|
786
|
+
export function findPythPriceIDs(routes: Router[]): string[] {
|
|
787
|
+
const priceIDs = new Set<string>()
|
|
788
|
+
|
|
789
|
+
for (const route of routes) {
|
|
790
|
+
for (const path of route.path) {
|
|
791
|
+
if (path.provider === HAEDALPMM) {
|
|
792
|
+
if (
|
|
793
|
+
path.extendedDetails &&
|
|
794
|
+
path.extendedDetails.haedalPmmBasePriceSeed &&
|
|
795
|
+
path.extendedDetails.haedalPmmQuotePriceSeed
|
|
796
|
+
) {
|
|
797
|
+
priceIDs.add(path.extendedDetails.haedalPmmBasePriceSeed)
|
|
798
|
+
priceIDs.add(path.extendedDetails.haedalPmmQuotePriceSeed)
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return Array.from(priceIDs)
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
export function parseRouterResponse(
|
|
807
|
+
data: any,
|
|
808
|
+
byAmountIn: boolean
|
|
809
|
+
): RouterData {
|
|
640
810
|
let totalDeepFee = 0
|
|
641
811
|
for (const route of data.routes) {
|
|
642
812
|
for (const path of route.path) {
|
|
@@ -674,7 +844,7 @@ export function parseRouterResponse(data: any, byAmountIn: boolean): RouterData
|
|
|
674
844
|
path.provider === AFTERMATH ||
|
|
675
845
|
path.provider === CETUS ||
|
|
676
846
|
path.provider === DEEPBOOKV3 ||
|
|
677
|
-
path.provider === SCALLOP ||
|
|
847
|
+
path.provider === SCALLOP ||
|
|
678
848
|
path.provider === HAEDALPMM
|
|
679
849
|
) {
|
|
680
850
|
extendedDetails = {
|
|
@@ -685,8 +855,10 @@ export function parseRouterResponse(data: any, byAmountIn: boolean): RouterData
|
|
|
685
855
|
deepbookv3DeepFee: path.extended_details?.deepbookv3_deep_fee,
|
|
686
856
|
scallopScoinTreasury:
|
|
687
857
|
path.extended_details?.scallop_scoin_treasury,
|
|
688
|
-
haedalPmmBasePriceSeed:
|
|
689
|
-
|
|
858
|
+
haedalPmmBasePriceSeed:
|
|
859
|
+
path.extended_details?.haedal_pmm_base_price_seed,
|
|
860
|
+
haedalPmmQuotePriceSeed:
|
|
861
|
+
path.extended_details?.haedal_pmm_quote_price_seed,
|
|
690
862
|
}
|
|
691
863
|
}
|
|
692
864
|
|
|
@@ -3,26 +3,23 @@ import {
|
|
|
3
3
|
TransactionArgument,
|
|
4
4
|
TransactionObjectArgument,
|
|
5
5
|
} from "@mysten/sui/transactions"
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import {
|
|
7
|
+
AggregatorClient,
|
|
8
|
+
CLOCK_ADDRESS,
|
|
9
|
+
Dex,
|
|
10
|
+
Env,
|
|
11
|
+
getAggregatorV2ExtendPublishedAt,
|
|
12
|
+
Path,
|
|
13
|
+
} from ".."
|
|
9
14
|
|
|
10
15
|
export class HaedalPmm implements Dex {
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(env: Env, suiClient: SuiClient) {
|
|
16
|
+
private pythPriceIDs: Map<string, string>
|
|
17
|
+
|
|
18
|
+
constructor(env: Env, pythPriceIDs: Map<string, string>) {
|
|
15
19
|
if (env === Env.Testnet) {
|
|
16
|
-
|
|
17
|
-
const wormholeStateId = "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790";
|
|
18
|
-
const pythStateId = "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c";
|
|
19
|
-
this.pythClient = new SuiPythClient(suiClient, pythStateId, wormholeStateId)
|
|
20
|
-
} else {
|
|
21
|
-
this.connection = new SuiPriceServiceConnection("https://hermes.pyth.network")
|
|
22
|
-
const wormholeStateId = "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c";
|
|
23
|
-
const pythStateId = "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8";
|
|
24
|
-
this.pythClient = new SuiPythClient(suiClient, pythStateId, wormholeStateId)
|
|
20
|
+
throw new Error("HaedalPmm is not supported on testnet")
|
|
25
21
|
}
|
|
22
|
+
this.pythPriceIDs = pythPriceIDs
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
async swap(
|
|
@@ -36,31 +33,43 @@ export class HaedalPmm implements Dex {
|
|
|
36
33
|
const [func, coinAType, coinBType] = direction
|
|
37
34
|
? ["swap_a2b", from, target]
|
|
38
35
|
: ["swap_b2a", target, from]
|
|
39
|
-
|
|
36
|
+
|
|
40
37
|
let basePriceSeed: string
|
|
41
38
|
let quotePriceSeed: string
|
|
42
39
|
|
|
43
40
|
if (path.extendedDetails == null) {
|
|
44
41
|
throw new Error("Extended details not supported haedal pmm")
|
|
45
42
|
} else {
|
|
46
|
-
if (
|
|
43
|
+
if (
|
|
44
|
+
!path.extendedDetails.haedalPmmBasePriceSeed ||
|
|
45
|
+
!path.extendedDetails.haedalPmmQuotePriceSeed
|
|
46
|
+
) {
|
|
47
47
|
throw new Error("Base price seed or quote price seed not supported")
|
|
48
48
|
}
|
|
49
49
|
basePriceSeed = path.extendedDetails.haedalPmmBasePriceSeed
|
|
50
50
|
quotePriceSeed = path.extendedDetails.haedalPmmQuotePriceSeed
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
53
|
+
const basePriceInfoObjectId = this.pythPriceIDs.get(basePriceSeed)
|
|
54
|
+
const quotePriceInfoObjectId = this.pythPriceIDs.get(quotePriceSeed)
|
|
55
|
+
|
|
56
|
+
if (!basePriceInfoObjectId || !quotePriceInfoObjectId) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Base price info object id or quote price info object id not found"
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
const args = [
|
|
57
63
|
txb.object(path.id),
|
|
58
|
-
txb.object(
|
|
59
|
-
txb.object(
|
|
64
|
+
txb.object(basePriceInfoObjectId),
|
|
65
|
+
txb.object(quotePriceInfoObjectId),
|
|
60
66
|
inputCoin,
|
|
61
67
|
txb.object(CLOCK_ADDRESS),
|
|
62
68
|
]
|
|
63
|
-
const publishedAt = getAggregatorV2ExtendPublishedAt(
|
|
69
|
+
const publishedAt = getAggregatorV2ExtendPublishedAt(
|
|
70
|
+
client.publishedAtV2Extend(),
|
|
71
|
+
packages
|
|
72
|
+
)
|
|
64
73
|
const res = txb.moveCall({
|
|
65
74
|
target: `${publishedAt}::haedalpmm::${func}`,
|
|
66
75
|
typeArguments: [coinAType, coinBType],
|
package/src/transaction/index.ts
CHANGED
|
@@ -10,14 +10,20 @@ export const CLOCK_ADDRESS =
|
|
|
10
10
|
export const AGGREGATOR_V2 = "aggregator_v2"
|
|
11
11
|
export const AGGREGATOR_V2_EXTEND = "aggregator_v2_extend"
|
|
12
12
|
|
|
13
|
-
export function getAggregatorV2PublishedAt(
|
|
13
|
+
export function getAggregatorV2PublishedAt(
|
|
14
|
+
aggregatorV2PublishedAt: string,
|
|
15
|
+
packages?: Map<string, string> | Record<string, string>
|
|
16
|
+
) {
|
|
14
17
|
if (packages instanceof Map) {
|
|
15
18
|
return packages.get(AGGREGATOR_V2) ?? aggregatorV2PublishedAt
|
|
16
19
|
}
|
|
17
20
|
return aggregatorV2PublishedAt
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
export function getAggregatorV2ExtendPublishedAt(
|
|
23
|
+
export function getAggregatorV2ExtendPublishedAt(
|
|
24
|
+
aggregatorV2ExtendPublishedAt: string,
|
|
25
|
+
packages?: Map<string, string> | Record<string, string>
|
|
26
|
+
) {
|
|
21
27
|
if (packages instanceof Map) {
|
|
22
28
|
return packages.get(AGGREGATOR_V2_EXTEND) ?? aggregatorV2ExtendPublishedAt
|
|
23
29
|
}
|
|
@@ -31,7 +37,6 @@ export interface Dex {
|
|
|
31
37
|
path: Path,
|
|
32
38
|
inputCoin: TransactionObjectArgument,
|
|
33
39
|
packages?: Map<string, string>,
|
|
34
|
-
deepbookv3DeepFee?: TransactionObjectArgument
|
|
40
|
+
deepbookv3DeepFee?: TransactionObjectArgument
|
|
35
41
|
): Promise<TransactionObjectArgument>
|
|
36
42
|
}
|
|
37
|
-
|
package/src/transaction/swap.ts
CHANGED
|
@@ -21,13 +21,12 @@ export async function swapInPools(
|
|
|
21
21
|
const tx = new Transaction()
|
|
22
22
|
const direction = compareCoins(fromCoin, targetCoin)
|
|
23
23
|
const integratePublishedAt = env === Env.Mainnet ?
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"0x2d8c2e0fc6dd25b0214b3fa747e0fd27fd54608142cd2e4f64c1cd350cc4add4" :
|
|
25
|
+
"0x4f920e1ef6318cfba77e20a0538a419a5a504c14230169438b99aba485db40a6"
|
|
26
26
|
const coinA = direction ? fromCoin : targetCoin
|
|
27
27
|
const coinB = direction ? targetCoin : fromCoin
|
|
28
28
|
|
|
29
29
|
const typeArguments = [coinA, coinB]
|
|
30
|
-
console.log("typeArguments", typeArguments, integratePublishedAt)
|
|
31
30
|
|
|
32
31
|
for (let i = 0; i < pools.length; i++) {
|
|
33
32
|
const args = [
|
|
@@ -50,8 +49,6 @@ export async function swapInPools(
|
|
|
50
49
|
)
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
printTransaction(tx)
|
|
54
|
-
|
|
55
52
|
const simulateRes = await client.devInspectTransactionBlock({
|
|
56
53
|
transactionBlock: tx,
|
|
57
54
|
sender,
|
|
@@ -99,8 +96,6 @@ export async function swapInPools(
|
|
|
99
96
|
|
|
100
97
|
const event = valueData[tempIndex].parsedJson.data
|
|
101
98
|
|
|
102
|
-
console.log("event", JSON.stringify(event, null, 2))
|
|
103
|
-
|
|
104
99
|
const currentSqrtPrice = event.step_results[0].current_sqrt_price
|
|
105
100
|
|
|
106
101
|
const [decimalA, decimalB] = await Promise.all([
|