@suilend/sdk 1.1.91 → 1.1.93

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/client.js CHANGED
@@ -24,6 +24,7 @@ const functions_2 = require("./_generated/suilend/lending-market-registry/functi
24
24
  const structs_3 = require("./_generated/suilend/obligation/structs");
25
25
  const functions_3 = require("./_generated/suilend/rate-limiter/functions");
26
26
  const functions_4 = require("./_generated/suilend/reserve-config/functions");
27
+ const pyth_1 = require("./lib/pyth");
27
28
  const types_1 = require("./lib/types");
28
29
  const SUI_COINTYPE = "0x2::sui::SUI";
29
30
  const NORMALIZED_SUI_COINTYPE = (0, utils_1.normalizeStructTag)(SUI_COINTYPE);
@@ -74,7 +75,10 @@ class SuilendClient {
74
75
  this.lendingMarket = lendingMarket;
75
76
  this.client = client;
76
77
  this.pythClient = new pyth_sui_js_1.SuiPythClient(client, PYTH_STATE_ID, WORMHOLE_STATE_ID);
77
- this.pythConnection = new pyth_sui_js_1.SuiPriceServiceConnection("https://hermes.pyth.network", { timeout: 30 * 1000 });
78
+ const pythEndpoint = pyth_1.PRIMARY_PYTH_ENDPOINT; // TODO: Use getWorkingPythEndpoint
79
+ this.pythConnection = new pyth_sui_js_1.SuiPriceServiceConnection(pythEndpoint, {
80
+ timeout: 30 * 1000,
81
+ });
78
82
  }
79
83
  static initialize(lendingMarketId, lendingMarketType, client, logPackageId) {
80
84
  return __awaiter(this, void 0, void 0, function* () {
@@ -8,7 +8,7 @@ export declare const RESERVES_CUSTOM_ORDER: Record<string, string[]>;
8
8
  export declare const NORMALIZED_MAYA_COINTYPE: string;
9
9
  export declare const NORMALIZED_mPOINTS_COINTYPE: string;
10
10
  export declare const NORMALIZED_TREATS_COINTYPE: string;
11
- export declare const initializeSuilend: (suiClient: SuiClient, suilendClient: SuilendClient, lendingMarketMetadata?: LendingMarketMetadata) => Promise<{
11
+ export declare const initializeSuilend: (suiClient: SuiClient, suilendClient: SuilendClient, lendingMarketMetadata?: LendingMarketMetadata, fallbackPythEndpoint?: string) => Promise<{
12
12
  lendingMarket: {
13
13
  version: bigint;
14
14
  reserves: {
package/lib/initialize.js CHANGED
@@ -54,6 +54,7 @@ const client_1 = require("../client");
54
54
  const parsers_1 = require("../parsers");
55
55
  const simulate = __importStar(require("../utils/simulate"));
56
56
  const constants_1 = require("./constants");
57
+ const pyth_1 = require("./pyth");
57
58
  const strategyOwnerCap_1 = require("./strategyOwnerCap");
58
59
  exports.RESERVES_CUSTOM_ORDER = {
59
60
  [client_1.LENDING_MARKET_ID]: [
@@ -101,14 +102,18 @@ exports.RESERVES_CUSTOM_ORDER = {
101
102
  sui_fe_1.NORMALIZED_HIPPO_COINTYPE,
102
103
  sui_fe_1.NORMALIZED_FUD_COINTYPE,
103
104
  ],
104
- "0x0d3a7f758d19d11e8526f66cca43403a99da16862c570c43efe0f8c4a500f7f2": [
105
- sui_fe_1.NORMALIZED_sdeUSD_COINTYPE,
106
- sui_fe_1.NORMALIZED_USDC_COINTYPE,
107
- ],
108
105
  "0x8a8d8e138a28de1c637d0b0955e621b017da7010de388db5a18493eca99c5e82": [
109
106
  sui_fe_1.NORMALIZED_XAUm_COINTYPE,
110
107
  sui_fe_1.NORMALIZED_USDC_COINTYPE,
111
108
  ],
109
+ "0xc1549fd5db74c3aad37a260c9fd251d93d6f2f3ccfacc277398a57718c275a17": [
110
+ sui_fe_1.NORMALIZED_SEND_COINTYPE,
111
+ sui_fe_1.NORMALIZED_USDC_COINTYPE,
112
+ ],
113
+ "0x0d3a7f758d19d11e8526f66cca43403a99da16862c570c43efe0f8c4a500f7f2": [
114
+ sui_fe_1.NORMALIZED_sdeUSD_COINTYPE,
115
+ sui_fe_1.NORMALIZED_USDC_COINTYPE,
116
+ ],
112
117
  };
113
118
  const MAYA_COINTYPE = "0x3bf0aeb7b9698b18ec7937290a5701088fcd5d43ad11a2564b074d022a6d71ec::maya::MAYA";
114
119
  const mPOINTS_COINTYPE = "0x7bae0b3b7b6c3da899fe3f4af95b7110633499c02b8c6945110d799d99deaa68::mpoints::MPOINTS";
@@ -116,7 +121,7 @@ const TREATS_COINTYPE = "0x0dadb7fa2771c2952f96161fc1f0c105d1f22d53926b9ff2498a8
116
121
  exports.NORMALIZED_MAYA_COINTYPE = (0, utils_1.normalizeStructTag)(MAYA_COINTYPE);
117
122
  exports.NORMALIZED_mPOINTS_COINTYPE = (0, utils_1.normalizeStructTag)(mPOINTS_COINTYPE);
118
123
  exports.NORMALIZED_TREATS_COINTYPE = (0, utils_1.normalizeStructTag)(TREATS_COINTYPE);
119
- const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata) => __awaiter(void 0, void 0, void 0, function* () {
124
+ const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata, fallbackPythEndpoint) => __awaiter(void 0, void 0, void 0, function* () {
120
125
  const nowMs = Date.now();
121
126
  const nowS = Math.floor(nowMs / 1000);
122
127
  const interestCompoundedRawReserves = suilendClient.lendingMarket.reserves.map((r) => simulate.compoundReserveInterest(r, nowS));
@@ -131,10 +136,13 @@ const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata) => _
131
136
  reservesWithoutTemporaryPythPriceFeeds.push(reserve);
132
137
  }
133
138
  }
139
+ // Get a working Pyth endpoint (try primary, fallback to fallbackPythEndpoint if provided)
140
+ const pythEndpoint = yield (0, pyth_1.getWorkingPythEndpoint)(fallbackPythEndpoint);
141
+ const pythConnection = new pyth_sui_js_1.SuiPriceServiceConnection(pythEndpoint, {
142
+ timeout: 30 * 1000,
143
+ });
134
144
  const [refreshedReservesWithoutTemporaryPythPriceFeeds] = yield Promise.all([
135
- simulate.refreshReservePrice(reservesWithoutTemporaryPythPriceFeeds, new pyth_sui_js_1.SuiPriceServiceConnection("https://hermes.pyth.network", {
136
- timeout: 30 * 1000,
137
- })),
145
+ simulate.refreshReservePrice(reservesWithoutTemporaryPythPriceFeeds, pythConnection),
138
146
  Promise.all(reservesWithTemporaryPythPriceFeeds.map((reserve) => (() => __awaiter(void 0, void 0, void 0, function* () {
139
147
  let cachedUsdPrice;
140
148
  try {
@@ -51,10 +51,10 @@ export declare const getDedupedPerDayRewards: (filteredRewards: RewardSummary[])
51
51
  export declare const getRewardsAprPercent: (side: Side, filteredRewards: RewardSummary[]) => BigNumber;
52
52
  export declare const getStakingYieldAprPercent: (side: Side, coinType: string, lstStatsMap: Record<string, {
53
53
  aprPercent: BigNumber;
54
- }>) => BigNumber | undefined;
54
+ }>, elixirSdeUsdAprPercent: BigNumber | undefined) => BigNumber | undefined;
55
55
  export declare const getTotalAprPercent: (side: Side, aprPercent: BigNumber, filteredRewards: RewardSummary[], stakingYieldAprPercent?: BigNumber) => BigNumber;
56
56
  export declare const getNetAprPercent: (obligation: ParsedObligation, rewardMap: RewardMap, lstStatsMap: Record<string, {
57
57
  aprPercent: BigNumber;
58
- }>, noShares?: boolean) => BigNumber;
58
+ }>, elixirSdeUsdAprPercent: BigNumber | undefined, noShares?: boolean) => BigNumber;
59
59
  export declare const getRewardsMap: (obligation: ParsedObligation | undefined, rewardMap: RewardMap, coinMetadataMap: Record<string, CoinMetadata>) => RewardsMap;
60
60
  export {};
@@ -145,17 +145,24 @@ const getDedupedPerDayRewards = (filteredRewards) => {
145
145
  exports.getDedupedPerDayRewards = getDedupedPerDayRewards;
146
146
  const getRewardsAprPercent = (side, filteredRewards) => (0, exports.getDedupedAprRewards)(filteredRewards).reduce((acc, reward) => acc.plus(reward.stats.aprPercent.times(side === types_1.Side.DEPOSIT ? 1 : -1)), new bignumber_js_1.default(0));
147
147
  exports.getRewardsAprPercent = getRewardsAprPercent;
148
- const getStakingYieldAprPercent = (side, coinType, lstStatsMap) => { var _a; return (side === types_1.Side.DEPOSIT ? (_a = lstStatsMap[coinType]) === null || _a === void 0 ? void 0 : _a.aprPercent : undefined); };
148
+ const getStakingYieldAprPercent = (side, coinType, lstStatsMap, elixirSdeUsdAprPercent) => {
149
+ var _a;
150
+ return side === types_1.Side.DEPOSIT
151
+ ? coinType === sui_fe_1.NORMALIZED_sdeUSD_COINTYPE
152
+ ? elixirSdeUsdAprPercent
153
+ : (_a = lstStatsMap[coinType]) === null || _a === void 0 ? void 0 : _a.aprPercent
154
+ : undefined;
155
+ };
149
156
  exports.getStakingYieldAprPercent = getStakingYieldAprPercent;
150
157
  const getTotalAprPercent = (side, aprPercent, filteredRewards, stakingYieldAprPercent) => aprPercent
151
158
  .plus((0, exports.getRewardsAprPercent)(side, filteredRewards))
152
159
  .plus(stakingYieldAprPercent !== null && stakingYieldAprPercent !== void 0 ? stakingYieldAprPercent : 0);
153
160
  exports.getTotalAprPercent = getTotalAprPercent;
154
- const getNetAprPercent = (obligation, rewardMap, lstStatsMap, noShares) => {
161
+ const getNetAprPercent = (obligation, rewardMap, lstStatsMap, elixirSdeUsdAprPercent, noShares) => {
155
162
  const weightedDepositedAmountUsd_aprPercent = obligation.deposits.reduce((acc, deposit) => {
156
163
  var _a;
157
164
  const weightedDepositedAmountUsd_baseAprPercent = deposit.reserve.depositAprPercent.times(deposit.depositedAmountUsd);
158
- const weightedDepositedAmountUsd_stakingYieldAprPercent = new bignumber_js_1.default((_a = (0, exports.getStakingYieldAprPercent)(types_1.Side.DEPOSIT, deposit.reserve.coinType, lstStatsMap)) !== null && _a !== void 0 ? _a : 0).times(deposit.depositedAmountUsd);
165
+ const weightedDepositedAmountUsd_stakingYieldAprPercent = new bignumber_js_1.default((_a = (0, exports.getStakingYieldAprPercent)(types_1.Side.DEPOSIT, deposit.reserve.coinType, lstStatsMap, elixirSdeUsdAprPercent)) !== null && _a !== void 0 ? _a : 0).times(deposit.depositedAmountUsd);
159
166
  const weightedDepositedAmountUsd_rewardsAprPercent = (0, exports.getRewardsAprPercent)(types_1.Side.DEPOSIT, (0, exports.getFilteredRewards)(rewardMap[deposit.reserve.coinType].deposit)).times(!noShares
160
167
  ? getDepositShareUsd(deposit.reserve, new bignumber_js_1.default(deposit.userRewardManager.share.toString()))
161
168
  : deposit.depositedAmountUsd);
package/lib/pyth.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export declare const PRIMARY_PYTH_ENDPOINT = "https://hermes.pyth.network";
2
+ /**
3
+ * Tests if the primary Pyth connection endpoint is working by checking the /live endpoint
4
+ * @returns true if the connection is working, false otherwise
5
+ */
6
+ export declare const testPrimaryPythConnection: () => Promise<boolean>;
7
+ /**
8
+ * Gets a working Pyth connection endpoint, trying primary first, then fallback if provided
9
+ * @param fallbackPythEndpoint Optional fallback endpoint
10
+ * @returns The endpoint URL that is working, or the primary endpoint if fallback fails
11
+ */
12
+ export declare const getWorkingPythEndpoint: (fallbackPythEndpoint?: string) => Promise<string>;
package/lib/pyth.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getWorkingPythEndpoint = exports.testPrimaryPythConnection = exports.PRIMARY_PYTH_ENDPOINT = void 0;
13
+ exports.PRIMARY_PYTH_ENDPOINT = "https://hermes.pyth.network";
14
+ /**
15
+ * Tests if the primary Pyth connection endpoint is working by checking the /live endpoint
16
+ * @returns true if the connection is working, false otherwise
17
+ */
18
+ const testPrimaryPythConnection = () => __awaiter(void 0, void 0, void 0, function* () {
19
+ try {
20
+ const res = yield fetch(`${exports.PRIMARY_PYTH_ENDPOINT}/live`, {
21
+ signal: AbortSignal.timeout(5 * 1000), // 5 second timeout
22
+ });
23
+ return res.ok;
24
+ }
25
+ catch (err) {
26
+ console.warn(`[testPrimaryPythConnection] Pyth connection test failed for ${exports.PRIMARY_PYTH_ENDPOINT}:`, err);
27
+ return false;
28
+ }
29
+ });
30
+ exports.testPrimaryPythConnection = testPrimaryPythConnection;
31
+ /**
32
+ * Gets a working Pyth connection endpoint, trying primary first, then fallback if provided
33
+ * @param fallbackPythEndpoint Optional fallback endpoint
34
+ * @returns The endpoint URL that is working, or the primary endpoint if fallback fails
35
+ */
36
+ const getWorkingPythEndpoint = (fallbackPythEndpoint) => __awaiter(void 0, void 0, void 0, function* () {
37
+ // Test primary endpoint first
38
+ const primaryWorking = yield (0, exports.testPrimaryPythConnection)();
39
+ if (primaryWorking) {
40
+ console.log(`[getWorkingPythEndpoint] Using primary Pyth endpoint: ${exports.PRIMARY_PYTH_ENDPOINT}`);
41
+ return exports.PRIMARY_PYTH_ENDPOINT;
42
+ }
43
+ // If primary fails and fallback is provided, use fallback
44
+ if (!!fallbackPythEndpoint) {
45
+ console.warn(`[getWorkingPythEndpoint] Primary Pyth endpoint failed, using fallback: ${fallbackPythEndpoint}`);
46
+ return fallbackPythEndpoint;
47
+ }
48
+ else {
49
+ console.error(`[getWorkingPythEndpoint] Primary Pyth endpoint failed, no fallback provided, using primary anyway`);
50
+ return exports.PRIMARY_PYTH_ENDPOINT;
51
+ }
52
+ });
53
+ exports.getWorkingPythEndpoint = getWorkingPythEndpoint;
@@ -11,7 +11,10 @@ export declare enum StrategyType {
11
11
  AUSD_sSUI_SUI_LOOPING = "4",
12
12
  xBTC_sSUI_SUI_LOOPING = "100",// Used to be for Slush Strategies #0
13
13
  xBTC_wBTC_LOOPING = "101",// Used to be for Slush Strategies #1
14
- suiUSDT_sSUI_SUI_LOOPING = "5"
14
+ suiUSDT_sSUI_SUI_LOOPING = "5",
15
+ AUSD_USDC_LOOPING = "6",
16
+ AUSD_suiUSDT_LOOPING = "7",
17
+ USDC_suiUSDT_LOOPING = "8"
15
18
  }
16
19
  export declare const STRATEGY_TYPE_INFO_MAP: Record<StrategyType, {
17
20
  queryParam: string;
@@ -30,6 +30,9 @@ var StrategyType;
30
30
  StrategyType["xBTC_sSUI_SUI_LOOPING"] = "100";
31
31
  StrategyType["xBTC_wBTC_LOOPING"] = "101";
32
32
  StrategyType["suiUSDT_sSUI_SUI_LOOPING"] = "5";
33
+ StrategyType["AUSD_USDC_LOOPING"] = "6";
34
+ StrategyType["AUSD_suiUSDT_LOOPING"] = "7";
35
+ StrategyType["USDC_suiUSDT_LOOPING"] = "8";
33
36
  })(StrategyType || (exports.StrategyType = StrategyType = {}));
34
37
  exports.STRATEGY_TYPE_INFO_MAP = {
35
38
  [StrategyType.sSUI_SUI_LOOPING]: {
@@ -130,6 +133,48 @@ exports.STRATEGY_TYPE_INFO_MAP = {
130
133
  currencyCoinTypes: [sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
131
134
  defaultCurrencyCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
132
135
  },
136
+ [StrategyType.AUSD_USDC_LOOPING]: {
137
+ queryParam: "AUSD-USDC-looping",
138
+ header: {
139
+ coinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_USDC_COINTYPE],
140
+ title: "AUSD/USDC",
141
+ tooltip: "Sets up an AUSD/USDC Looping strategy by depositing AUSD and borrowing USDC to the desired leverage",
142
+ type: "Looping",
143
+ },
144
+ depositBaseCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
145
+ depositLstCoinType: undefined,
146
+ borrowCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
147
+ currencyCoinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_USDC_COINTYPE],
148
+ defaultCurrencyCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
149
+ },
150
+ [StrategyType.AUSD_suiUSDT_LOOPING]: {
151
+ queryParam: "AUSD-suiUSDT-looping",
152
+ header: {
153
+ coinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
154
+ title: "AUSD/suiUSDT",
155
+ tooltip: "Sets up an AUSD/suiUSDT Looping strategy by depositing AUSD and borrowing suiUSDT to the desired leverage",
156
+ type: "Looping",
157
+ },
158
+ depositBaseCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
159
+ depositLstCoinType: undefined,
160
+ borrowCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
161
+ currencyCoinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
162
+ defaultCurrencyCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
163
+ },
164
+ [StrategyType.USDC_suiUSDT_LOOPING]: {
165
+ queryParam: "USDC-suiUSDT-looping",
166
+ header: {
167
+ coinTypes: [sui_fe_1.NORMALIZED_USDC_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
168
+ title: "USDC/suiUSDT",
169
+ tooltip: "Sets up a USDC/suiUSDT Looping strategy by depositing USDC and borrowing suiUSDT to the desired leverage",
170
+ type: "Looping",
171
+ },
172
+ depositBaseCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
173
+ depositLstCoinType: undefined,
174
+ borrowCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
175
+ currencyCoinTypes: [sui_fe_1.NORMALIZED_USDC_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
176
+ defaultCurrencyCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
177
+ },
133
178
  };
134
179
  const strategyDeposit = (coin, coinType, strategyOwnerCap, reserveArrayIndex, transaction) => transaction.moveCall({
135
180
  target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::deposit_liquidity_and_deposit_into_obligation`,
@@ -273,23 +318,29 @@ const strategyClaimRewardsAndSwapForCoinType = (address, cetusSdk, cetusPartnerI
273
318
  if (routers === undefined)
274
319
  continue; // Skip coin if no swap quote found
275
320
  console.log("[strategyClaimRewardsAndSwapForCoinType] swapping coinType", coinType);
276
- let coinOut;
277
321
  try {
278
- coinOut = yield cetusSdk.fixableRouterSwapV3({
279
- router: routers,
280
- inputCoin: coinIn,
281
- slippage: 3 / 100,
282
- txb: transaction,
283
- partner: cetusPartnerId,
284
- });
322
+ let coinOut;
323
+ try {
324
+ coinOut = yield cetusSdk.fixableRouterSwapV3({
325
+ router: routers,
326
+ inputCoin: coinIn,
327
+ slippage: 3 / 100,
328
+ txb: transaction,
329
+ partner: cetusPartnerId,
330
+ });
331
+ if (resultCoin)
332
+ transaction.mergeCoins(resultCoin, [coinOut]);
333
+ else
334
+ resultCoin = coinOut;
335
+ }
336
+ catch (err) {
337
+ throw new Error(`No swap quote found for ${coinType}`);
338
+ }
285
339
  }
286
340
  catch (err) {
287
- throw new Error(`No swap quote found for ${coinType}`);
341
+ console.error(err);
342
+ continue; // Skip coin if swap fails
288
343
  }
289
- if (resultCoin)
290
- transaction.mergeCoins(resultCoin, [coinOut]);
291
- else
292
- resultCoin = coinOut;
293
344
  }
294
345
  // 4) Deposit
295
346
  if (!resultCoin)
@@ -329,46 +380,60 @@ depositReserve, strategyOwnerCap, transaction) => __awaiter(void 0, void 0, void
329
380
  let resultCoin = undefined;
330
381
  // 2.1) Get routers
331
382
  const amountsAndSortedQuotesMap = Object.fromEntries(yield Promise.all(Object.entries(withdrawnCoinsMap).map(([coinType, { deposit, coin }]) => (() => __awaiter(void 0, void 0, void 0, function* () {
332
- // Get amount
333
- const amount = new bignumber_js_1.default(deposit.depositedAmount.times(swapPercent.div(100)))
334
- .times(10 ** deposit.reserve.token.decimals)
335
- .integerValue(bignumber_js_1.default.ROUND_DOWN); // Use underestimate (deposits keep accruing if deposit APR >0)
336
- // Get routes
337
- const routers = yield cetusSdk.findRouters({
338
- from: deposit.coinType,
339
- target: depositReserve.coinType,
340
- amount: new bn_js_1.default(amount.toString()), // Underestimate (deposits keep accruing if deposit APR >0)
341
- byAmountIn: true,
342
- });
343
- if (!routers)
344
- throw new Error(`No swap quote found for ${deposit.coinType}`);
345
- console.log("[strategySwapSomeDepositsForCoinType] routers", {
346
- coinType: deposit.coinType,
347
- routers,
348
- });
349
- return [deposit.coinType, { coin, routers }];
383
+ try {
384
+ // Get amount
385
+ const amount = new bignumber_js_1.default(deposit.depositedAmount.times(swapPercent.div(100)))
386
+ .times(10 ** deposit.reserve.token.decimals)
387
+ .integerValue(bignumber_js_1.default.ROUND_DOWN); // Use underestimate (deposits keep accruing if deposit APR >0)
388
+ // Get routes
389
+ const routers = yield cetusSdk.findRouters({
390
+ from: deposit.coinType,
391
+ target: depositReserve.coinType,
392
+ amount: new bn_js_1.default(amount.toString()), // Underestimate (deposits keep accruing if deposit APR >0)
393
+ byAmountIn: true,
394
+ });
395
+ if (!routers)
396
+ throw new Error(`No swap quote found for ${deposit.coinType}`);
397
+ console.log("[strategySwapSomeDepositsForCoinType] routers", {
398
+ coinType: deposit.coinType,
399
+ routers,
400
+ });
401
+ return [deposit.coinType, { coin, routers }];
402
+ }
403
+ catch (err) {
404
+ console.error(err);
405
+ return [coinType, { coin, routers: undefined }];
406
+ }
350
407
  }))())));
351
408
  console.log("[strategySwapSomeDepositsForCoinType] amountsAndSortedQuotesMap", { amountsAndSortedQuotesMap });
352
409
  // 2.2) Swap
353
410
  for (const [coinType, { coin: coinIn, routers }] of Object.entries(amountsAndSortedQuotesMap)) {
411
+ if (routers === undefined)
412
+ continue; // Skip coin if no swap quote found
354
413
  console.log("[strategySwapSomeDepositsForCoinType] swapping coinType", coinType);
355
- let coinOut;
356
414
  try {
357
- coinOut = yield cetusSdk.fixableRouterSwapV3({
358
- router: routers,
359
- inputCoin: coinIn,
360
- slippage: 3 / 100,
361
- txb: transaction,
362
- partner: cetusPartnerId,
363
- });
415
+ let coinOut;
416
+ try {
417
+ coinOut = yield cetusSdk.fixableRouterSwapV3({
418
+ router: routers,
419
+ inputCoin: coinIn,
420
+ slippage: 3 / 100,
421
+ txb: transaction,
422
+ partner: cetusPartnerId,
423
+ });
424
+ }
425
+ catch (err) {
426
+ throw new Error(`No swap quote found for ${coinType}`);
427
+ }
428
+ if (resultCoin)
429
+ transaction.mergeCoins(resultCoin, [coinOut]);
430
+ else
431
+ resultCoin = coinOut;
364
432
  }
365
433
  catch (err) {
366
- throw new Error(`No swap quote found for ${coinType}`);
434
+ console.error(err);
435
+ continue; // Skip coin if swap fails
367
436
  }
368
- if (resultCoin)
369
- transaction.mergeCoins(resultCoin, [coinOut]);
370
- else
371
- resultCoin = coinOut;
372
437
  }
373
438
  // 3) Deposit
374
439
  if (!resultCoin)
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@suilend/sdk","version":"1.1.91","private":false,"description":"A TypeScript SDK for interacting with the Suilend program","author":"Suilend","license":"MIT","main":"./index.js","exports":{".":"./index.js","./client":"./client.js","./mmt":"./mmt.js","./strategies":"./strategies.js","./api/events":"./api/events.js","./api":"./api/index.js","./lib/constants":"./lib/constants.js","./lib":"./lib/index.js","./lib/initialize":"./lib/initialize.js","./lib/liquidityMining":"./lib/liquidityMining.js","./lib/strategyOwnerCap":"./lib/strategyOwnerCap.js","./lib/transactions":"./lib/transactions.js","./lib/types":"./lib/types.js","./parsers/apiReserveAssetDataEvent":"./parsers/apiReserveAssetDataEvent.js","./parsers":"./parsers/index.js","./parsers/lendingMarket":"./parsers/lendingMarket.js","./parsers/obligation":"./parsers/obligation.js","./parsers/rateLimiter":"./parsers/rateLimiter.js","./parsers/reserve":"./parsers/reserve.js","./swap":"./swap/index.js","./swap/quote":"./swap/quote.js","./swap/transaction":"./swap/transaction.js","./utils/events":"./utils/events.js","./utils":"./utils/index.js","./utils/obligation":"./utils/obligation.js","./utils/simulate":"./utils/simulate.js","./_generated/_framework/reified":"./_generated/_framework/reified.js","./_generated/_framework/util":"./_generated/_framework/util.js","./_generated/_framework/vector":"./_generated/_framework/vector.js","./_generated/suilend":"./_generated/suilend/index.js","./_generated/suilend/cell/structs":"./_generated/suilend/cell/structs.js","./_generated/suilend/decimal/structs":"./_generated/suilend/decimal/structs.js","./_generated/suilend/lending-market/functions":"./_generated/suilend/lending-market/functions.js","./_generated/suilend/lending-market/structs":"./_generated/suilend/lending-market/structs.js","./_generated/suilend/lending-market-registry/functions":"./_generated/suilend/lending-market-registry/functions.js","./_generated/suilend/liquidity-mining/structs":"./_generated/suilend/liquidity-mining/structs.js","./_generated/suilend/obligation/structs":"./_generated/suilend/obligation/structs.js","./_generated/suilend/rate-limiter/functions":"./_generated/suilend/rate-limiter/functions.js","./_generated/suilend/rate-limiter/structs":"./_generated/suilend/rate-limiter/structs.js","./_generated/suilend/reserve/structs":"./_generated/suilend/reserve/structs.js","./_generated/suilend/reserve-config/functions":"./_generated/suilend/reserve-config/functions.js","./_generated/suilend/reserve-config/structs":"./_generated/suilend/reserve-config/structs.js","./_generated/_dependencies/source/0x1":"./_generated/_dependencies/source/0x1/index.js","./_generated/_dependencies/source/0x2":"./_generated/_dependencies/source/0x2/index.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/index.js","./_generated/_dependencies/source/0x1/ascii/structs":"./_generated/_dependencies/source/0x1/ascii/structs.js","./_generated/_dependencies/source/0x1/option/structs":"./_generated/_dependencies/source/0x1/option/structs.js","./_generated/_dependencies/source/0x1/type-name/structs":"./_generated/_dependencies/source/0x1/type-name/structs.js","./_generated/_dependencies/source/0x2/bag/structs":"./_generated/_dependencies/source/0x2/bag/structs.js","./_generated/_dependencies/source/0x2/balance/structs":"./_generated/_dependencies/source/0x2/balance/structs.js","./_generated/_dependencies/source/0x2/object/structs":"./_generated/_dependencies/source/0x2/object/structs.js","./_generated/_dependencies/source/0x2/object-table/structs":"./_generated/_dependencies/source/0x2/object-table/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.js"},"types":"./index.js","scripts":{"build":"rm -rf ./dist && bun tsc","eslint":"eslint --fix \"./src/**/*.ts\"","prettier":"prettier --write \"./src/**/*\"","lint":"bun eslint && bun prettier && bun tsc --noEmit","release":"bun run build && bun ts-node ./release.ts && cd ./dist && npm publish --access public"},"repository":{"type":"git","url":"git+https://github.com/suilend/suilend-fe-public.git"},"bugs":{"url":"https://github.com/suilend/suilend-fe-public/issues"},"dependencies":{"@7kprotocol/sdk-ts":"^3.4.1","@cetusprotocol/aggregator-sdk":"^1.2.1","@flowx-finance/sdk":"^1.13.5","@pythnetwork/pyth-sui-js":"^2.2.0","@suilend/springsui-sdk":"^1.0.27","aftermath-ts-sdk":"^1.3.22","bignumber.js":"^9.1.2","bn.js":"^5.2.2","crypto-js":"^4.2.0","lodash":"^4.17.21","p-limit":"3.1.0","uuid":"^11.0.3"},"devDependencies":{"@types/bn.js":"^5.2.0","@types/lodash":"^4.17.20","ts-node":"^10.9.2"},"peerDependencies":{"@mysten/bcs":"1.8.1","@mysten/sui":"1.42.0","@suilend/sui-fe":"^0.3.40"},"overrides":{"chalk":"5.3.0","strip-ansi":"7.1.0","color-convert":"2.0.1","color-name":"1.1.4","is-core-module":"2.13.1","error-ex":"1.3.2","has-ansi":"5.0.1"}}
1
+ {"name":"@suilend/sdk","version":"1.1.93","private":false,"description":"A TypeScript SDK for interacting with the Suilend program","author":"Suilend","license":"MIT","main":"./index.js","exports":{".":"./index.js","./client":"./client.js","./mmt":"./mmt.js","./strategies":"./strategies.js","./api/events":"./api/events.js","./api":"./api/index.js","./lib/constants":"./lib/constants.js","./lib":"./lib/index.js","./lib/initialize":"./lib/initialize.js","./lib/liquidityMining":"./lib/liquidityMining.js","./lib/pyth":"./lib/pyth.js","./lib/strategyOwnerCap":"./lib/strategyOwnerCap.js","./lib/transactions":"./lib/transactions.js","./lib/types":"./lib/types.js","./parsers/apiReserveAssetDataEvent":"./parsers/apiReserveAssetDataEvent.js","./parsers":"./parsers/index.js","./parsers/lendingMarket":"./parsers/lendingMarket.js","./parsers/obligation":"./parsers/obligation.js","./parsers/rateLimiter":"./parsers/rateLimiter.js","./parsers/reserve":"./parsers/reserve.js","./swap":"./swap/index.js","./swap/quote":"./swap/quote.js","./swap/transaction":"./swap/transaction.js","./utils/events":"./utils/events.js","./utils":"./utils/index.js","./utils/obligation":"./utils/obligation.js","./utils/simulate":"./utils/simulate.js","./_generated/_framework/reified":"./_generated/_framework/reified.js","./_generated/_framework/util":"./_generated/_framework/util.js","./_generated/_framework/vector":"./_generated/_framework/vector.js","./_generated/suilend":"./_generated/suilend/index.js","./_generated/suilend/cell/structs":"./_generated/suilend/cell/structs.js","./_generated/suilend/decimal/structs":"./_generated/suilend/decimal/structs.js","./_generated/suilend/lending-market/functions":"./_generated/suilend/lending-market/functions.js","./_generated/suilend/lending-market/structs":"./_generated/suilend/lending-market/structs.js","./_generated/suilend/lending-market-registry/functions":"./_generated/suilend/lending-market-registry/functions.js","./_generated/suilend/liquidity-mining/structs":"./_generated/suilend/liquidity-mining/structs.js","./_generated/suilend/obligation/structs":"./_generated/suilend/obligation/structs.js","./_generated/suilend/rate-limiter/functions":"./_generated/suilend/rate-limiter/functions.js","./_generated/suilend/rate-limiter/structs":"./_generated/suilend/rate-limiter/structs.js","./_generated/suilend/reserve/structs":"./_generated/suilend/reserve/structs.js","./_generated/suilend/reserve-config/functions":"./_generated/suilend/reserve-config/functions.js","./_generated/suilend/reserve-config/structs":"./_generated/suilend/reserve-config/structs.js","./_generated/_dependencies/source/0x1":"./_generated/_dependencies/source/0x1/index.js","./_generated/_dependencies/source/0x2":"./_generated/_dependencies/source/0x2/index.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/index.js","./_generated/_dependencies/source/0x1/ascii/structs":"./_generated/_dependencies/source/0x1/ascii/structs.js","./_generated/_dependencies/source/0x1/option/structs":"./_generated/_dependencies/source/0x1/option/structs.js","./_generated/_dependencies/source/0x1/type-name/structs":"./_generated/_dependencies/source/0x1/type-name/structs.js","./_generated/_dependencies/source/0x2/bag/structs":"./_generated/_dependencies/source/0x2/bag/structs.js","./_generated/_dependencies/source/0x2/balance/structs":"./_generated/_dependencies/source/0x2/balance/structs.js","./_generated/_dependencies/source/0x2/object/structs":"./_generated/_dependencies/source/0x2/object/structs.js","./_generated/_dependencies/source/0x2/object-table/structs":"./_generated/_dependencies/source/0x2/object-table/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.js"},"types":"./index.js","scripts":{"build":"rm -rf ./dist && bun tsc","eslint":"eslint --fix \"./src/**/*.ts\"","prettier":"prettier --write \"./src/**/*\"","lint":"bun eslint && bun prettier && bun tsc --noEmit","release":"bun run build && bun ts-node ./release.ts && cd ./dist && npm publish --access public"},"repository":{"type":"git","url":"git+https://github.com/suilend/suilend-fe-public.git"},"bugs":{"url":"https://github.com/suilend/suilend-fe-public/issues"},"dependencies":{"@7kprotocol/sdk-ts":"^3.5.0","@cetusprotocol/aggregator-sdk":"^1.4.2","@flowx-finance/sdk":"^1.14.0","@pythnetwork/pyth-sui-js":"^2.2.0","@suilend/springsui-sdk":"^1.0.27","aftermath-ts-sdk":"^1.3.24","bignumber.js":"^9.1.2","bn.js":"^5.2.2","crypto-js":"^4.2.0","lodash":"^4.17.21","p-limit":"3.1.0","uuid":"^11.0.3"},"devDependencies":{"@types/bn.js":"^5.2.0","@types/lodash":"^4.17.20","ts-node":"^10.9.2"},"peerDependencies":{"@mysten/bcs":"1.8.1","@mysten/sui":"1.42.0","@suilend/sui-fe":"^0.3.43"},"overrides":{"chalk":"5.3.0","strip-ansi":"7.1.0","color-convert":"2.0.1","color-name":"1.1.4","is-core-module":"2.13.1","error-ex":"1.3.2","has-ansi":"5.0.1"}}
package/strategies.d.ts CHANGED
@@ -22,7 +22,7 @@ export type StrategyWithdraw = {
22
22
  export declare enum StrategyFlashLoanProvider {
23
23
  MMT = "mmt"
24
24
  }
25
- export declare const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP: Record<string, {
25
+ export declare const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP: Record<StrategyType, {
26
26
  provider: StrategyFlashLoanProvider;
27
27
  poolId: string;
28
28
  coinTypeA: string;
@@ -336,6 +336,11 @@ export declare const strategyMaxWithdrawTx: (reserveMap: Record<string, ParsedRe
336
336
  borrowedAmount: BigNumber;
337
337
  transaction: Transaction;
338
338
  }>;
339
+ export declare const strategyAdjustRepayTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiClient: SuiClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, flashLoanBorrowedAmount: BigNumber, transaction: Transaction, dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<DevInspectResults>) => Promise<{
340
+ deposits: StrategyDeposit[];
341
+ borrowedAmount: BigNumber;
342
+ transaction: Transaction;
343
+ }>;
339
344
  export declare const strategyDepositAdjustWithdrawTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiClient: SuiClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, flashLoanBorrowedAmount: BigNumber, transaction: Transaction, dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<DevInspectResults>) => Promise<{
340
345
  deposits: StrategyDeposit[];
341
346
  borrowedAmount: BigNumber;
package/strategies.js CHANGED
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.strategyAdjustTx = exports.strategyDepositAdjustWithdrawTx = exports.strategyMaxWithdrawTx = exports.strategyWithdrawTx = exports.strategyDepositAndLoopToExposureTx = exports.strategyDepositTx = exports.strategyUnloopToExposureTx = exports.strategyLoopToExposureTx = exports.getStrategyLiquidationPrice = exports.getStrategyHealthPercent = exports.getStrategyAprPercent = exports.getStrategyUnclaimedRewardsAmount = exports.fetchStrategyGlobalTvlAmountUsdMap = exports.strategySimulateDepositAndLoopToExposure = exports.strategySimulateDeposit = exports.strategySimulateLoopToExposure = exports.getStrategyStepMaxWithdrawnAmount = exports.getStrategyStepMaxBorrowedAmount = exports.getStrategyExposure = exports.getStrategyTvlAmount = exports.getStrategyBorrowedAmount = exports.getStrategyDepositedAmount = exports.getStrategySimulatedObligation = exports.getStrategyDefaultCurrencyReserve = exports.getStrategyBorrowReserve = exports.getStrategyDepositReserves = exports.STRATEGY_TYPE_EXPOSURE_MAP = exports.getStrategyLstRedeemFee = exports.getStrategyLstMintFee = exports.fetchStrategyLstMap = exports.getStrategySuiReserve = exports.hasStrategyPosition = exports.addOrInsertStrategyDeposit = exports.getReserveSafeDepositLimit = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = exports.StrategyFlashLoanProvider = exports.LST_DECIMALS = exports.STRATEGY_E = void 0;
15
+ exports.strategyAdjustTx = exports.strategyDepositAdjustWithdrawTx = exports.strategyAdjustRepayTx = exports.strategyMaxWithdrawTx = exports.strategyWithdrawTx = exports.strategyDepositAndLoopToExposureTx = exports.strategyDepositTx = exports.strategyUnloopToExposureTx = exports.strategyLoopToExposureTx = exports.getStrategyLiquidationPrice = exports.getStrategyHealthPercent = exports.getStrategyAprPercent = exports.getStrategyUnclaimedRewardsAmount = exports.fetchStrategyGlobalTvlAmountUsdMap = exports.strategySimulateDepositAndLoopToExposure = exports.strategySimulateDeposit = exports.strategySimulateLoopToExposure = exports.getStrategyStepMaxWithdrawnAmount = exports.getStrategyStepMaxBorrowedAmount = exports.getStrategyExposure = exports.getStrategyTvlAmount = exports.getStrategyBorrowedAmount = exports.getStrategyDepositedAmount = exports.getStrategySimulatedObligation = exports.getStrategyDefaultCurrencyReserve = exports.getStrategyBorrowReserve = exports.getStrategyDepositReserves = exports.STRATEGY_TYPE_EXPOSURE_MAP = exports.getStrategyLstRedeemFee = exports.getStrategyLstMintFee = exports.fetchStrategyLstMap = exports.getStrategySuiReserve = exports.hasStrategyPosition = exports.addOrInsertStrategyDeposit = exports.getReserveSafeDepositLimit = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = exports.StrategyFlashLoanProvider = exports.LST_DECIMALS = exports.STRATEGY_E = void 0;
16
16
  const bcs_1 = require("@mysten/bcs");
17
17
  const transactions_1 = require("@mysten/sui/transactions");
18
18
  const utils_1 = require("@mysten/sui/utils");
@@ -89,6 +89,30 @@ exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = {
89
89
  borrowA: true,
90
90
  feePercent: 0.001,
91
91
  },
92
+ [strategyOwnerCap_1.StrategyType.AUSD_USDC_LOOPING]: {
93
+ provider: StrategyFlashLoanProvider.MMT,
94
+ poolId: "0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b", // AUSD-USDC 0.01% https://app.mmt.finance/liquidity/0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b
95
+ coinTypeA: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
96
+ coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
97
+ borrowA: true,
98
+ feePercent: 0.01,
99
+ },
100
+ [strategyOwnerCap_1.StrategyType.AUSD_suiUSDT_LOOPING]: {
101
+ provider: StrategyFlashLoanProvider.MMT,
102
+ poolId: "0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b", // AUSD-USDC 0.01% https://app.mmt.finance/liquidity/0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b
103
+ coinTypeA: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
104
+ coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
105
+ borrowA: true,
106
+ feePercent: 0.01,
107
+ },
108
+ [strategyOwnerCap_1.StrategyType.USDC_suiUSDT_LOOPING]: {
109
+ provider: StrategyFlashLoanProvider.MMT,
110
+ poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
111
+ coinTypeA: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
112
+ coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
113
+ borrowA: false,
114
+ feePercent: 0.001,
115
+ },
92
116
  };
93
117
  const getReserveSafeDepositLimit = (reserve) => {
94
118
  // Calculate safe deposit limit (subtract 10 mins of deposit APR from cap)
@@ -232,6 +256,21 @@ exports.STRATEGY_TYPE_EXPOSURE_MAP = {
232
256
  max: new bignumber_js_1.default(3), // Actual max: 1 + (suiUSDT Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where suiUSDT Open LTV % = 77% and sSUI Open LTV % = 70%
233
257
  default: new bignumber_js_1.default(3),
234
258
  },
259
+ [strategyOwnerCap_1.StrategyType.AUSD_USDC_LOOPING]: {
260
+ min: new bignumber_js_1.default(1),
261
+ max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (AUSD Open LTV %)) = 4.347x, where AUSD Open LTV % = 77%
262
+ default: new bignumber_js_1.default(4),
263
+ },
264
+ [strategyOwnerCap_1.StrategyType.AUSD_suiUSDT_LOOPING]: {
265
+ min: new bignumber_js_1.default(1),
266
+ max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (AUSD Open LTV %)) = 4.347x, where AUSD Open LTV % = 77%
267
+ default: new bignumber_js_1.default(4),
268
+ },
269
+ [strategyOwnerCap_1.StrategyType.USDC_suiUSDT_LOOPING]: {
270
+ min: new bignumber_js_1.default(1),
271
+ max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (USDC Open LTV %)) = 4.347x, where USDC Open LTV % = 77%
272
+ default: new bignumber_js_1.default(4),
273
+ },
235
274
  };
236
275
  // Reserves
237
276
  const getStrategyDepositReserves = (
@@ -734,7 +773,8 @@ lstMap, strategyType, obligation, exposure) => {
734
773
  depositedAmount: new bignumber_js_1.default(1), // Any number will do
735
774
  }, exposure).obligation;
736
775
  }
737
- return (0, lib_1.getNetAprPercent)(_obligation, rewardMap, lstStatsMap, !obligation ||
776
+ return (0, lib_1.getNetAprPercent)(_obligation, rewardMap, lstStatsMap, undefined, // elixirSdeUsdAprPercent
777
+ !obligation ||
738
778
  !(0, exports.hasStrategyPosition)(obligation) ||
739
779
  obligation.deposits.some((d) => !d.userRewardManager));
740
780
  };
@@ -764,7 +804,7 @@ lstMap, strategyType, obligation, exposure) => {
764
804
  const weightedBorrowsUsd = (0, utils_2.getWeightedBorrowsUsd)(_obligation);
765
805
  const borrowLimitUsd = _obligation.minPriceBorrowLimitUsd.times(depositReserves.base !== undefined
766
806
  ? 0.99 // 1% buffer
767
- : 0.999);
807
+ : 1);
768
808
  const liquidationThresholdUsd = _obligation.unhealthyBorrowValueUsd;
769
809
  if (weightedBorrowsUsd.lte(borrowLimitUsd))
770
810
  return new bignumber_js_1.default(100);
@@ -1102,8 +1142,8 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1102
1142
  if (depositReserves.lst === undefined)
1103
1143
  throw new Error("LST reserve not found");
1104
1144
  const borrowedAmountUsd = borrowedAmount.times(borrowReserve.price);
1105
- const fullRepaymentAmount = (borrowedAmountUsd.lt(0.02)
1106
- ? new bignumber_js_1.default(0.02).div(borrowReserve.price) // $0.02 in borrow coinType (still well over E borrows, e.g. E SUI, or E wBTC)
1145
+ const fullRepaymentAmount = (borrowedAmountUsd.lt(0.1)
1146
+ ? new bignumber_js_1.default(0.1).div(borrowReserve.price) // $0.1 in borrow coinType
1107
1147
  : borrowedAmountUsd.lt(1)
1108
1148
  ? borrowedAmount.times(1.1) // 10% buffer
1109
1149
  : borrowedAmountUsd.lt(10)
@@ -1222,9 +1262,9 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1222
1262
  .toFixed(20),
1223
1263
  });
1224
1264
  // 2.2) Swap
1225
- let baseCoin;
1265
+ let swapCoin;
1226
1266
  try {
1227
- baseCoin = yield cetusSdk.fixableRouterSwapV3({
1267
+ swapCoin = yield cetusSdk.fixableRouterSwapV3({
1228
1268
  router: routers,
1229
1269
  inputCoin: withdrawnRemainingLstCoin,
1230
1270
  slippage: 100 / 100,
@@ -1236,7 +1276,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1236
1276
  throw new Error("No swap quote found");
1237
1277
  }
1238
1278
  // 3) Deposit base
1239
- (0, strategyOwnerCap_1.strategyDeposit)(baseCoin, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), transaction);
1279
+ (0, strategyOwnerCap_1.strategyDeposit)(swapCoin, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), transaction);
1240
1280
  }
1241
1281
  });
1242
1282
  const fullyRepayBorrowsUsingBase = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1244,8 +1284,8 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1244
1284
  if (depositReserves.base === undefined)
1245
1285
  throw new Error("Base reserve not found");
1246
1286
  const borrowedAmountUsd = borrowedAmount.times(borrowReserve.price);
1247
- const fullRepaymentAmount = (borrowedAmountUsd.lt(0.02)
1248
- ? new bignumber_js_1.default(0.02).div(borrowReserve.price) // $0.02 in borrow coinType (still well over E borrows, e.g. E SUI, or E wBTC)
1287
+ const fullRepaymentAmount = (borrowedAmountUsd.lt(0.1)
1288
+ ? new bignumber_js_1.default(0.1).div(borrowReserve.price) // $0.1 in borrow coinType
1249
1289
  : borrowedAmountUsd.lt(1)
1250
1290
  ? borrowedAmount.times(1.1) // 10% buffer
1251
1291
  : borrowedAmountUsd.lt(10)
@@ -1280,7 +1320,8 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1280
1320
  // 2) Withdraw base
1281
1321
  const baseWithdrawnAmount = new bignumber_js_1.default(fullRepaymentAmount.times(borrowReserve.price))
1282
1322
  .div(depositReserves.base.price)
1283
- .times(1.03); // 3% buffer
1323
+ .times(1.03) // 3% buffer
1324
+ .decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_UP);
1284
1325
  console.log(`[unloopStrategyToExposure.fullyRepayBorrowsUsingBase] withdraw_base |`, JSON.stringify({
1285
1326
  baseWithdrawnAmount: baseWithdrawnAmount.toFixed(20),
1286
1327
  }, null, 2));
@@ -1329,9 +1370,9 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1329
1370
  .toFixed(20),
1330
1371
  });
1331
1372
  // 3.2) Swap
1332
- let borrowCoin;
1373
+ let swapCoin;
1333
1374
  try {
1334
- borrowCoin = yield cetusSdk.fixableRouterSwapV3({
1375
+ swapCoin = yield cetusSdk.fixableRouterSwapV3({
1335
1376
  router: routers,
1336
1377
  inputCoin: withdrawnBaseCoin,
1337
1378
  slippage: 1 / 100,
@@ -1350,15 +1391,15 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1350
1391
  }, null, 2));
1351
1392
  try {
1352
1393
  const txCopy = transactions_1.Transaction.from(transaction);
1353
- suilendClient.repay(obligationId, borrowReserve.coinType, borrowCoin, txCopy);
1354
- txCopy.transferObjects([borrowCoin], _address); // Transfer remaining borrow to user
1394
+ suilendClient.repay(obligationId, borrowReserve.coinType, swapCoin, txCopy);
1395
+ txCopy.transferObjects([swapCoin], _address); // Transfer remaining to user
1355
1396
  yield dryRunTransaction(txCopy); // Throws error if fails
1356
1397
  transaction = txCopy;
1357
1398
  }
1358
1399
  catch (err) {
1359
1400
  // Don't block user if fails
1360
1401
  console.error(err);
1361
- transaction.transferObjects([borrowCoin], _address); // Transfer borrow to user
1402
+ transaction.transferObjects([swapCoin], _address); // Transfer to user
1362
1403
  }
1363
1404
  // 4.2) Update state
1364
1405
  borrowedAmount = bignumber_js_1.default.max(borrowedAmount.minus(repaidAmount), new bignumber_js_1.default(0));
@@ -1369,7 +1410,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1369
1410
  })),
1370
1411
  borrowedAmount: borrowedAmount.toFixed(20),
1371
1412
  }, null, 2));
1372
- // 5) Swap remaining borrow to base and redeposit (not possible because coin is a mutable reference (?))
1413
+ // 5) Swap remaining to base and redeposit (not possible because coin is a mutable reference (?))
1373
1414
  });
1374
1415
  for (let i = 0; i < 30; i++) {
1375
1416
  const exposure = (0, exports.getStrategyExposure)(reserveMap, lstMap, strategyType, (0, exports.getStrategySimulatedObligation)(reserveMap, lstMap, strategyType, deposits, borrowedAmount));
@@ -2019,6 +2060,176 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2019
2060
  return { deposits, borrowedAmount, transaction };
2020
2061
  });
2021
2062
  exports.strategyMaxWithdrawTx = strategyMaxWithdrawTx;
2063
+ const strategyAdjustRepayTx = (
2064
+ // AppContext
2065
+ reserveMap,
2066
+ // Strategy
2067
+ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2068
+ var _a, _b, _c, _d;
2069
+ const strategyInfo = strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP[strategyType];
2070
+ const lst = strategyInfo.depositLstCoinType !== undefined
2071
+ ? lstMap[strategyInfo.depositLstCoinType]
2072
+ : undefined;
2073
+ const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
2074
+ const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
2075
+ const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
2076
+ const adjustRepayExposure = exports.STRATEGY_TYPE_EXPOSURE_MAP[strategyType].min;
2077
+ console.log(`[strategyAdjustRepay] args |`, JSON.stringify({
2078
+ _address,
2079
+ strategyOwnerCapId,
2080
+ obligationId,
2081
+ _deposits: _deposits.map((d) => ({
2082
+ coinType: d.coinType,
2083
+ depositedAmount: d.depositedAmount.toFixed(20),
2084
+ })),
2085
+ _borrowedAmount: _borrowedAmount.toFixed(20),
2086
+ flashLoanBorrowedAmount: flashLoanBorrowedAmount.toFixed(20),
2087
+ }, null, 2));
2088
+ // const depositReserve = (depositReserves.base ?? depositReserves.lst)!; // Must have LST if no base
2089
+ if (!depositReserves.base)
2090
+ throw new Error("Base reserve not found");
2091
+ //
2092
+ let deposits = (0, lodash_1.cloneDeep)(_deposits);
2093
+ let borrowedAmount = _borrowedAmount;
2094
+ // 1) Flash loan base
2095
+ const flashLoanObj = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
2096
+ let borrowedBalanceA, borrowedBalanceB, receipt;
2097
+ if (flashLoanObj.provider === StrategyFlashLoanProvider.MMT) {
2098
+ [borrowedBalanceA, borrowedBalanceB, receipt] = transaction.moveCall({
2099
+ target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::flash_loan`,
2100
+ typeArguments: [flashLoanObj.coinTypeA, flashLoanObj.coinTypeB],
2101
+ arguments: [
2102
+ transaction.object(flashLoanObj.poolId),
2103
+ transaction.pure.u64(flashLoanObj.borrowA
2104
+ ? flashLoanBorrowedAmount
2105
+ .times(10 ** depositReserves.base.token.decimals)
2106
+ .integerValue(bignumber_js_1.default.ROUND_DOWN)
2107
+ .toString()
2108
+ : 0),
2109
+ transaction.pure.u64(flashLoanObj.borrowA
2110
+ ? 0
2111
+ : flashLoanBorrowedAmount
2112
+ .times(10 ** depositReserves.base.token.decimals)
2113
+ .integerValue(bignumber_js_1.default.ROUND_DOWN)
2114
+ .toString()),
2115
+ transaction.object(mmt_1.MMT_VERSION_OBJECT_ID),
2116
+ ],
2117
+ });
2118
+ }
2119
+ else {
2120
+ throw new Error("Invalid flash loan provider");
2121
+ }
2122
+ const flashLoanBorrowedCoin = transaction.moveCall({
2123
+ target: "0x2::coin::from_balance",
2124
+ typeArguments: [
2125
+ flashLoanObj.borrowA ? flashLoanObj.coinTypeA : flashLoanObj.coinTypeB,
2126
+ ],
2127
+ arguments: [flashLoanObj.borrowA ? borrowedBalanceA : borrowedBalanceB],
2128
+ });
2129
+ // 2) Swap flash loaned base for borrow
2130
+ // 2.1) Get routers
2131
+ const routers = yield cetusSdk.findRouters({
2132
+ from: depositReserves.base.coinType,
2133
+ target: borrowReserve.coinType,
2134
+ amount: new bn_js_1.BN(flashLoanBorrowedAmount
2135
+ .times(10 ** depositReserves.base.token.decimals)
2136
+ .integerValue(bignumber_js_1.default.ROUND_DOWN)
2137
+ .toString()),
2138
+ byAmountIn: true,
2139
+ });
2140
+ if (!routers)
2141
+ throw new Error("No swap quote found");
2142
+ console.log(`[strategyAdjustRepay] swap_flash_loan_base_for_borrows.get_routers`, {
2143
+ routers,
2144
+ amountIn: new bignumber_js_1.default(routers.amountIn.toString())
2145
+ .div(10 ** depositReserves.base.token.decimals)
2146
+ .decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_DOWN)
2147
+ .toFixed(20),
2148
+ amountOut: new bignumber_js_1.default(routers.amountOut.toString())
2149
+ .div(10 ** borrowReserve.token.decimals)
2150
+ .decimalPlaces(borrowReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN)
2151
+ .toFixed(20),
2152
+ });
2153
+ // 2.2) Swap
2154
+ let swapCoin;
2155
+ try {
2156
+ swapCoin = yield cetusSdk.fixableRouterSwapV3({
2157
+ router: routers,
2158
+ inputCoin: flashLoanBorrowedCoin,
2159
+ slippage: 1 / 100,
2160
+ txb: transaction,
2161
+ partner: cetusPartnerId,
2162
+ });
2163
+ }
2164
+ catch (err) {
2165
+ throw new Error("No swap quote found");
2166
+ }
2167
+ // 3) Fully repay borrows
2168
+ // 3.1) Repay
2169
+ suilendClient.repay(obligationId, borrowReserve.coinType, swapCoin, transaction);
2170
+ transaction.transferObjects([swapCoin], _address); // Transfer remaining to user
2171
+ // 3.2) Update state
2172
+ borrowedAmount = new bignumber_js_1.default(0);
2173
+ console.log(`[strategyAdjustRepay] repay_borrows.update_state |`, JSON.stringify({
2174
+ deposits: deposits.map((d) => ({
2175
+ coinType: d.coinType,
2176
+ depositedAmount: d.depositedAmount.toFixed(20),
2177
+ })),
2178
+ borrowedAmount: borrowedAmount.toFixed(20),
2179
+ }, null, 2));
2180
+ // 4) Swap remaining to base and redeposit (not possible because coin is a mutable reference (?))
2181
+ // 5) Repay flash loan + fee
2182
+ const receiptDebts = transaction.moveCall({
2183
+ target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::flash_receipt_debts`,
2184
+ typeArguments: [],
2185
+ arguments: [receipt],
2186
+ });
2187
+ const dryRunResults = yield dryRunTransaction(transaction);
2188
+ const flashLoanRepayAmount = new bignumber_js_1.default(bcs_1.bcs
2189
+ .u64()
2190
+ .parse(new Uint8Array((_d = (_c = (_b = (_a = dryRunResults.results) === null || _a === void 0 ? void 0 : _a.find((r, index) => index === receiptDebts.Result)) === null || _b === void 0 ? void 0 : _b.returnValues) === null || _c === void 0 ? void 0 : _c[flashLoanObj.borrowA ? 0 : 1][0]) !== null && _d !== void 0 ? _d : [0])))
2191
+ .div(10 ** depositReserves.base.token.decimals)
2192
+ .decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_UP);
2193
+ // 5.1) Withdraw base + fee
2194
+ const withdrawnAmount = flashLoanRepayAmount;
2195
+ const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield (0, exports.strategyWithdrawTx)(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2196
+ coinType: depositReserves.base.coinType,
2197
+ withdrawnAmount,
2198
+ }, transaction, dryRunTransaction, true);
2199
+ if (!withdrawnCoin)
2200
+ throw new Error("Withdrawn coin not found");
2201
+ // 5.2) Update state
2202
+ deposits = newDeposits2;
2203
+ borrowedAmount = newBorrowedAmount2;
2204
+ transaction = newTransaction2;
2205
+ // 5.3) Repay flash loan
2206
+ const flashLoanRepayCoin = withdrawnCoin;
2207
+ const flashLoanRepayBalance = transaction.moveCall({
2208
+ target: "0x2::coin::into_balance",
2209
+ typeArguments: [
2210
+ flashLoanObj.borrowA ? flashLoanObj.coinTypeA : flashLoanObj.coinTypeB,
2211
+ ],
2212
+ arguments: [flashLoanRepayCoin],
2213
+ });
2214
+ if (flashLoanObj.provider === StrategyFlashLoanProvider.MMT) {
2215
+ transaction.moveCall({
2216
+ target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::repay_flash_loan`,
2217
+ typeArguments: [flashLoanObj.coinTypeA, flashLoanObj.coinTypeB],
2218
+ arguments: [
2219
+ transaction.object(flashLoanObj.poolId),
2220
+ receipt,
2221
+ flashLoanObj.borrowA ? flashLoanRepayBalance : borrowedBalanceA,
2222
+ flashLoanObj.borrowA ? borrowedBalanceB : flashLoanRepayBalance,
2223
+ transaction.object(mmt_1.MMT_VERSION_OBJECT_ID),
2224
+ ],
2225
+ });
2226
+ }
2227
+ else {
2228
+ throw new Error("Invalid flash loan provider");
2229
+ }
2230
+ return { deposits, borrowedAmount, transaction };
2231
+ });
2232
+ exports.strategyAdjustRepayTx = strategyAdjustRepayTx;
2022
2233
  const strategyDepositAdjustWithdrawTx = (
2023
2234
  // AppContext
2024
2235
  reserveMap,
@@ -2048,7 +2259,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2048
2259
  //
2049
2260
  let deposits = (0, lodash_1.cloneDeep)(_deposits);
2050
2261
  let borrowedAmount = _borrowedAmount;
2051
- // 1) Flash loan borrow
2262
+ // 1) Flash loan base/LST
2052
2263
  const flashLoanObj = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
2053
2264
  if (depositReserve.coinType === ((_b = depositReserves.lst) === null || _b === void 0 ? void 0 : _b.coinType)) {
2054
2265
  // TODO: Account for LST mint fees