@kamino-finance/klend-sdk 7.0.6 → 7.0.8

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 (38) hide show
  1. package/dist/classes/action.d.ts +1 -1
  2. package/dist/classes/action.d.ts.map +1 -1
  3. package/dist/classes/action.js +15 -15
  4. package/dist/classes/action.js.map +1 -1
  5. package/dist/classes/manager.d.ts +8 -0
  6. package/dist/classes/manager.d.ts.map +1 -1
  7. package/dist/classes/manager.js +10 -0
  8. package/dist/classes/manager.js.map +1 -1
  9. package/dist/classes/obligation.js +7 -6
  10. package/dist/classes/obligation.js.map +1 -1
  11. package/dist/classes/vault.d.ts +8 -0
  12. package/dist/classes/vault.d.ts.map +1 -1
  13. package/dist/classes/vault.js +90 -1
  14. package/dist/classes/vault.js.map +1 -1
  15. package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
  16. package/dist/lending_operations/repay_with_collateral_operations.js +36 -32
  17. package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
  18. package/dist/lending_operations/swap_collateral_operations.d.ts.map +1 -1
  19. package/dist/lending_operations/swap_collateral_operations.js +6 -6
  20. package/dist/lending_operations/swap_collateral_operations.js.map +1 -1
  21. package/dist/leverage/operations.d.ts +4 -3
  22. package/dist/leverage/operations.d.ts.map +1 -1
  23. package/dist/leverage/operations.js +175 -149
  24. package/dist/leverage/operations.js.map +1 -1
  25. package/dist/leverage/types.d.ts +1 -0
  26. package/dist/leverage/types.d.ts.map +1 -1
  27. package/dist/manager/client_kamino_manager.js +15 -2
  28. package/dist/manager/client_kamino_manager.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/classes/action.ts +15 -15
  31. package/src/classes/manager.ts +24 -1
  32. package/src/classes/obligation.ts +9 -9
  33. package/src/classes/vault.ts +100 -1
  34. package/src/lending_operations/repay_with_collateral_operations.ts +78 -74
  35. package/src/lending_operations/swap_collateral_operations.ts +15 -13
  36. package/src/leverage/operations.ts +350 -318
  37. package/src/leverage/types.ts +1 -0
  38. package/src/manager/client_kamino_manager.ts +19 -2
@@ -330,7 +330,7 @@ export class KaminoAction {
330
330
  );
331
331
 
332
332
  if (extraComputeBudget > 0) {
333
- axn.addComputeBudgetIxn(extraComputeBudget);
333
+ axn.addComputeBudgetIx(extraComputeBudget);
334
334
  }
335
335
 
336
336
  await axn.addRefreshObligation(payer);
@@ -363,7 +363,7 @@ export class KaminoAction {
363
363
  );
364
364
 
365
365
  if (extraComputeBudget > 0) {
366
- axn.addComputeBudgetIxn(extraComputeBudget);
366
+ axn.addComputeBudgetIx(extraComputeBudget);
367
367
  }
368
368
 
369
369
  await axn.addRefreshObligation(owner);
@@ -404,7 +404,7 @@ export class KaminoAction {
404
404
  const addInitObligationForFarm = true;
405
405
 
406
406
  if (extraComputeBudget > 0) {
407
- axn.addComputeBudgetIxn(extraComputeBudget);
407
+ axn.addComputeBudgetIx(extraComputeBudget);
408
408
  }
409
409
 
410
410
  await axn.addSupportIxs(
@@ -467,7 +467,7 @@ export class KaminoAction {
467
467
  );
468
468
  const addInitObligationForFarm = true;
469
469
  if (extraComputeBudget > 0) {
470
- axn.addComputeBudgetIxn(extraComputeBudget);
470
+ axn.addComputeBudgetIx(extraComputeBudget);
471
471
  }
472
472
 
473
473
  if (isSome(axn.referrer)) {
@@ -529,7 +529,7 @@ export class KaminoAction {
529
529
  const addInitObligationForFarm = true;
530
530
 
531
531
  if (extraComputeBudget > 0) {
532
- axn.addComputeBudgetIxn(extraComputeBudget);
532
+ axn.addComputeBudgetIx(extraComputeBudget);
533
533
  }
534
534
 
535
535
  await axn.addSupportIxs(
@@ -572,7 +572,7 @@ export class KaminoAction {
572
572
  const addInitObligationForFarm = true;
573
573
 
574
574
  if (extraComputeBudget > 0) {
575
- axn.addComputeBudgetIxn(extraComputeBudget);
575
+ axn.addComputeBudgetIx(extraComputeBudget);
576
576
  }
577
577
 
578
578
  await axn.addSupportIxs(
@@ -620,7 +620,7 @@ export class KaminoAction {
620
620
  const addInitObligationForFarm = true;
621
621
 
622
622
  if (extraComputeBudget > 0) {
623
- axn.addComputeBudgetIxn(extraComputeBudget);
623
+ axn.addComputeBudgetIx(extraComputeBudget);
624
624
  }
625
625
 
626
626
  await axn.addSupportIxs(
@@ -679,7 +679,7 @@ export class KaminoAction {
679
679
  const twoTokenAction = true;
680
680
 
681
681
  if (extraComputeBudget > 0) {
682
- axn.addComputeBudgetIxn(extraComputeBudget);
682
+ axn.addComputeBudgetIx(extraComputeBudget);
683
683
  }
684
684
 
685
685
  if (isSome(axn.referrer)) {
@@ -776,7 +776,7 @@ export class KaminoAction {
776
776
  const addInitObligationForFarm = true;
777
777
  const twoTokenAction = true;
778
778
  if (extraComputeBudget > 0) {
779
- axn.addComputeBudgetIxn(extraComputeBudget);
779
+ axn.addComputeBudgetIx(extraComputeBudget);
780
780
  }
781
781
 
782
782
  await axn.addSupportIxs(
@@ -830,7 +830,7 @@ export class KaminoAction {
830
830
  const addInitObligationForFarm = true;
831
831
  const twoTokenAction = true;
832
832
  if (extraComputeBudget > 0) {
833
- axn.addComputeBudgetIxn(extraComputeBudget);
833
+ axn.addComputeBudgetIx(extraComputeBudget);
834
834
  }
835
835
 
836
836
  await axn.addSupportIxs(
@@ -886,7 +886,7 @@ export class KaminoAction {
886
886
  const addInitObligationForFarmForWithdraw = false;
887
887
  const twoTokenAction = true;
888
888
  if (extraComputeBudget > 0) {
889
- axn.addComputeBudgetIxn(extraComputeBudget);
889
+ axn.addComputeBudgetIx(extraComputeBudget);
890
890
  }
891
891
 
892
892
  await axn.addSupportIxs(
@@ -975,7 +975,7 @@ export class KaminoAction {
975
975
  const addInitObligationForFarm = true;
976
976
 
977
977
  if (extraComputeBudget > 0) {
978
- axn.addComputeBudgetIxn(extraComputeBudget);
978
+ axn.addComputeBudgetIx(extraComputeBudget);
979
979
  }
980
980
 
981
981
  axn.depositReserves.push(...(obligationCustomizations?.addedDepositReserves || []));
@@ -1054,7 +1054,7 @@ export class KaminoAction {
1054
1054
  const addInitObligationForFarm = true;
1055
1055
 
1056
1056
  if (extraComputeBudget > 0) {
1057
- axn.addComputeBudgetIxn(extraComputeBudget);
1057
+ axn.addComputeBudgetIx(extraComputeBudget);
1058
1058
  }
1059
1059
 
1060
1060
  await axn.addSupportIxs(
@@ -1114,7 +1114,7 @@ export class KaminoAction {
1114
1114
  const addInitObligationForFarm = true;
1115
1115
 
1116
1116
  if (extraComputeBudget > 0) {
1117
- axn.addComputeBudgetIxn(extraComputeBudget);
1117
+ axn.addComputeBudgetIx(extraComputeBudget);
1118
1118
  }
1119
1119
 
1120
1120
  await axn.addSupportIxs(
@@ -3082,7 +3082,7 @@ export class KaminoAction {
3082
3082
  this.lendingIxsLabels.push(`WithdrawReferrerFeesIx[${this.owner.toString()}]`);
3083
3083
  }
3084
3084
 
3085
- private addComputeBudgetIxn(units: number) {
3085
+ private addComputeBudgetIx(units: number) {
3086
3086
  this.computeBudgetIxs.push(buildComputeBudgetIx(units));
3087
3087
  this.computeBudgetIxsLabels.push(`AddComputeBudget[${units}]`);
3088
3088
  }
@@ -1042,7 +1042,15 @@ export class KaminoManager {
1042
1042
  currentSlot?: Slot,
1043
1043
  tokensPrices?: Map<Address, Decimal>
1044
1044
  ): Promise<VaultOverview> {
1045
- return this._vaultClient.getVaultOverview(vault, price, slot, vaultReserves, kaminoMarkets, currentSlot, tokensPrices);
1045
+ return this._vaultClient.getVaultOverview(
1046
+ vault,
1047
+ price,
1048
+ slot,
1049
+ vaultReserves,
1050
+ kaminoMarkets,
1051
+ currentSlot,
1052
+ tokensPrices
1053
+ );
1046
1054
  }
1047
1055
 
1048
1056
  /**
@@ -1205,6 +1213,21 @@ export class KaminoManager {
1205
1213
  return this._vaultClient.getVaultRewardsAPY(vault, vaultTokenPrice, farmsClient, slot);
1206
1214
  }
1207
1215
 
1216
+ /**
1217
+ * Get all the token mints of the vault, vault farm rewards and the allocation rewards
1218
+ * @param vaults - the vaults to get the token mints for
1219
+ * @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
1220
+ * @param farmsMap - the farms map to get the farms for
1221
+ * @returns a set of token mints
1222
+ */
1223
+ async getAllVaultsTokenMintsIncludingRewards(
1224
+ vaults: KaminoVault[],
1225
+ vaultReservesMap?: Map<Address, KaminoReserve>,
1226
+ farmsMap?: Map<Address, FarmState>
1227
+ ) {
1228
+ return this._vaultClient.getAllVaultsTokenMintsIncludingRewards(vaults, vaultReservesMap, farmsMap);
1229
+ }
1230
+
1208
1231
  /**
1209
1232
  * This will return the APY of the reserve farms (debt and supply)
1210
1233
  * @param reserve - the reserve to get the farms APY for
@@ -1399,6 +1399,13 @@ export class KaminoObligation {
1399
1399
  throw new Error('Reserve not found');
1400
1400
  }
1401
1401
 
1402
+ const reserveAvailableLiquidity = depositReserve.getLiquidityAvailableAmount();
1403
+ const withdrawalCapRemained = depositReserve
1404
+ .getDepositWithdrawalCapCapacity()
1405
+ .sub(depositReserve.getDepositWithdrawalCapCurrent(slot));
1406
+
1407
+ const reserveWithdrawalLimit = Decimal.min(withdrawalCapRemained, reserveAvailableLiquidity);
1408
+
1402
1409
  const userDepositPosition = this.getDepositByReserve(depositReserve.address);
1403
1410
 
1404
1411
  if (!userDepositPosition) {
@@ -1408,7 +1415,7 @@ export class KaminoObligation {
1408
1415
  const userDepositPositionAmount = userDepositPosition.amount;
1409
1416
 
1410
1417
  if (this.refreshedStats.userTotalBorrowBorrowFactorAdjusted.equals(new Decimal(0))) {
1411
- return new Decimal(userDepositPositionAmount);
1418
+ return Decimal.max(0, Decimal.min(userDepositPositionAmount, reserveWithdrawalLimit));
1412
1419
  }
1413
1420
 
1414
1421
  const { maxLtv: reserveMaxLtv } = KaminoObligation.getLtvForReserve(
@@ -1436,15 +1443,8 @@ export class KaminoObligation {
1436
1443
  const maxWithdrawAmount = maxWithdrawValue
1437
1444
  .div(depositReserve.getOracleMarketPrice())
1438
1445
  .mul(depositReserve.getMintFactor());
1439
- const reserveAvailableLiquidity = depositReserve.getLiquidityAvailableAmount();
1440
1446
 
1441
- const withdrawalCapRemained = depositReserve
1442
- .getDepositWithdrawalCapCapacity()
1443
- .sub(depositReserve.getDepositWithdrawalCapCurrent(slot));
1444
- return Decimal.max(
1445
- 0,
1446
- Decimal.min(userDepositPositionAmount, maxWithdrawAmount, reserveAvailableLiquidity, withdrawalCapRemained)
1447
- );
1447
+ return Decimal.max(0, Decimal.min(userDepositPositionAmount, maxWithdrawAmount, reserveWithdrawalLimit));
1448
1448
  }
1449
1449
 
1450
1450
  getObligationLiquidityByReserve(reserveAddress: Address): ObligationLiquidity {
@@ -1545,7 +1545,6 @@ export class KaminoVaultClient {
1545
1545
  vaultReservesMap?: Map<Address, KaminoReserve>,
1546
1546
  createAtaIfNeeded: boolean = true
1547
1547
  ): Promise<IInstruction[]> {
1548
- console.log('create invest ix for reserve', reserve.address);
1549
1548
  const vaultState = await vault.getState(this.getConnection());
1550
1549
  const cTokenVault = await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId);
1551
1550
  const [lendingMarketAuth] = await lendingMarketAuthPda(reserve.state.lendingMarket, this._kaminoLendProgramId);
@@ -3082,6 +3081,106 @@ export class KaminoVaultClient {
3082
3081
  return getFarmIncentives(kFarmsClient, vaultState.vaultFarm, sharePrice, stakedTokenMintDecimals, tokensPrices);
3083
3082
  }
3084
3083
 
3084
+ /**
3085
+ * Get all the token mints of the vault, vault farm rewards and the allocation rewards
3086
+ * @param vaults - the vaults to get the token mints for
3087
+ * @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
3088
+ * @param farmsMap - the farms map to get the farms for
3089
+ * @returns a set of token mints
3090
+ */
3091
+ async getAllVaultsTokenMintsIncludingRewards(
3092
+ vaults: KaminoVault[],
3093
+ vaultReservesMap?: Map<Address, KaminoReserve>,
3094
+ farmsMap?: Map<Address, FarmState>
3095
+ ) {
3096
+ const vaultsTokenMints = new Set<Address>();
3097
+
3098
+ const kFarmsMap = farmsMap ? farmsMap : new Map<Address, FarmState>();
3099
+
3100
+ const farmsToFetch = new Set<Address>();
3101
+ const reservesToFetch = new Set<Address>();
3102
+
3103
+ for (const vault of vaults) {
3104
+ const vaultState = await vault.getState(this.getConnection());
3105
+ vaultsTokenMints.add(vaultState.tokenMint);
3106
+ const hasFarm = await vault.hasFarm(this.getConnection());
3107
+ if (hasFarm) {
3108
+ const farmAddress = vaultState.vaultFarm;
3109
+ if (!kFarmsMap.has(farmAddress)) {
3110
+ farmsToFetch.add(farmAddress);
3111
+ } else {
3112
+ const farmState = kFarmsMap.get(farmAddress)!;
3113
+ farmState.rewardInfos.forEach((rewardInfo) => {
3114
+ if (rewardInfo.token.mint !== DEFAULT_PUBLIC_KEY) {
3115
+ vaultsTokenMints.add(rewardInfo.token.mint);
3116
+ }
3117
+ });
3118
+ }
3119
+ }
3120
+
3121
+ const reserves = vaultState.vaultAllocationStrategy.map((allocationStrategy) => allocationStrategy.reserve);
3122
+ reserves.forEach((reserve) => {
3123
+ if (reserve === DEFAULT_PUBLIC_KEY) {
3124
+ return;
3125
+ }
3126
+
3127
+ if (vaultReservesMap && !vaultReservesMap.has(reserve)) {
3128
+ const reserveState = vaultReservesMap.get(reserve)!;
3129
+ const supplyFarm = reserveState.state.farmCollateral;
3130
+ if (supplyFarm !== DEFAULT_PUBLIC_KEY) {
3131
+ if (!kFarmsMap.has(supplyFarm)) {
3132
+ farmsToFetch.add(supplyFarm);
3133
+ } else {
3134
+ const farmState = kFarmsMap.get(supplyFarm)!;
3135
+ farmState.rewardInfos.forEach((rewardInfo) => {
3136
+ if (rewardInfo.token.mint !== DEFAULT_PUBLIC_KEY) {
3137
+ vaultsTokenMints.add(rewardInfo.token.mint);
3138
+ }
3139
+ });
3140
+ }
3141
+ }
3142
+ } else {
3143
+ reservesToFetch.add(reserve);
3144
+ }
3145
+ });
3146
+ }
3147
+
3148
+ // fetch the reserves first so we can add their farms to farms to be fetched, if needed
3149
+ const missingReservesStates = await Reserve.fetchMultiple(this.getConnection(), Array.from(reservesToFetch));
3150
+
3151
+ missingReservesStates.forEach((reserveState) => {
3152
+ if (reserveState) {
3153
+ const supplyFarm = reserveState.farmCollateral;
3154
+ if (supplyFarm !== DEFAULT_PUBLIC_KEY) {
3155
+ if (!kFarmsMap.has(supplyFarm)) {
3156
+ farmsToFetch.add(supplyFarm);
3157
+ } else {
3158
+ const farmState = kFarmsMap.get(supplyFarm)!;
3159
+ farmState.rewardInfos.forEach((rewardInfo) => {
3160
+ if (rewardInfo.token.mint !== DEFAULT_PUBLIC_KEY) {
3161
+ vaultsTokenMints.add(rewardInfo.token.mint);
3162
+ }
3163
+ });
3164
+ }
3165
+ }
3166
+ }
3167
+ });
3168
+
3169
+ // fetch the missing farms
3170
+ const missingFarmsStates = await FarmState.fetchMultiple(this.getConnection(), Array.from(farmsToFetch));
3171
+ missingFarmsStates.forEach((farmState) => {
3172
+ if (farmState) {
3173
+ farmState.rewardInfos.forEach((rewardInfo) => {
3174
+ if (rewardInfo.token.mint !== DEFAULT_PUBLIC_KEY) {
3175
+ vaultsTokenMints.add(rewardInfo.token.mint);
3176
+ }
3177
+ });
3178
+ }
3179
+ });
3180
+
3181
+ return vaultsTokenMints;
3182
+ }
3183
+
3085
3184
  async getVaultReservesFarmsIncentives(
3086
3185
  vaultOrState: KaminoVault | VaultState,
3087
3186
  vaultTokenPrice: Decimal,
@@ -120,27 +120,31 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
120
120
  const inputAmountLamports = Decimal.min(maxWithdrawableCollLamports, maxCollNeededFromOracle);
121
121
 
122
122
  // Build the repay & withdraw collateral tx to get the number of accounts
123
- const klendIxs: LeverageIxsOutput = await buildRepayWithCollateralIxs(
124
- kaminoMarket,
125
- debtReserve,
126
- collReserve,
127
- owner,
128
- obligation,
129
- referrer,
130
- currentSlot,
131
- budgetAndPriorityFeeIxs,
132
- scopeRefreshConfig,
133
- {
134
- preActionIxs: [],
135
- swapIxs: [],
136
- lookupTables: [],
137
- quote: {} as SwapQuote<QuoteResponse>,
138
- },
139
- isClosingPosition,
140
- repayAmountLamports,
141
- inputAmountLamports,
142
- useV2Ixs
143
- );
123
+ const klendIxs: LeverageIxsOutput = (
124
+ await buildRepayWithCollateralIxs(
125
+ kaminoMarket,
126
+ debtReserve,
127
+ collReserve,
128
+ owner,
129
+ obligation,
130
+ referrer,
131
+ currentSlot,
132
+ budgetAndPriorityFeeIxs,
133
+ scopeRefreshConfig,
134
+ [
135
+ {
136
+ preActionIxs: [],
137
+ swapIxs: [],
138
+ lookupTables: [],
139
+ quote: {} as SwapQuote<QuoteResponse>,
140
+ },
141
+ ],
142
+ isClosingPosition,
143
+ repayAmountLamports,
144
+ inputAmountLamports,
145
+ useV2Ixs
146
+ )
147
+ )[0];
144
148
  const uniqueKlendAccounts = uniqueAccountsWithProgramIds(klendIxs.instructions);
145
149
 
146
150
  const swapQuoteInputs: SwapInputs = {
@@ -244,35 +248,33 @@ export async function getRepayWithCollIxs<QuoteResponse>({
244
248
 
245
249
  const swapResponses = await swapper(swapInputs, initialInputs.klendAccounts, swapQuote);
246
250
 
247
- return Promise.all(
248
- swapResponses.map(async (swapResponse) => {
249
- const ixs: LeverageIxsOutput = await buildRepayWithCollateralIxs(
250
- kaminoMarket,
251
- debtReserve,
252
- collReserve,
253
- owner,
254
- obligation,
255
- referrer,
256
- currentSlot,
257
- budgetAndPriorityFeeIxs,
258
- scopeRefreshConfig,
259
- swapResponse,
260
- isClosingPosition,
261
- debtRepayAmountLamports,
262
- swapInputs.inputAmountLamports,
263
- useV2Ixs
264
- );
265
-
266
- return {
267
- ixs: ixs.instructions,
268
- lookupTables: swapResponse.lookupTables,
269
- swapInputs,
270
- flashLoanInfo: ixs.flashLoanInfo,
271
- initialInputs,
272
- quote: swapResponse.quote.quoteResponse,
273
- };
274
- })
251
+ const repayWithCollateralIxs = await buildRepayWithCollateralIxs(
252
+ kaminoMarket,
253
+ debtReserve,
254
+ collReserve,
255
+ owner,
256
+ obligation,
257
+ referrer,
258
+ currentSlot,
259
+ budgetAndPriorityFeeIxs,
260
+ scopeRefreshConfig,
261
+ swapResponses,
262
+ isClosingPosition,
263
+ debtRepayAmountLamports,
264
+ swapInputs.inputAmountLamports,
265
+ useV2Ixs
275
266
  );
267
+
268
+ return repayWithCollateralIxs.map((ixs, index) => {
269
+ return {
270
+ ixs: ixs.instructions,
271
+ lookupTables: swapResponses[index].lookupTables,
272
+ swapInputs,
273
+ flashLoanInfo: ixs.flashLoanInfo,
274
+ initialInputs,
275
+ quote: swapResponses[index].quote.quoteResponse,
276
+ };
277
+ });
276
278
  }
277
279
 
278
280
  async function buildRepayWithCollateralIxs<QuoteResponse>(
@@ -285,12 +287,12 @@ async function buildRepayWithCollateralIxs<QuoteResponse>(
285
287
  currentSlot: Slot,
286
288
  budgetAndPriorityFeeIxs: IInstruction[] | undefined,
287
289
  scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
288
- swapQuoteIxs: SwapIxs<QuoteResponse>,
290
+ swapQuoteIxsArray: SwapIxs<QuoteResponse>[],
289
291
  isClosingPosition: boolean,
290
292
  debtRepayAmountLamports: Decimal,
291
293
  collWithdrawLamports: Decimal,
292
294
  useV2Ixs: boolean
293
- ): Promise<LeverageIxsOutput> {
295
+ ): Promise<LeverageIxsOutput[]> {
294
296
  // 1. Create atas & budget txns
295
297
  const budgetIxs = budgetAndPriorityFeeIxs || getComputeBudgetAndPriorityFeeIxs(1_400_000);
296
298
 
@@ -369,29 +371,31 @@ async function buildRepayWithCollateralIxs<QuoteResponse>(
369
371
  }
370
372
 
371
373
  // 4. Swap collateral to debt to repay flash loan
372
- const { preActionIxs, swapIxs } = swapQuoteIxs;
373
- const swapInstructions = removeBudgetIxs(swapIxs);
374
-
375
- const ixs = [
376
- ...scopeRefreshIx,
377
- ...budgetIxs,
378
- ...atasAndIxs.map((x) => x.createAtaIx),
379
- flashBorrowIx,
380
- ...preActionIxs,
381
- ...KaminoAction.actionToIxs(repayAndWithdrawAction),
382
- ...swapInstructions,
383
- flashRepayIx,
384
- ];
385
-
386
- const res: LeverageIxsOutput = {
387
- flashLoanInfo: {
388
- flashBorrowReserve: debtReserve.address,
389
- flashLoanFee: debtReserve.getFlashLoanFee(),
390
- },
391
- instructions: ixs,
392
- };
393
-
394
- return res;
374
+ return swapQuoteIxsArray.map((swapQuoteIxs) => {
375
+ const { preActionIxs, swapIxs } = swapQuoteIxs;
376
+ const swapInstructions = removeBudgetIxs(swapIxs);
377
+
378
+ const ixs = [
379
+ ...scopeRefreshIx,
380
+ ...budgetIxs,
381
+ ...atasAndIxs.map((x) => x.createAtaIx),
382
+ flashBorrowIx,
383
+ ...preActionIxs,
384
+ ...KaminoAction.actionToIxs(repayAndWithdrawAction),
385
+ ...swapInstructions,
386
+ flashRepayIx,
387
+ ];
388
+
389
+ const res: LeverageIxsOutput = {
390
+ flashLoanInfo: {
391
+ flashBorrowReserve: debtReserve.address,
392
+ flashLoanFee: debtReserve.getFlashLoanFee(),
393
+ },
394
+ instructions: ixs,
395
+ };
396
+
397
+ return res;
398
+ });
395
399
  }
396
400
 
397
401
  export const getMaxWithdrawLtvCheck = (
@@ -164,7 +164,16 @@ export async function getSwapCollIxs<QuoteResponse>(
164
164
  // - To construct 1. (i.e. flash-borrow), we need to know the target collateral swap-out from 4.
165
165
 
166
166
  // Construct the Klend's own ixs with a fake swap-out (only to learn the klend accounts used):
167
- const fakeKlendIxs = await getKlendIxs(args, FAKE_TARGET_COLL_SWAP_OUT_AMOUNT, context);
167
+
168
+ const scopeRefreshIx = await getScopeRefreshIx(
169
+ context.market,
170
+ context.sourceCollReserve,
171
+ context.targetCollReserve,
172
+ context.obligation,
173
+ context.scopeRefreshConfig
174
+ );
175
+
176
+ const fakeKlendIxs = await getKlendIxs(args, FAKE_TARGET_COLL_SWAP_OUT_AMOUNT, context, scopeRefreshIx);
168
177
  const klendAccounts = uniqueAccountsWithProgramIds(listIxs(fakeKlendIxs));
169
178
 
170
179
  // Construct the external swap ixs (and learn the actual swap-out amount):
@@ -179,7 +188,7 @@ export async function getSwapCollIxs<QuoteResponse>(
179
188
  checkResultingObligationValid(args, externalSwapIxs.swapOutAmount, context);
180
189
 
181
190
  // Construct the Klend's own ixs with an actual swap-out amount:
182
- const klendIxs = await getKlendIxs(args, externalSwapIxs.swapOutAmount, context);
191
+ const klendIxs = await getKlendIxs(args, externalSwapIxs.swapOutAmount, context, scopeRefreshIx);
183
192
 
184
193
  return {
185
194
  ixs: listIxs(klendIxs, externalSwapIxs.ixs),
@@ -275,21 +284,14 @@ type SwapCollKlendIxs = {
275
284
  async function getKlendIxs(
276
285
  args: SwapCollArgs,
277
286
  targetCollSwapOutAmount: Decimal,
278
- context: SwapCollContext<any>
287
+ context: SwapCollContext<any>,
288
+ scopeRefreshIx: IInstruction[]
279
289
  ): Promise<SwapCollKlendIxs> {
280
290
  const { ataCreationIxs, targetCollAta } = await getAtaCreationIxs(context);
281
291
  const setupIxs = [...context.budgetAndPriorityFeeIxs, ...ataCreationIxs];
282
292
 
283
- const scopeRefreshIxn = await getScopeRefreshIx(
284
- context.market,
285
- context.sourceCollReserve,
286
- context.targetCollReserve,
287
- context.obligation,
288
- context.scopeRefreshConfig
289
- );
290
-
291
- if (scopeRefreshIxn) {
292
- setupIxs.unshift(...scopeRefreshIxn);
293
+ if (scopeRefreshIx) {
294
+ setupIxs.unshift(...scopeRefreshIx);
293
295
  }
294
296
 
295
297
  const targetCollFlashBorrowedAmount = calculateTargetCollFlashBorrowedAmount(targetCollSwapOutAmount, context);