@cetusprotocol/aggregator-sdk 0.4.0 → 0.4.1

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/README.md CHANGED
@@ -41,9 +41,22 @@ npm install @cetusprotocol/aggregator-sdk
41
41
 
42
42
  ## 1. Init client with rpc and package config
43
43
 
44
- ```typescript
45
- const client = new AggregatorClient()
46
- ```
44
+ 1. Fast init:
45
+ ```typescript
46
+ const client = new AggregatorClient()
47
+ ```
48
+
49
+ 2. Full init:
50
+ ```typescript
51
+ const client = new AggregatorClient({
52
+ // endpoint, // If you do not have a exclusive aggregator api domain,just use cetus default aggregator endpoints.
53
+ signer: wallet,
54
+ client: suiClient,
55
+ env: Env.Mainnet,
56
+ pythUrls: ["YOUR_PYTH_URL", "ANOTHER_PYTH_URL"],
57
+ })
58
+ ```
59
+ **Notes**: Some providers, such as HaedalHMM and Metastable, rely on Pyth oracle prices when build transactions. Currently, we have a default configuration that connects to Pyth's publicly available node. However, if you frequently build transactions, we recommend setting up a private Pyth node interface as an additional backup. This will ensure uninterrupted access to HaedalHMM and Metastable, even if the public node experiences occasional downtime.
47
60
 
48
61
  ## 2. Get best router swap result from aggregator service
49
62
 
@@ -53,7 +66,7 @@ const from = "0x2::sui::SUI"
53
66
  const target =
54
67
  "0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS"
55
68
 
56
- const routerRes = await client.findRouters({
69
+ const routers = await client.findRouters({
57
70
  from,
58
71
  target,
59
72
  amount,
@@ -68,8 +81,7 @@ const routerTx = new Transaction()
68
81
 
69
82
  if (routerRes != null) {
70
83
  await client.fastRouterSwap({
71
- routers: routerRes.routes,
72
- byAmountIn,
84
+ routers,
73
85
  txb: routerTx,
74
86
  slippage: 0.01,
75
87
  isMergeTragetCoin: true,
@@ -94,8 +106,7 @@ const byAmountIn = true;
94
106
 
95
107
  if (routerRes != null) {
96
108
  const targetCoin = await client.routerSwap({
97
- routers: routerRes.routes,
98
- byAmountIn,
109
+ routers,
99
110
  txb: routerTx,
100
111
  inputCoin,
101
112
  slippage: 0.01,
package/dist/index.d.mts CHANGED
@@ -4,6 +4,7 @@ import { TransactionObjectArgument, Transaction } from '@mysten/sui/transactions
4
4
  import { Signer } from '@mysten/sui/cryptography';
5
5
  import BN from 'bn.js';
6
6
  import Decimal from 'decimal.js';
7
+ import { SuiPriceServiceConnection } from '@pythnetwork/pyth-sui-js';
7
8
 
8
9
  /**
9
10
  * Represents a SUI address, which is a string.
@@ -128,16 +129,26 @@ interface SwapInPoolsResult {
128
129
  isExceed: boolean;
129
130
  routeData?: RouterData;
130
131
  }
132
+ type AggregatorClientParams = {
133
+ endpoint?: string;
134
+ signer?: string;
135
+ client?: SuiClient;
136
+ env?: Env;
137
+ pythUrls?: string[];
138
+ apiKey?: string;
139
+ };
131
140
  declare class AggregatorClient {
132
141
  endpoint: string;
133
142
  signer: string;
134
143
  client: SuiClient;
135
144
  env: Env;
145
+ apiKey: string;
136
146
  private allCoins;
137
147
  private pythConnections;
138
148
  private pythClient;
139
149
  private static readonly CONFIG;
140
- constructor(endpoint?: string, signer?: string, client?: SuiClient, env?: Env);
150
+ constructor(params: AggregatorClientParams);
151
+ newPythClients(pythUrls: string[]): SuiPriceServiceConnection[];
141
152
  getCoins(coinType: string, refresh?: boolean): Promise<CoinAsset[]>;
142
153
  findRouters(params: FindRouterParams): Promise<RouterData | null>;
143
154
  executeFlexibleInputSwap(txb: Transaction, inputCoin: TransactionObjectArgument, routers: Router[], amountOutLimit: BN, pythPriceIDs: Map<string, string>, partner?: string, deepbookv3DeepFee?: TransactionObjectArgument, packages?: Map<string, string>): Promise<TransactionObjectArgument>;
@@ -296,7 +307,7 @@ type AggregatorResponse = {
296
307
  msg: string;
297
308
  data: RouterData;
298
309
  };
299
- declare function getRouterResult(endpoint: string, params: FindRouterParams): Promise<RouterData | null>;
310
+ declare function getRouterResult(endpoint: string, apiKey: string, params: FindRouterParams): Promise<RouterData | null>;
300
311
  type DeepbookV3Config = {
301
312
  id: string;
302
313
  is_alternative_payment: boolean;
@@ -321,4 +332,4 @@ declare enum Env {
321
332
  Testnet = 1
322
333
  }
323
334
 
324
- export { AFSUI, AFTERMATH, AGGREGATOR_V2, AGGREGATOR_V2_EXTEND, ALPHAFI, AggregatorClient, type AggregatorResponse, BLUEFIN, BLUEMOVE, type BuildCoinResult, type BuildFastRouterSwapParams, type BuildFastRouterSwapParamsV2, type BuildRouterSwapParams, type BuildRouterSwapParamsV2, CETUS, CLOCK_ADDRESS, DEEPBOOKV2, DEEPBOOKV3, DEFAULT_ENDPOINT, type DeepbookV3Config, type DeepbookV3ConfigResponse, type Dex, Env, type ExtendedDetails, FLOWXV2, FLOWXV3, type FindRouterParams, HAEDAL, HAEDALPMM, KRIYA, KRIYAV3, METASTABLE, OBRIC, ONE, type Path, type PreSwapLpChangeParams, type Router, type RouterData, type RouterError, SCALLOP, SPRINGSUI, STEAMM, SUILEND, type SwapInPoolsParams, type SwapInPoolsResult, TEN_POW_NINE, TURBOS, TWO, U128, U64_MAX, U64_MAX_BN, VOLO, ZERO, buildInputCoin, checkInvalidSuiAddress, compareCoins, completionCoin, composeType, createTarget, dealWithFastRouterSwapParamsForMsafe, extractAddressFromType, extractStructTagFromType, findPythPriceIDs, fixSuiObjectId, getAggregatorV2ExtendPublishedAt, getAggregatorV2PublishedAt, getDeepbookV3Config, getRouterResult, isSortedSymbols, mintZeroCoin, normalizeCoinType, parseRouterResponse, patchFixSuiObjectId, printTransaction, processEndpoint, restituteMsafeFastRouterSwapParams };
335
+ export { AFSUI, AFTERMATH, AGGREGATOR_V2, AGGREGATOR_V2_EXTEND, ALPHAFI, AggregatorClient, type AggregatorClientParams, type AggregatorResponse, BLUEFIN, BLUEMOVE, type BuildCoinResult, type BuildFastRouterSwapParams, type BuildFastRouterSwapParamsV2, type BuildRouterSwapParams, type BuildRouterSwapParamsV2, CETUS, CLOCK_ADDRESS, DEEPBOOKV2, DEEPBOOKV3, DEFAULT_ENDPOINT, type DeepbookV3Config, type DeepbookV3ConfigResponse, type Dex, Env, type ExtendedDetails, FLOWXV2, FLOWXV3, type FindRouterParams, HAEDAL, HAEDALPMM, KRIYA, KRIYAV3, METASTABLE, OBRIC, ONE, type Path, type PreSwapLpChangeParams, type Router, type RouterData, type RouterError, SCALLOP, SPRINGSUI, STEAMM, SUILEND, type SwapInPoolsParams, type SwapInPoolsResult, TEN_POW_NINE, TURBOS, TWO, U128, U64_MAX, U64_MAX_BN, VOLO, ZERO, buildInputCoin, checkInvalidSuiAddress, compareCoins, completionCoin, composeType, createTarget, dealWithFastRouterSwapParamsForMsafe, extractAddressFromType, extractStructTagFromType, findPythPriceIDs, fixSuiObjectId, getAggregatorV2ExtendPublishedAt, getAggregatorV2PublishedAt, getDeepbookV3Config, getRouterResult, isSortedSymbols, mintZeroCoin, normalizeCoinType, parseRouterResponse, patchFixSuiObjectId, printTransaction, processEndpoint, restituteMsafeFastRouterSwapParams };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { TransactionObjectArgument, Transaction } from '@mysten/sui/transactions
4
4
  import { Signer } from '@mysten/sui/cryptography';
5
5
  import BN from 'bn.js';
6
6
  import Decimal from 'decimal.js';
7
+ import { SuiPriceServiceConnection } from '@pythnetwork/pyth-sui-js';
7
8
 
8
9
  /**
9
10
  * Represents a SUI address, which is a string.
@@ -128,16 +129,26 @@ interface SwapInPoolsResult {
128
129
  isExceed: boolean;
129
130
  routeData?: RouterData;
130
131
  }
132
+ type AggregatorClientParams = {
133
+ endpoint?: string;
134
+ signer?: string;
135
+ client?: SuiClient;
136
+ env?: Env;
137
+ pythUrls?: string[];
138
+ apiKey?: string;
139
+ };
131
140
  declare class AggregatorClient {
132
141
  endpoint: string;
133
142
  signer: string;
134
143
  client: SuiClient;
135
144
  env: Env;
145
+ apiKey: string;
136
146
  private allCoins;
137
147
  private pythConnections;
138
148
  private pythClient;
139
149
  private static readonly CONFIG;
140
- constructor(endpoint?: string, signer?: string, client?: SuiClient, env?: Env);
150
+ constructor(params: AggregatorClientParams);
151
+ newPythClients(pythUrls: string[]): SuiPriceServiceConnection[];
141
152
  getCoins(coinType: string, refresh?: boolean): Promise<CoinAsset[]>;
142
153
  findRouters(params: FindRouterParams): Promise<RouterData | null>;
143
154
  executeFlexibleInputSwap(txb: Transaction, inputCoin: TransactionObjectArgument, routers: Router[], amountOutLimit: BN, pythPriceIDs: Map<string, string>, partner?: string, deepbookv3DeepFee?: TransactionObjectArgument, packages?: Map<string, string>): Promise<TransactionObjectArgument>;
@@ -296,7 +307,7 @@ type AggregatorResponse = {
296
307
  msg: string;
297
308
  data: RouterData;
298
309
  };
299
- declare function getRouterResult(endpoint: string, params: FindRouterParams): Promise<RouterData | null>;
310
+ declare function getRouterResult(endpoint: string, apiKey: string, params: FindRouterParams): Promise<RouterData | null>;
300
311
  type DeepbookV3Config = {
301
312
  id: string;
302
313
  is_alternative_payment: boolean;
@@ -321,4 +332,4 @@ declare enum Env {
321
332
  Testnet = 1
322
333
  }
323
334
 
324
- export { AFSUI, AFTERMATH, AGGREGATOR_V2, AGGREGATOR_V2_EXTEND, ALPHAFI, AggregatorClient, type AggregatorResponse, BLUEFIN, BLUEMOVE, type BuildCoinResult, type BuildFastRouterSwapParams, type BuildFastRouterSwapParamsV2, type BuildRouterSwapParams, type BuildRouterSwapParamsV2, CETUS, CLOCK_ADDRESS, DEEPBOOKV2, DEEPBOOKV3, DEFAULT_ENDPOINT, type DeepbookV3Config, type DeepbookV3ConfigResponse, type Dex, Env, type ExtendedDetails, FLOWXV2, FLOWXV3, type FindRouterParams, HAEDAL, HAEDALPMM, KRIYA, KRIYAV3, METASTABLE, OBRIC, ONE, type Path, type PreSwapLpChangeParams, type Router, type RouterData, type RouterError, SCALLOP, SPRINGSUI, STEAMM, SUILEND, type SwapInPoolsParams, type SwapInPoolsResult, TEN_POW_NINE, TURBOS, TWO, U128, U64_MAX, U64_MAX_BN, VOLO, ZERO, buildInputCoin, checkInvalidSuiAddress, compareCoins, completionCoin, composeType, createTarget, dealWithFastRouterSwapParamsForMsafe, extractAddressFromType, extractStructTagFromType, findPythPriceIDs, fixSuiObjectId, getAggregatorV2ExtendPublishedAt, getAggregatorV2PublishedAt, getDeepbookV3Config, getRouterResult, isSortedSymbols, mintZeroCoin, normalizeCoinType, parseRouterResponse, patchFixSuiObjectId, printTransaction, processEndpoint, restituteMsafeFastRouterSwapParams };
335
+ export { AFSUI, AFTERMATH, AGGREGATOR_V2, AGGREGATOR_V2_EXTEND, ALPHAFI, AggregatorClient, type AggregatorClientParams, type AggregatorResponse, BLUEFIN, BLUEMOVE, type BuildCoinResult, type BuildFastRouterSwapParams, type BuildFastRouterSwapParamsV2, type BuildRouterSwapParams, type BuildRouterSwapParamsV2, CETUS, CLOCK_ADDRESS, DEEPBOOKV2, DEEPBOOKV3, DEFAULT_ENDPOINT, type DeepbookV3Config, type DeepbookV3ConfigResponse, type Dex, Env, type ExtendedDetails, FLOWXV2, FLOWXV3, type FindRouterParams, HAEDAL, HAEDALPMM, KRIYA, KRIYAV3, METASTABLE, OBRIC, ONE, type Path, type PreSwapLpChangeParams, type Router, type RouterData, type RouterError, SCALLOP, SPRINGSUI, STEAMM, SUILEND, type SwapInPoolsParams, type SwapInPoolsResult, TEN_POW_NINE, TURBOS, TWO, U128, U64_MAX, U64_MAX_BN, VOLO, ZERO, buildInputCoin, checkInvalidSuiAddress, compareCoins, completionCoin, composeType, createTarget, dealWithFastRouterSwapParamsForMsafe, extractAddressFromType, extractStructTagFromType, findPythPriceIDs, fixSuiObjectId, getAggregatorV2ExtendPublishedAt, getAggregatorV2PublishedAt, getDeepbookV3Config, getRouterResult, isSortedSymbols, mintZeroCoin, normalizeCoinType, parseRouterResponse, patchFixSuiObjectId, printTransaction, processEndpoint, restituteMsafeFastRouterSwapParams };
package/dist/index.js CHANGED
@@ -6514,19 +6514,28 @@ function isBuilderFastRouterSwapParams(params) {
6514
6514
  return Array.isArray(params.routers);
6515
6515
  }
6516
6516
  var _AggregatorClient = class _AggregatorClient {
6517
- constructor(endpoint, signer, client$1, env) {
6518
- this.endpoint = endpoint ? processEndpoint(endpoint) : DEFAULT_ENDPOINT;
6519
- this.client = client$1 || new client.SuiClient({ url: client.getFullnodeUrl("mainnet") });
6520
- this.signer = signer || "";
6521
- this.env = env || 0 /* Mainnet */;
6517
+ constructor(params) {
6518
+ var _a;
6519
+ this.endpoint = params.endpoint ? processEndpoint(params.endpoint) : DEFAULT_ENDPOINT;
6520
+ this.client = params.client || new client.SuiClient({ url: client.getFullnodeUrl("mainnet") });
6521
+ this.signer = params.signer || "";
6522
+ this.env = params.env || 0 /* Mainnet */;
6522
6523
  this.allCoins = /* @__PURE__ */ new Map();
6523
6524
  const config2 = _AggregatorClient.CONFIG[this.env];
6524
- this.pythConnections = config2.connections;
6525
+ this.pythConnections = this.newPythClients((_a = params.pythUrls) != null ? _a : []);
6525
6526
  this.pythClient = new pythSuiJs.SuiPythClient(
6526
6527
  this.client,
6527
6528
  config2.pythStateId,
6528
6529
  config2.wormholeStateId
6529
6530
  );
6531
+ this.apiKey = params.apiKey || "";
6532
+ }
6533
+ newPythClients(pythUrls) {
6534
+ if (!pythUrls.includes("https://hermes.pyth.network")) {
6535
+ pythUrls.push("https://hermes.pyth.network");
6536
+ }
6537
+ const connections = pythUrls.map((url) => new pythSuiJs.SuiPriceServiceConnection(url, { timeout: 3e3 }));
6538
+ return connections;
6530
6539
  }
6531
6540
  getCoins(coinType, refresh = true) {
6532
6541
  return __async(this, null, function* () {
@@ -6572,7 +6581,7 @@ var _AggregatorClient = class _AggregatorClient {
6572
6581
  }
6573
6582
  findRouters(params) {
6574
6583
  return __async(this, null, function* () {
6575
- return getRouterResult(this.endpoint, params);
6584
+ return getRouterResult(this.endpoint, this.apiKey, params);
6576
6585
  });
6577
6586
  }
6578
6587
  executeFlexibleInputSwap(txb, inputCoin, routers, amountOutLimit, pythPriceIDs, partner, deepbookv3DeepFee, packages) {
@@ -7104,7 +7113,7 @@ var _AggregatorClient = class _AggregatorClient {
7104
7113
  }
7105
7114
  if (priceUpdateData == null) {
7106
7115
  throw new Error(
7107
- `No pyth price seeds update data found: ${lastError == null ? void 0 : lastError.message}`
7116
+ `All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes. Detailed error: ${lastError == null ? void 0 : lastError.message}`
7108
7117
  );
7109
7118
  }
7110
7119
  let priceInfoObjectIds = [];
@@ -7115,7 +7124,7 @@ var _AggregatorClient = class _AggregatorClient {
7115
7124
  priceIDs
7116
7125
  );
7117
7126
  } catch (e) {
7118
- throw new Error(`Failed to update price feeds: ${e}`);
7127
+ throw new Error(`All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes in the pythUrls parameter when initializing AggregatorClient, for example: new AggregatorClient({ pythUrls: ["https://your-pyth-node-url"] }). Detailed error: ${e}`);
7119
7128
  }
7120
7129
  let priceInfoObjectIdsMap = /* @__PURE__ */ new Map();
7121
7130
  for (let i = 0; i < priceIDs.length; i++) {
@@ -7127,24 +7136,10 @@ var _AggregatorClient = class _AggregatorClient {
7127
7136
  };
7128
7137
  _AggregatorClient.CONFIG = {
7129
7138
  [1 /* Testnet */]: {
7130
- connections: [
7131
- new pythSuiJs.SuiPriceServiceConnection("https://hermes-beta.pyth.network")
7132
- ],
7133
7139
  wormholeStateId: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
7134
7140
  pythStateId: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c"
7135
7141
  },
7136
7142
  [0 /* Mainnet */]: {
7137
- connections: [
7138
- new pythSuiJs.SuiPriceServiceConnection(
7139
- "https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes",
7140
- {
7141
- timeout: 3e3
7142
- }
7143
- ),
7144
- new pythSuiJs.SuiPriceServiceConnection("https://hermes.pyth.network", {
7145
- timeout: 3e3
7146
- })
7147
- ],
7148
7143
  wormholeStateId: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
7149
7144
  pythStateId: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8"
7150
7145
  }
@@ -7324,14 +7319,14 @@ function processEndpoint(endpoint) {
7324
7319
  }
7325
7320
 
7326
7321
  // src/api.ts
7327
- var SDK_VERSION = 1000400;
7328
- function getRouterResult(endpoint, params) {
7322
+ var SDK_VERSION = 1000401;
7323
+ function getRouterResult(endpoint, apiKey, params) {
7329
7324
  return __async(this, null, function* () {
7330
7325
  let response;
7331
7326
  if (params.liquidityChanges && params.liquidityChanges.length > 0) {
7332
7327
  response = yield postRouterWithLiquidityChanges(endpoint, params);
7333
7328
  } else {
7334
- response = yield getRouter(endpoint, params);
7329
+ response = yield getRouter(endpoint, apiKey, params);
7335
7330
  }
7336
7331
  if (!response) {
7337
7332
  return null;
@@ -7389,7 +7384,7 @@ function getRouterResult(endpoint, params) {
7389
7384
  };
7390
7385
  });
7391
7386
  }
7392
- function getRouter(endpoint, params) {
7387
+ function getRouter(endpoint, apiKey, params) {
7393
7388
  return __async(this, null, function* () {
7394
7389
  try {
7395
7390
  const {
@@ -7423,6 +7418,9 @@ function getRouter(endpoint, params) {
7423
7418
  url += `&providers=${providers.join(",")}`;
7424
7419
  }
7425
7420
  }
7421
+ if (apiKey.length > 0) {
7422
+ url += `&apiKey=${apiKey}`;
7423
+ }
7426
7424
  url += `&v=${SDK_VERSION}`;
7427
7425
  const response = yield fetch(url);
7428
7426
  return response;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
2
2
  import { normalizeSuiObjectId, SUI_CLOCK_OBJECT_ID, SUI_FRAMEWORK_ADDRESS } from '@mysten/sui/utils';
3
3
  import { Transaction } from '@mysten/sui/transactions';
4
- import { SuiPriceServiceConnection, SuiPythClient } from '@pythnetwork/pyth-sui-js';
4
+ import { SuiPythClient, SuiPriceServiceConnection } from '@pythnetwork/pyth-sui-js';
5
5
 
6
6
  var __create = Object.create;
7
7
  var __defProp = Object.defineProperty;
@@ -6512,19 +6512,28 @@ function isBuilderFastRouterSwapParams(params) {
6512
6512
  return Array.isArray(params.routers);
6513
6513
  }
6514
6514
  var _AggregatorClient = class _AggregatorClient {
6515
- constructor(endpoint, signer, client, env) {
6516
- this.endpoint = endpoint ? processEndpoint(endpoint) : DEFAULT_ENDPOINT;
6517
- this.client = client || new SuiClient({ url: getFullnodeUrl("mainnet") });
6518
- this.signer = signer || "";
6519
- this.env = env || 0 /* Mainnet */;
6515
+ constructor(params) {
6516
+ var _a;
6517
+ this.endpoint = params.endpoint ? processEndpoint(params.endpoint) : DEFAULT_ENDPOINT;
6518
+ this.client = params.client || new SuiClient({ url: getFullnodeUrl("mainnet") });
6519
+ this.signer = params.signer || "";
6520
+ this.env = params.env || 0 /* Mainnet */;
6520
6521
  this.allCoins = /* @__PURE__ */ new Map();
6521
6522
  const config2 = _AggregatorClient.CONFIG[this.env];
6522
- this.pythConnections = config2.connections;
6523
+ this.pythConnections = this.newPythClients((_a = params.pythUrls) != null ? _a : []);
6523
6524
  this.pythClient = new SuiPythClient(
6524
6525
  this.client,
6525
6526
  config2.pythStateId,
6526
6527
  config2.wormholeStateId
6527
6528
  );
6529
+ this.apiKey = params.apiKey || "";
6530
+ }
6531
+ newPythClients(pythUrls) {
6532
+ if (!pythUrls.includes("https://hermes.pyth.network")) {
6533
+ pythUrls.push("https://hermes.pyth.network");
6534
+ }
6535
+ const connections = pythUrls.map((url) => new SuiPriceServiceConnection(url, { timeout: 3e3 }));
6536
+ return connections;
6528
6537
  }
6529
6538
  getCoins(coinType, refresh = true) {
6530
6539
  return __async(this, null, function* () {
@@ -6570,7 +6579,7 @@ var _AggregatorClient = class _AggregatorClient {
6570
6579
  }
6571
6580
  findRouters(params) {
6572
6581
  return __async(this, null, function* () {
6573
- return getRouterResult(this.endpoint, params);
6582
+ return getRouterResult(this.endpoint, this.apiKey, params);
6574
6583
  });
6575
6584
  }
6576
6585
  executeFlexibleInputSwap(txb, inputCoin, routers, amountOutLimit, pythPriceIDs, partner, deepbookv3DeepFee, packages) {
@@ -7102,7 +7111,7 @@ var _AggregatorClient = class _AggregatorClient {
7102
7111
  }
7103
7112
  if (priceUpdateData == null) {
7104
7113
  throw new Error(
7105
- `No pyth price seeds update data found: ${lastError == null ? void 0 : lastError.message}`
7114
+ `All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes. Detailed error: ${lastError == null ? void 0 : lastError.message}`
7106
7115
  );
7107
7116
  }
7108
7117
  let priceInfoObjectIds = [];
@@ -7113,7 +7122,7 @@ var _AggregatorClient = class _AggregatorClient {
7113
7122
  priceIDs
7114
7123
  );
7115
7124
  } catch (e) {
7116
- throw new Error(`Failed to update price feeds: ${e}`);
7125
+ throw new Error(`All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes in the pythUrls parameter when initializing AggregatorClient, for example: new AggregatorClient({ pythUrls: ["https://your-pyth-node-url"] }). Detailed error: ${e}`);
7117
7126
  }
7118
7127
  let priceInfoObjectIdsMap = /* @__PURE__ */ new Map();
7119
7128
  for (let i = 0; i < priceIDs.length; i++) {
@@ -7125,24 +7134,10 @@ var _AggregatorClient = class _AggregatorClient {
7125
7134
  };
7126
7135
  _AggregatorClient.CONFIG = {
7127
7136
  [1 /* Testnet */]: {
7128
- connections: [
7129
- new SuiPriceServiceConnection("https://hermes-beta.pyth.network")
7130
- ],
7131
7137
  wormholeStateId: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
7132
7138
  pythStateId: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c"
7133
7139
  },
7134
7140
  [0 /* Mainnet */]: {
7135
- connections: [
7136
- new SuiPriceServiceConnection(
7137
- "https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes",
7138
- {
7139
- timeout: 3e3
7140
- }
7141
- ),
7142
- new SuiPriceServiceConnection("https://hermes.pyth.network", {
7143
- timeout: 3e3
7144
- })
7145
- ],
7146
7141
  wormholeStateId: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
7147
7142
  pythStateId: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8"
7148
7143
  }
@@ -7322,14 +7317,14 @@ function processEndpoint(endpoint) {
7322
7317
  }
7323
7318
 
7324
7319
  // src/api.ts
7325
- var SDK_VERSION = 1000400;
7326
- function getRouterResult(endpoint, params) {
7320
+ var SDK_VERSION = 1000401;
7321
+ function getRouterResult(endpoint, apiKey, params) {
7327
7322
  return __async(this, null, function* () {
7328
7323
  let response;
7329
7324
  if (params.liquidityChanges && params.liquidityChanges.length > 0) {
7330
7325
  response = yield postRouterWithLiquidityChanges(endpoint, params);
7331
7326
  } else {
7332
- response = yield getRouter(endpoint, params);
7327
+ response = yield getRouter(endpoint, apiKey, params);
7333
7328
  }
7334
7329
  if (!response) {
7335
7330
  return null;
@@ -7387,7 +7382,7 @@ function getRouterResult(endpoint, params) {
7387
7382
  };
7388
7383
  });
7389
7384
  }
7390
- function getRouter(endpoint, params) {
7385
+ function getRouter(endpoint, apiKey, params) {
7391
7386
  return __async(this, null, function* () {
7392
7387
  try {
7393
7388
  const {
@@ -7421,6 +7416,9 @@ function getRouter(endpoint, params) {
7421
7416
  url += `&providers=${providers.join(",")}`;
7422
7417
  }
7423
7418
  }
7419
+ if (apiKey.length > 0) {
7420
+ url += `&apiKey=${apiKey}`;
7421
+ }
7424
7422
  url += `&v=${SDK_VERSION}`;
7425
7423
  const response = yield fetch(url);
7426
7424
  return response;
package/dist/src/api.d.ts CHANGED
@@ -83,7 +83,7 @@ export type AggregatorResponse = {
83
83
  msg: string;
84
84
  data: RouterData;
85
85
  };
86
- export declare function getRouterResult(endpoint: string, params: FindRouterParams): Promise<RouterData | null>;
86
+ export declare function getRouterResult(endpoint: string, apiKey: string, params: FindRouterParams): Promise<RouterData | null>;
87
87
  export type DeepbookV3Config = {
88
88
  id: string;
89
89
  is_alternative_payment: boolean;
@@ -4,6 +4,7 @@ import { Signer } from "@mysten/sui/cryptography";
4
4
  import BN from "bn.js";
5
5
  import { Dex, Env, FindRouterParams, Router, RouterData, DeepbookV3Config } from ".";
6
6
  import { CoinAsset } from "./types/sui";
7
+ import { SuiPriceServiceConnection } from "@pythnetwork/pyth-sui-js";
7
8
  export declare const CETUS = "CETUS";
8
9
  export declare const DEEPBOOKV2 = "DEEPBOOK";
9
10
  export declare const KRIYA = "KRIYA";
@@ -72,16 +73,26 @@ export interface SwapInPoolsResult {
72
73
  isExceed: boolean;
73
74
  routeData?: RouterData;
74
75
  }
76
+ export type AggregatorClientParams = {
77
+ endpoint?: string;
78
+ signer?: string;
79
+ client?: SuiClient;
80
+ env?: Env;
81
+ pythUrls?: string[];
82
+ apiKey?: string;
83
+ };
75
84
  export declare class AggregatorClient {
76
85
  endpoint: string;
77
86
  signer: string;
78
87
  client: SuiClient;
79
88
  env: Env;
89
+ apiKey: string;
80
90
  private allCoins;
81
91
  private pythConnections;
82
92
  private pythClient;
83
93
  private static readonly CONFIG;
84
- constructor(endpoint?: string, signer?: string, client?: SuiClient, env?: Env);
94
+ constructor(params: AggregatorClientParams);
95
+ newPythClients(pythUrls: string[]): SuiPriceServiceConnection[];
85
96
  getCoins(coinType: string, refresh?: boolean): Promise<CoinAsset[]>;
86
97
  findRouters(params: FindRouterParams): Promise<RouterData | null>;
87
98
  executeFlexibleInputSwap(txb: Transaction, inputCoin: TransactionObjectArgument, routers: Router[], amountOutLimit: BN, pythPriceIDs: Map<string, string>, partner?: string, deepbookv3DeepFee?: TransactionObjectArgument, packages?: Map<string, string>): Promise<TransactionObjectArgument>;
@@ -0,0 +1,2 @@
1
+ import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
2
+ export declare function buildTestAccount(): Ed25519Keypair;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cetusprotocol/aggregator-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "sideEffects": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/api.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./errors"
9
9
  import { parseRouterResponse } from "./client"
10
10
 
11
- const SDK_VERSION = 1000400
11
+ const SDK_VERSION = 1000401
12
12
 
13
13
  export interface FindRouterParams {
14
14
  from: string
@@ -110,13 +110,14 @@ export type AggregatorResponse = {
110
110
 
111
111
  export async function getRouterResult(
112
112
  endpoint: string,
113
+ apiKey: string,
113
114
  params: FindRouterParams
114
115
  ): Promise<RouterData | null> {
115
116
  let response
116
117
  if (params.liquidityChanges && params.liquidityChanges.length > 0) {
117
118
  response = await postRouterWithLiquidityChanges(endpoint, params)
118
119
  } else {
119
- response = await getRouter(endpoint, params)
120
+ response = await getRouter(endpoint, apiKey, params)
120
121
  }
121
122
 
122
123
  if (!response) {
@@ -179,7 +180,7 @@ export async function getRouterResult(
179
180
  }
180
181
  }
181
182
 
182
- async function getRouter(endpoint: string, params: FindRouterParams) {
183
+ async function getRouter(endpoint: string, apiKey: string, params: FindRouterParams) {
183
184
  try {
184
185
  const {
185
186
  from,
@@ -219,6 +220,10 @@ async function getRouter(endpoint: string, params: FindRouterParams) {
219
220
  }
220
221
  }
221
222
 
223
+ if (apiKey.length > 0) {
224
+ url += `&apiKey=${apiKey}`
225
+ }
226
+
222
227
  // set newest sdk version
223
228
  url += `&v=${SDK_VERSION}`
224
229
 
package/src/client.ts CHANGED
@@ -126,7 +126,6 @@ export interface SwapInPoolsParams {
126
126
  }
127
127
 
128
128
  interface PythConfig {
129
- connections: SuiPriceServiceConnection[]
130
129
  wormholeStateId: string
131
130
  pythStateId: string
132
131
  }
@@ -148,11 +147,21 @@ function isBuilderFastRouterSwapParams(
148
147
  return Array.isArray((params as BuildFastRouterSwapParams).routers)
149
148
  }
150
149
 
150
+ export type AggregatorClientParams = {
151
+ endpoint?: string
152
+ signer?: string
153
+ client?: SuiClient
154
+ env?: Env
155
+ pythUrls?: string[]
156
+ apiKey?: string
157
+ }
158
+
151
159
  export class AggregatorClient {
152
160
  public endpoint: string
153
161
  public signer: string
154
162
  public client: SuiClient
155
163
  public env: Env
164
+ public apiKey: string
156
165
  private allCoins: Map<string, CoinAsset[]>
157
166
 
158
167
  private pythConnections: SuiPriceServiceConnection[]
@@ -160,26 +169,12 @@ export class AggregatorClient {
160
169
 
161
170
  private static readonly CONFIG: Record<Env, PythConfig> = {
162
171
  [Env.Testnet]: {
163
- connections: [
164
- new SuiPriceServiceConnection("https://hermes-beta.pyth.network"),
165
- ],
166
172
  wormholeStateId:
167
173
  "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
168
174
  pythStateId:
169
175
  "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
170
176
  },
171
177
  [Env.Mainnet]: {
172
- connections: [
173
- new SuiPriceServiceConnection(
174
- "https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes",
175
- {
176
- timeout: 3000,
177
- }
178
- ),
179
- new SuiPriceServiceConnection("https://hermes.pyth.network", {
180
- timeout: 3000,
181
- }),
182
- ],
183
178
  wormholeStateId:
184
179
  "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
185
180
  pythStateId:
@@ -187,25 +182,30 @@ export class AggregatorClient {
187
182
  },
188
183
  }
189
184
 
190
- constructor(
191
- endpoint?: string,
192
- signer?: string,
193
- client?: SuiClient,
194
- env?: Env
195
- ) {
196
- this.endpoint = endpoint ? processEndpoint(endpoint) : DEFAULT_ENDPOINT
197
- this.client = client || new SuiClient({ url: getFullnodeUrl("mainnet") })
198
- this.signer = signer || ""
199
- this.env = env || Env.Mainnet
185
+ constructor(params: AggregatorClientParams) {
186
+ this.endpoint = params.endpoint ? processEndpoint(params.endpoint) : DEFAULT_ENDPOINT
187
+ this.client = params.client || new SuiClient({ url: getFullnodeUrl("mainnet") })
188
+ this.signer = params.signer || ""
189
+ this.env = params.env || Env.Mainnet
200
190
  this.allCoins = new Map<string, CoinAsset[]>()
201
191
 
202
192
  const config = AggregatorClient.CONFIG[this.env]
203
- this.pythConnections = config.connections
193
+ this.pythConnections = this.newPythClients(params.pythUrls ?? [])
204
194
  this.pythClient = new SuiPythClient(
205
195
  this.client,
206
196
  config.pythStateId,
207
197
  config.wormholeStateId
208
198
  )
199
+ this.apiKey = params.apiKey || ""
200
+ }
201
+
202
+ newPythClients(pythUrls: string[]) {
203
+ if (!pythUrls.includes("https://hermes.pyth.network")) {
204
+ pythUrls.push("https://hermes.pyth.network")
205
+ }
206
+
207
+ const connections = pythUrls.map(url => new SuiPriceServiceConnection(url, { timeout: 3000 }))
208
+ return connections
209
209
  }
210
210
 
211
211
  async getCoins(
@@ -257,7 +257,7 @@ export class AggregatorClient {
257
257
  }
258
258
 
259
259
  async findRouters(params: FindRouterParams): Promise<RouterData | null> {
260
- return getRouterResult(this.endpoint, params)
260
+ return getRouterResult(this.endpoint, this.apiKey, params)
261
261
  }
262
262
 
263
263
  async executeFlexibleInputSwap(
@@ -916,7 +916,7 @@ export class AggregatorClient {
916
916
 
917
917
  if (priceUpdateData == null) {
918
918
  throw new Error(
919
- `No pyth price seeds update data found: ${lastError?.message}`
919
+ `All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes. Detailed error: ${lastError?.message}`
920
920
  )
921
921
  }
922
922
 
@@ -928,7 +928,7 @@ export class AggregatorClient {
928
928
  priceIDs
929
929
  )
930
930
  } catch (e) {
931
- throw new Error(`Failed to update price feeds: ${e}`)
931
+ throw new Error(`All Pyth price nodes are unavailable. Cannot fetch price data. Please switch to or add new available Pyth nodes in the pythUrls parameter when initializing AggregatorClient, for example: new AggregatorClient({ pythUrls: ["https://your-pyth-node-url"] }). Detailed error: ${e}`)
932
932
  }
933
933
 
934
934
  let priceInfoObjectIdsMap = new Map<string, string>()
@@ -0,0 +1,132 @@
1
+ import { describe, test } from "@jest/globals"
2
+ import dotenv from "dotenv"
3
+ import { AggregatorClient } from "~/client"
4
+ import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"
5
+ import { printTransaction } from "~/utils/transaction"
6
+ import BN from "bn.js"
7
+ import { fromB64 } from "@mysten/sui/utils"
8
+ import { SuiClient } from "@mysten/sui/client"
9
+ import { Env } from "~/index"
10
+ import { Transaction } from "@mysten/sui/transactions"
11
+
12
+ dotenv.config()
13
+
14
+ export function buildTestAccount(): Ed25519Keypair {
15
+ const mnemonics = process.env.SUI_WALLET_MNEMONICS || ""
16
+ const testAccountObject = Ed25519Keypair.deriveKeypair(mnemonics)
17
+ return testAccountObject
18
+ }
19
+
20
+ describe("Test scallop provider", () => {
21
+ let client: AggregatorClient
22
+ let keypair: Ed25519Keypair
23
+
24
+ const T_SUI = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"
25
+ const LSDT_SUI = "0xd1b72982e40348d069bb1ff701e634c117bb5f741f44dff91e472d3b01461e55::stsui::STSUI"
26
+ const T_USDC = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
27
+
28
+ beforeAll(() => {
29
+ const fullNodeURL = process.env.SUI_RPC!
30
+ const aggregatorURL = process.env.CETUS_AGGREGATOR!
31
+ const secret = process.env.SUI_WALLET_SECRET!
32
+
33
+ if (secret) {
34
+ keypair = Ed25519Keypair.fromSecretKey(fromB64(secret).slice(1, 33))
35
+ } else {
36
+ keypair = buildTestAccount()
37
+ }
38
+
39
+ const wallet =
40
+ "0x4dde66fc52ec16d5e6c0fbd0968580cdf0d962cbb970591ec1e47617b9265617"
41
+
42
+ console.log("wallet: ", wallet)
43
+
44
+ const endpoint = aggregatorURL
45
+
46
+ const suiClient = new SuiClient({
47
+ url: fullNodeURL,
48
+ })
49
+
50
+ client = new AggregatorClient({
51
+ endpoint,
52
+ signer: wallet,
53
+ client: suiClient,
54
+ env: Env.Mainnet,
55
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
56
+ apiKey: "8MJDUzLDPJxCgbc7I0bHXSg994mVfh8NRMqV6hcQ",
57
+ })
58
+ })
59
+
60
+ test("Find Routers", async () => {
61
+ const amounts = ["1000", "1000000", "100000000", "5000000000", "1000000000000000000000000000"]
62
+
63
+ while (true) {
64
+ const res = await client.findRouters({
65
+ from: LSDT_SUI,
66
+ target: T_USDC,
67
+ amount: new BN("1000000000000"),
68
+ byAmountIn: true,
69
+ depth: 3,
70
+ splitCount: 1,
71
+ providers: ["ALPHAFI"],
72
+ })
73
+
74
+ if (res != null) {
75
+ console.log(JSON.stringify(res, null, 2))
76
+ }
77
+ console.log("amount in", res?.amountIn.toString())
78
+ console.log("amount out", res?.amountOut.toString())
79
+ }
80
+ }, 6000000)
81
+
82
+ test("Build Router TX", async () => {
83
+ const amount = "100000"
84
+
85
+ const res = await client.findRouters({
86
+ from: LSDT_SUI,
87
+ target: T_SUI,
88
+ amount: new BN(amount),
89
+ byAmountIn: true,
90
+ depth: 3,
91
+ splitCount: 2,
92
+ providers: ["ALPHAFI", "CETUS"],
93
+ })
94
+
95
+ console.log("amount in", res?.amountIn.toString())
96
+ console.log("amount out", res?.amountOut.toString())
97
+
98
+ const txb = new Transaction()
99
+
100
+ if (res != null) {
101
+ console.log(JSON.stringify(res, null, 2))
102
+ await client.fastRouterSwap({
103
+ routers: res,
104
+ txb,
105
+ slippage: 0.01,
106
+ refreshAllCoins: true,
107
+ payDeepFeeAmount: 0,
108
+ })
109
+
110
+ txb.setSender(client.signer)
111
+ const buildTxb = await txb.build({ client: client.client })
112
+ // const buildTxb = await txb.getData()
113
+
114
+ console.log("buildTxb", buildTxb)
115
+
116
+ printTransaction(txb)
117
+
118
+ let result = await client.devInspectTransactionBlock(txb)
119
+ console.log("🚀 ~ file: router.test.ts:180 ~ test ~ result:", result)
120
+ for (const event of result.events) {
121
+ console.log("event", JSON.stringify(event, null, 2))
122
+ }
123
+
124
+ if (result.effects.status.status === "success") {
125
+ const result = await client.signAndExecuteTransaction(txb, keypair)
126
+ console.log("result", result)
127
+ } else {
128
+ console.log("result", result)
129
+ }
130
+ }
131
+ }, 600000)
132
+ })
@@ -57,7 +57,13 @@ describe("Test metastable provider", () => {
57
57
  const suiClient = new SuiClient({
58
58
  url: fullNodeURL,
59
59
  })
60
- client = new AggregatorClient(endpoint, wallet, suiClient, Env.Mainnet)
60
+ client = new AggregatorClient({
61
+ endpoint,
62
+ signer: wallet,
63
+ client: suiClient,
64
+ env: Env.Mainnet,
65
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
66
+ })
61
67
  })
62
68
 
63
69
  test("Find Routers --> SUI -> SUPER_SUI", async () => {
@@ -46,7 +46,13 @@ describe("Test obric provider", () => {
46
46
  const suiClient = new SuiClient({
47
47
  url: fullNodeURL,
48
48
  })
49
- client = new AggregatorClient(endpoint, wallet, suiClient, Env.Mainnet)
49
+ client = new AggregatorClient({
50
+ endpoint,
51
+ signer: wallet,
52
+ client: suiClient,
53
+ env: Env.Mainnet,
54
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
55
+ })
50
56
  })
51
57
 
52
58
  test("Find Routers --> SUI -> USDC, locked", async () => {
@@ -50,7 +50,13 @@ describe("Test scallop provider", () => {
50
50
  url: fullNodeURL,
51
51
  })
52
52
 
53
- client = new AggregatorClient(endpoint, wallet, suiClient, Env.Mainnet)
53
+ client = new AggregatorClient({
54
+ endpoint,
55
+ signer: wallet,
56
+ client: suiClient,
57
+ env: Env.Mainnet,
58
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
59
+ })
54
60
  })
55
61
 
56
62
  test("Find Routers", async () => {
@@ -47,7 +47,13 @@ describe("Test steammfe module", () => {
47
47
  url: fullNodeURL,
48
48
  })
49
49
 
50
- client = new AggregatorClient(endpoint, wallet, suiClient, Env.Mainnet)
50
+ client = new AggregatorClient({
51
+ endpoint,
52
+ signer: wallet,
53
+ client: suiClient,
54
+ env: Env.Mainnet,
55
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
56
+ })
51
57
  })
52
58
 
53
59
  test("Find Routers", async () => {
@@ -43,7 +43,13 @@ describe("router module", () => {
43
43
  url: fullNodeURL,
44
44
  })
45
45
 
46
- client = new AggregatorClient(endpoint, wallet, suiClient, Env.Mainnet)
46
+ client = new AggregatorClient({
47
+ endpoint,
48
+ signer: wallet,
49
+ client: suiClient,
50
+ env: Env.Mainnet,
51
+ pythUrls: ["https://cetus-pythnet-a648.mainnet.pythnet.rpcpool.com/219cf7a8-6d75-432d-a648-d487a6dd5dc3/hermes"],
52
+ })
47
53
  })
48
54
 
49
55
  test("Get coins", () => {