@suilend/sdk 2.0.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/_generated/_dependencies/source/0x1/ascii/structs.d.ts +7 -11
  2. package/_generated/_dependencies/source/0x1/ascii/structs.js +6 -63
  3. package/_generated/_dependencies/source/0x1/option/structs.d.ts +3 -9
  4. package/_generated/_dependencies/source/0x1/option/structs.js +4 -42
  5. package/_generated/_dependencies/source/0x1/type-name/structs.d.ts +5 -7
  6. package/_generated/_dependencies/source/0x1/type-name/structs.js +3 -32
  7. package/_generated/_dependencies/source/0x2/bag/structs.d.ts +7 -9
  8. package/_generated/_dependencies/source/0x2/bag/structs.js +3 -31
  9. package/_generated/_dependencies/source/0x2/balance/structs.d.ts +7 -11
  10. package/_generated/_dependencies/source/0x2/balance/structs.js +7 -82
  11. package/_generated/_dependencies/source/0x2/object/structs.d.ts +8 -12
  12. package/_generated/_dependencies/source/0x2/object/structs.js +7 -61
  13. package/_generated/_dependencies/source/0x2/object-table/structs.d.ts +7 -9
  14. package/_generated/_dependencies/source/0x2/object-table/structs.js +4 -44
  15. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.d.ts +5 -7
  16. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.js +3 -31
  17. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.d.ts +11 -13
  18. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.js +3 -32
  19. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.d.ts +23 -25
  20. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.js +3 -32
  21. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.d.ts +4 -6
  22. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js +3 -33
  23. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.d.ts +55 -59
  24. package/_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.js +6 -64
  25. package/_generated/_framework/reified.d.ts +2 -4
  26. package/_generated/_framework/vector.d.ts +2 -12
  27. package/_generated/suilend/cell/structs.d.ts +4 -10
  28. package/_generated/suilend/cell/structs.js +4 -42
  29. package/_generated/suilend/decimal/structs.d.ts +4 -6
  30. package/_generated/suilend/decimal/structs.js +3 -32
  31. package/_generated/suilend/lending-market/structs.d.ts +152 -392
  32. package/_generated/suilend/lending-market/structs.js +50 -548
  33. package/_generated/suilend/liquidity-mining/structs.d.ts +50 -158
  34. package/_generated/suilend/liquidity-mining/structs.js +16 -169
  35. package/_generated/suilend/obligation/structs.d.ts +108 -148
  36. package/_generated/suilend/obligation/structs.js +23 -232
  37. package/_generated/suilend/rate-limiter/structs.d.ts +15 -19
  38. package/_generated/suilend/rate-limiter/structs.js +6 -64
  39. package/_generated/suilend/reserve/structs.d.ts +138 -362
  40. package/_generated/suilend/reserve/structs.js +29 -327
  41. package/_generated/suilend/reserve-config/structs.d.ts +33 -37
  42. package/_generated/suilend/reserve-config/structs.js +6 -65
  43. package/client.d.ts +8 -8
  44. package/client.js +55 -88
  45. package/lib/initialize.d.ts +29 -28
  46. package/lib/initialize.js +16 -12
  47. package/lib/liquidityMining.d.ts +3 -3
  48. package/lib/pythAdapter.d.ts +9 -0
  49. package/lib/pythAdapter.js +121 -0
  50. package/lib/strategyOwnerCap.d.ts +12 -7
  51. package/lib/strategyOwnerCap.js +159 -156
  52. package/margin/margin/admin_cap.d.ts +2 -2
  53. package/margin/margin/deps/std/type_name.d.ts +1 -1
  54. package/margin/margin/deps/sui/vec_set.d.ts +3 -5
  55. package/margin/margin/deps/suilend/lending_market.d.ts +2 -2
  56. package/margin/margin/market.d.ts +21 -38
  57. package/margin/margin/position.d.ts +47 -47
  58. package/margin/margin/router.d.ts +5 -5
  59. package/margin/margin/version.d.ts +1 -1
  60. package/package.json +1 -1
  61. package/parsers/lendingMarket.d.ts +6 -6
  62. package/parsers/obligation.d.ts +8 -8
  63. package/parsers/reserve.d.ts +8 -8
  64. package/strategies.d.ts +38 -21
  65. package/strategies.js +239 -79
  66. package/swap/quote.d.ts +1 -9
  67. package/swap/quote.js +1 -52
  68. package/swap/transaction.d.ts +2 -4
  69. package/swap/transaction.js +9 -25
  70. package/utils/events.d.ts +6 -5
  71. package/utils/events.js +11 -8
  72. package/utils/obligation.d.ts +6 -5
  73. package/utils/obligation.js +118 -117
package/strategies.js CHANGED
@@ -17,7 +17,7 @@ import { LstClient, SPRING_SUI_UPGRADE_CAP_ID, getLatestPackageId as getLatestSp
17
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";
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,15 +35,23 @@ 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
+ provider: StrategyFlashLoanProvider.MMT,
48
+ poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
49
+ coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
50
+ coinTypeB: NORMALIZED_USDC_COINTYPE,
51
+ borrowA: false,
52
+ feePercent: 0.001,
53
+ },
54
+ [StrategyType.eEARN_USDC_LOOPING]: {
47
55
  provider: StrategyFlashLoanProvider.MMT,
48
56
  poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
49
57
  coinTypeA: NORMALIZED_suiUSDT_COINTYPE,
@@ -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,8 +158,11 @@ export const hasStrategyPosition = (obligation) => obligation.deposits.length >
133
158
  // SUI
134
159
  export const getStrategySuiReserve = (
135
160
  // AppContext
136
- reserveMap) => reserveMap[NORMALIZED_SUI_COINTYPE];
137
- export const fetchStrategyLstMap = (suiClient) => __awaiter(void 0, void 0, void 0, function* () {
161
+ reserveMap) => {
162
+ var _a;
163
+ return (_a = reserveMap[NORMALIZED_SUI_COINTYPE]) !== null && _a !== void 0 ? _a : { price: new BigNumber(1) };
164
+ };
165
+ export const fetchStrategyLstMap = (suiGrpcClient) => __awaiter(void 0, void 0, void 0, function* () {
138
166
  try {
139
167
  const lstCoinTypes = Array.from(new Set([
140
168
  ...Object.values(STRATEGY_TYPE_INFO_MAP)
@@ -143,7 +171,7 @@ export const fetchStrategyLstMap = (suiClient) => __awaiter(void 0, void 0, void
143
171
  // LSTs that will be/are/have been used as rewards
144
172
  NORMALIZED_sSUI_COINTYPE,
145
173
  ]));
146
- const publishedAt = yield getLatestSpringSuiPackageId(suiClient, SPRING_SUI_UPGRADE_CAP_ID);
174
+ const publishedAt = yield getLatestSpringSuiPackageId(suiGrpcClient, SPRING_SUI_UPGRADE_CAP_ID);
147
175
  const lstInfoUrl = `${API_URL}/springsui/lst-info?${new URLSearchParams({
148
176
  coinTypes: lstCoinTypes.join(","),
149
177
  })}`;
@@ -157,7 +185,7 @@ export const fetchStrategyLstMap = (suiClient) => __awaiter(void 0, void 0, void
157
185
  const result = Object.fromEntries(yield Promise.all(lstCoinTypes.map((lstCoinType) => __awaiter(void 0, void 0, void 0, function* () {
158
186
  var _a, _b, _c, _d;
159
187
  const lstInfo = lstInfoMap[lstCoinType];
160
- const lstClient = yield LstClient.initialize(suiClient, lstInfo.LIQUID_STAKING_INFO, publishedAt);
188
+ const lstClient = yield LstClient.initialize(suiGrpcClient, lstInfo.LIQUID_STAKING_INFO, publishedAt);
161
189
  const mintFeePercent = new BigNumber((_b = (_a = lstInfo.liquidStakingInfo.feeConfig.element) === null || _a === void 0 ? void 0 : _a.suiMintFeeBps.toString()) !== null && _b !== void 0 ? _b : 0).div(100);
162
190
  const redeemFeePercent = new BigNumber((_d = (_c = lstInfo.liquidStakingInfo.feeConfig.element) === null || _c === void 0 ? void 0 : _c.redeemFeeBps.toString()) !== null && _d !== void 0 ? _d : 0).div(100);
163
191
  const res = yield fetch(`${API_URL}/springsui/historical-rates?coinType=${lstCoinType}&timestamps=${Math.floor(Date.now() / 1000)}`);
@@ -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;
@@ -832,7 +876,7 @@ export const strategyLoopToExposureTx = (
832
876
  // AppContext
833
877
  reserveMap,
834
878
  // Strategy
835
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, _targetBorrowedAmount, _targetExposure, // Must be defined if _targetBorrowedAmount is undefined
879
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, _targetBorrowedAmount, _targetExposure, // Must be defined if _targetBorrowedAmount is undefined
836
880
  transaction) => __awaiter(void 0, void 0, void 0, function* () {
837
881
  var _a, _b, _c, _d, _e;
838
882
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
@@ -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,
@@ -1069,7 +1117,7 @@ export const strategyUnloopToExposureTx = (
1069
1117
  // AppContext
1070
1118
  reserveMap,
1071
1119
  // Strategy
1072
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, _targetBorrowedAmount, _targetExposure, // Must be defined if _targetBorrowedAmount is undefined
1120
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, _targetBorrowedAmount, _targetExposure, // Must be defined if _targetBorrowedAmount is undefined
1073
1121
  transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1074
1122
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1075
1123
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
@@ -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),
@@ -1659,7 +1720,7 @@ export const strategyDepositTx = (
1659
1720
  // AppContext
1660
1721
  reserveMap,
1661
1722
  // Strategy
1662
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, deposit, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1723
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, deposit, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1663
1724
  var _a, _b, _c;
1664
1725
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
1665
1726
  const lst = strategyInfo.depositLstCoinType !== undefined
@@ -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,16 @@ 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);
1779
+ const allCoinsLst = yield getAllCoins(suiGrpcClient, _address, depositReserves.lst.coinType);
1719
1780
  const mergeCoinLst = mergeAllCoins(depositReserves.lst.coinType, transaction, allCoinsLst);
1720
- const lstCoin = transaction.splitCoins(transaction.object(mergeCoinLst.coinObjectId), [
1781
+ const lstCoin = transaction.splitCoins(transaction.object(mergeCoinLst.objectId), [
1721
1782
  BigInt(deposit.depositedAmount
1722
1783
  .times(10 ** LST_DECIMALS)
1723
1784
  .integerValue(BigNumber.ROUND_DOWN)
1724
1785
  .toString()),
1725
1786
  ]);
1726
1787
  // 1.2.2) Deposit LST (1x exposure)
1727
- strategyDeposit(lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1788
+ strategyDeposit(strategyType, lstCoin, depositReserves.lst.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.lst.coinType), transaction);
1728
1789
  // 1.2.3) Update state
1729
1790
  deposits = addOrInsertStrategyDeposit(deposits, deposit);
1730
1791
  // 1.3) Other
@@ -1732,18 +1793,57 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1732
1793
  else {
1733
1794
  const otherReserve = reserveMap[deposit.coinType];
1734
1795
  // 1.3.1) Split coins
1735
- const allCoinsOther = yield getAllCoins(suiClient, _address, otherReserve.coinType);
1796
+ const allCoinsOther = yield getAllCoins(suiGrpcClient, _address, otherReserve.coinType);
1736
1797
  const mergeCoinOther = mergeAllCoins(otherReserve.coinType, transaction, allCoinsOther);
1737
- const otherCoin = transaction.splitCoins(transaction.object(mergeCoinOther.coinObjectId), [
1798
+ const otherCoin = transaction.splitCoins(transaction.object(mergeCoinOther.objectId), [
1738
1799
  BigInt(deposit.depositedAmount
1739
1800
  .times(10 ** otherReserve.token.decimals)
1740
1801
  .integerValue(BigNumber.ROUND_DOWN)
1741
1802
  .toString()),
1742
1803
  ]);
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);
1804
+ // 1.3.2) If the deposit coin is the same as the borrow coin, swap to base first
1805
+ if (deposit.coinType === borrowReserve.coinType && depositReserve) {
1806
+ const routers = yield cetusSdk.findRouters({
1807
+ from: otherReserve.coinType,
1808
+ target: depositReserve.coinType,
1809
+ amount: new BN(deposit.depositedAmount
1810
+ .times(10 ** otherReserve.token.decimals)
1811
+ .integerValue(BigNumber.ROUND_DOWN)
1812
+ .toString()),
1813
+ byAmountIn: true,
1814
+ splitCount: 0,
1815
+ });
1816
+ if (!routers)
1817
+ throw new Error("No swap quote found");
1818
+ const slippagePercent = 1;
1819
+ let baseCoin;
1820
+ try {
1821
+ baseCoin = (yield cetusSdk.fixableRouterSwapV3({
1822
+ router: routers,
1823
+ inputCoin: otherCoin,
1824
+ slippage: slippagePercent / 100,
1825
+ txb: transaction,
1826
+ partner: cetusPartnerId,
1827
+ }));
1828
+ }
1829
+ catch (err) {
1830
+ throw new Error("No swap quote found");
1831
+ }
1832
+ const swappedAmount = new BigNumber(routers.amountOut.toString())
1833
+ .div(10 ** depositReserve.token.decimals)
1834
+ .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_DOWN);
1835
+ strategyDeposit(strategyType, baseCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
1836
+ deposits = addOrInsertStrategyDeposit(deposits, {
1837
+ coinType: depositReserve.coinType,
1838
+ depositedAmount: swappedAmount,
1839
+ });
1840
+ }
1841
+ else {
1842
+ // 1.3.3) Deposit other (1x exposure)
1843
+ strategyDeposit(strategyType, otherCoin, otherReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(otherReserve.coinType), transaction);
1844
+ // 1.3.4) Update state
1845
+ deposits = addOrInsertStrategyDeposit(deposits, deposit);
1846
+ }
1747
1847
  }
1748
1848
  console.log(`[deposit] deposit |`, JSON.stringify({
1749
1849
  deposits: deposits.map((d) => ({
@@ -1758,7 +1858,7 @@ export const strategyDepositAndLoopToExposureTx = (
1758
1858
  // AppContext
1759
1859
  reserveMap,
1760
1860
  // Strategy
1761
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, deposit, targetExposure, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1861
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, deposit, targetExposure, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
1762
1862
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
1763
1863
  const lst = strategyInfo.depositLstCoinType !== undefined
1764
1864
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -1786,7 +1886,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1786
1886
  let borrowedAmount = _borrowedAmount;
1787
1887
  // 1) Deposit (1x exposure)
1788
1888
  // 1.1) Deposit
1789
- const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyDepositTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, deposit, transaction, dryRunTransaction);
1889
+ const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyDepositTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, deposit, transaction, dryRunTransaction);
1790
1890
  // 1.2) Update state
1791
1891
  deposits = newDeposits;
1792
1892
  borrowedAmount = newBorrowedAmount;
@@ -1794,7 +1894,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1794
1894
  if (targetExposure.gt(1)) {
1795
1895
  // 2) Loop to target exposure
1796
1896
  // 2.1) Loop
1797
- const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, } = yield strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
1897
+ const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, } = yield strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
1798
1898
  targetExposure, // Pass targetExposure
1799
1899
  transaction);
1800
1900
  // 2.2) Update state
@@ -1808,7 +1908,7 @@ export const strategyWithdrawTx = (
1808
1908
  // AppContext
1809
1909
  reserveMap,
1810
1910
  // Strategy
1811
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdraw, transaction, dryRunTransaction, returnWithdrawnCoin) => __awaiter(void 0, void 0, void 0, function* () {
1911
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdraw, transaction, dryRunTransaction, returnWithdrawnCoin) => __awaiter(void 0, void 0, void 0, function* () {
1812
1912
  var _a, _b, _c, _d, _e, _f, _g, _h;
1813
1913
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
1814
1914
  const lst = strategyInfo.depositLstCoinType !== undefined
@@ -1867,7 +1967,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1867
1967
  // 1) Unloop to targetBorrowedAmount borrows
1868
1968
  // 1.1) Unloop
1869
1969
  if (borrowedAmount.gt(targetBorrowedAmount)) {
1870
- const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, targetBorrowedAmount, // Pass targetBorrowedAmount
1970
+ const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, targetBorrowedAmount, // Pass targetBorrowedAmount
1871
1971
  undefined, // Don't pass targetExposure
1872
1972
  transaction, dryRunTransaction);
1873
1973
  // 1.2) Update state
@@ -1885,7 +1985,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1885
1985
  }
1886
1986
  // 2) Withdraw base or LST
1887
1987
  // 2.1) Withdraw
1888
- const [withdrawnCoin] = strategyWithdraw(depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(new BigNumber(withdrawnAmount
1988
+ const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(new BigNumber(withdrawnAmount
1889
1989
  .times(10 ** depositReserve.token.decimals)
1890
1990
  .integerValue(BigNumber.ROUND_DOWN)
1891
1991
  .toString())
@@ -1916,8 +2016,38 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1916
2016
  return { deposits, borrowedAmount, transaction, withdrawnCoin };
1917
2017
  else {
1918
2018
  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);
2019
+ if (withdraw.coinType !== depositReserve.coinType) {
2020
+ const routers = yield cetusSdk.findRouters({
2021
+ from: depositReserve.coinType,
2022
+ target: withdraw.coinType,
2023
+ amount: new BN(withdrawnAmount
2024
+ .times(10 ** depositReserve.token.decimals)
2025
+ .integerValue(BigNumber.ROUND_DOWN)
2026
+ .toString()),
2027
+ byAmountIn: true,
2028
+ splitCount: 0,
2029
+ });
2030
+ if (!routers)
2031
+ throw new Error("No swap quote found");
2032
+ const slippagePercent = 1;
2033
+ let swappedCoin;
2034
+ try {
2035
+ swappedCoin = (yield cetusSdk.fixableRouterSwapV3({
2036
+ router: routers,
2037
+ inputCoin: withdrawnCoin,
2038
+ slippage: slippagePercent / 100,
2039
+ txb: transaction,
2040
+ partner: cetusPartnerId,
2041
+ }));
2042
+ }
2043
+ catch (err) {
2044
+ throw new Error("No swap quote found");
2045
+ }
2046
+ transaction.transferObjects([swappedCoin], _address);
2047
+ }
2048
+ else {
2049
+ transaction.transferObjects([withdrawnCoin], _address);
2050
+ }
1921
2051
  }
1922
2052
  else {
1923
2053
  if (isSui(withdraw.coinType)) {
@@ -1936,10 +2066,10 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1936
2066
  });
1937
2067
  export const strategyMaxWithdrawTx = (
1938
2068
  // AppContext
1939
- reserveMap, rewardPriceMap, rewardsMap,
2069
+ reserveMap, rewardsMap,
1940
2070
  // Strategy
1941
- 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;
2071
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdrawCoinType, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2072
+ var _a, _b, _c, _d;
1943
2073
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
1944
2074
  const lst = strategyInfo.depositLstCoinType !== undefined
1945
2075
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -1966,7 +2096,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1966
2096
  // 1) Unloop to 1x (base+LST: no LST and no borrows, LST: no borrows)
1967
2097
  if (borrowedAmount.gt(0)) {
1968
2098
  // 1.1) Unloop
1969
- const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2099
+ const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
1970
2100
  new BigNumber(1), // Pass targetExposure
1971
2101
  transaction, dryRunTransaction);
1972
2102
  // 1.2) Update state
@@ -1982,7 +2112,8 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1982
2112
  }, null, 2));
1983
2113
  }
1984
2114
  // 2) MAX withdraw base or LST
1985
- const [withdrawnCoin] = strategyWithdraw(depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
2115
+ 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);
2116
+ const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
1986
2117
  // 2.2) Update state
1987
2118
  deposits = [];
1988
2119
  console.log(`[strategyMaxWithdraw] max_withdraw.update_state |`, JSON.stringify({
@@ -1993,9 +2124,39 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
1993
2124
  borrowedAmount: borrowedAmount.toFixed(20),
1994
2125
  }, null, 2));
1995
2126
  // 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);
2127
+ if (depositReserve.coinType === ((_d = depositReserves.base) === null || _d === void 0 ? void 0 : _d.coinType)) {
2128
+ if (withdrawCoinType !== depositReserve.coinType) {
2129
+ const routers = yield cetusSdk.findRouters({
2130
+ from: depositReserve.coinType,
2131
+ target: withdrawCoinType,
2132
+ amount: new BN(estimatedWithdrawnAmount
2133
+ .times(10 ** depositReserve.token.decimals)
2134
+ .integerValue(BigNumber.ROUND_DOWN)
2135
+ .toString()),
2136
+ byAmountIn: true,
2137
+ splitCount: 0,
2138
+ });
2139
+ if (!routers)
2140
+ throw new Error("No swap quote found");
2141
+ const slippagePercent = 1;
2142
+ let swappedCoin;
2143
+ try {
2144
+ swappedCoin = (yield cetusSdk.fixableRouterSwapV3({
2145
+ router: routers,
2146
+ inputCoin: withdrawnCoin,
2147
+ slippage: slippagePercent / 100,
2148
+ txb: transaction,
2149
+ partner: cetusPartnerId,
2150
+ }));
2151
+ }
2152
+ catch (err) {
2153
+ throw new Error("No swap quote found");
2154
+ }
2155
+ transaction.transferObjects([swappedCoin], _address);
2156
+ }
2157
+ else {
2158
+ transaction.transferObjects([withdrawnCoin], _address);
2159
+ }
1999
2160
  }
2000
2161
  else {
2001
2162
  if (isSui(withdrawCoinType)) {
@@ -2009,14 +2170,13 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2009
2170
  transaction.transferObjects([withdrawnCoin], _address);
2010
2171
  }
2011
2172
  }
2012
- // 4) Claim rewards, swap for withdrawCoinType, and transfer to user
2173
+ // 4) Claim rewards and transfer to user
2013
2174
  if (hasClaimableRewards) {
2014
2175
  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;
2176
+ const mergedCoinsMap = strategyClaimRewardsAndMergeCoins(strategyType, rewardsMap, strategyOwnerCapId, transaction);
2177
+ for (const coin of Object.values(mergedCoinsMap)) {
2178
+ transaction.transferObjects([coin], _address);
2179
+ }
2020
2180
  }
2021
2181
  catch (err) {
2022
2182
  // Don't block user if fails
@@ -2029,8 +2189,8 @@ export const strategyAdjustRepayTx = (
2029
2189
  // AppContext
2030
2190
  reserveMap,
2031
2191
  // Strategy
2032
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2033
- var _a, _b, _c, _d;
2192
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2193
+ var _a, _b, _c, _d, _e;
2034
2194
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
2035
2195
  const lst = strategyInfo.depositLstCoinType !== undefined
2036
2196
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -2152,12 +2312,12 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2152
2312
  const dryRunResults = yield dryRunTransaction(transaction);
2153
2313
  const flashLoanRepayAmount = new BigNumber(bcs
2154
2314
  .u64()
2155
- .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])))
2315
+ .parse((_e = (_d = (_c = (_b = (_a = dryRunResults.commandResults) === null || _a === void 0 ? void 0 : _a[receiptDebts.Result]) === null || _b === void 0 ? void 0 : _b.returnValues) === null || _c === void 0 ? void 0 : _c[flashLoanObj.borrowA ? 0 : 1]) === null || _d === void 0 ? void 0 : _d.bcs) !== null && _e !== void 0 ? _e : new Uint8Array([0])))
2156
2316
  .div(10 ** depositReserves.base.token.decimals)
2157
2317
  .decimalPlaces(depositReserves.base.token.decimals, BigNumber.ROUND_UP);
2158
2318
  // 5.1) Withdraw base + fee
2159
2319
  const withdrawnAmount = flashLoanRepayAmount;
2160
- const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield strategyWithdrawTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2320
+ const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield strategyWithdrawTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2161
2321
  coinType: depositReserves.base.coinType,
2162
2322
  withdrawnAmount,
2163
2323
  }, transaction, dryRunTransaction, true);
@@ -2198,8 +2358,8 @@ export const strategyDepositAdjustWithdrawTx = (
2198
2358
  // AppContext
2199
2359
  reserveMap,
2200
2360
  // Strategy
2201
- 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;
2361
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2362
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
2203
2363
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
2204
2364
  const lst = strategyInfo.depositLstCoinType !== undefined
2205
2365
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -2279,7 +2439,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2279
2439
  });
2280
2440
  if (depositReserve.coinType === ((_h = depositReserves.lst) === null || _h === void 0 ? void 0 : _h.coinType))
2281
2441
  flashLoanBorrowedCoin = lst.client.mint(transaction, flashLoanBorrowedCoin);
2282
- strategyDeposit(flashLoanBorrowedCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
2442
+ strategyDeposit(strategyType, flashLoanBorrowedCoin, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), transaction);
2283
2443
  // 2.2) Update state
2284
2444
  deposits = addOrInsertStrategyDeposit(deposits, {
2285
2445
  coinType: depositReserve.coinType,
@@ -2287,7 +2447,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2287
2447
  });
2288
2448
  // 3) Unloop to max exposure
2289
2449
  // 3.1) Unloop
2290
- const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2450
+ const { deposits: newDeposits, borrowedAmount: newBorrowedAmount, transaction: newTransaction, } = yield strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2291
2451
  depositAdjustWithdrawExposure, // Pass targetExposure
2292
2452
  transaction, dryRunTransaction);
2293
2453
  // 3.2) Update state
@@ -2303,16 +2463,16 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2303
2463
  const dryRunResults = yield dryRunTransaction(transaction);
2304
2464
  const flashLoanRepayAmount = new BigNumber(bcs
2305
2465
  .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])))
2466
+ .parse((_o = (_m = (_l = (_k = (_j = dryRunResults.commandResults) === null || _j === void 0 ? void 0 : _j[receiptDebts.Result]) === null || _k === void 0 ? void 0 : _k.returnValues) === null || _l === void 0 ? void 0 : _l[flashLoanObj.borrowA ? 0 : 1]) === null || _m === void 0 ? void 0 : _m.bcs) !== null && _o !== void 0 ? _o : new Uint8Array([0])))
2307
2467
  .div(10 ** depositReserve.token.decimals)
2308
2468
  .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
2309
2469
  // 4.1) Withdraw additional + fee
2310
2470
  let withdrawnAmount = flashLoanRepayAmount;
2311
- if (depositReserve.coinType === ((_o = depositReserves.lst) === null || _o === void 0 ? void 0 : _o.coinType))
2471
+ if (depositReserve.coinType === ((_p = depositReserves.lst) === null || _p === void 0 ? void 0 : _p.coinType))
2312
2472
  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)
2473
+ .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
2474
  .decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
2315
- const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield strategyWithdrawTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2475
+ const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield strategyWithdrawTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
2316
2476
  coinType: depositReserve.coinType,
2317
2477
  withdrawnAmount,
2318
2478
  }, transaction, dryRunTransaction, true);
@@ -2324,7 +2484,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2324
2484
  transaction = newTransaction2;
2325
2485
  // 4.3) Repay flash loan
2326
2486
  let flashLoanRepayCoin = withdrawnCoin;
2327
- if (depositReserve.coinType === ((_q = depositReserves.lst) === null || _q === void 0 ? void 0 : _q.coinType))
2487
+ if (depositReserve.coinType === ((_r = depositReserves.lst) === null || _r === void 0 ? void 0 : _r.coinType))
2328
2488
  flashLoanRepayCoin = lst.client.redeem(transaction, flashLoanRepayCoin);
2329
2489
  const flashLoanRepayBalance = transaction.moveCall({
2330
2490
  target: "0x2::coin::into_balance",
@@ -2355,7 +2515,7 @@ export const strategyAdjustTx = (
2355
2515
  // AppContext
2356
2516
  reserveMap,
2357
2517
  // Strategy
2358
- lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation, _deposits, _borrowedAmount, targetExposure, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2518
+ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation, _deposits, _borrowedAmount, targetExposure, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
2359
2519
  const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
2360
2520
  const lst = strategyInfo.depositLstCoinType !== undefined
2361
2521
  ? lstMap[strategyInfo.depositLstCoinType]
@@ -2380,11 +2540,11 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
2380
2540
  const borrowedAmount = _borrowedAmount;
2381
2541
  // 1) Loop or unloop to target exposure
2382
2542
  if (targetExposure.gt(exposure))
2383
- return strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2543
+ return strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2384
2544
  targetExposure, // Pass targetExposure
2385
2545
  transaction);
2386
2546
  else if (targetExposure.lt(exposure))
2387
- return strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2547
+ return strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
2388
2548
  targetExposure, // Pass targetExposure
2389
2549
  transaction, dryRunTransaction);
2390
2550
  else