@suilend/sdk 2.0.4 → 2.0.6

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/strategies.js CHANGED
@@ -14,10 +14,10 @@ import BigNumber from "bignumber.js";
14
14
  import { BN } from "bn.js";
15
15
  import { cloneDeep } from "lodash";
16
16
  import { LstClient, SPRING_SUI_UPGRADE_CAP_ID, getLatestPackageId as getLatestSpringSuiPackageId, } from "@suilend/springsui-sdk";
17
- import { API_URL, MAX_U64, MS_PER_YEAR, NORMALIZED_AUSD_COINTYPE, NORMALIZED_SUI_COINTYPE, NORMALIZED_USDC_COINTYPE, NORMALIZED_sSUI_COINTYPE, NORMALIZED_suiUSDT_COINTYPE, NORMALIZED_suiWBTC_COINTYPE, NORMALIZED_xBTC_COINTYPE, getAllCoins, isSui, mergeAllCoins, } from "@suilend/sui-fe";
17
+ import { API_URL, MAX_U64, MS_PER_YEAR, NORMALIZED_AUSD_COINTYPE, NORMALIZED_SUI_COINTYPE, NORMALIZED_USDC_COINTYPE, NORMALIZED_sSUI_COINTYPE, NORMALIZED_suiUSDT_COINTYPE, NORMALIZED_suiWBTC_COINTYPE, NORMALIZED_xBTC_COINTYPE, getSpendableCoin, isSui, } from "@suilend/sui-fe";
18
18
  import { getNetAprPercent } from "./lib";
19
19
  import { getRewardsMap } from "./lib/liquidityMining";
20
- import { STRATEGY_TYPE_INFO_MAP, StrategyType, strategyBorrow, strategyClaimRewardsAndSwapForCoinType, strategyDeposit, strategyWithdraw, } from "./lib/strategyOwnerCap";
20
+ import { STRATEGY_TYPE_INFO_MAP, StrategyType, strategyBorrow, strategyClaimRewardsAndMergeCoins, strategyDeposit, strategyWithdraw, } from "./lib/strategyOwnerCap";
21
21
  import { MMT_CONTRACT_PACKAGE_ID, MMT_VERSION_OBJECT_ID } from "./mmt";
22
22
  import { getWeightedBorrowsUsd } from "./utils";
23
23
  export const STRATEGY_E = 10 ** -7;
@@ -35,20 +35,28 @@ export const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = {
35
35
  borrowA: false,
36
36
  feePercent: 0.01,
37
37
  },
38
- [StrategyType.stratSUI_SUI_LOOPING]: {
38
+ [StrategyType.USDC_sSUI_SUI_LOOPING]: {
39
39
  provider: StrategyFlashLoanProvider.MMT,
40
- poolId: "0x9c92c5b8e9d83e485fb4c86804ac8b920bb0beaace5e61a5b0239218f627f8e9", // xSUI-SUI 0.01% https://app.mmt.finance/liquidity/0x9c92c5b8e9d83e485fb4c86804ac8b920bb0beaace5e61a5b0239218f627f8e9
41
- coinTypeA: "0x2b6602099970374cf58a2a1b9d96f005fccceb81e92eb059873baf420eb6c717::x_sui::X_SUI",
42
- coinTypeB: NORMALIZED_SUI_COINTYPE,
40
+ poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
41
+ coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
42
+ coinTypeB: NORMALIZED_USDC_COINTYPE,
43
43
  borrowA: false,
44
- feePercent: 0.01,
44
+ feePercent: 0.001,
45
45
  },
46
- [StrategyType.USDC_sSUI_SUI_LOOPING]: {
46
+ [StrategyType.USDsui_USDC_LOOPING]: {
47
47
  provider: StrategyFlashLoanProvider.MMT,
48
48
  poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
49
49
  coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
50
50
  coinTypeB: NORMALIZED_USDC_COINTYPE,
51
- borrowA: false,
51
+ borrowA: false, // Requires swap from USDT to USDsui
52
+ feePercent: 0.001,
53
+ },
54
+ [StrategyType.eEARN_USDC_LOOPING]: {
55
+ provider: StrategyFlashLoanProvider.MMT,
56
+ poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
57
+ coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
58
+ coinTypeB: NORMALIZED_USDC_COINTYPE,
59
+ borrowA: false, // Requires swap from USDC to eEARN
52
60
  feePercent: 0.001,
53
61
  },
54
62
  [StrategyType.AUSD_sSUI_SUI_LOOPING]: {
@@ -107,6 +115,23 @@ export const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = {
107
115
  borrowA: false,
108
116
  feePercent: 0.001,
109
117
  },
118
+ // TODO: Update poolId for USDsui sSUI-SUI
119
+ [StrategyType.USDsui_sSUI_SUI_LOOPING]: {
120
+ provider: StrategyFlashLoanProvider.MMT,
121
+ poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
122
+ coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
123
+ coinTypeB: NORMALIZED_USDC_COINTYPE,
124
+ borrowA: false,
125
+ feePercent: 0.001,
126
+ },
127
+ [StrategyType.stratSUI_SUI_LOOPING]: {
128
+ provider: StrategyFlashLoanProvider.MMT,
129
+ poolId: "0x9c92c5b8e9d83e485fb4c86804ac8b920bb0beaace5e61a5b0239218f627f8e9", // xSUI-SUI 0.01% https://app.mmt.finance/liquidity/0x9c92c5b8e9d83e485fb4c86804ac8b920bb0beaace5e61a5b0239218f627f8e9
130
+ coinTypeA: "0x2b6602099970374cf58a2a1b9d96f005fccceb81e92eb059873baf420eb6c717::x_sui::X_SUI",
131
+ coinTypeB: NORMALIZED_SUI_COINTYPE,
132
+ borrowA: false,
133
+ feePercent: 0.01,
134
+ },
110
135
  };
111
136
  export const getReserveSafeDepositLimit = (reserve) => {
112
137
  // Calculate safe deposit limit (subtract 10 mins of deposit APR from cap)
@@ -133,7 +158,10 @@ export const hasStrategyPosition = (obligation) => obligation.deposits.length >
133
158
  // SUI
134
159
  export const getStrategySuiReserve = (
135
160
  // AppContext
136
- reserveMap) => reserveMap[NORMALIZED_SUI_COINTYPE];
161
+ reserveMap) => {
162
+ var _a;
163
+ return (_a = reserveMap[NORMALIZED_SUI_COINTYPE]) !== null && _a !== void 0 ? _a : { price: new BigNumber(1) };
164
+ };
137
165
  export const fetchStrategyLstMap = (suiClient) => __awaiter(void 0, void 0, void 0, function* () {
138
166
  try {
139
167
  const lstCoinTypes = Array.from(new Set([
@@ -213,16 +241,21 @@ export const STRATEGY_TYPE_EXPOSURE_MAP = {
213
241
  max: new BigNumber(3), // Actual max: 1 / (1 - (sSUI Open LTV %)) = 3.333x, where sSUI Open LTV % = 70%
214
242
  default: new BigNumber(3),
215
243
  },
216
- [StrategyType.stratSUI_SUI_LOOPING]: {
217
- min: new BigNumber(1),
218
- max: new BigNumber(3), // Actual max: 1 / (1 - (sSUI Open LTV %)) = 3.333x, where sSUI Open LTV % = 70%
219
- default: new BigNumber(3),
220
- },
221
244
  [StrategyType.USDC_sSUI_SUI_LOOPING]: {
222
245
  min: new BigNumber(1),
223
246
  max: new BigNumber(3), // Actual max: 1 + (USDC Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where USDC Open LTV % = 77% and sSUI Open LTV % = 70%
224
247
  default: new BigNumber(3),
225
248
  },
249
+ [StrategyType.USDsui_USDC_LOOPING]: {
250
+ min: new BigNumber(1),
251
+ max: new BigNumber(4), // Actual max: 1 / (1 - (USDsui Open LTV %)) = 4.347x, where USDsui Open LTV % = 77%
252
+ default: new BigNumber(4),
253
+ },
254
+ [StrategyType.eEARN_USDC_LOOPING]: {
255
+ min: new BigNumber(1),
256
+ max: new BigNumber(4.5), // Actual max: 1 / (1 - (eEARN Open LTV %)) = 5x, where eEARN Open LTV % = 80%
257
+ default: new BigNumber(4.5),
258
+ },
226
259
  [StrategyType.AUSD_sSUI_SUI_LOOPING]: {
227
260
  min: new BigNumber(1),
228
261
  max: new BigNumber(3), // Actual max: 1 + (AUSD Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where AUSD Open LTV % = 77% and sSUI Open LTV % = 70%
@@ -258,6 +291,16 @@ export const STRATEGY_TYPE_EXPOSURE_MAP = {
258
291
  max: new BigNumber(4), // Actual max: 1 / (1 - (USDC Open LTV %)) = 4.347x, where USDC Open LTV % = 77%
259
292
  default: new BigNumber(4),
260
293
  },
294
+ [StrategyType.USDsui_sSUI_SUI_LOOPING]: {
295
+ min: new BigNumber(1),
296
+ max: new BigNumber(3), // Actual max: 1 + (USDsui Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where USDsui Open LTV % = 77% and sSUI Open LTV % = 70%
297
+ default: new BigNumber(3),
298
+ },
299
+ [StrategyType.stratSUI_SUI_LOOPING]: {
300
+ min: new BigNumber(1),
301
+ max: new BigNumber(3), // Actual max: 1 / (1 - (sSUI Open LTV %)) = 3.333x, where sSUI Open LTV % = 70%
302
+ default: new BigNumber(3),
303
+ },
261
304
  };
262
305
  // Reserves
263
306
  export const getStrategyDepositReserves = (
@@ -801,6 +844,7 @@ lstMap, strategyType, obligation, exposure) => {
801
844
  StrategyType.AUSD_sSUI_SUI_LOOPING,
802
845
  StrategyType.xBTC_sSUI_SUI_LOOPING,
803
846
  StrategyType.suiUSDT_sSUI_SUI_LOOPING,
847
+ StrategyType.USDsui_sSUI_SUI_LOOPING,
804
848
  ].includes(strategyType))
805
849
  return new BigNumber(0); // Not shown in UI
806
850
  let _obligation;
@@ -897,12 +941,14 @@ transaction) => __awaiter(void 0, void 0, void 0, function* () {
897
941
  }, null, 2));
898
942
  // 1.2) Borrow
899
943
  const stepBorrowedAmount = BigNumber.min(pendingBorrowedAmount, stepMaxBorrowedAmount).decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_DOWN);
944
+ if (stepBorrowedAmount.lte(0))
945
+ break;
900
946
  const isMaxBorrow = stepBorrowedAmount.eq(stepMaxBorrowedAmount);
901
947
  console.log(`[loopStrategyToExposure] ${i} borrow_sui.borrow |`, JSON.stringify({
902
948
  stepBorrowedAmount: stepBorrowedAmount.toFixed(20),
903
949
  isMaxBorrow,
904
950
  }, null, 2));
905
- const [borrowedCoin] = strategyBorrow(borrowReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(borrowReserve.coinType), BigInt(stepBorrowedAmount
951
+ const [borrowedCoin] = strategyBorrow(strategyType, borrowReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(borrowReserve.coinType), BigInt(stepBorrowedAmount
906
952
  .times(10 ** borrowReserve.token.decimals)
907
953
  .integerValue(BigNumber.ROUND_DOWN)
908
954
  .toString()), transaction);
@@ -927,7 +973,7 @@ transaction) => __awaiter(void 0, void 0, void 0, function* () {
927
973
  stepDepositedAmount: stepDepositedAmount.toFixed(20),
928
974
  isMaxDeposit,
929
975
  }, null, 2));
930
- strategyDeposit(stepLstCoin, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), transaction);
976
+ strategyDeposit(strategyType, stepLstCoin, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), transaction);
931
977
  // 2.3) Update state
932
978
  deposits = addOrInsertStrategyDeposit(deposits, {
933
979
  coinType: loopingDepositReserve.coinType,
@@ -983,12 +1029,14 @@ transaction) => __awaiter(void 0, void 0, void 0, function* () {
983
1029
  }, null, 2));
984
1030
  // 1.2) Borrow
985
1031
  const stepBorrowedAmount = BigNumber.min(pendingBorrowedAmount, stepMaxBorrowedAmount).decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_DOWN);
1032
+ if (stepBorrowedAmount.lte(0))
1033
+ break;
986
1034
  const isMaxBorrow = stepBorrowedAmount.eq(stepMaxBorrowedAmount);
987
1035
  console.log(`[loopStrategyToExposure] ${i} borrow.borrow |`, JSON.stringify({
988
1036
  stepBorrowedAmount: stepBorrowedAmount.toFixed(20),
989
1037
  isMaxBorrow,
990
1038
  }, null, 2));
991
- const [stepBorrowedCoin] = strategyBorrow(borrowReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(borrowReserve.coinType), BigInt(stepBorrowedAmount
1039
+ const [stepBorrowedCoin] = strategyBorrow(strategyType, borrowReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(borrowReserve.coinType), BigInt(stepBorrowedAmount
992
1040
  .times(10 ** borrowReserve.token.decimals)
993
1041
  .integerValue(BigNumber.ROUND_DOWN)
994
1042
  .toString()), transaction);
@@ -1045,7 +1093,7 @@ transaction) => __awaiter(void 0, void 0, void 0, function* () {
1045
1093
  stepDepositedAmount: stepDepositedAmount.toFixed(20),
1046
1094
  isMaxDeposit,
1047
1095
  }, null, 2));
1048
- strategyDeposit(stepBaseCoin, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), transaction);
1096
+ strategyDeposit(strategyType, stepBaseCoin, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), transaction);
1049
1097
  // 2.3) Update state
1050
1098
  deposits = addOrInsertStrategyDeposit(deposits, {
1051
1099
  coinType: loopingDepositReserve.coinType,
@@ -1135,7 +1183,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1135
1183
  lstWithdrawnAmount: lstWithdrawnAmount.toFixed(20),
1136
1184
  }));
1137
1185
  // 1.1) Withdraw
1138
- const [withdrawnLstCoin] = strategyWithdraw(depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(new BigNumber(lstWithdrawnAmount
1186
+ const [withdrawnLstCoin] = strategyWithdraw(strategyType, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(new BigNumber(lstWithdrawnAmount
1139
1187
  .times(10 ** LST_DECIMALS)
1140
1188
  .integerValue(BigNumber.ROUND_DOWN)
1141
1189
  .toString())
@@ -1194,7 +1242,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1194
1242
  remainingLstWithdrawnAmount: remainingLstWithdrawnAmount.toFixed(20),
1195
1243
  }));
1196
1244
  // 1.1) MAX Withdraw
1197
- const [withdrawnRemainingLstCoin] = strategyWithdraw(depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(MAX_U64.toString()), transaction);
1245
+ const [withdrawnRemainingLstCoin] = strategyWithdraw(strategyType, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(MAX_U64.toString()), transaction);
1198
1246
  // 1.2) Update state
1199
1247
  deposits = addOrInsertStrategyDeposit(deposits, {
1200
1248
  coinType: depositReserves.lst.coinType,
@@ -1246,7 +1294,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1246
1294
  throw new Error("No swap quote found");
1247
1295
  }
1248
1296
  // 3) Deposit base
1249
- strategyDeposit(swapCoin, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), transaction);
1297
+ strategyDeposit(strategyType, swapCoin, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), transaction);
1250
1298
  }
1251
1299
  });
1252
1300
  const fullyRepayBorrowsUsingBase = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1269,7 +1317,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1269
1317
  // 1) MAX withdraw LST
1270
1318
  if (depositReserves.lst !== undefined) {
1271
1319
  // 1.1) MAX withdraw
1272
- const [withdrawnMaxLstCoin] = strategyWithdraw(depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(MAX_U64.toString()), transaction);
1320
+ const [withdrawnMaxLstCoin] = strategyWithdraw(strategyType, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), BigInt(MAX_U64.toString()), transaction);
1273
1321
  // 1.2) Update state
1274
1322
  deposits = addOrInsertStrategyDeposit(deposits, {
1275
1323
  coinType: depositReserves.lst.coinType,
@@ -1296,7 +1344,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1296
1344
  baseWithdrawnAmount: baseWithdrawnAmount.toFixed(20),
1297
1345
  }, null, 2));
1298
1346
  // 2.1) Withdraw
1299
- const [withdrawnBaseCoin] = strategyWithdraw(depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), BigInt(new BigNumber(baseWithdrawnAmount
1347
+ const [withdrawnBaseCoin] = strategyWithdraw(strategyType, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), BigInt(new BigNumber(baseWithdrawnAmount
1300
1348
  .times(10 ** depositReserves.base.token.decimals)
1301
1349
  .integerValue(BigNumber.ROUND_DOWN)
1302
1350
  .toString())
@@ -1463,7 +1511,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1463
1511
  stepWithdrawnAmount: stepWithdrawnAmount.toFixed(20),
1464
1512
  isMaxWithdraw,
1465
1513
  }, null, 2));
1466
- const [stepWithdrawnCoin] = strategyWithdraw(loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), BigInt(new BigNumber(stepWithdrawnAmount
1514
+ const [stepWithdrawnCoin] = strategyWithdraw(strategyType, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), BigInt(new BigNumber(stepWithdrawnAmount
1467
1515
  .times(10 ** loopingDepositReserve.token.decimals)
1468
1516
  .integerValue(BigNumber.ROUND_DOWN)
1469
1517
  .toString())
@@ -1564,7 +1612,13 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1564
1612
  stepWithdrawnAmount: stepWithdrawnAmount.toFixed(20),
1565
1613
  isMaxWithdraw,
1566
1614
  }, null, 2));
1567
- const [stepWithdrawnCoin] = strategyWithdraw(loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), BigInt(new BigNumber(stepWithdrawnAmount
1615
+ // `pendingBorrowedAmount` can fall below a single unit of base after
1616
+ // rounding down to the deposit coin's decimals, leaving
1617
+ // `stepWithdrawnAmount = 0`. Cetus returns "No swap quote found" for a
1618
+ // zero-amount quote — there's nothing meaningful left to unloop, so stop.
1619
+ if (stepWithdrawnAmount.lte(0))
1620
+ break;
1621
+ const [stepWithdrawnCoin] = strategyWithdraw(strategyType, loopingDepositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(loopingDepositReserve.coinType), BigInt(new BigNumber(stepWithdrawnAmount
1568
1622
  .times(10 ** loopingDepositReserve.token.decimals)
1569
1623
  .integerValue(BigNumber.ROUND_DOWN)
1570
1624
  .toString())
@@ -1621,7 +1675,14 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
1621
1675
  }, null, 2), routers);
1622
1676
  // 3) Repay borrows
1623
1677
  // 3.1) Repay
1624
- const stepRepaidAmount = new BigNumber(new BigNumber(routers.amountOut.toString()).div(10 ** borrowReserve.token.decimals)).decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_DOWN);
1678
+ // Actual on-chain swap output can be up to `slippagePercent`% less than the
1679
+ // Cetus quote — track pessimistically so `borrowedAmount` stays ≥ real debt.
1680
+ // Otherwise per-step under-counting accumulates and the final
1681
+ // `fullyRepayBorrowsUsingBase` sizes off a near-zero tracked value, stranding
1682
+ // dust borrow that blocks the subsequent `MAX_U64` deposit withdraw.
1683
+ const stepRepaidAmount = new BigNumber(new BigNumber(routers.amountOut.toString())
1684
+ .times(1 - slippagePercent / 100)
1685
+ .div(10 ** borrowReserve.token.decimals)).decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_DOWN);
1625
1686
  const isMaxRepay = stepRepaidAmount.eq(stepMaxRepaidAmount);
1626
1687
  console.log(`[unloopStrategyToExposure] ${i} repay_borrows.repay |`, JSON.stringify({
1627
1688
  stepRepaidAmount: stepRepaidAmount.toFixed(20),
@@ -1705,7 +1766,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1705
1766
  // 1.1.2) Stake SUI for LST
1706
1767
  const lstCoin = lst.client.mint(transaction, suiCoin);
1707
1768
  // 1.1.3) Deposit LST (1x exposure)
1708
- strategyDeposit(lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1769
+ strategyDeposit(strategyType, lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1709
1770
  // 1.1.4) Update state
1710
1771
  deposits = addOrInsertStrategyDeposit(deposits, {
1711
1772
  coinType: depositReserves.lst.coinType,
@@ -1715,16 +1776,12 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1715
1776
  // 1.2) LST
1716
1777
  else if (deposit.coinType === ((_c = depositReserves.lst) === null || _c === void 0 ? void 0 : _c.coinType)) {
1717
1778
  // 1.2.1) Split coins
1718
- const allCoinsLst = yield getAllCoins(suiClient, _address, depositReserves.lst.coinType);
1719
- const mergeCoinLst = mergeAllCoins(depositReserves.lst.coinType, transaction, allCoinsLst);
1720
- const lstCoin = transaction.splitCoins(transaction.object(mergeCoinLst.coinObjectId), [
1721
- BigInt(deposit.depositedAmount
1722
- .times(10 ** LST_DECIMALS)
1723
- .integerValue(BigNumber.ROUND_DOWN)
1724
- .toString()),
1725
- ]);
1779
+ const lstCoin = yield getSpendableCoin(suiClient, _address, depositReserves.lst.coinType, deposit.depositedAmount
1780
+ .times(10 ** LST_DECIMALS)
1781
+ .integerValue(BigNumber.ROUND_DOWN)
1782
+ .toString(), transaction);
1726
1783
  // 1.2.2) Deposit LST (1x exposure)
1727
- strategyDeposit(lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1784
+ strategyDeposit(strategyType, lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1728
1785
  // 1.2.3) Update state
1729
1786
  deposits = addOrInsertStrategyDeposit(deposits, deposit);
1730
1787
  // 1.3) Other
@@ -1732,18 +1789,53 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1732
1789
  else {
1733
1790
  const otherReserve = reserveMap[deposit.coinType];
1734
1791
  // 1.3.1) Split coins
1735
- const allCoinsOther = yield getAllCoins(suiClient, _address, otherReserve.coinType);
1736
- const mergeCoinOther = mergeAllCoins(otherReserve.coinType, transaction, allCoinsOther);
1737
- const otherCoin = transaction.splitCoins(transaction.object(mergeCoinOther.coinObjectId), [
1738
- BigInt(deposit.depositedAmount
1739
- .times(10 ** otherReserve.token.decimals)
1740
- .integerValue(BigNumber.ROUND_DOWN)
1741
- .toString()),
1742
- ]);
1743
- // 1.3.2) Deposit other (1x exposure)
1744
- strategyDeposit(otherCoin, otherReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(otherReserve.coinType), transaction);
1745
- // 1.3.3) Update state
1746
- deposits = addOrInsertStrategyDeposit(deposits, deposit);
1792
+ const otherCoin = yield getSpendableCoin(suiClient, _address, otherReserve.coinType, deposit.depositedAmount
1793
+ .times(10 ** otherReserve.token.decimals)
1794
+ .integerValue(BigNumber.ROUND_DOWN)
1795
+ .toString(), transaction);
1796
+ // 1.3.2) If the deposit coin is the same as the borrow coin, swap to base first
1797
+ if (deposit.coinType === borrowReserve.coinType && depositReserve) {
1798
+ const routers = yield cetusSdk.findRouters({
1799
+ from: otherReserve.coinType,
1800
+ target: depositReserve.coinType,
1801
+ amount: new BN(deposit.depositedAmount
1802
+ .times(10 ** otherReserve.token.decimals)
1803
+ .integerValue(BigNumber.ROUND_DOWN)
1804
+ .toString()),
1805
+ byAmountIn: true,
1806
+ splitCount: 0,
1807
+ });
1808
+ if (!routers)
1809
+ throw new Error("No swap quote found");
1810
+ const slippagePercent = 1;
1811
+ let baseCoin;
1812
+ try {
1813
+ baseCoin = (yield cetusSdk.fixableRouterSwapV3({
1814
+ router: routers,
1815
+ inputCoin: otherCoin,
1816
+ slippage: slippagePercent / 100,
1817
+ txb: transaction,
1818
+ partner: cetusPartnerId,
1819
+ }));
1820
+ }
1821
+ catch (err) {
1822
+ throw new Error("No swap quote found");
1823
+ }
1824
+ const swappedAmount = new BigNumber(routers.amountOut.toString())
1825
+ .div(10 ** depositReserve.token.decimals)
1826
+ .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_DOWN);
1827
+ strategyDeposit(strategyType, baseCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
1828
+ deposits = addOrInsertStrategyDeposit(deposits, {
1829
+ coinType: depositReserve.coinType,
1830
+ depositedAmount: swappedAmount,
1831
+ });
1832
+ }
1833
+ else {
1834
+ // 1.3.3) Deposit other (1x exposure)
1835
+ strategyDeposit(strategyType, otherCoin, otherReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(otherReserve.coinType), transaction);
1836
+ // 1.3.4) Update state
1837
+ deposits = addOrInsertStrategyDeposit(deposits, deposit);
1838
+ }
1747
1839
  }
1748
1840
  console.log(`[deposit] deposit |`, JSON.stringify({
1749
1841
  deposits: deposits.map((d) => ({
@@ -1885,7 +1977,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1885
1977
  }
1886
1978
  // 2) Withdraw base or LST
1887
1979
  // 2.1) Withdraw
1888
- const [withdrawnCoin] = strategyWithdraw(depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(new BigNumber(withdrawnAmount
1980
+ const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(new BigNumber(withdrawnAmount
1889
1981
  .times(10 ** depositReserve.token.decimals)
1890
1982
  .integerValue(BigNumber.ROUND_DOWN)
1891
1983
  .toString())
@@ -1916,8 +2008,38 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1916
2008
  return { deposits, borrowedAmount, transaction, withdrawnCoin };
1917
2009
  else {
1918
2010
  if (depositReserve.coinType === ((_h = depositReserves.base) === null || _h === void 0 ? void 0 : _h.coinType)) {
1919
- // 3.1) Transfer base to user
1920
- transaction.transferObjects([withdrawnCoin], _address);
2011
+ if (withdraw.coinType !== depositReserve.coinType) {
2012
+ const routers = yield cetusSdk.findRouters({
2013
+ from: depositReserve.coinType,
2014
+ target: withdraw.coinType,
2015
+ amount: new BN(withdrawnAmount
2016
+ .times(10 ** depositReserve.token.decimals)
2017
+ .integerValue(BigNumber.ROUND_DOWN)
2018
+ .toString()),
2019
+ byAmountIn: true,
2020
+ splitCount: 0,
2021
+ });
2022
+ if (!routers)
2023
+ throw new Error("No swap quote found");
2024
+ const slippagePercent = 1;
2025
+ let swappedCoin;
2026
+ try {
2027
+ swappedCoin = (yield cetusSdk.fixableRouterSwapV3({
2028
+ router: routers,
2029
+ inputCoin: withdrawnCoin,
2030
+ slippage: slippagePercent / 100,
2031
+ txb: transaction,
2032
+ partner: cetusPartnerId,
2033
+ }));
2034
+ }
2035
+ catch (err) {
2036
+ throw new Error("No swap quote found");
2037
+ }
2038
+ transaction.transferObjects([swappedCoin], _address);
2039
+ }
2040
+ else {
2041
+ transaction.transferObjects([withdrawnCoin], _address);
2042
+ }
1921
2043
  }
1922
2044
  else {
1923
2045
  if (isSui(withdraw.coinType)) {
@@ -1936,10 +2058,10 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1936
2058
  });
1937
2059
  export const strategyMaxWithdrawTx = (
1938
2060
  // AppContext
1939
- reserveMap, rewardPriceMap, rewardsMap,
2061
+ reserveMap, rewardsMap,
1940
2062
  // Strategy
1941
2063
  lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdrawCoinType, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1942
- var _a, _b;
2064
+ var _a, _b, _c, _d;
1943
2065
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
1944
2066
  const lst = strategyInfo.depositLstCoinType !== undefined
1945
2067
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -1982,7 +2104,8 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1982
2104
  }, null, 2));
1983
2105
  }
1984
2106
  // 2) MAX withdraw base or LST
1985
- const [withdrawnCoin] = strategyWithdraw(depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
2107
+ const estimatedWithdrawnAmount = (_c = (_b = deposits.find((d) => d.coinType === depositReserve.coinType)) === null || _b === void 0 ? void 0 : _b.depositedAmount) !== null && _c !== void 0 ? _c : new BigNumber(0);
2108
+ const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
1986
2109
  // 2.2) Update state
1987
2110
  deposits = [];
1988
2111
  console.log(`[strategyMaxWithdraw] max_withdraw.update_state |`, JSON.stringify({
@@ -1993,9 +2116,39 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1993
2116
  borrowedAmount: borrowedAmount.toFixed(20),
1994
2117
  }, null, 2));
1995
2118
  // 3) Transfer coin to user
1996
- if (depositReserve.coinType === ((_b = depositReserves.base) === null || _b === void 0 ? void 0 : _b.coinType)) {
1997
- // 3.1) Transfer base to user
1998
- transaction.transferObjects([withdrawnCoin], _address);
2119
+ if (depositReserve.coinType === ((_d = depositReserves.base) === null || _d === void 0 ? void 0 : _d.coinType)) {
2120
+ if (withdrawCoinType !== depositReserve.coinType) {
2121
+ const routers = yield cetusSdk.findRouters({
2122
+ from: depositReserve.coinType,
2123
+ target: withdrawCoinType,
2124
+ amount: new BN(estimatedWithdrawnAmount
2125
+ .times(10 ** depositReserve.token.decimals)
2126
+ .integerValue(BigNumber.ROUND_DOWN)
2127
+ .toString()),
2128
+ byAmountIn: true,
2129
+ splitCount: 0,
2130
+ });
2131
+ if (!routers)
2132
+ throw new Error("No swap quote found");
2133
+ const slippagePercent = 1;
2134
+ let swappedCoin;
2135
+ try {
2136
+ swappedCoin = (yield cetusSdk.fixableRouterSwapV3({
2137
+ router: routers,
2138
+ inputCoin: withdrawnCoin,
2139
+ slippage: slippagePercent / 100,
2140
+ txb: transaction,
2141
+ partner: cetusPartnerId,
2142
+ }));
2143
+ }
2144
+ catch (err) {
2145
+ throw new Error("No swap quote found");
2146
+ }
2147
+ transaction.transferObjects([swappedCoin], _address);
2148
+ }
2149
+ else {
2150
+ transaction.transferObjects([withdrawnCoin], _address);
2151
+ }
1999
2152
  }
2000
2153
  else {
2001
2154
  if (isSui(withdrawCoinType)) {
@@ -2009,14 +2162,13 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2009
2162
  transaction.transferObjects([withdrawnCoin], _address);
2010
2163
  }
2011
2164
  }
2012
- // 4) Claim rewards, swap for withdrawCoinType, and transfer to user
2165
+ // 4) Claim rewards and transfer to user
2013
2166
  if (hasClaimableRewards) {
2014
2167
  try {
2015
- const txCopy = Transaction.from(transaction);
2016
- yield strategyClaimRewardsAndSwapForCoinType(_address, cetusSdk, cetusPartnerId, rewardsMap, rewardPriceMap, reserveMap[withdrawCoinType], strategyOwnerCapId, false, // isDepositing (false = transfer to user)
2017
- txCopy);
2018
- yield dryRunTransaction(txCopy); // Throws error if fails
2019
- transaction = txCopy;
2168
+ const mergedCoinsMap = strategyClaimRewardsAndMergeCoins(strategyType, rewardsMap, strategyOwnerCapId, transaction);
2169
+ for (const coin of Object.values(mergedCoinsMap)) {
2170
+ transaction.transferObjects([coin], _address);
2171
+ }
2020
2172
  }
2021
2173
  catch (err) {
2022
2174
  // Don't block user if fails
@@ -2199,7 +2351,7 @@ export const strategyDepositAdjustWithdrawTx = (
2199
2351
  reserveMap,
2200
2352
  // Strategy
2201
2353
  lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2202
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
2354
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
2203
2355
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
2204
2356
  const lst = strategyInfo.depositLstCoinType !== undefined
2205
2357
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -2225,12 +2377,23 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2225
2377
  let borrowedAmount = _borrowedAmount;
2226
2378
  // 1) Flash loan base/LST
2227
2379
  const flashLoanObj = STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
2228
- if (depositReserve.coinType === ((_b = depositReserves.lst) === null || _b === void 0 ? void 0 : _b.coinType)) {
2380
+ const flashLoanCoinType = flashLoanObj.borrowA
2381
+ ? flashLoanObj.coinTypeA
2382
+ : flashLoanObj.coinTypeB;
2383
+ const flashLoanCoinReserve = (_b = reserveMap[flashLoanCoinType]) !== null && _b !== void 0 ? _b : depositReserve;
2384
+ const needsFlashLoanCoinSwap = flashLoanCoinType !== depositReserve.coinType;
2385
+ if (depositReserve.coinType === ((_c = depositReserves.lst) === null || _c === void 0 ? void 0 : _c.coinType)) {
2229
2386
  // TODO: Account for LST mint fees
2230
2387
  flashLoanBorrowedAmount = flashLoanBorrowedAmount
2231
- .times((_c = lst === null || lst === void 0 ? void 0 : lst.lstToSuiExchangeRate) !== null && _c !== void 0 ? _c : 1)
2388
+ .times((_d = lst === null || lst === void 0 ? void 0 : lst.lstToSuiExchangeRate) !== null && _d !== void 0 ? _d : 1)
2232
2389
  .decimalPlaces(SUI_DECIMALS, BigNumber.ROUND_UP);
2233
2390
  }
2391
+ let flashLoanBorrowAmountForLoan = flashLoanBorrowedAmount;
2392
+ if (needsFlashLoanCoinSwap) {
2393
+ flashLoanBorrowAmountForLoan = flashLoanBorrowAmountForLoan
2394
+ .times(1.01) // Buffer for swap slippage
2395
+ .decimalPlaces(flashLoanCoinReserve.token.decimals, BigNumber.ROUND_UP);
2396
+ }
2234
2397
  let borrowedBalanceA, borrowedBalanceB, receipt;
2235
2398
  if (flashLoanObj.provider === StrategyFlashLoanProvider.MMT) {
2236
2399
  [borrowedBalanceA, borrowedBalanceB, receipt] = transaction.moveCall({
@@ -2239,9 +2402,9 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2239
2402
  arguments: [
2240
2403
  transaction.object(flashLoanObj.poolId),
2241
2404
  transaction.pure.u64(flashLoanObj.borrowA
2242
- ? flashLoanBorrowedAmount
2405
+ ? flashLoanBorrowAmountForLoan
2243
2406
  .times(10 **
2244
- (depositReserve.coinType === ((_d = depositReserves.lst) === null || _d === void 0 ? void 0 : _d.coinType)
2407
+ (depositReserve.coinType === ((_e = depositReserves.lst) === null || _e === void 0 ? void 0 : _e.coinType)
2245
2408
  ? SUI_DECIMALS
2246
2409
  : depositReserve.token.decimals))
2247
2410
  .integerValue(BigNumber.ROUND_DOWN)
@@ -2249,11 +2412,11 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2249
2412
  : 0),
2250
2413
  transaction.pure.u64(flashLoanObj.borrowA
2251
2414
  ? 0
2252
- : flashLoanBorrowedAmount
2415
+ : flashLoanBorrowAmountForLoan
2253
2416
  .times(10 **
2254
- (depositReserve.coinType === ((_e = depositReserves.lst) === null || _e === void 0 ? void 0 : _e.coinType)
2417
+ (depositReserve.coinType === ((_f = depositReserves.lst) === null || _f === void 0 ? void 0 : _f.coinType)
2255
2418
  ? SUI_DECIMALS
2256
- : depositReserve.token.decimals))
2419
+ : flashLoanCoinReserve.token.decimals))
2257
2420
  .integerValue(BigNumber.ROUND_DOWN)
2258
2421
  .toString()),
2259
2422
  transaction.object(MMT_VERSION_OBJECT_ID),
@@ -2266,9 +2429,9 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2266
2429
  // 2) Deposit additional (to get back up to 100% health, so the user can then unloop back down to the max leverage shown in the UI)
2267
2430
  // 2.1) Deposit
2268
2431
  let depositedAmount = flashLoanBorrowedAmount;
2269
- if (depositReserve.coinType === ((_f = depositReserves.lst) === null || _f === void 0 ? void 0 : _f.coinType))
2432
+ if (depositReserve.coinType === ((_g = depositReserves.lst) === null || _g === void 0 ? void 0 : _g.coinType))
2270
2433
  depositedAmount = new BigNumber(depositedAmount.minus(getStrategyLstMintFee(lstMap, depositReserve.coinType, depositedAmount)))
2271
- .times((_g = lst === null || lst === void 0 ? void 0 : lst.suiToLstExchangeRate) !== null && _g !== void 0 ? _g : 1)
2434
+ .times((_h = lst === null || lst === void 0 ? void 0 : lst.suiToLstExchangeRate) !== null && _h !== void 0 ? _h : 1)
2272
2435
  .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_DOWN);
2273
2436
  let flashLoanBorrowedCoin = transaction.moveCall({
2274
2437
  target: "0x2::coin::from_balance",
@@ -2277,9 +2440,35 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2277
2440
  ],
2278
2441
  arguments: [flashLoanObj.borrowA ? borrowedBalanceA : borrowedBalanceB],
2279
2442
  });
2280
- if (depositReserve.coinType === ((_h = depositReserves.lst) === null || _h === void 0 ? void 0 : _h.coinType))
2443
+ if (depositReserve.coinType === ((_j = depositReserves.lst) === null || _j === void 0 ? void 0 : _j.coinType))
2281
2444
  flashLoanBorrowedCoin = lst.client.mint(transaction, flashLoanBorrowedCoin);
2282
- strategyDeposit(flashLoanBorrowedCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
2445
+ if (needsFlashLoanCoinSwap) {
2446
+ const depositRouters = yield cetusSdk.findRouters({
2447
+ from: flashLoanCoinType,
2448
+ target: depositReserve.coinType,
2449
+ amount: new BN(flashLoanBorrowAmountForLoan
2450
+ .times(10 ** flashLoanCoinReserve.token.decimals)
2451
+ .integerValue(BigNumber.ROUND_DOWN)
2452
+ .toString()),
2453
+ byAmountIn: true,
2454
+ splitCount: 0,
2455
+ });
2456
+ if (!depositRouters)
2457
+ throw new Error("No swap quote found");
2458
+ try {
2459
+ flashLoanBorrowedCoin = (yield cetusSdk.fixableRouterSwapV3({
2460
+ router: depositRouters,
2461
+ inputCoin: flashLoanBorrowedCoin,
2462
+ slippage: 1 / 100,
2463
+ txb: transaction,
2464
+ partner: cetusPartnerId,
2465
+ }));
2466
+ }
2467
+ catch (err) {
2468
+ throw new Error("No swap quote found");
2469
+ }
2470
+ }
2471
+ strategyDeposit(strategyType, flashLoanBorrowedCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
2283
2472
  // 2.2) Update state
2284
2473
  deposits = addOrInsertStrategyDeposit(deposits, {
2285
2474
  coinType: depositReserve.coinType,
@@ -2303,14 +2492,18 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2303
2492
  const dryRunResults = yield dryRunTransaction(transaction);
2304
2493
  const flashLoanRepayAmount = new BigNumber(bcs
2305
2494
  .u64()
2306
- .parse(new Uint8Array((_m = (_l = (_k = (_j = dryRunResults.results) === null || _j === void 0 ? void 0 : _j.find((r, index) => index === receiptDebts.Result)) === null || _k === void 0 ? void 0 : _k.returnValues) === null || _l === void 0 ? void 0 : _l[flashLoanObj.borrowA ? 0 : 1][0]) !== null && _m !== void 0 ? _m : [0])))
2307
- .div(10 ** depositReserve.token.decimals)
2308
- .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
2495
+ .parse(new Uint8Array((_o = (_m = (_l = (_k = dryRunResults.results) === null || _k === void 0 ? void 0 : _k.find((r, index) => index === receiptDebts.Result)) === null || _l === void 0 ? void 0 : _l.returnValues) === null || _m === void 0 ? void 0 : _m[flashLoanObj.borrowA ? 0 : 1][0]) !== null && _o !== void 0 ? _o : [0])))
2496
+ .div(10 ** flashLoanCoinReserve.token.decimals)
2497
+ .decimalPlaces(flashLoanCoinReserve.token.decimals, BigNumber.ROUND_UP);
2309
2498
  // 4.1) Withdraw additional + fee
2310
2499
  let withdrawnAmount = flashLoanRepayAmount;
2311
- if (depositReserve.coinType === ((_o = depositReserves.lst) === null || _o === void 0 ? void 0 : _o.coinType))
2500
+ if (needsFlashLoanCoinSwap)
2501
+ withdrawnAmount = flashLoanRepayAmount
2502
+ .times(1.01) // Buffer for swap slippage
2503
+ .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
2504
+ else if (depositReserve.coinType === ((_p = depositReserves.lst) === null || _p === void 0 ? void 0 : _p.coinType))
2312
2505
  withdrawnAmount = withdrawnAmount
2313
- .div(1 - +((_p = lst === null || lst === void 0 ? void 0 : lst.redeemFeePercent) !== null && _p !== void 0 ? _p : 0) / 100) // Potential rounding issue (max 1 MIST)
2506
+ .div(1 - +((_q = lst === null || lst === void 0 ? void 0 : lst.redeemFeePercent) !== null && _q !== void 0 ? _q : 0) / 100) // Potential rounding issue (max 1 MIST)
2314
2507
  .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
2315
2508
  const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield strategyWithdrawTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2316
2509
  coinType: depositReserve.coinType,
@@ -2324,8 +2517,34 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2324
2517
  transaction = newTransaction2;
2325
2518
  // 4.3) Repay flash loan
2326
2519
  let flashLoanRepayCoin = withdrawnCoin;
2327
- if (depositReserve.coinType === ((_q = depositReserves.lst) === null || _q === void 0 ? void 0 : _q.coinType))
2520
+ if (depositReserve.coinType === ((_r = depositReserves.lst) === null || _r === void 0 ? void 0 : _r.coinType))
2328
2521
  flashLoanRepayCoin = lst.client.redeem(transaction, flashLoanRepayCoin);
2522
+ if (needsFlashLoanCoinSwap) {
2523
+ const repayRouters = yield cetusSdk.findRouters({
2524
+ from: depositReserve.coinType,
2525
+ target: flashLoanCoinType,
2526
+ amount: new BN(withdrawnAmount
2527
+ .times(10 ** depositReserve.token.decimals)
2528
+ .integerValue(BigNumber.ROUND_DOWN)
2529
+ .toString()),
2530
+ byAmountIn: true,
2531
+ splitCount: 0,
2532
+ });
2533
+ if (!repayRouters)
2534
+ throw new Error("No swap quote found");
2535
+ try {
2536
+ flashLoanRepayCoin = (yield cetusSdk.fixableRouterSwapV3({
2537
+ router: repayRouters,
2538
+ inputCoin: flashLoanRepayCoin,
2539
+ slippage: 1 / 100,
2540
+ txb: transaction,
2541
+ partner: cetusPartnerId,
2542
+ }));
2543
+ }
2544
+ catch (err) {
2545
+ throw new Error("No swap quote found");
2546
+ }
2547
+ }
2329
2548
  const flashLoanRepayBalance = transaction.moveCall({
2330
2549
  target: "0x2::coin::into_balance",
2331
2550
  typeArguments: [