@kamino-finance/klend-sdk 6.0.5 → 7.0.0

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 (97) hide show
  1. package/dist/@codegen/kvault/accounts/Reserve.js +1 -1
  2. package/dist/@codegen/kvault/accounts/VaultState.d.ts +6 -6
  3. package/dist/@codegen/kvault/accounts/VaultState.d.ts.map +1 -1
  4. package/dist/@codegen/kvault/accounts/VaultState.js +12 -12
  5. package/dist/@codegen/kvault/accounts/VaultState.js.map +1 -1
  6. package/dist/@codegen/kvault/errors/custom.d.ts +9 -1
  7. package/dist/@codegen/kvault/errors/custom.d.ts.map +1 -1
  8. package/dist/@codegen/kvault/errors/custom.js +15 -1
  9. package/dist/@codegen/kvault/errors/custom.js.map +1 -1
  10. package/dist/@codegen/kvault/types/VaultConfigField.d.ts +26 -0
  11. package/dist/@codegen/kvault/types/VaultConfigField.d.ts.map +1 -1
  12. package/dist/@codegen/kvault/types/VaultConfigField.js +49 -1
  13. package/dist/@codegen/kvault/types/VaultConfigField.js.map +1 -1
  14. package/dist/@codegen/kvault/types/index.d.ts +2 -2
  15. package/dist/@codegen/kvault/types/index.d.ts.map +1 -1
  16. package/dist/@codegen/kvault/types/index.js.map +1 -1
  17. package/dist/classes/action.d.ts +1 -1
  18. package/dist/classes/action.d.ts.map +1 -1
  19. package/dist/classes/action.js +26 -11
  20. package/dist/classes/action.js.map +1 -1
  21. package/dist/classes/manager.d.ts +25 -6
  22. package/dist/classes/manager.d.ts.map +1 -1
  23. package/dist/classes/manager.js +59 -27
  24. package/dist/classes/manager.js.map +1 -1
  25. package/dist/classes/market.d.ts +7 -2
  26. package/dist/classes/market.d.ts.map +1 -1
  27. package/dist/classes/market.js +12 -6
  28. package/dist/classes/market.js.map +1 -1
  29. package/dist/classes/vault.d.ts +22 -3
  30. package/dist/classes/vault.d.ts.map +1 -1
  31. package/dist/classes/vault.js +73 -40
  32. package/dist/classes/vault.js.map +1 -1
  33. package/dist/classes/vault_types.d.ts +9 -1
  34. package/dist/classes/vault_types.d.ts.map +1 -1
  35. package/dist/client/commands/borrow.d.ts.map +1 -1
  36. package/dist/client/commands/borrow.js +2 -1
  37. package/dist/client/commands/borrow.js.map +1 -1
  38. package/dist/client/commands/deposit.d.ts.map +1 -1
  39. package/dist/client/commands/deposit.js +2 -1
  40. package/dist/client/commands/deposit.js.map +1 -1
  41. package/dist/client/commands/repay.d.ts.map +1 -1
  42. package/dist/client/commands/repay.js +2 -1
  43. package/dist/client/commands/repay.js.map +1 -1
  44. package/dist/client/commands/withdraw.d.ts.map +1 -1
  45. package/dist/client/commands/withdraw.js +2 -1
  46. package/dist/client/commands/withdraw.js.map +1 -1
  47. package/dist/leverage/operations.d.ts.map +1 -1
  48. package/dist/leverage/operations.js +8 -5
  49. package/dist/leverage/operations.js.map +1 -1
  50. package/dist/manager/client_kamino_manager.js +10 -3
  51. package/dist/manager/client_kamino_manager.js.map +1 -1
  52. package/dist/utils/index.d.ts +1 -0
  53. package/dist/utils/index.d.ts.map +1 -1
  54. package/dist/utils/index.js +1 -0
  55. package/dist/utils/index.js.map +1 -1
  56. package/dist/utils/managerTypes.d.ts +2 -3
  57. package/dist/utils/managerTypes.d.ts.map +1 -1
  58. package/dist/utils/managerTypes.js +37 -34
  59. package/dist/utils/managerTypes.js.map +1 -1
  60. package/dist/utils/map.d.ts +2 -0
  61. package/dist/utils/map.d.ts.map +1 -0
  62. package/dist/utils/map.js +13 -0
  63. package/dist/utils/map.js.map +1 -0
  64. package/dist/utils/oracle.d.ts +2 -1
  65. package/dist/utils/oracle.d.ts.map +1 -1
  66. package/dist/utils/oracle.js +4 -4
  67. package/dist/utils/oracle.js.map +1 -1
  68. package/dist/utils/vault.js +2 -2
  69. package/dist/utils/vault.js.map +1 -1
  70. package/dist/utils/vaultAllocation.d.ts +21 -0
  71. package/dist/utils/vaultAllocation.d.ts.map +1 -0
  72. package/dist/utils/vaultAllocation.js +71 -0
  73. package/dist/utils/vaultAllocation.js.map +1 -0
  74. package/package.json +2 -2
  75. package/src/@codegen/kvault/accounts/Reserve.ts +1 -1
  76. package/src/@codegen/kvault/accounts/VaultState.ts +16 -16
  77. package/src/@codegen/kvault/errors/custom.ts +14 -0
  78. package/src/@codegen/kvault/types/VaultConfigField.ts +60 -0
  79. package/src/@codegen/kvault/types/index.ts +4 -0
  80. package/src/classes/action.ts +26 -11
  81. package/src/classes/manager.ts +92 -30
  82. package/src/classes/market.ts +15 -9
  83. package/src/classes/vault.ts +125 -42
  84. package/src/classes/vault_types.ts +11 -1
  85. package/src/client/commands/borrow.ts +2 -1
  86. package/src/client/commands/deposit.ts +2 -1
  87. package/src/client/commands/repay.ts +2 -1
  88. package/src/client/commands/withdraw.ts +2 -1
  89. package/src/idl/kvault.json +34 -12
  90. package/src/leverage/operations.ts +9 -10
  91. package/src/manager/client_kamino_manager.ts +15 -3
  92. package/src/utils/index.ts +1 -0
  93. package/src/utils/managerTypes.ts +29 -28
  94. package/src/utils/map.ts +8 -0
  95. package/src/utils/oracle.ts +4 -3
  96. package/src/utils/vault.ts +2 -2
  97. package/src/utils/vaultAllocation.ts +93 -0
@@ -87,12 +87,14 @@ import {
87
87
  AcceptVaultOwnershipIxs,
88
88
  APYs,
89
89
  DepositIxs,
90
+ DisinvestAllReservesIxs,
90
91
  InitVaultIxs,
91
92
  ReserveAllocationOverview,
92
93
  SyncVaultLUTIxs,
93
94
  UpdateReserveAllocationIxs,
94
95
  UpdateVaultConfigIxs,
95
96
  UserSharesForVault,
97
+ VaultComputedAllocation,
96
98
  WithdrawAndBlockReserveIxs,
97
99
  WithdrawIxs,
98
100
  } from './vault_types';
@@ -121,6 +123,7 @@ import { noopSigner } from '../utils/signer';
121
123
  import { getExtendLookupTableInstruction } from '@solana-program/address-lookup-table';
122
124
  import { Farms } from '@kamino-finance/farms-sdk';
123
125
  import { getFarmIncentives } from '@kamino-finance/farms-sdk/dist/utils/apy';
126
+ import { computeReservesAllocation } from '../utils/vaultAllocation';
124
127
 
125
128
  export const kaminoVaultId = address('KvauGMspG5k6rtzrqqn7WNn3oZdyKqLKwK2XWQ8FLjd');
126
129
  export const kaminoVaultStagingId = address('stKvQfwRsQiKnLtMNVLHKS3exFJmZFsgfzBPWHECUYK');
@@ -453,6 +456,50 @@ export class KaminoVaultClient {
453
456
  return updateReserveAllocationIxs;
454
457
  }
455
458
 
459
+ /**
460
+ * This method updates the unallocated weight and cap of a vault (both are optional, if not provided the current values will be used)
461
+ * @param vault - the vault to update the unallocated weight and cap for
462
+ * @param [vaultAdminAuthority] - vault admin - a noop vaultAdminAuthority is provided when absent for multisigs
463
+ * @param [unallocatedWeight] - the new unallocated weight to set. If not provided, the current unallocated weight will be used
464
+ * @param [unallocatedCap] - the new unallocated cap to set. If not provided, the current unallocated cap will be used
465
+ * @returns - a list of instructions to update the unallocated weight and cap
466
+ */
467
+ async updateVaultUnallocatedWeightAndCapIxs(
468
+ vault: KaminoVault,
469
+ vaultAdminAuthority?: TransactionSigner,
470
+ unallocatedWeight?: BN,
471
+ unallocatedCap?: BN
472
+ ) {
473
+ const vaultState = await vault.getState(this.getConnection());
474
+
475
+ const unallocatedWeightToUse = unallocatedWeight ? unallocatedWeight : vaultState.unallocatedWeight;
476
+ const unallocatedCapToUse = unallocatedCap ? unallocatedCap : vaultState.unallocatedTokensCap;
477
+
478
+ const ixs: IInstruction[] = [];
479
+
480
+ if (!unallocatedWeightToUse.eq(vaultState.unallocatedWeight)) {
481
+ const updateVaultUnallocatedWeightIx = await this.updateVaultConfigIxs(
482
+ vault,
483
+ new VaultConfigField.UnallocatedWeight(),
484
+ unallocatedWeightToUse.toString(),
485
+ vaultAdminAuthority
486
+ );
487
+ ixs.push(updateVaultUnallocatedWeightIx.updateVaultConfigIx);
488
+ }
489
+
490
+ if (!unallocatedCapToUse.eq(vaultState.unallocatedTokensCap)) {
491
+ const updateVaultUnallocatedCapIx = await this.updateVaultConfigIxs(
492
+ vault,
493
+ new VaultConfigField.UnallocatedTokensCap(),
494
+ unallocatedCapToUse.toString(),
495
+ vaultAdminAuthority
496
+ );
497
+ ixs.push(updateVaultUnallocatedCapIx.updateVaultConfigIx);
498
+ }
499
+
500
+ return ixs;
501
+ }
502
+
456
503
  /**
457
504
  * This method withdraws all the funds from a reserve and blocks it from being invested by setting its weight and ctoken allocation to 0
458
505
  * @param vault - the vault to withdraw the funds from
@@ -506,7 +553,7 @@ export class KaminoVaultClient {
506
553
  * @param vault - the vault to withdraw the invested funds from
507
554
  * @param [vaultReservesMap] - optional parameter to pass a map of the vault reserves. If not provided, the reserves will be loaded from the vault
508
555
  * @param [payer] - optional parameter to pass a different payer for the transaction. If not provided, the admin of the vault will be used; this is the payer for the invest ixs and it should have an ATA and some lamports (2x no_of_reserves) of the token vault
509
- * @returns - a struct with an instruction to update the reserve allocation and an optional list of instructions to update the lookup table for the allocation changes
556
+ * @returns - a struct with an instruction to update the reserve allocations (set weight and ctoken allocation to 0) and an a list of instructions to disinvest the funds in the reserves
510
557
  */
511
558
  async withdrawEverythingFromAllReservesAndBlockInvest(
512
559
  vault: KaminoVault,
@@ -544,6 +591,59 @@ export class KaminoVaultClient {
544
591
  return withdrawAndBlockReserveIxs;
545
592
  }
546
593
 
594
+ /**
595
+ * This method disinvests all the funds from all the reserves and set their weight to 0; for vaults that are managed by external bot/crank, the bot can change the weight and invest in the reserves again
596
+ * @param vault - the vault to disinvest the invested funds from
597
+ * @param [vaultReservesMap] - optional parameter to pass a map of the vault reserves. If not provided, the reserves will be loaded from the vault
598
+ * @param [payer] - optional parameter to pass a different payer for the transaction. If not provided, the admin of the vault will be used; this is the payer for the invest ixs and it should have an ATA and some lamports (2x no_of_reserves) of the token vault
599
+ * @returns - a struct with an instruction to update the reserve allocations to 0 weight and a list of instructions to disinvest the funds in the reserves
600
+ */
601
+ async disinvestAllReservesIxs(
602
+ vault: KaminoVault,
603
+ vaultReservesMap?: Map<Address, KaminoReserve>,
604
+ payer?: TransactionSigner
605
+ ): Promise<DisinvestAllReservesIxs> {
606
+ const vaultState = await vault.getState(this.getConnection());
607
+
608
+ const reserves = this.getVaultReserves(vaultState);
609
+ const disinvestAllReservesIxs: DisinvestAllReservesIxs = {
610
+ updateReserveAllocationIxs: [],
611
+ investIxs: [],
612
+ };
613
+
614
+ if (!vaultReservesMap) {
615
+ vaultReservesMap = await this.loadVaultReserves(vaultState);
616
+ }
617
+
618
+ for (const reserve of reserves) {
619
+ const reserveWithAddress: ReserveWithAddress = {
620
+ address: reserve,
621
+ state: vaultReservesMap.get(reserve)!.state,
622
+ };
623
+ const existingReserveAllocation = vaultState.vaultAllocationStrategy.find(
624
+ (allocation) => allocation.reserve === reserve
625
+ );
626
+ if (!existingReserveAllocation) {
627
+ continue;
628
+ }
629
+ const reserveAllocationConfig = new ReserveAllocationConfig(
630
+ reserveWithAddress,
631
+ 0,
632
+ new Decimal(existingReserveAllocation.tokenAllocationCap.toString())
633
+ );
634
+
635
+ // update allocation to have 0 weight and 0 cap
636
+ const updateAllocIxs = await this.updateReserveAllocationIxs(vault, reserveAllocationConfig, payer);
637
+ disinvestAllReservesIxs.updateReserveAllocationIxs.push(updateAllocIxs.updateReserveAllocationIx);
638
+ }
639
+
640
+ const investPayer = payer ? payer : noopSigner(vaultState.vaultAdminAuthority);
641
+ const investIxs = await this.investAllReservesIxs(investPayer, vault);
642
+ disinvestAllReservesIxs.investIxs = investIxs;
643
+
644
+ return disinvestAllReservesIxs;
645
+ }
646
+
547
647
  /**
548
648
  * This method removes a reserve from the vault allocation strategy if already part of the allocation strategy
549
649
  * @param vault - vault to remove the reserve from
@@ -1354,7 +1454,7 @@ export class KaminoVaultClient {
1354
1454
  for (let index = 0; index < allReserves.length; index++) {
1355
1455
  const reservePubkey = allReserves[index];
1356
1456
  const reserveState = allReservesStateMap.get(reservePubkey)!;
1357
- const computedAllocation = computedReservesAllocation.get(reservePubkey)!;
1457
+ const computedAllocation = computedReservesAllocation.targetReservesAllocation.get(reservePubkey)!;
1358
1458
  const currentCTokenAllocation = curentVaultAllocations.get(reservePubkey)!.ctokenAllocation;
1359
1459
  const currentAllocationCap = curentVaultAllocations.get(reservePubkey)!.tokenAllocationCap;
1360
1460
 
@@ -1790,7 +1890,10 @@ export class KaminoVaultClient {
1790
1890
  slot?: Slot,
1791
1891
  vaultReserves?: Map<Address, KaminoReserve>,
1792
1892
  currentSlot?: Slot
1793
- ): Promise<Map<Address, Decimal>> {
1893
+ ): Promise<VaultComputedAllocation> {
1894
+ // 1. Read the states
1895
+ const holdings = await this.getVaultHoldings(vaultState, slot, vaultReserves, currentSlot);
1896
+
1794
1897
  // if there are no vault reserves or all have weight 0 everything has to be in Available
1795
1898
  const allReservesPubkeys = this.getVaultReserves(vaultState);
1796
1899
  const reservesAllocations = this.getVaultAllocations(vaultState);
@@ -1803,50 +1906,30 @@ export class KaminoVaultClient {
1803
1906
  allReservesPubkeys.forEach((reserve) => {
1804
1907
  computedHoldings.set(reserve, new Decimal(0));
1805
1908
  });
1806
- return computedHoldings;
1909
+ return {
1910
+ targetUnallocatedAmount: holdings.totalAUMIncludingFees.sub(holdings.pendingFees),
1911
+ targetReservesAllocation: computedHoldings,
1912
+ };
1807
1913
  }
1808
1914
 
1809
- const holdings = await this.getVaultHoldings(vaultState, slot, vaultReserves, currentSlot);
1810
1915
  const initialVaultAllocations = this.getVaultAllocations(vaultState);
1811
1916
 
1812
- const allReserves = this.getVaultReserves(vaultState);
1813
-
1814
- let totalAllocation = new Decimal(0);
1815
- initialVaultAllocations.forEach((allocation) => {
1816
- totalAllocation = totalAllocation.add(allocation.targetWeight);
1817
- });
1818
- const expectedHoldingsDistribution = new Map<Address, Decimal>();
1819
- allReserves.forEach((reserve) => {
1820
- expectedHoldingsDistribution.set(reserve, new Decimal(0));
1821
- });
1822
-
1823
- let totalLeftToInvest = holdings.totalAUMIncludingFees.sub(holdings.pendingFees);
1824
- let currentAllocationSum = totalAllocation;
1825
- const ONE = new Decimal(1);
1826
- while (totalLeftToInvest.gt(ONE)) {
1827
- const totalLeftover = totalLeftToInvest;
1828
- for (const reserve of allReserves) {
1829
- const reserveWithWeight = initialVaultAllocations.get(reserve);
1830
- const targetAllocation = reserveWithWeight!.targetWeight.mul(totalLeftover).div(currentAllocationSum);
1831
- const reserveCap = reserveWithWeight!.tokenAllocationCap;
1832
- let amountToInvest = Decimal.min(targetAllocation, totalLeftToInvest);
1833
- if (reserveCap.gt(ZERO)) {
1834
- amountToInvest = Decimal.min(amountToInvest, reserveCap);
1835
- }
1836
- totalLeftToInvest = totalLeftToInvest.sub(amountToInvest);
1837
- if (amountToInvest.eq(reserveCap) && reserveCap.gt(ZERO)) {
1838
- currentAllocationSum = currentAllocationSum.sub(reserveWithWeight!.targetWeight);
1839
- }
1840
- const reserveHasPreallocation = expectedHoldingsDistribution.has(reserve);
1841
- if (reserveHasPreallocation) {
1842
- expectedHoldingsDistribution.set(reserve, expectedHoldingsDistribution.get(reserve)!.add(amountToInvest));
1843
- } else {
1844
- expectedHoldingsDistribution.set(reserve, amountToInvest);
1845
- }
1846
- }
1847
- }
1917
+ // 2. Compute the allocation
1918
+ return this.computeReservesAllocation(
1919
+ holdings.totalAUMIncludingFees.sub(holdings.pendingFees),
1920
+ new Decimal(vaultState.unallocatedWeight.toString()),
1921
+ new Decimal(vaultState.unallocatedTokensCap.toString()),
1922
+ initialVaultAllocations
1923
+ );
1924
+ }
1848
1925
 
1849
- return expectedHoldingsDistribution;
1926
+ private computeReservesAllocation(
1927
+ vaultAUM: Decimal,
1928
+ vaultUnallocatedWeight: Decimal,
1929
+ vaultUnallocatedCap: Decimal,
1930
+ initialVaultAllocations: Map<Address, ReserveAllocationOverview>
1931
+ ) {
1932
+ return computeReservesAllocation(vaultAUM, vaultUnallocatedWeight, vaultUnallocatedCap, initialVaultAllocations);
1850
1933
  }
1851
1934
 
1852
1935
  /**
@@ -1,4 +1,4 @@
1
- import { IInstruction } from '@solana/kit';
1
+ import { Address, IInstruction } from '@solana/kit';
2
2
  import Decimal from 'decimal.js/decimal';
3
3
 
4
4
  /** the populateLUTIxs should be executed in a separate transaction as we cannot create and populate a lookup table in the same tx */
@@ -27,11 +27,21 @@ export type WithdrawAndBlockReserveIxs = {
27
27
  investIxs: IInstruction[];
28
28
  };
29
29
 
30
+ export type DisinvestAllReservesIxs = {
31
+ updateReserveAllocationIxs: IInstruction[];
32
+ investIxs: IInstruction[];
33
+ };
34
+
30
35
  export type UpdateVaultConfigIxs = {
31
36
  updateVaultConfigIx: IInstruction;
32
37
  updateLUTIxs: IInstruction[];
33
38
  };
34
39
 
40
+ export type VaultComputedAllocation = {
41
+ targetUnallocatedAmount: Decimal;
42
+ targetReservesAllocation: Map<Address, Decimal>;
43
+ };
44
+
35
45
  /** If there are ixs to setup the LUT it means it doesn't already exist and it needs to be created in a separate tx before inserting into it */
36
46
  export type SyncVaultLUTIxs = {
37
47
  setupLUTIfNeededIxs: IInstruction[];
@@ -10,6 +10,7 @@ export async function borrow(env: CliEnv, mode: SendTxMode, token: string, borro
10
10
  const signer = await env.getSigner();
11
11
  const programId = getProgramId('staging');
12
12
  const kaminoMarket = await getMarket(env.c.rpc, programId);
13
+ const scope = new Scope('mainnet-beta', env.c.rpc);
13
14
  const kaminoAction = await KaminoAction.buildBorrowTxns(
14
15
  kaminoMarket,
15
16
  borrowAmount,
@@ -17,7 +18,7 @@ export async function borrow(env: CliEnv, mode: SendTxMode, token: string, borro
17
18
  signer,
18
19
  new VanillaObligation(STAGING_LENDING_MARKET),
19
20
  true,
20
- { scope: new Scope('mainnet-beta', env.c.rpc), scopeFeed: 'hubble' }
21
+ { scope, scopeConfigurations: await scope.getAllConfigurations() }
21
22
  );
22
23
  console.log('User obligation', await kaminoAction.getObligationPda());
23
24
 
@@ -10,6 +10,7 @@ export async function deposit(env: CliEnv, mode: SendTxMode, token: string, depo
10
10
  const signer = await env.getSigner();
11
11
  const programId = getProgramId('staging');
12
12
  const kaminoMarket = await getMarket(env.c.rpc, programId);
13
+ const scope = new Scope('mainnet-beta', env.c.rpc);
13
14
  const kaminoAction = await KaminoAction.buildDepositTxns(
14
15
  kaminoMarket,
15
16
  depositAmount,
@@ -17,7 +18,7 @@ export async function deposit(env: CliEnv, mode: SendTxMode, token: string, depo
17
18
  signer,
18
19
  new VanillaObligation(STAGING_LENDING_MARKET),
19
20
  true,
20
- { scope: new Scope('mainnet-beta', env.c.rpc), scopeFeed: 'hubble' }
21
+ { scope, scopeConfigurations: await scope.getAllConfigurations() }
21
22
  );
22
23
  console.log('User obligation', await kaminoAction.getObligationPda());
23
24
 
@@ -10,6 +10,7 @@ export async function repay(env: CliEnv, mode: SendTxMode, token: string, borrow
10
10
  const signer = await env.getSigner();
11
11
  const programId = getProgramId('staging');
12
12
  const kaminoMarket = await getMarket(env.c.rpc, programId);
13
+ const scope = new Scope('mainnet-beta', env.c.rpc);
13
14
  const kaminoAction = await KaminoAction.buildRepayTxns(
14
15
  kaminoMarket,
15
16
  borrowAmount,
@@ -17,7 +18,7 @@ export async function repay(env: CliEnv, mode: SendTxMode, token: string, borrow
17
18
  signer,
18
19
  new VanillaObligation(STAGING_LENDING_MARKET),
19
20
  true,
20
- { scope: new Scope('mainnet-beta', env.c.rpc), scopeFeed: 'hubble' },
21
+ { scope, scopeConfigurations: await scope.getAllConfigurations() },
21
22
  await env.c.rpc.getSlot().send()
22
23
  );
23
24
  console.log('User obligation', await kaminoAction.getObligationPda());
@@ -10,6 +10,7 @@ export async function withdraw(env: CliEnv, mode: SendTxMode, token: string, dep
10
10
  const signer = await env.getSigner();
11
11
  const programId = getProgramId('staging');
12
12
  const kaminoMarket = await getMarket(env.c.rpc, programId);
13
+ const scope = new Scope('mainnet-beta', env.c.rpc);
13
14
  const kaminoAction = await KaminoAction.buildWithdrawTxns(
14
15
  kaminoMarket,
15
16
  depositAmount,
@@ -17,7 +18,7 @@ export async function withdraw(env: CliEnv, mode: SendTxMode, token: string, dep
17
18
  signer,
18
19
  new VanillaObligation(STAGING_LENDING_MARKET),
19
20
  true,
20
- { scope: new Scope('mainnet-beta', env.c.rpc), scopeFeed: 'hubble' }
21
+ { scope, scopeConfigurations: await scope.getAllConfigurations() }
21
22
  );
22
23
  console.log('User obligation', await kaminoAction.getObligationPda());
23
24
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.0",
2
+ "version": "1.0.0",
3
3
  "name": "kamino_vault",
4
4
  "instructions": [
5
5
  {
@@ -880,7 +880,7 @@
880
880
  "type": {
881
881
  "array": [
882
882
  "u64",
883
- 116
883
+ 115
884
884
  ]
885
885
  }
886
886
  },
@@ -967,7 +967,7 @@
967
967
  "type": "u64"
968
968
  },
969
969
  {
970
- "name": "padding0",
970
+ "name": "unallocatedWeight",
971
971
  "type": "u64"
972
972
  },
973
973
  {
@@ -1068,7 +1068,7 @@
1068
1068
  "type": "u64"
1069
1069
  },
1070
1070
  {
1071
- "name": "padding2",
1071
+ "name": "unallocatedTokensCap",
1072
1072
  "type": "u64"
1073
1073
  },
1074
1074
  {
@@ -1236,7 +1236,7 @@
1236
1236
  "type": "u16"
1237
1237
  },
1238
1238
  {
1239
- "name": "reserved2",
1239
+ "name": "reserved1",
1240
1240
  "docs": [
1241
1241
  "[DEPRECATED] Space that used to hold 2 fields:",
1242
1242
  "- Boost for side (debt or collateral)",
@@ -1422,13 +1422,15 @@
1422
1422
  "type": "u8"
1423
1423
  },
1424
1424
  {
1425
- "name": "reserved1",
1426
- "type": {
1427
- "array": [
1428
- "u8",
1429
- 1
1430
- ]
1431
- }
1425
+ "name": "proposerAuthorityLocked",
1426
+ "docs": [
1427
+ "Boolean flag indicating whether the reserve is locked for the proposer authority.",
1428
+ "",
1429
+ "Once the proposer have finished preparing the reserve, it must be locked to prevent",
1430
+ "further changes to the reserve configuration allowing review and voting on the proposal",
1431
+ "without alteration during the voting period."
1432
+ ],
1433
+ "type": "u8"
1432
1434
  },
1433
1435
  {
1434
1436
  "name": "borrowLimitOutsideElevationGroup",
@@ -1461,6 +1463,15 @@
1461
1463
  "Only relevant when `autodeleverage_enabled == 1`, and must not be 0 in such case."
1462
1464
  ],
1463
1465
  "type": "u64"
1466
+ },
1467
+ {
1468
+ "name": "debtMaturityTimestamp",
1469
+ "docs": [
1470
+ "The timestamp at which all [Obligation::borrows] using this reserve become liquidatable",
1471
+ "(on the same terms as reserve-wide deleveraging).",
1472
+ "Inactive when zeroed (i.e. debt never matures)."
1473
+ ],
1474
+ "type": "u64"
1464
1475
  }
1465
1476
  ]
1466
1477
  }
@@ -1954,6 +1965,12 @@
1954
1965
  },
1955
1966
  {
1956
1967
  "name": "AllocationAdmin"
1968
+ },
1969
+ {
1970
+ "name": "UnallocatedWeight"
1971
+ },
1972
+ {
1973
+ "name": "UnallocatedTokensCap"
1957
1974
  }
1958
1975
  ]
1959
1976
  }
@@ -2332,6 +2349,11 @@
2332
2349
  "code": 7047,
2333
2350
  "name": "ReserveHasNonZeroAllocationOrCTokens",
2334
2351
  "msg": "Reserve has non-zero allocation or ctokens so cannot be removed"
2352
+ },
2353
+ {
2354
+ "code": 7048,
2355
+ "name": "DepositAmountGreaterThanRequestedAmount",
2356
+ "msg": "Deposit amount is greater than requested amount"
2335
2357
  }
2336
2358
  ]
2337
2359
  }
@@ -1676,18 +1676,17 @@ export const getScopeRefreshIx = async (
1676
1676
  ]),
1677
1677
  ]
1678
1678
  : [...new Set<Address>([collReserve.address, debtReserve.address])];
1679
- const tokenIds = getTokenIdsForScopeRefresh(market, allReserves);
1680
1679
 
1681
1680
  const scopeRefreshIxs: IInstruction[] = [];
1682
- if (tokenIds.length > 0 && scopeRefreshConfig) {
1683
- scopeRefreshIxs.push(
1684
- await scopeRefreshConfig.scope.refreshPriceListIx(
1685
- {
1686
- feed: scopeRefreshConfig.scopeFeed,
1687
- },
1688
- tokenIds
1689
- )
1690
- );
1681
+ const scopeTokensMap = getTokenIdsForScopeRefresh(market, allReserves);
1682
+
1683
+ if (scopeTokensMap.size > 0 && scopeRefreshConfig) {
1684
+ for (const [configPubkey, config] of scopeRefreshConfig.scopeConfigurations) {
1685
+ const tokenIds = scopeTokensMap.get(config.oraclePrices);
1686
+ if (tokenIds && tokenIds.length > 0) {
1687
+ scopeRefreshIxs.push(await scopeRefreshConfig.scope.refreshPriceListIx({ config: configPubkey }, tokenIds));
1688
+ }
1689
+ }
1691
1690
  }
1692
1691
 
1693
1692
  return scopeRefreshIxs;
@@ -1502,8 +1502,9 @@ async function main() {
1502
1502
 
1503
1503
  commands
1504
1504
  .command('get-oracle-mappings')
1505
+ .requiredOption('--lending-market <string>', 'Lending Market Address')
1505
1506
  .option(`--staging`, 'If true, will use the staging programs')
1506
- .action(async ({ staging }) => {
1507
+ .action(async ({ staging, lendingMarket }) => {
1507
1508
  const env = await initEnv(staging);
1508
1509
  const kaminoManager = new KaminoManager(
1509
1510
  env.c.rpc,
@@ -1511,10 +1512,21 @@ async function main() {
1511
1512
  env.klendProgramId,
1512
1513
  env.kvaultProgramId
1513
1514
  );
1515
+ const market = await KaminoMarket.load(
1516
+ env.c.rpc,
1517
+ address(lendingMarket),
1518
+ DEFAULT_RECENT_SLOT_DURATION_MS,
1519
+ env.klendProgramId
1520
+ );
1521
+ if (!market) {
1522
+ throw Error(`Lending market ${lendingMarket} not found`);
1523
+ }
1514
1524
 
1515
1525
  console.log('Getting oracle mappings');
1516
- const oracleConfigs = await kaminoManager.getScopeOracleConfigs();
1517
- console.log('oracleConfigs', JSON.parse(JSON.stringify(oracleConfigs)));
1526
+ const oracleConfigs = await kaminoManager.getScopeOracleConfigs(market);
1527
+ for (const [oraclePrices, configs] of oracleConfigs.entries()) {
1528
+ console.log(`OraclePrices pubkey: ${oraclePrices}`, 'Configs:', JSON.parse(JSON.stringify(configs)));
1529
+ }
1518
1530
  });
1519
1531
 
1520
1532
  commands
@@ -14,3 +14,4 @@ export * from './lookupTable';
14
14
  export * from './managerTypes';
15
15
  export * from './fuzz';
16
16
  export * from './rpc';
17
+ export * from './map';
@@ -13,7 +13,7 @@ import {
13
13
  WithdrawalCaps,
14
14
  } from '../@codegen/klend/types';
15
15
  import Decimal from 'decimal.js';
16
- import { Fraction, ZERO_FRACTION } from '../classes/fraction';
16
+ import { Fraction, ZERO_FRACTION } from '../classes';
17
17
  import BN from 'bn.js';
18
18
  import { numberToLamportsDecimal } from '../classes';
19
19
  import { NULL_PUBKEY } from './pubkey';
@@ -22,7 +22,6 @@ import { OracleType } from '@kamino-finance/scope-sdk/dist/@codegen/scope/types'
22
22
  import { LendingMarket } from '../lib';
23
23
 
24
24
  export type ScopeOracleConfig = {
25
- scopePriceConfigAddress: Address;
26
25
  name: string;
27
26
  oracleType: string;
28
27
  oracleId: number;
@@ -80,7 +79,7 @@ export class AssetReserveConfig implements AssetConfig {
80
79
  this.mintTokenProgram = fields.mintTokenProgram;
81
80
 
82
81
  // TODO: verify defaults and ensure opinionated
83
- this.assetReserveConfigParams = DefaultConfigParams;
82
+ this.assetReserveConfigParams = getDefaultConfigParams();
84
83
  this.assetReserveConfigParams.priceFeed = fields.priceFeed;
85
84
  this.assetReserveConfigParams.loanToValuePct = fields.loanToValuePct;
86
85
  this.assetReserveConfigParams.liquidationThresholdPct = fields.liquidationThresholdPct;
@@ -114,7 +113,7 @@ export class AssetReserveConfigCli implements AssetConfig {
114
113
  this.reserveConfig = reserveConfig;
115
114
  this.tokenName = '';
116
115
  this.mintDecimals = 0;
117
- this.assetReserveConfigParams = DefaultConfigParams;
116
+ this.assetReserveConfigParams = getDefaultConfigParams();
118
117
  this.mint = mint;
119
118
  this.mintTokenProgram = mintTokenProgram;
120
119
  }
@@ -160,7 +159,7 @@ export class CollateralConfig implements AssetConfig {
160
159
  this.mintTokenProgram = fields.mintTokenProgram;
161
160
 
162
161
  // TODO: verify defaults and ensure opinionated
163
- this.assetReserveConfigParams = DefaultConfigParams;
162
+ this.assetReserveConfigParams = getDefaultConfigParams();
164
163
  this.assetReserveConfigParams.priceFeed = fields.priceFeed;
165
164
  this.assetReserveConfigParams.loanToValuePct = fields.loanToValuePct;
166
165
  this.assetReserveConfigParams.liquidationThresholdPct = fields.liquidationThresholdPct;
@@ -207,7 +206,7 @@ export class DebtConfig implements AssetConfig {
207
206
  this.debtWithdrawalCapConfigCapacity = fields.debtWithdrawalCapConfigCapacity;
208
207
 
209
208
  // TODO: verify defaults and ensure opinionated
210
- this.assetReserveConfigParams = DefaultConfigParams;
209
+ this.assetReserveConfigParams = getDefaultConfigParams();
211
210
  this.assetReserveConfigParams.priceFeed = fields.priceFeed;
212
211
  this.assetReserveConfigParams.borrowRateCurve = fields.borrowRateCurve;
213
212
  }
@@ -254,28 +253,30 @@ export type AssetReserveConfigParams = {
254
253
  borrowRateCurve: BorrowRateCurve;
255
254
  };
256
255
 
257
- export const DefaultConfigParams: AssetReserveConfigParams = {
258
- loanToValuePct: 70,
259
- maxLiquidationBonusBps: 500,
260
- minLiquidationBonusBps: 200,
261
- badDebtLiquidationBonusBps: 10,
262
- liquidationThresholdPct: 75,
263
- borrowFeeSf: ZERO_FRACTION,
264
- flashLoanFeeSf: ZERO_FRACTION,
265
- protocolTakeRate: 0,
266
- elevationGroups: new Array(20).fill(0),
267
- priceFeed: null,
268
- borrowLimit: new Decimal(1000.0),
269
- depositLimit: new Decimal(1000.0),
270
- borrowRateCurve: new BorrowRateCurve({
271
- points: [
272
- new CurvePoint({ utilizationRateBps: 0, borrowRateBps: 1000 }),
273
- new CurvePoint({ utilizationRateBps: 10000, borrowRateBps: 1000 }),
274
- ...Array(9).fill(new CurvePoint({ utilizationRateBps: 10000, borrowRateBps: 1000 })),
275
- ],
276
- } as BorrowRateCurveFields),
277
- maxAgePriceSeconds: 180,
278
- maxAgeTwapSeconds: 240,
256
+ export const getDefaultConfigParams = (): AssetReserveConfigParams => {
257
+ return {
258
+ loanToValuePct: 70,
259
+ maxLiquidationBonusBps: 500,
260
+ minLiquidationBonusBps: 200,
261
+ badDebtLiquidationBonusBps: 10,
262
+ liquidationThresholdPct: 75,
263
+ borrowFeeSf: ZERO_FRACTION,
264
+ flashLoanFeeSf: ZERO_FRACTION,
265
+ protocolTakeRate: 0,
266
+ elevationGroups: new Array(20).fill(0),
267
+ priceFeed: null,
268
+ borrowLimit: new Decimal(1000.0),
269
+ depositLimit: new Decimal(1000.0),
270
+ borrowRateCurve: new BorrowRateCurve({
271
+ points: [
272
+ new CurvePoint({ utilizationRateBps: 0, borrowRateBps: 1000 }),
273
+ new CurvePoint({ utilizationRateBps: 10000, borrowRateBps: 1000 }),
274
+ ...Array(9).fill(new CurvePoint({ utilizationRateBps: 10000, borrowRateBps: 1000 })),
275
+ ],
276
+ } as BorrowRateCurveFields),
277
+ maxAgePriceSeconds: 180,
278
+ maxAgeTwapSeconds: 240,
279
+ };
279
280
  };
280
281
 
281
282
  export const encodeTokenName = (tokenName: string): number[] => {
@@ -0,0 +1,8 @@
1
+ export function setOrAppend<K, V>(map: Map<K, V[]>, key: K, value: V): void {
2
+ const existing = map.get(key);
3
+ if (existing) {
4
+ existing.push(value);
5
+ } else {
6
+ map.set(key, [value]);
7
+ }
8
+ }
@@ -7,11 +7,12 @@ import { parseTokenSymbol } from '../classes';
7
7
  import { Reserve } from '../lib';
8
8
  import { batchFetch } from '@kamino-finance/kliquidity-sdk';
9
9
  import BN from 'bn.js';
10
- import { priceUpdateV2 } from '../@codegen/pyth_rec/accounts/priceUpdateV2';
11
- import { AggregatorAccountData } from '../@codegen/switchboard_v2/accounts/AggregatorAccountData';
10
+ import { priceUpdateV2 } from '../@codegen/pyth_rec/accounts';
11
+ import { AggregatorAccountData } from '../@codegen/switchboard_v2/accounts';
12
12
  import { Buffer } from 'buffer';
13
13
  import { getLatestAggregatorValue } from './switchboard';
14
14
  import { PROGRAM_ID as SWITCHBOARD_V2_PROGRAM_ID } from '../@codegen/switchboard_v2/programId';
15
+ import { Configuration } from '@kamino-finance/scope-sdk/dist/@codegen/scope/accounts/Configuration';
15
16
 
16
17
  // validate price confidence - confidence/price ratio should be less than 2%
17
18
  export const MAX_CONFIDENCE_PERCENTAGE: Decimal = new Decimal('2');
@@ -39,7 +40,7 @@ export type CandidatePrice = {
39
40
 
40
41
  export type ScopePriceRefreshConfig = {
41
42
  scope: Scope;
42
- scopeFeed: string;
43
+ scopeConfigurations: [Address, Configuration][];
43
44
  };
44
45
 
45
46
  export function getTokenOracleDataSync(allOracleAccounts: AllOracleAccounts, reserves: Reserve[]) {
@@ -21,7 +21,8 @@ export function decodeVaultState(data: Buffer): VaultState {
21
21
  tokenAvailable: dec.tokenAvailable,
22
22
  sharesIssued: dec.sharesIssued,
23
23
  availableCrankFunds: dec.availableCrankFunds,
24
- padding0: dec.padding0,
24
+ unallocatedWeight: dec.unallocatedWeight,
25
+ unallocatedTokensCap: dec.unallocatedTokensCap,
25
26
  performanceFeeBps: dec.performanceFeeBps,
26
27
  managementFeeBps: dec.managementFeeBps,
27
28
  lastFeeChargeTimestamp: dec.lastFeeChargeTimestamp,
@@ -44,7 +45,6 @@ export function decodeVaultState(data: Buffer): VaultState {
44
45
  vaultLookupTable: dec.vaultLookupTable,
45
46
  vaultFarm: dec.vaultFarm,
46
47
  creationTimestamp: dec.creationTimestamp,
47
- padding2: dec.padding2,
48
48
  allocationAdmin: dec.allocationAdmin,
49
49
  padding3: dec.padding3,
50
50
  });