@cetusprotocol/aggregator-sdk 0.3.21 → 0.3.22
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 +159 -41
- package/dist/index.mjs +159 -42
- 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 +229 -56
- package/src/transaction/haedal_pmm.ts +33 -24
- package/src/transaction/index.ts +9 -4
- 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,23 @@ 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
|
console.log("packages11", packages)
|
|
352
426
|
|
|
353
|
-
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
427
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
428
|
+
this.publishedAtV2(),
|
|
429
|
+
packages
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
const priceIDs = findPythPriceIDs(routerData)
|
|
433
|
+
|
|
434
|
+
const priceInfoObjectIds =
|
|
435
|
+
priceIDs.length > 0
|
|
436
|
+
? await this.updatePythPriceIDs(priceIDs, txb)
|
|
437
|
+
: new Map<string, string>()
|
|
354
438
|
|
|
355
439
|
if (byAmountIn) {
|
|
356
440
|
const targetCoin = await this.expectInputSwap(
|
|
@@ -358,9 +442,10 @@ export class AggregatorClient {
|
|
|
358
442
|
inputCoin,
|
|
359
443
|
routerData,
|
|
360
444
|
amountLimit,
|
|
445
|
+
priceInfoObjectIds,
|
|
361
446
|
partner,
|
|
362
447
|
deepbookv3DeepFee,
|
|
363
|
-
packages
|
|
448
|
+
packages
|
|
364
449
|
)
|
|
365
450
|
return targetCoin
|
|
366
451
|
}
|
|
@@ -369,7 +454,12 @@ export class AggregatorClient {
|
|
|
369
454
|
const splitedInputCoins = txb.splitCoins(inputCoin, [
|
|
370
455
|
amountLimit.toString(),
|
|
371
456
|
])
|
|
372
|
-
this.transferOrDestoryCoin(
|
|
457
|
+
this.transferOrDestoryCoin(
|
|
458
|
+
txb,
|
|
459
|
+
inputCoin,
|
|
460
|
+
routerData[0].path[0].from,
|
|
461
|
+
aggregatorV2PublishedAt
|
|
462
|
+
)
|
|
373
463
|
const targetCoin = await this.expectOutputSwap(
|
|
374
464
|
txb,
|
|
375
465
|
splitedInputCoins[0],
|
|
@@ -381,7 +471,9 @@ export class AggregatorClient {
|
|
|
381
471
|
|
|
382
472
|
// auto build input coin
|
|
383
473
|
// auto merge, transfer or destory target coin.
|
|
384
|
-
async fastRouterSwap(
|
|
474
|
+
async fastRouterSwap(
|
|
475
|
+
params: BuildFastRouterSwapParams | BuildFastRouterSwapParamsV2
|
|
476
|
+
) {
|
|
385
477
|
const {
|
|
386
478
|
routers,
|
|
387
479
|
slippage,
|
|
@@ -395,7 +487,8 @@ export class AggregatorClient {
|
|
|
395
487
|
const fromCoinType = routerData[0].path[0].from
|
|
396
488
|
let fromCoins = await this.getCoins(fromCoinType, refreshAllCoins)
|
|
397
489
|
|
|
398
|
-
const targetCoinType =
|
|
490
|
+
const targetCoinType =
|
|
491
|
+
routerData[0].path[routerData[0].path.length - 1].target
|
|
399
492
|
const amountIn = routerData.reduce(
|
|
400
493
|
(acc, router) => acc.add(router.amountIn),
|
|
401
494
|
new BN(0)
|
|
@@ -405,7 +498,9 @@ export class AggregatorClient {
|
|
|
405
498
|
new BN(0)
|
|
406
499
|
)
|
|
407
500
|
|
|
408
|
-
const byAmountIn = isBuilderFastRouterSwapParams(params)
|
|
501
|
+
const byAmountIn = isBuilderFastRouterSwapParams(params)
|
|
502
|
+
? params.byAmountIn
|
|
503
|
+
: params.routers.byAmountIn
|
|
409
504
|
const amountLimit = CalculateAmountLimit(
|
|
410
505
|
byAmountIn ? amountOut : amountIn,
|
|
411
506
|
byAmountIn,
|
|
@@ -430,23 +525,25 @@ export class AggregatorClient {
|
|
|
430
525
|
).targetCoin
|
|
431
526
|
}
|
|
432
527
|
|
|
433
|
-
const routerSwapParams = isBuilderFastRouterSwapParams(params)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
528
|
+
const routerSwapParams = isBuilderFastRouterSwapParams(params)
|
|
529
|
+
? {
|
|
530
|
+
routers: routerData,
|
|
531
|
+
inputCoin: buildFromCoinRes.targetCoin,
|
|
532
|
+
slippage,
|
|
533
|
+
byAmountIn,
|
|
534
|
+
txb,
|
|
535
|
+
partner,
|
|
536
|
+
deepbookv3DeepFee: deepCoin,
|
|
537
|
+
}
|
|
538
|
+
: {
|
|
539
|
+
routers: params.routers,
|
|
540
|
+
inputCoin: buildFromCoinRes.targetCoin,
|
|
541
|
+
slippage,
|
|
542
|
+
byAmountIn,
|
|
543
|
+
txb,
|
|
544
|
+
partner,
|
|
545
|
+
deepbookv3DeepFee: deepCoin,
|
|
546
|
+
}
|
|
450
547
|
|
|
451
548
|
const targetCoin = await this.routerSwap(routerSwapParams)
|
|
452
549
|
|
|
@@ -460,10 +557,15 @@ export class AggregatorClient {
|
|
|
460
557
|
BigInt(0),
|
|
461
558
|
targetCoinType
|
|
462
559
|
)
|
|
463
|
-
|
|
464
|
-
const packages = isBuilderFastRouterSwapParams(params)
|
|
465
|
-
|
|
466
|
-
|
|
560
|
+
|
|
561
|
+
const packages = isBuilderFastRouterSwapParams(params)
|
|
562
|
+
? undefined
|
|
563
|
+
: params.routers.packages
|
|
564
|
+
const aggregatorV2PublishedAt = getAggregatorV2PublishedAt(
|
|
565
|
+
this.publishedAtV2(),
|
|
566
|
+
packages
|
|
567
|
+
)
|
|
568
|
+
|
|
467
569
|
txb.mergeCoins(targetCoinRes.targetCoin, [targetCoin])
|
|
468
570
|
if (targetCoinRes.isMintZeroCoin) {
|
|
469
571
|
this.transferOrDestoryCoin(
|
|
@@ -498,7 +600,7 @@ export class AggregatorClient {
|
|
|
498
600
|
// return "0x3b6d71bdeb8ce5b06febfd3cfc29ecd60d50da729477c8b8038ecdae34541b91" // version 5, add bluefin
|
|
499
601
|
// return "0x81ade554cb24a7564ca43a4bfb7381b08d9e5c5f375162c95215b696ab903502" // version 6, force upgrade scallop
|
|
500
602
|
// return "0x347dd58bbd11cd82c8b386b344729717c04a998da73386e82a239cc196d5706b" // version 7
|
|
501
|
-
return "0xf2fcea41dc217385019828375764fa06d9bd25e8e4726ba1962680849fb8d613"
|
|
603
|
+
return "0xf2fcea41dc217385019828375764fa06d9bd25e8e4726ba1962680849fb8d613" // version 8
|
|
502
604
|
} else {
|
|
503
605
|
return "0xabb6a81c8a216828e317719e06125de5bb2cb0fe8f9916ff8c023ca5be224c78"
|
|
504
606
|
}
|
|
@@ -551,7 +653,11 @@ export class AggregatorClient {
|
|
|
551
653
|
return targetCoin
|
|
552
654
|
}
|
|
553
655
|
|
|
554
|
-
newDex(
|
|
656
|
+
newDex(
|
|
657
|
+
provider: string,
|
|
658
|
+
pythPriceIDs: Map<string, string>,
|
|
659
|
+
partner?: string
|
|
660
|
+
): Dex {
|
|
555
661
|
switch (provider) {
|
|
556
662
|
case CETUS:
|
|
557
663
|
return new Cetus(this.env, partner)
|
|
@@ -588,7 +694,7 @@ export class AggregatorClient {
|
|
|
588
694
|
case BLUEFIN:
|
|
589
695
|
return new Bluefin(this.env)
|
|
590
696
|
case HAEDALPMM:
|
|
591
|
-
return new HaedalPmm(this.env,
|
|
697
|
+
return new HaedalPmm(this.env, pythPriceIDs)
|
|
592
698
|
case ALPHAFI:
|
|
593
699
|
return new Alphafi(this.env)
|
|
594
700
|
default:
|
|
@@ -634,9 +740,74 @@ export class AggregatorClient {
|
|
|
634
740
|
}
|
|
635
741
|
return null
|
|
636
742
|
}
|
|
743
|
+
|
|
744
|
+
async updatePythPriceIDs(
|
|
745
|
+
priceIDs: string[],
|
|
746
|
+
txb: Transaction
|
|
747
|
+
): Promise<Map<string, string>> {
|
|
748
|
+
let priceUpdateData: Buffer[] | null = null
|
|
749
|
+
let lastError: Error | null = null
|
|
750
|
+
|
|
751
|
+
for (const connection of this.pythConnections) {
|
|
752
|
+
try {
|
|
753
|
+
priceUpdateData = await connection.getPriceFeedsUpdateData(priceIDs)
|
|
754
|
+
break
|
|
755
|
+
} catch (e) {
|
|
756
|
+
lastError = e as Error
|
|
757
|
+
console.log("Error: ", e)
|
|
758
|
+
continue
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (priceUpdateData == null) {
|
|
763
|
+
throw new Error(
|
|
764
|
+
`No pyth price seeds update data found: ${lastError?.message}`
|
|
765
|
+
)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
let priceInfoObjectIds = []
|
|
769
|
+
try {
|
|
770
|
+
priceInfoObjectIds = await this.pythClient.updatePriceFeeds(
|
|
771
|
+
txb,
|
|
772
|
+
priceUpdateData,
|
|
773
|
+
priceIDs
|
|
774
|
+
)
|
|
775
|
+
} catch (e) {
|
|
776
|
+
throw new Error(`Failed to update price feeds: ${e}`)
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
let priceInfoObjectIdsMap = new Map<string, string>()
|
|
780
|
+
for (let i = 0; i < priceIDs.length; i++) {
|
|
781
|
+
priceInfoObjectIdsMap.set(priceIDs[i], priceInfoObjectIds[i])
|
|
782
|
+
}
|
|
783
|
+
return priceInfoObjectIdsMap
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
export function findPythPriceIDs(routes: Router[]): string[] {
|
|
788
|
+
const priceIDs = new Set<string>()
|
|
789
|
+
|
|
790
|
+
for (const route of routes) {
|
|
791
|
+
for (const path of route.path) {
|
|
792
|
+
if (path.provider === HAEDALPMM) {
|
|
793
|
+
if (
|
|
794
|
+
path.extendedDetails &&
|
|
795
|
+
path.extendedDetails.haedalPmmBasePriceSeed &&
|
|
796
|
+
path.extendedDetails.haedalPmmQuotePriceSeed
|
|
797
|
+
) {
|
|
798
|
+
priceIDs.add(path.extendedDetails.haedalPmmBasePriceSeed)
|
|
799
|
+
priceIDs.add(path.extendedDetails.haedalPmmQuotePriceSeed)
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return Array.from(priceIDs)
|
|
637
805
|
}
|
|
638
806
|
|
|
639
|
-
export function parseRouterResponse(
|
|
807
|
+
export function parseRouterResponse(
|
|
808
|
+
data: any,
|
|
809
|
+
byAmountIn: boolean
|
|
810
|
+
): RouterData {
|
|
640
811
|
let totalDeepFee = 0
|
|
641
812
|
for (const route of data.routes) {
|
|
642
813
|
for (const path of route.path) {
|
|
@@ -674,7 +845,7 @@ export function parseRouterResponse(data: any, byAmountIn: boolean): RouterData
|
|
|
674
845
|
path.provider === AFTERMATH ||
|
|
675
846
|
path.provider === CETUS ||
|
|
676
847
|
path.provider === DEEPBOOKV3 ||
|
|
677
|
-
path.provider === SCALLOP ||
|
|
848
|
+
path.provider === SCALLOP ||
|
|
678
849
|
path.provider === HAEDALPMM
|
|
679
850
|
) {
|
|
680
851
|
extendedDetails = {
|
|
@@ -685,8 +856,10 @@ export function parseRouterResponse(data: any, byAmountIn: boolean): RouterData
|
|
|
685
856
|
deepbookv3DeepFee: path.extended_details?.deepbookv3_deep_fee,
|
|
686
857
|
scallopScoinTreasury:
|
|
687
858
|
path.extended_details?.scallop_scoin_treasury,
|
|
688
|
-
haedalPmmBasePriceSeed:
|
|
689
|
-
|
|
859
|
+
haedalPmmBasePriceSeed:
|
|
860
|
+
path.extended_details?.haedal_pmm_base_price_seed,
|
|
861
|
+
haedalPmmQuotePriceSeed:
|
|
862
|
+
path.extended_details?.haedal_pmm_quote_price_seed,
|
|
690
863
|
}
|
|
691
864
|
}
|
|
692
865
|
|
|
@@ -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/tests/router.test.ts
CHANGED
|
@@ -33,7 +33,10 @@ describe("router module", () => {
|
|
|
33
33
|
keypair = buildTestAccount()
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const wallet = keypair.getPublicKey().toSuiAddress()
|
|
36
|
+
// const wallet = keypair.getPublicKey().toSuiAddress()
|
|
37
|
+
const wallet =
|
|
38
|
+
"0x073dfdcbb5d6552efd954273f7ab9e0b918d7bf30103e3f4e632502289cd92ee"
|
|
39
|
+
|
|
37
40
|
console.log("wallet: ", wallet)
|
|
38
41
|
|
|
39
42
|
const endpoint = aggregatorURL
|
|
@@ -61,7 +64,7 @@ describe("router module", () => {
|
|
|
61
64
|
amount: new BN(amount),
|
|
62
65
|
byAmountIn,
|
|
63
66
|
pools: [
|
|
64
|
-
|
|
67
|
+
"0xb8d7d9e66a60c239e7a60110efcf8de6c705580ed924d0dde141f4a0e2c90105",
|
|
65
68
|
],
|
|
66
69
|
})
|
|
67
70
|
|
|
@@ -108,8 +111,9 @@ describe("router module", () => {
|
|
|
108
111
|
|
|
109
112
|
test("Build router tx", async () => {
|
|
110
113
|
const byAmountIn = true
|
|
111
|
-
const amount = "
|
|
112
|
-
const from =
|
|
114
|
+
const amount = "100000"
|
|
115
|
+
const from =
|
|
116
|
+
"0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
|
|
113
117
|
const target = "0x2::sui::SUI"
|
|
114
118
|
|
|
115
119
|
const res = await client.findRouters({
|
|
@@ -118,8 +122,8 @@ describe("router module", () => {
|
|
|
118
122
|
amount: new BN(amount),
|
|
119
123
|
byAmountIn,
|
|
120
124
|
depth: 3,
|
|
121
|
-
providers: ["
|
|
122
|
-
splitCount:
|
|
125
|
+
providers: ["CETUS"],
|
|
126
|
+
splitCount: 1,
|
|
123
127
|
})
|
|
124
128
|
|
|
125
129
|
if (res != null) {
|
|
@@ -205,8 +209,18 @@ describe("router module", () => {
|
|
|
205
209
|
|
|
206
210
|
test("Test Multi Input", async () => {
|
|
207
211
|
const amounts = [1000000000, 2000000000, 10000000000000]
|
|
208
|
-
const froms = [
|
|
209
|
-
|
|
212
|
+
const froms = [
|
|
213
|
+
testData.M_USDC,
|
|
214
|
+
testData.M_SUI,
|
|
215
|
+
testData.M_CETUS,
|
|
216
|
+
testData.M_NAVI,
|
|
217
|
+
]
|
|
218
|
+
const tos = [
|
|
219
|
+
testData.M_SUI,
|
|
220
|
+
testData.M_USDC,
|
|
221
|
+
testData.M_USDC,
|
|
222
|
+
testData.M_SUI,
|
|
223
|
+
]
|
|
210
224
|
|
|
211
225
|
for (let i = 0; i < froms.length; i++) {
|
|
212
226
|
const from = froms[i]
|
|
@@ -339,12 +353,12 @@ describe("router module", () => {
|
|
|
339
353
|
console.log("config", config)
|
|
340
354
|
}, 60000)
|
|
341
355
|
|
|
342
|
-
|
|
343
356
|
test("Find router", async () => {
|
|
344
357
|
const amount = "4239267610000000000"
|
|
345
358
|
const res = await client.findRouters({
|
|
346
|
-
from:
|
|
347
|
-
target:
|
|
359
|
+
from: "0x2::sui::SUI",
|
|
360
|
+
target:
|
|
361
|
+
"0x188c6239bda71ba5751990cc0271e91b6362c67bccf7aa381e018db7fe39c6d7::BUILD::BUILD",
|
|
348
362
|
amount: new BN(amount),
|
|
349
363
|
byAmountIn: true,
|
|
350
364
|
depth: 3,
|