@cetusprotocol/aggregator-sdk 1.1.2 → 1.1.4
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/.claude/settings.local.json +41 -0
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +86 -52
- package/dist/index.mjs +86 -52
- package/package.json +2 -2
- package/.github/workflows/test.yml +0 -152
- package/.vscode/settings.json +0 -8
- package/CLAUDE.md +0 -101
- package/benchmark-results/benchmark-results-2025-07-17T12-03-15-563Z.csv +0 -3
- package/benchmark-results/benchmark-results-2025-07-17T12-03-15-563Z.json +0 -56
- package/benchmark-results/benchmark-results-2025-07-17T12-03-34-148Z.csv +0 -3
- package/benchmark-results/benchmark-results-2025-07-17T12-03-34-148Z.json +0 -56
- package/benchmark-results/benchmark-results-2025-07-21T03-31-59-263Z.csv +0 -21
- package/benchmark-results/benchmark-results-2025-07-21T03-31-59-263Z.json +0 -444
- package/benchmark-results/benchmark-results-2025-07-21T07-54-54-916Z.csv +0 -21
- package/benchmark-results/benchmark-results-2025-07-21T07-54-54-916Z.json +0 -503
- package/benchmark-results/error-report-2025-07-17T12-03-34-148Z.md +0 -18
- package/benchmark-results/error-report-2025-07-21T03-31-59-263Z.md +0 -18
- package/benchmark-results/error-report-2025-07-21T07-54-54-916Z.md +0 -18
- package/benchmark-results/gas-analysis-report-2025-07-17T12-03-15-563Z.md +0 -80
- package/benchmark-results/gas-analysis-report-2025-07-17T12-03-34-148Z.md +0 -80
- package/benchmark-results/gas-analysis-report-2025-07-21T03-31-59-263Z.md +0 -296
- package/benchmark-results/gas-analysis-report-2025-07-21T07-54-54-916Z.md +0 -323
- package/docs/Cetus_Aggregator_V3_/346/216/245/345/217/243/346/226/207/346/241/243.md +0 -706
- package/docs/REFACTOR.md +0 -24
- package/docs//350/267/257/345/276/204/346/213/223/346/211/221/346/216/222/345/272/217.md +0 -208
- package/script/copy-to-sui-aggregator.sh +0 -85
package/dist/index.mjs
CHANGED
|
@@ -2993,7 +2993,7 @@ var GAS_TYPE_ARG = "0x2::sui::SUI";
|
|
|
2993
2993
|
var GAS_TYPE_ARG_LONG = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
|
|
2994
2994
|
var GAS_SYMBOL = "SUI";
|
|
2995
2995
|
var DEFAULT_NFT_TRANSFER_GAS_FEE = 450;
|
|
2996
|
-
var SUI_SYSTEM_STATE_OBJECT_ID = "
|
|
2996
|
+
var SUI_SYSTEM_STATE_OBJECT_ID = "0x0000000000000000000000000000000000000000000000000000000000000005";
|
|
2997
2997
|
var CoinUtils = class _CoinUtils {
|
|
2998
2998
|
/**
|
|
2999
2999
|
* Get the coin type argument from a SuiMoveObject.
|
|
@@ -3101,10 +3101,18 @@ var CoinUtils = class _CoinUtils {
|
|
|
3101
3101
|
* @returns The CoinAsset objects that have a balance greater than or equal to the given amount.
|
|
3102
3102
|
*/
|
|
3103
3103
|
static selectCoinObjectIdGreaterThanOrEqual(coins, amount, exclude = []) {
|
|
3104
|
-
const selectedResult = _CoinUtils.selectCoinAssetGreaterThanOrEqual(
|
|
3105
|
-
|
|
3104
|
+
const selectedResult = _CoinUtils.selectCoinAssetGreaterThanOrEqual(
|
|
3105
|
+
coins,
|
|
3106
|
+
amount,
|
|
3107
|
+
exclude
|
|
3108
|
+
);
|
|
3109
|
+
const objectArray = selectedResult.selectedCoins.map(
|
|
3110
|
+
(item) => item.coinObjectId
|
|
3111
|
+
);
|
|
3106
3112
|
const remainCoins = selectedResult.remainingCoins;
|
|
3107
|
-
const amountArray = selectedResult.selectedCoins.map(
|
|
3113
|
+
const amountArray = selectedResult.selectedCoins.map(
|
|
3114
|
+
(item) => item.balance.toString()
|
|
3115
|
+
);
|
|
3108
3116
|
return { objectArray, remainCoins, amountArray };
|
|
3109
3117
|
}
|
|
3110
3118
|
/**
|
|
@@ -3116,7 +3124,9 @@ var CoinUtils = class _CoinUtils {
|
|
|
3116
3124
|
* @returns The CoinAsset objects that have a balance greater than or equal to the given amount.
|
|
3117
3125
|
*/
|
|
3118
3126
|
static selectCoinAssetGreaterThanOrEqual(coins, amount, exclude = []) {
|
|
3119
|
-
const sortedCoins = _CoinUtils.sortByBalance(
|
|
3127
|
+
const sortedCoins = _CoinUtils.sortByBalance(
|
|
3128
|
+
coins.filter((c) => !exclude.includes(c.coinObjectId))
|
|
3129
|
+
);
|
|
3120
3130
|
const total = _CoinUtils.calculateTotalBalance(sortedCoins);
|
|
3121
3131
|
if (total < amount) {
|
|
3122
3132
|
return { selectedCoins: [], remainingCoins: sortedCoins };
|
|
@@ -3129,9 +3139,13 @@ var CoinUtils = class _CoinUtils {
|
|
|
3129
3139
|
const remainingCoins = [...sortedCoins];
|
|
3130
3140
|
while (sum2 < total) {
|
|
3131
3141
|
const target = amount - sum2;
|
|
3132
|
-
const coinWithSmallestSufficientBalanceIndex = remainingCoins.findIndex(
|
|
3142
|
+
const coinWithSmallestSufficientBalanceIndex = remainingCoins.findIndex(
|
|
3143
|
+
(c) => c.balance >= target
|
|
3144
|
+
);
|
|
3133
3145
|
if (coinWithSmallestSufficientBalanceIndex !== -1) {
|
|
3134
|
-
selectedCoins.push(
|
|
3146
|
+
selectedCoins.push(
|
|
3147
|
+
remainingCoins[coinWithSmallestSufficientBalanceIndex]
|
|
3148
|
+
);
|
|
3135
3149
|
remainingCoins.splice(coinWithSmallestSufficientBalanceIndex, 1);
|
|
3136
3150
|
break;
|
|
3137
3151
|
}
|
|
@@ -3141,7 +3155,10 @@ var CoinUtils = class _CoinUtils {
|
|
|
3141
3155
|
sum2 += coinWithLargestBalance.balance;
|
|
3142
3156
|
}
|
|
3143
3157
|
}
|
|
3144
|
-
return {
|
|
3158
|
+
return {
|
|
3159
|
+
selectedCoins: _CoinUtils.sortByBalance(selectedCoins),
|
|
3160
|
+
remainingCoins: _CoinUtils.sortByBalance(remainingCoins)
|
|
3161
|
+
};
|
|
3145
3162
|
}
|
|
3146
3163
|
/**
|
|
3147
3164
|
* Sort the CoinAsset objects by their balance.
|
|
@@ -3150,10 +3167,14 @@ var CoinUtils = class _CoinUtils {
|
|
|
3150
3167
|
* @returns The sorted CoinAsset objects.
|
|
3151
3168
|
*/
|
|
3152
3169
|
static sortByBalance(coins) {
|
|
3153
|
-
return coins.sort(
|
|
3170
|
+
return coins.sort(
|
|
3171
|
+
(a, b) => a.balance < b.balance ? -1 : a.balance > b.balance ? 1 : 0
|
|
3172
|
+
);
|
|
3154
3173
|
}
|
|
3155
3174
|
static sortByBalanceDes(coins) {
|
|
3156
|
-
return coins.sort(
|
|
3175
|
+
return coins.sort(
|
|
3176
|
+
(a, b) => a.balance > b.balance ? -1 : a.balance < b.balance ? 0 : 1
|
|
3177
|
+
);
|
|
3157
3178
|
}
|
|
3158
3179
|
/**
|
|
3159
3180
|
* Calculate the total balance of a list of CoinAsset objects.
|
|
@@ -3391,8 +3412,9 @@ var DEEPBOOK_V3_DEEP_FEE_TYPES = {
|
|
|
3391
3412
|
var CLIENT_CONFIG = {
|
|
3392
3413
|
DEFAULT_PYTH_URL: "https://hermes.pyth.network",
|
|
3393
3414
|
PYTH_TIMEOUT: 3e3,
|
|
3394
|
-
|
|
3415
|
+
MAX_OVERLAY_FEE_RATE_PARAMS: 0.1,
|
|
3395
3416
|
FEE_RATE_MULTIPLIER: 1e6,
|
|
3417
|
+
MAX_FEE_RATE: 1e5,
|
|
3396
3418
|
DEFAULT_OVERLAY_FEE_RECEIVER: "0x0",
|
|
3397
3419
|
// Error Messages
|
|
3398
3420
|
ERRORS: {
|
|
@@ -3405,7 +3427,8 @@ var CLIENT_CONFIG = {
|
|
|
3405
3427
|
PYTH_UNAVAILABLE: "All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes",
|
|
3406
3428
|
QUOTE_ID_REQUIRED: "Quote ID is required",
|
|
3407
3429
|
AGGREGATOR_V3_PACKAGE_REQUIRED: "Aggregator V3 package is required",
|
|
3408
|
-
PACKAGES_REQUIRED: "Packages are required"
|
|
3430
|
+
PACKAGES_REQUIRED: "Packages are required",
|
|
3431
|
+
OVERLAY_FEE_RECEIVER_REQUIRED: "Overlay fee rate is set, but overlay fee receiver is not set"
|
|
3409
3432
|
}
|
|
3410
3433
|
};
|
|
3411
3434
|
var AGGREGATOR_V3_CONFIG = {
|
|
@@ -3420,7 +3443,7 @@ var AGGREGATOR_V3_CONFIG = {
|
|
|
3420
3443
|
};
|
|
3421
3444
|
|
|
3422
3445
|
// src/api.ts
|
|
3423
|
-
var SDK_VERSION =
|
|
3446
|
+
var SDK_VERSION = 1010104;
|
|
3424
3447
|
function parseRouterResponse(data, byAmountIn) {
|
|
3425
3448
|
let packages = /* @__PURE__ */ new Map();
|
|
3426
3449
|
if (data.packages) {
|
|
@@ -3438,6 +3461,7 @@ function parseRouterResponse(data, byAmountIn) {
|
|
|
3438
3461
|
amountOut: new import_bn2.default(data.amount_out.toString()),
|
|
3439
3462
|
byAmountIn,
|
|
3440
3463
|
insufficientLiquidity: false,
|
|
3464
|
+
deviationRatio: data.deviation_ratio,
|
|
3441
3465
|
packages,
|
|
3442
3466
|
paths: data.paths.map((path) => ({
|
|
3443
3467
|
id: path.id,
|
|
@@ -6689,7 +6713,7 @@ var SpringsuiRouter = class {
|
|
|
6689
6713
|
const args = [
|
|
6690
6714
|
swapContext,
|
|
6691
6715
|
txb.object(swapData.poolId),
|
|
6692
|
-
txb.object(
|
|
6716
|
+
txb.object(SUI_SYSTEM_STATE_OBJECT_ID),
|
|
6693
6717
|
txb.pure.u64(swapData.amountIn),
|
|
6694
6718
|
txb.pure.bool(swapData.direction)
|
|
6695
6719
|
];
|
|
@@ -7371,8 +7395,7 @@ var VoloRouter = class {
|
|
|
7371
7395
|
swapContext,
|
|
7372
7396
|
txb.object(this.stakePool),
|
|
7373
7397
|
txb.object(this.metadata),
|
|
7374
|
-
txb.object(
|
|
7375
|
-
// SuiSystemState
|
|
7398
|
+
txb.object(SUI_SYSTEM_STATE_OBJECT_ID),
|
|
7376
7399
|
txb.pure.bool(swapData.direction),
|
|
7377
7400
|
txb.pure.u64(swapData.amountIn)
|
|
7378
7401
|
];
|
|
@@ -7423,8 +7446,7 @@ var AfsuiRouter = class {
|
|
|
7423
7446
|
swapContext,
|
|
7424
7447
|
txb.object(this.stakedSuiVault),
|
|
7425
7448
|
txb.object(this.safe),
|
|
7426
|
-
txb.object(
|
|
7427
|
-
// SuiSystemState
|
|
7449
|
+
txb.object(SUI_SYSTEM_STATE_OBJECT_ID),
|
|
7428
7450
|
txb.object(this.referVault),
|
|
7429
7451
|
txb.object(this.validator),
|
|
7430
7452
|
txb.pure.bool(swapData.direction),
|
|
@@ -7469,8 +7491,7 @@ var HaedalRouter = class {
|
|
|
7469
7491
|
const args = [
|
|
7470
7492
|
swapContext,
|
|
7471
7493
|
txb.object(swapData.poolId),
|
|
7472
|
-
txb.object(
|
|
7473
|
-
// SuiSystemState
|
|
7494
|
+
txb.object(SUI_SYSTEM_STATE_OBJECT_ID),
|
|
7474
7495
|
txb.pure.bool(swapData.direction),
|
|
7475
7496
|
txb.pure.u64(swapData.amountIn)
|
|
7476
7497
|
];
|
|
@@ -8229,7 +8250,7 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8229
8250
|
this.apiKey = params.apiKey || "";
|
|
8230
8251
|
this.partner = params.partner;
|
|
8231
8252
|
if (params.overlayFeeRate) {
|
|
8232
|
-
if (params.overlayFeeRate > 0 && params.overlayFeeRate <= CLIENT_CONFIG.
|
|
8253
|
+
if (params.overlayFeeRate > 0 && params.overlayFeeRate <= CLIENT_CONFIG.MAX_OVERLAY_FEE_RATE_PARAMS) {
|
|
8233
8254
|
this.overlayFeeRate = params.overlayFeeRate * AGGREGATOR_V3_CONFIG.FEE_DENOMINATOR;
|
|
8234
8255
|
if (this.overlayFeeRate > AGGREGATOR_V3_CONFIG.MAX_FEE_RATE) {
|
|
8235
8256
|
throw new Error(
|
|
@@ -8260,6 +8281,11 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8260
8281
|
return DEEPBOOK_V3_DEEP_FEE_TYPES.Testnet;
|
|
8261
8282
|
}
|
|
8262
8283
|
}
|
|
8284
|
+
getDeepbookV3Config() {
|
|
8285
|
+
return __async(this, null, function* () {
|
|
8286
|
+
return yield getDeepbookV3Config(this.endpoint);
|
|
8287
|
+
});
|
|
8288
|
+
}
|
|
8263
8289
|
getOneCoinUsedToMerge(coinType) {
|
|
8264
8290
|
return __async(this, null, function* () {
|
|
8265
8291
|
try {
|
|
@@ -8510,20 +8536,22 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8510
8536
|
}
|
|
8511
8537
|
routerSwap(params) {
|
|
8512
8538
|
return __async(this, null, function* () {
|
|
8513
|
-
const { router, inputCoin, slippage, txb,
|
|
8539
|
+
const { router, inputCoin, slippage, txb, partner } = params;
|
|
8514
8540
|
if (slippage > 1 || slippage < 0) {
|
|
8515
8541
|
throw new Error(CLIENT_CONFIG.ERRORS.INVALID_SLIPPAGE);
|
|
8516
8542
|
}
|
|
8543
|
+
if (!params.router.packages || !params.router.packages.get(PACKAGE_NAMES.AGGREGATOR_V3)) {
|
|
8544
|
+
throw new Error(CLIENT_CONFIG.ERRORS.PACKAGES_REQUIRED);
|
|
8545
|
+
}
|
|
8517
8546
|
const byAmountIn = params.router.byAmountIn;
|
|
8518
8547
|
const amountIn = router.amountIn;
|
|
8519
8548
|
const amountOut = router.amountOut;
|
|
8549
|
+
checkOverlayFeeConfig(this.overlayFeeRate, this.overlayFeeReceiver);
|
|
8520
8550
|
let overlayFee = new import_bn6.default(0);
|
|
8521
|
-
if (
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
overlayFee = amountIn.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6));
|
|
8526
|
-
}
|
|
8551
|
+
if (byAmountIn) {
|
|
8552
|
+
overlayFee = amountOut.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6));
|
|
8553
|
+
} else {
|
|
8554
|
+
overlayFee = amountIn.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6));
|
|
8527
8555
|
}
|
|
8528
8556
|
const expectedAmountOut = byAmountIn ? amountOut.sub(overlayFee) : amountOut;
|
|
8529
8557
|
const expectedAmountIn = byAmountIn ? amountIn : amountIn.add(overlayFee);
|
|
@@ -8532,9 +8560,6 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8532
8560
|
byAmountIn,
|
|
8533
8561
|
slippage
|
|
8534
8562
|
);
|
|
8535
|
-
if (!params.router.packages || !params.router.packages.get(PACKAGE_NAMES.AGGREGATOR_V3)) {
|
|
8536
|
-
throw new Error(CLIENT_CONFIG.ERRORS.PACKAGES_REQUIRED);
|
|
8537
|
-
}
|
|
8538
8563
|
const priceIDs = findPythPriceIDs(router.paths);
|
|
8539
8564
|
const priceInfoObjectIds = priceIDs.length > 0 ? yield this.updatePythPriceIDs(priceIDs, txb) : /* @__PURE__ */ new Map();
|
|
8540
8565
|
if (byAmountIn) {
|
|
@@ -8567,17 +8592,16 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8567
8592
|
const fromCoinType = router.paths[0].from;
|
|
8568
8593
|
const targetCoinType = router.paths[router.paths.length - 1].target;
|
|
8569
8594
|
const byAmountIn = router.byAmountIn;
|
|
8595
|
+
checkOverlayFeeConfig(this.overlayFeeRate, this.overlayFeeReceiver);
|
|
8570
8596
|
let overlayFee = 0;
|
|
8571
|
-
if (
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
);
|
|
8580
|
-
}
|
|
8597
|
+
if (byAmountIn) {
|
|
8598
|
+
overlayFee = Number(
|
|
8599
|
+
router.amountOut.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6)).toString()
|
|
8600
|
+
);
|
|
8601
|
+
} else {
|
|
8602
|
+
overlayFee = Number(
|
|
8603
|
+
router.amountIn.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6)).toString()
|
|
8604
|
+
);
|
|
8581
8605
|
}
|
|
8582
8606
|
const expectedAmountOut = byAmountIn ? router.amountOut.sub(new import_bn6.default(overlayFee)) : router.amountOut;
|
|
8583
8607
|
const expectedAmountIn = byAmountIn ? router.amountIn : router.amountIn.add(new import_bn6.default(overlayFee));
|
|
@@ -8629,18 +8653,17 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8629
8653
|
}
|
|
8630
8654
|
fixableRouterSwapV3(params) {
|
|
8631
8655
|
return __async(this, null, function* () {
|
|
8632
|
-
const { router, inputCoin, slippage, txb,
|
|
8656
|
+
const { router, inputCoin, slippage, txb, partner } = params;
|
|
8657
|
+
checkOverlayFeeConfig(this.overlayFeeRate, this.overlayFeeReceiver);
|
|
8633
8658
|
let overlayFee = 0;
|
|
8634
|
-
if (
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
);
|
|
8643
|
-
}
|
|
8659
|
+
if (router.byAmountIn) {
|
|
8660
|
+
overlayFee = Number(
|
|
8661
|
+
router.amountOut.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6)).toString()
|
|
8662
|
+
);
|
|
8663
|
+
} else {
|
|
8664
|
+
overlayFee = Number(
|
|
8665
|
+
router.amountIn.mul(new import_bn6.default(this.overlayFeeRate)).div(new import_bn6.default(1e6)).toString()
|
|
8666
|
+
);
|
|
8644
8667
|
}
|
|
8645
8668
|
const expectedAmountOut = router.byAmountIn ? router.amountOut.sub(new import_bn6.default(overlayFee)) : router.amountOut;
|
|
8646
8669
|
const expectedAmountIn = router.byAmountIn ? router.amountIn : router.amountIn.add(new import_bn6.default(overlayFee));
|
|
@@ -8749,6 +8772,7 @@ var _AggregatorClient = class _AggregatorClient {
|
|
|
8749
8772
|
const routeData = {
|
|
8750
8773
|
amountIn,
|
|
8751
8774
|
amountOut: new import_bn6.default((_d = event.amount_out) != null ? _d : 0),
|
|
8775
|
+
deviationRatio: 0,
|
|
8752
8776
|
paths: [
|
|
8753
8777
|
{
|
|
8754
8778
|
id: pools[tempIndex],
|
|
@@ -8866,6 +8890,16 @@ function recordFirstCoinIndex(paths) {
|
|
|
8866
8890
|
}
|
|
8867
8891
|
return newCoinRecord;
|
|
8868
8892
|
}
|
|
8893
|
+
function checkOverlayFeeConfig(overlayFeeRate, overlayFeeReceiver) {
|
|
8894
|
+
if (overlayFeeRate > CLIENT_CONFIG.MAX_FEE_RATE) {
|
|
8895
|
+
throw new Error(CLIENT_CONFIG.ERRORS.INVALID_OVERLAY_FEE_RATE);
|
|
8896
|
+
}
|
|
8897
|
+
if (overlayFeeReceiver === "0x0" && overlayFeeRate > 0) {
|
|
8898
|
+
throw new Error(
|
|
8899
|
+
CLIENT_CONFIG.ERRORS.OVERLAY_FEE_RECEIVER_REQUIRED
|
|
8900
|
+
);
|
|
8901
|
+
}
|
|
8902
|
+
}
|
|
8869
8903
|
|
|
8870
8904
|
// src/types/sui.ts
|
|
8871
8905
|
var getDefaultSuiInputType = (value) => {
|
package/package.json
CHANGED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
name: Automated Testing with Success Rate
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main, develop, refactor-v3 ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ main, develop, refactor-v3 ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- name: Checkout code
|
|
15
|
-
uses: actions/checkout@v4
|
|
16
|
-
|
|
17
|
-
- name: Setup Bun
|
|
18
|
-
uses: oven-sh/setup-bun@v1
|
|
19
|
-
with:
|
|
20
|
-
bun-version: latest
|
|
21
|
-
|
|
22
|
-
- name: Install dependencies
|
|
23
|
-
run: bun install
|
|
24
|
-
|
|
25
|
-
- name: Run tests with coverage and statistics
|
|
26
|
-
run: |
|
|
27
|
-
echo "🧪 Running all tests..."
|
|
28
|
-
|
|
29
|
-
# Run tests with JSON output for parsing
|
|
30
|
-
bun test --json --outputFile=test-results.json --coverage || true
|
|
31
|
-
|
|
32
|
-
# Also run regular test output for display
|
|
33
|
-
echo "📊 Test Results:"
|
|
34
|
-
bun test --verbose || TEST_EXIT_CODE=$?
|
|
35
|
-
|
|
36
|
-
# Parse test results and calculate success rate
|
|
37
|
-
echo "📈 Calculating test success rate..."
|
|
38
|
-
|
|
39
|
-
# Create a simple Node.js script to parse JSON results
|
|
40
|
-
cat > calculate-stats.js << 'EOF'
|
|
41
|
-
const fs = require('fs');
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
// Try to read the JSON results file
|
|
45
|
-
let results;
|
|
46
|
-
if (fs.existsSync('test-results.json')) {
|
|
47
|
-
const data = fs.readFileSync('test-results.json', 'utf8');
|
|
48
|
-
results = JSON.parse(data);
|
|
49
|
-
} else {
|
|
50
|
-
console.log('⚠️ JSON results file not found, using alternative method');
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Calculate statistics
|
|
55
|
-
const totalTests = results.numTotalTests || 0;
|
|
56
|
-
const passedTests = results.numPassedTests || 0;
|
|
57
|
-
const failedTests = results.numFailedTests || 0;
|
|
58
|
-
const successRate = totalTests > 0 ? ((passedTests / totalTests) * 100).toFixed(2) : 0;
|
|
59
|
-
|
|
60
|
-
console.log('\n📊 =================================');
|
|
61
|
-
console.log('📊 TEST EXECUTION SUMMARY');
|
|
62
|
-
console.log('📊 =================================');
|
|
63
|
-
console.log(`📊 Total Tests: ${totalTests}`);
|
|
64
|
-
console.log(`✅ Passed Tests: ${passedTests}`);
|
|
65
|
-
console.log(`❌ Failed Tests: ${failedTests}`);
|
|
66
|
-
console.log(`📈 Success Rate: ${successRate}%`);
|
|
67
|
-
console.log('📊 =================================\n');
|
|
68
|
-
|
|
69
|
-
// Set environment variables for GitHub Actions
|
|
70
|
-
console.log(`::set-output name=total_tests::${totalTests}`);
|
|
71
|
-
console.log(`::set-output name=passed_tests::${passedTests}`);
|
|
72
|
-
console.log(`::set-output name=failed_tests::${failedTests}`);
|
|
73
|
-
console.log(`::set-output name=success_rate::${successRate}`);
|
|
74
|
-
|
|
75
|
-
// Exit with non-zero code if tests failed
|
|
76
|
-
if (failedTests > 0) {
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.error('Error parsing test results:', error);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
EOF
|
|
85
|
-
|
|
86
|
-
# Run the statistics calculation
|
|
87
|
-
node calculate-stats.js || {
|
|
88
|
-
echo "⚠️ Falling back to alternative statistics calculation..."
|
|
89
|
-
|
|
90
|
-
# Alternative method using grep on test output
|
|
91
|
-
echo "📊 ================================="
|
|
92
|
-
echo "📊 TEST EXECUTION SUMMARY"
|
|
93
|
-
echo "📊 ================================="
|
|
94
|
-
|
|
95
|
-
# Count test files
|
|
96
|
-
TEST_FILES=$(find tests -name "*.test.ts" | wc -l)
|
|
97
|
-
echo "📊 Total Test Files: $TEST_FILES"
|
|
98
|
-
|
|
99
|
-
# Try to get basic stats from bun test output
|
|
100
|
-
echo "📊 Running tests again for statistics..."
|
|
101
|
-
bun test 2>&1 | tee test-output.log
|
|
102
|
-
|
|
103
|
-
# Parse the output for basic statistics
|
|
104
|
-
if grep -q "Tests:" test-output.log; then
|
|
105
|
-
STATS=$(grep "Tests:" test-output.log | tail -1)
|
|
106
|
-
echo "📊 $STATS"
|
|
107
|
-
fi
|
|
108
|
-
|
|
109
|
-
echo "📊 ================================="
|
|
110
|
-
|
|
111
|
-
# Clean up
|
|
112
|
-
rm -f test-output.log
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
# Clean up
|
|
116
|
-
rm -f calculate-stats.js test-results.json
|
|
117
|
-
|
|
118
|
-
# Exit with the original test exit code
|
|
119
|
-
exit ${TEST_EXIT_CODE:-0}
|
|
120
|
-
|
|
121
|
-
- name: Upload test results
|
|
122
|
-
uses: actions/upload-artifact@v3
|
|
123
|
-
if: always()
|
|
124
|
-
with:
|
|
125
|
-
name: test-results
|
|
126
|
-
path: |
|
|
127
|
-
coverage/
|
|
128
|
-
test-results.json
|
|
129
|
-
retention-days: 30
|
|
130
|
-
|
|
131
|
-
- name: Comment PR with test results
|
|
132
|
-
uses: actions/github-script@v6
|
|
133
|
-
if: github.event_name == 'pull_request'
|
|
134
|
-
with:
|
|
135
|
-
script: |
|
|
136
|
-
const output = `## 🧪 Test Results
|
|
137
|
-
|
|
138
|
-
**Test Execution Summary:**
|
|
139
|
-
- Total Tests: \${{ steps.test.outputs.total_tests || 'N/A' }}
|
|
140
|
-
- Passed Tests: \${{ steps.test.outputs.passed_tests || 'N/A' }}
|
|
141
|
-
- Failed Tests: \${{ steps.test.outputs.failed_tests || 'N/A' }}
|
|
142
|
-
- Success Rate: \${{ steps.test.outputs.success_rate || 'N/A' }}%
|
|
143
|
-
|
|
144
|
-
\${{ steps.test.outputs.failed_tests > 0 && '❌ Some tests failed. Please review the test output above.' || '✅ All tests passed!' }}
|
|
145
|
-
`;
|
|
146
|
-
|
|
147
|
-
github.rest.issues.createComment({
|
|
148
|
-
issue_number: context.issue.number,
|
|
149
|
-
owner: context.repo.owner,
|
|
150
|
-
repo: context.repo.repo,
|
|
151
|
-
body: output
|
|
152
|
-
});
|
package/.vscode/settings.json
DELETED
package/CLAUDE.md
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
The **Cetus Aggregator SDK** is a TypeScript library for the Sui blockchain ecosystem that provides swap aggregation across 25+ decentralized exchanges (DEXs). The SDK finds optimal trading routes, best prices, and lowest slippage by integrating multiple DEXs including Cetus, DeepBook, Kriya, FlowX, Turbos, Aftermath, and many others.
|
|
8
|
-
|
|
9
|
-
## Development Commands
|
|
10
|
-
|
|
11
|
-
### Build and Development
|
|
12
|
-
|
|
13
|
-
- `bun run build` - Compile TypeScript to CommonJS/ESM with type definitions using tsup
|
|
14
|
-
- `bun run dev` - Development mode with file watching
|
|
15
|
-
- `bun run clean` - Remove build artifacts and dependencies
|
|
16
|
-
- `bun run publish:test` - Publish experimental version to bun
|
|
17
|
-
|
|
18
|
-
### Testing
|
|
19
|
-
|
|
20
|
-
- `bun test` - Run Jest test suite with ESM support
|
|
21
|
-
- Tests are organized by aggregator versions (v2/v3) in `/tests/` directory
|
|
22
|
-
- Individual DEX tests located in `/tests/aggregatorv2/router/`
|
|
23
|
-
- Mathematical function tests in `/tests/math.test.ts`
|
|
24
|
-
|
|
25
|
-
## Architecture
|
|
26
|
-
|
|
27
|
-
### Core Components
|
|
28
|
-
|
|
29
|
-
**Main Entry Points:**
|
|
30
|
-
|
|
31
|
-
- `src/index.ts` - Main export barrel
|
|
32
|
-
- `src/client.ts` - Aggregator v2 client implementation
|
|
33
|
-
- `src/clientv3.ts` - Aggregator v3 client implementation
|
|
34
|
-
|
|
35
|
-
**Key Directories:**
|
|
36
|
-
|
|
37
|
-
- `src/transaction/` - DEX-specific swap implementations (25+ integrations)
|
|
38
|
-
- `src/utils/` - Utility functions for coins, transactions, API calls
|
|
39
|
-
- `src/types/` - TypeScript type definitions
|
|
40
|
-
- `src/movecall/` - Move contract interaction helpers
|
|
41
|
-
- `src/api/` - API interaction layer
|
|
42
|
-
- `src/math/` - Mathematical calculations for trading
|
|
43
|
-
|
|
44
|
-
### DEX Integration Pattern
|
|
45
|
-
|
|
46
|
-
Each DEX has its own transaction module in `src/transaction/` following a consistent pattern:
|
|
47
|
-
|
|
48
|
-
- Import from main client class (AggregatorClient/AggregatorClient)
|
|
49
|
-
- Implement DEX-specific swap logic
|
|
50
|
-
- Handle transaction building and execution
|
|
51
|
-
- Support both amount-in and amount-out calculations
|
|
52
|
-
|
|
53
|
-
### TypeScript Configuration
|
|
54
|
-
|
|
55
|
-
- Uses path mapping: `~/*` maps to `src/*`
|
|
56
|
-
- Jest configured with same path mapping
|
|
57
|
-
- Targets ES6 with CommonJS modules
|
|
58
|
-
- Strict TypeScript enabled
|
|
59
|
-
|
|
60
|
-
### Key Dependencies
|
|
61
|
-
|
|
62
|
-
- `@mysten/sui@^1.6.0` - Official Sui SDK for blockchain interactions
|
|
63
|
-
- `@pythnetwork/pyth-sui-js@^2.1.0` - Pyth oracle integration for price feeds
|
|
64
|
-
- `bn.js@^5.2.1` - Big number handling for precise calculations
|
|
65
|
-
- `decimal.js@^10.4.3` - Decimal arithmetic for financial calculations
|
|
66
|
-
|
|
67
|
-
### Multi-Version Support
|
|
68
|
-
|
|
69
|
-
The SDK supports both Aggregator v2 and v3 APIs:
|
|
70
|
-
|
|
71
|
-
- v2: Legacy aggregator with extensive DEX support
|
|
72
|
-
- v3: Newer aggregator with enhanced features and performance
|
|
73
|
-
|
|
74
|
-
### Testing Strategy
|
|
75
|
-
|
|
76
|
-
- Unit tests for mathematical functions (`tests/math.test.ts`)
|
|
77
|
-
- Integration tests for each DEX in `tests/aggregatorv2/router/`
|
|
78
|
-
- Router functionality tests (`tests/aggregatorv2/router.test.ts`)
|
|
79
|
-
- Wallet interaction tests (`tests/wallet.test.ts`)
|
|
80
|
-
|
|
81
|
-
### Build Process
|
|
82
|
-
|
|
83
|
-
Uses `tsup` for bundling with:
|
|
84
|
-
|
|
85
|
-
- Multiple output formats (CJS, ESM, TypeScript declarations)
|
|
86
|
-
- Tree shaking enabled
|
|
87
|
-
- Code splitting support
|
|
88
|
-
- Development watch mode
|
|
89
|
-
|
|
90
|
-
### Contract Addresses
|
|
91
|
-
|
|
92
|
-
The SDK works with multiple contract versions on Sui mainnet:
|
|
93
|
-
|
|
94
|
-
- CetusAggregatorV2: `0x3864c7c59a4889fec05d1aae4bc9dba5a0e0940594b424fbed44cb3f6ac4c032`
|
|
95
|
-
- CetusAggregatorV2ExtendV1: `0x39402d188b7231036e52266ebafad14413b4bf3daea4ac17115989444e6cd516`
|
|
96
|
-
- CetusAggregatorV2ExtendV2: `0x368d13376443a8051b22b42a9125f6a3bc836422bb2d9c4a53984b8d6624c326`
|
|
97
|
-
- CetusAggregatorSimple: `0x594d67abc0778023ac852800578271dd7e18698ad06e6298034858c77612333d`
|
|
98
|
-
|
|
99
|
-
### Environment Setup
|
|
100
|
-
|
|
101
|
-
The SDK works with Sui mainnet and testnet environments via the `Env` enum. Configure clients with appropriate RPC endpoints and package configurations for the target network.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"v2": [
|
|
3
|
-
{
|
|
4
|
-
"gasMetrics": {
|
|
5
|
-
"computationCost": "1420000",
|
|
6
|
-
"storageCost": "8352400",
|
|
7
|
-
"storageRebate": "7290756",
|
|
8
|
-
"nonRefundableStorageFee": "73644",
|
|
9
|
-
"totalGasCost": "2555288",
|
|
10
|
-
"gasUsed": "1420000",
|
|
11
|
-
"gasPrice": "1000",
|
|
12
|
-
"success": true
|
|
13
|
-
},
|
|
14
|
-
"amountIn": "4c4b40",
|
|
15
|
-
"amountOut": "4a240be7",
|
|
16
|
-
"priceImpact": -24777.52,
|
|
17
|
-
"gasEfficiency": 486,
|
|
18
|
-
"provider": "MAGMA",
|
|
19
|
-
"route": [
|
|
20
|
-
"MAGMA"
|
|
21
|
-
],
|
|
22
|
-
"timestamp": 1752753791128
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"v3": [
|
|
26
|
-
{
|
|
27
|
-
"gasMetrics": {
|
|
28
|
-
"computationCost": "710000",
|
|
29
|
-
"storageCost": "8352400",
|
|
30
|
-
"storageRebate": "7290756",
|
|
31
|
-
"nonRefundableStorageFee": "73644",
|
|
32
|
-
"totalGasCost": "1845288",
|
|
33
|
-
"gasUsed": "710000",
|
|
34
|
-
"gasPrice": "1000",
|
|
35
|
-
"success": true
|
|
36
|
-
},
|
|
37
|
-
"amountIn": "4c4b40",
|
|
38
|
-
"amountOut": "4a289111",
|
|
39
|
-
"priceImpact": -24783.45,
|
|
40
|
-
"gasEfficiency": 674,
|
|
41
|
-
"provider": "MAGMA",
|
|
42
|
-
"route": [
|
|
43
|
-
"MAGMA"
|
|
44
|
-
],
|
|
45
|
-
"timestamp": 1752753794556
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
"summary": {
|
|
49
|
-
"v2AverageGas": "2555288",
|
|
50
|
-
"v3AverageGas": "1845288",
|
|
51
|
-
"gasSavingsPercent": 27.78,
|
|
52
|
-
"v2SuccessRate": 100,
|
|
53
|
-
"v3SuccessRate": 100,
|
|
54
|
-
"totalTests": 2
|
|
55
|
-
}
|
|
56
|
-
}
|