@suilend/sdk 2.0.4 → 2.0.5

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