@kamino-finance/klend-sdk 5.2.8 → 5.2.10

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.
@@ -154,7 +154,6 @@ export class KaminoAction {
154
154
  borrowReserves: Array<PublicKey>;
155
155
 
156
156
  preLoadedDepositReservesSameTx: Array<PublicKey>;
157
- preLoadedBorrowReservesSameTx: Array<PublicKey>;
158
157
 
159
158
  currentSlot: number;
160
159
 
@@ -216,7 +215,6 @@ export class KaminoAction {
216
215
  this.outflowReserve = outflowReserveState;
217
216
  this.outflowAmount = outflowAmount ? new BN(outflowAmount) : undefined;
218
217
  this.preLoadedDepositReservesSameTx = [];
219
- this.preLoadedBorrowReservesSameTx = [];
220
218
  this.referrer = referrer ? referrer : PublicKey.default;
221
219
  this.currentSlot = currentSlot;
222
220
  }
@@ -798,7 +796,6 @@ export class KaminoAction {
798
796
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
799
797
  requestElevationGroup: boolean = false,
800
798
  includeUserMetadata: boolean = true, // if true it includes user metadata,
801
- isClosingPosition: boolean = false,
802
799
  referrer: PublicKey = PublicKey.default,
803
800
  scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
804
801
  ) {
@@ -847,8 +844,7 @@ export class KaminoAction {
847
844
  'repayAndWithdraw',
848
845
  includeAtaIxns,
849
846
  requestElevationGroup,
850
- addInitObligationForFarmForWithdraw,
851
- isClosingPosition
847
+ addInitObligationForFarmForWithdraw
852
848
  );
853
849
  axn.addRefreshFarmsCleanupTxnIxsToCleanupIxs();
854
850
  return axn;
@@ -1582,16 +1578,14 @@ export class KaminoAction {
1582
1578
  action: ActionType,
1583
1579
  includeAtaIxns: boolean,
1584
1580
  requestElevationGroup: boolean,
1585
- addInitObligationForFarm: boolean,
1586
- isClosingPosition: boolean = false
1581
+ addInitObligationForFarm: boolean
1587
1582
  ) {
1588
1583
  await this.addSupportIxsWithoutInitObligation(
1589
1584
  action,
1590
1585
  includeAtaIxns,
1591
1586
  'inBetween',
1592
1587
  requestElevationGroup,
1593
- addInitObligationForFarm,
1594
- isClosingPosition
1588
+ addInitObligationForFarm
1595
1589
  );
1596
1590
  }
1597
1591
 
@@ -1615,7 +1609,7 @@ export class KaminoAction {
1615
1609
  ReserveFarmKind.Debt,
1616
1610
  crank
1617
1611
  );
1618
- this.addRefreshObligationIx(addAllToSetupIxns, false);
1612
+ this.addRefreshObligationIx(addAllToSetupIxns);
1619
1613
  }
1620
1614
 
1621
1615
  async addSupportIxsWithoutInitObligation(
@@ -1624,7 +1618,6 @@ export class KaminoAction {
1624
1618
  addAsSupportIx: AuxiliaryIx = 'setup',
1625
1619
  requestElevationGroup: boolean = false,
1626
1620
  addInitObligationForFarm: boolean = false,
1627
- isClosingPosition: boolean = false,
1628
1621
  twoTokenAction: boolean = false,
1629
1622
  overrideElevationGroupRequest?: number
1630
1623
  ) {
@@ -1668,43 +1661,16 @@ export class KaminoAction {
1668
1661
 
1669
1662
  if (action === 'depositAndBorrow' || action === 'repayAndWithdraw') {
1670
1663
  currentReserves = [this.reserve, this.outflowReserve];
1671
- if (this.obligation) {
1672
- if (action === 'depositAndBorrow') {
1673
- const deposit = this.obligation.state.deposits.find((deposit) =>
1674
- deposit.depositReserve.equals(this.reserve.address)
1675
- );
1676
-
1664
+ if (action === 'depositAndBorrow') {
1665
+ if (this.obligation) {
1666
+ const deposit = this.obligation.getDepositByReserve(this.reserve.address);
1677
1667
  if (!deposit) {
1678
1668
  this.preLoadedDepositReservesSameTx.push(this.reserve.address);
1679
1669
  }
1680
1670
  } else {
1681
- const borrow = this.obligation.state.borrows.find((borrow) =>
1682
- borrow.borrowReserve.equals(this.reserve.address)
1683
- );
1684
-
1685
- if (!borrow) {
1686
- throw Error(`Unable to find obligation borrow to repay for ${this.obligation.state.owner.toBase58()}`);
1687
- }
1688
-
1689
- const cumulativeBorrowRateObligation = KaminoObligation.getCumulativeBorrowRate(borrow);
1690
-
1691
- const cumulativeBorrowRateReserve = this.reserve.getEstimatedCumulativeBorrowRate(
1692
- this.currentSlot,
1693
- this.kaminoMarket.state.referralFeeBps
1694
- );
1695
- const fullRepay = KaminoObligation.getBorrowAmount(borrow)
1696
- .mul(cumulativeBorrowRateReserve)
1697
- .div(cumulativeBorrowRateObligation);
1698
-
1699
- const amountDecimal = new Decimal(this.amount.toString());
1700
-
1701
- if (fullRepay.lte(amountDecimal)) {
1702
- this.preLoadedBorrowReservesSameTx.push(this.reserve.address);
1703
- }
1671
+ // Obligation doesn't exist yet, so we have to preload the deposit reserve
1672
+ this.preLoadedDepositReservesSameTx.push(this.reserve.address);
1704
1673
  }
1705
- } else {
1706
- // Obligation doesn't exist yet, so we have to preload the deposit reserve
1707
- this.preLoadedDepositReservesSameTx.push(this.reserve.address);
1708
1674
  }
1709
1675
  } else if (action === 'liquidate' && !this.outflowReserve.address.equals(this.reserve.address)) {
1710
1676
  currentReserves = [this.outflowReserve, this.reserve];
@@ -1755,14 +1721,17 @@ export class KaminoAction {
1755
1721
  }
1756
1722
  this.addRefreshReserveIxs(currentReserveAddresses.toArray(), addAsSupportIx);
1757
1723
 
1758
- if (action === 'repayAndWithdraw' && addAsSupportIx === 'inBetween' && isClosingPosition) {
1759
- // addToSetupIxs === addInBetween (same thing)
1760
- // If this is a repay and withdraw, and it's not the first action, and it's closing a position
1761
- // we don't need to include the repay reserve in the refresh obligation
1762
- // I am ashamed of this code, we need to rewrite this entire thing
1763
- this.addRefreshObligationIx(addAsSupportIx, true);
1724
+ if (action === 'repayAndWithdraw' && addAsSupportIx === 'inBetween') {
1725
+ const repayObligationLiquidity = this.obligation!.getBorrowByReserve(this.reserve.address);
1726
+ if (!repayObligationLiquidity) {
1727
+ throw new Error(`Could not find debt reserve ${this.reserve.address} in obligation`);
1728
+ }
1729
+ const repaidBorrowReservesToSkip = repayObligationLiquidity.amount.lte(new Decimal(this.amount.toString()))
1730
+ ? [repayObligationLiquidity.reserveAddress]
1731
+ : [];
1732
+ this.addRefreshObligationIx(addAsSupportIx, repaidBorrowReservesToSkip);
1764
1733
  } else {
1765
- this.addRefreshObligationIx(addAsSupportIx, false);
1734
+ this.addRefreshObligationIx(addAsSupportIx);
1766
1735
  }
1767
1736
 
1768
1737
  if (requestElevationGroup) {
@@ -1774,14 +1743,14 @@ export class KaminoAction {
1774
1743
  }
1775
1744
 
1776
1745
  if (
1777
- new Decimal(repayObligationLiquidity.amount).lte(new Decimal(this.amount.toString())) &&
1746
+ repayObligationLiquidity.amount.lte(new Decimal(this.amount.toString())) &&
1778
1747
  this.obligation!.borrows.size === 1 &&
1779
1748
  this.obligation?.state.elevationGroup !== 0
1780
1749
  ) {
1781
1750
  this.addRefreshReserveIxs(allReservesExcludingCurrent, 'cleanup');
1782
1751
  // Skip the borrow reserve, since we repay in the same tx
1783
- this.addRefreshObligationIx('cleanup', true);
1784
- this.addRequestElevationIx(overrideElevationGroupRequest ?? 0, 'cleanup', true);
1752
+ this.addRefreshObligationIx('cleanup', [this.reserve.address]);
1753
+ this.addRequestElevationIx(overrideElevationGroupRequest ?? 0, 'cleanup', [this.reserve.address]);
1785
1754
  }
1786
1755
  } else if (action === 'depositAndBorrow' || action === 'borrow') {
1787
1756
  let newElevationGroup: number = -1;
@@ -1940,7 +1909,6 @@ export class KaminoAction {
1940
1909
  'setup',
1941
1910
  requestElevationGroup,
1942
1911
  addInitObligationForFarm,
1943
- false,
1944
1912
  twoTokenAction,
1945
1913
  overrideElevationGroupRequest
1946
1914
  );
@@ -2031,7 +1999,7 @@ export class KaminoAction {
2031
1999
  });
2032
2000
  }
2033
2001
 
2034
- private addRefreshObligationIx(addAsSupportIx: AuxiliaryIx = 'setup', skipBorrowObligations: boolean = false) {
2002
+ private addRefreshObligationIx(addAsSupportIx: AuxiliaryIx = 'setup', borrowReservesToSkip: PublicKey[] = []) {
2035
2003
  const marketAddress = this.kaminoMarket.getAddress();
2036
2004
  const obligationPda = this.getObligationPda();
2037
2005
  const refreshObligationIx = refreshObligation(
@@ -2048,10 +2016,8 @@ export class KaminoAction {
2048
2016
  return { pubkey: reserve, isSigner: false, isWritable: true };
2049
2017
  });
2050
2018
 
2051
- const preloadedBorrowReservesString = this.preLoadedBorrowReservesSameTx.map((reserve) => reserve.toString());
2052
- const borrowReservesList = this.borrowReserves.filter(
2053
- (reserve) => !preloadedBorrowReservesString.includes(reserve.toString())
2054
- );
2019
+ const skipBorrowsSet = new PublicKeySet(borrowReservesToSkip);
2020
+ const borrowReservesList = this.borrowReserves.filter((reserve) => !skipBorrowsSet.contains(reserve));
2055
2021
 
2056
2022
  const borrowReserveAccountMetas = borrowReservesList.map((reserve) => {
2057
2023
  return { pubkey: reserve, isSigner: false, isWritable: true };
@@ -2069,7 +2035,8 @@ export class KaminoAction {
2069
2035
 
2070
2036
  refreshObligationIx.keys = refreshObligationIx.keys.concat([
2071
2037
  ...depositReserveAccountMetas,
2072
- ...(skipBorrowObligations ? [] : [...borrowReserveAccountMetas, ...borrowReservesReferrerTokenStates]),
2038
+ ...borrowReserveAccountMetas,
2039
+ ...borrowReservesReferrerTokenStates,
2073
2040
  ]);
2074
2041
 
2075
2042
  if (addAsSupportIx === 'setup') {
@@ -2087,7 +2054,7 @@ export class KaminoAction {
2087
2054
  private addRequestElevationIx(
2088
2055
  elevationGroup: number,
2089
2056
  addAsSupportIx: AuxiliaryIx,
2090
- skipBorrowObligations: boolean = false
2057
+ skipBorrowReserves: PublicKey[] = []
2091
2058
  ) {
2092
2059
  const obligationPda = this.getObligationPda();
2093
2060
  const args: RequestElevationGroupArgs = {
@@ -2107,10 +2074,8 @@ export class KaminoAction {
2107
2074
  return { pubkey: reserve, isSigner: false, isWritable: true };
2108
2075
  });
2109
2076
 
2110
- const preloadedBorrowReservesString = this.preLoadedBorrowReservesSameTx.map((reserve) => reserve.toString());
2111
- const borrowReservesList = this.borrowReserves.filter(
2112
- (reserve) => !preloadedBorrowReservesString.includes(reserve.toString())
2113
- );
2077
+ const skipBorrowReservesSet = new PublicKeySet<PublicKey>(skipBorrowReserves);
2078
+ const borrowReservesList = this.borrowReserves.filter((reserve) => !skipBorrowReservesSet.contains(reserve));
2114
2079
 
2115
2080
  const borrowReserveAccountMetas = borrowReservesList.map((reserve) => {
2116
2081
  return { pubkey: reserve, isSigner: false, isWritable: true };
@@ -2133,7 +2098,8 @@ export class KaminoAction {
2133
2098
 
2134
2099
  requestElevationGroupIx.keys = requestElevationGroupIx.keys.concat([
2135
2100
  ...depositReserveAccountMetas,
2136
- ...(skipBorrowObligations ? [] : [...borrowReserveAccountMetas, ...borrowReservesReferrerTokenStates]),
2101
+ ...borrowReserveAccountMetas,
2102
+ ...borrowReservesReferrerTokenStates,
2137
2103
  ]);
2138
2104
 
2139
2105
  if (addAsSupportIx === 'setup') {
@@ -1314,6 +1314,10 @@ export class KaminoVaultClient {
1314
1314
  ): Promise<VaultReserveTotalBorrowedAndInvested> {
1315
1315
  const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
1316
1316
 
1317
+ const totalAvailable = lamportsToDecimal(
1318
+ new Decimal(vault.tokenAvailable.toString()),
1319
+ new Decimal(vault.tokenMintDecimals.toString())
1320
+ );
1317
1321
  let totalInvested = new Decimal(0);
1318
1322
  let totalBorrowed = new Decimal(0);
1319
1323
 
@@ -1343,7 +1347,7 @@ export class KaminoVaultClient {
1343
1347
 
1344
1348
  let utilizationRatio = new Decimal(0);
1345
1349
  if (!totalInvested.isZero()) {
1346
- utilizationRatio = totalBorrowed.div(totalInvested);
1350
+ utilizationRatio = totalBorrowed.div(totalInvested.add(totalAvailable));
1347
1351
  }
1348
1352
  return {
1349
1353
  totalInvested: totalInvested,
@@ -1,4 +1,3 @@
1
- import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
2
1
  import { KaminoAction, KaminoMarket, KaminoObligation, KaminoReserve } from '../classes';
3
2
  import {
4
3
  getFlashLoanInstructions,
@@ -253,7 +252,6 @@ async function buildRepayWithCollateralIxs(
253
252
  const atas = [
254
253
  { mint: collReserve.getLiquidityMint(), tokenProgram: collReserve.getLiquidityTokenProgram() },
255
254
  { mint: debtReserve.getLiquidityMint(), tokenProgram: debtReserve.getLiquidityTokenProgram() },
256
- { mint: collReserve.getCTokenMint(), tokenProgram: TOKEN_PROGRAM_ID },
257
255
  ];
258
256
 
259
257
  const atasAndIxs = createAtasIdempotent(obligation.state.owner, atas);
@@ -289,7 +287,6 @@ async function buildRepayWithCollateralIxs(
289
287
  false,
290
288
  requestElevationGroup,
291
289
  undefined,
292
- isClosingPosition,
293
290
  referrer,
294
291
  scopeRefresh
295
292
  );
@@ -911,7 +911,6 @@ export async function buildWithdrawWithLeverageIxns(
911
911
  obligation,
912
912
  0,
913
913
  false,
914
- false,
915
914
  false, // to be checked and created in a setup tx in the UI (won't be the case for withdraw anyway as this would be created in deposit)
916
915
  isClosingPosition,
917
916
  referrer,