@kamino-finance/klend-sdk 7.2.6 → 7.3.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.
- package/README.md +1 -0
- package/dist/@codegen/klend/accounts/LendingMarket.d.ts +33 -0
- package/dist/@codegen/klend/accounts/LendingMarket.d.ts.map +1 -1
- package/dist/@codegen/klend/accounts/LendingMarket.js +24 -2
- package/dist/@codegen/klend/accounts/LendingMarket.js.map +1 -1
- package/dist/@codegen/klend/errors/custom.d.ts +26 -2
- package/dist/@codegen/klend/errors/custom.d.ts.map +1 -1
- package/dist/@codegen/klend/errors/custom.js +45 -3
- package/dist/@codegen/klend/errors/custom.js.map +1 -1
- package/dist/@codegen/klend/instructions/index.d.ts +2 -0
- package/dist/@codegen/klend/instructions/index.d.ts.map +1 -1
- package/dist/@codegen/klend/instructions/index.js +3 -1
- package/dist/@codegen/klend/instructions/index.js.map +1 -1
- package/dist/@codegen/klend/instructions/initReserve.d.ts +1 -1
- package/dist/@codegen/klend/instructions/initReserve.d.ts.map +1 -1
- package/dist/@codegen/klend/instructions/initReserve.js +1 -5
- package/dist/@codegen/klend/instructions/initReserve.js.map +1 -1
- package/dist/@codegen/klend/instructions/liquidateObligationAndRedeemReserveCollateralV2.js +1 -1
- package/dist/@codegen/klend/instructions/seedDepositOnInitReserve.d.ts +13 -0
- package/dist/@codegen/klend/instructions/seedDepositOnInitReserve.d.ts.map +1 -0
- package/dist/@codegen/klend/instructions/seedDepositOnInitReserve.js +24 -0
- package/dist/@codegen/klend/instructions/seedDepositOnInitReserve.js.map +1 -0
- package/dist/@codegen/klend/instructions/withdrawObligationCollateral.js +1 -1
- package/dist/@codegen/klend/instructions/withdrawObligationCollateralV2.js +1 -1
- package/dist/@codegen/klend/types/ReserveConfig.d.ts +58 -24
- package/dist/@codegen/klend/types/ReserveConfig.d.ts.map +1 -1
- package/dist/@codegen/klend/types/ReserveConfig.js +40 -18
- package/dist/@codegen/klend/types/ReserveConfig.js.map +1 -1
- package/dist/@codegen/klend/types/ReserveFees.d.ts +8 -8
- package/dist/@codegen/klend/types/ReserveFees.d.ts.map +1 -1
- package/dist/@codegen/klend/types/ReserveFees.js +8 -8
- package/dist/@codegen/klend/types/ReserveFees.js.map +1 -1
- package/dist/@codegen/klend/types/UpdateConfigMode.d.ts +46 -7
- package/dist/@codegen/klend/types/UpdateConfigMode.d.ts.map +1 -1
- package/dist/@codegen/klend/types/UpdateConfigMode.js +85 -12
- package/dist/@codegen/klend/types/UpdateConfigMode.js.map +1 -1
- package/dist/@codegen/klend/types/UpdateLendingMarketMode.d.ts +26 -0
- package/dist/@codegen/klend/types/UpdateLendingMarketMode.d.ts.map +1 -1
- package/dist/@codegen/klend/types/UpdateLendingMarketMode.js +49 -1
- package/dist/@codegen/klend/types/UpdateLendingMarketMode.js.map +1 -1
- package/dist/@codegen/klend/types/index.d.ts +4 -4
- package/dist/@codegen/klend/types/index.d.ts.map +1 -1
- package/dist/@codegen/klend/types/index.js.map +1 -1
- package/dist/@codegen/kvault/accounts/GlobalConfig.d.ts +32 -0
- package/dist/@codegen/kvault/accounts/GlobalConfig.d.ts.map +1 -0
- package/dist/@codegen/kvault/accounts/GlobalConfig.js +125 -0
- package/dist/@codegen/kvault/accounts/GlobalConfig.js.map +1 -0
- package/dist/@codegen/kvault/accounts/Reserve.js +1 -1
- package/dist/@codegen/kvault/accounts/ReserveWhitelistEntry.d.ts +52 -0
- package/dist/@codegen/kvault/accounts/ReserveWhitelistEntry.d.ts.map +1 -0
- package/dist/@codegen/kvault/accounts/ReserveWhitelistEntry.js +127 -0
- package/dist/@codegen/kvault/accounts/ReserveWhitelistEntry.js.map +1 -0
- package/dist/@codegen/kvault/accounts/VaultState.d.ts +18 -0
- package/dist/@codegen/kvault/accounts/VaultState.d.ts.map +1 -1
- package/dist/@codegen/kvault/accounts/VaultState.js +39 -1
- package/dist/@codegen/kvault/accounts/VaultState.js.map +1 -1
- package/dist/@codegen/kvault/accounts/index.d.ts +4 -0
- package/dist/@codegen/kvault/accounts/index.d.ts.map +1 -1
- package/dist/@codegen/kvault/accounts/index.js +5 -1
- package/dist/@codegen/kvault/accounts/index.js.map +1 -1
- package/dist/@codegen/kvault/errors/custom.d.ts +61 -5
- package/dist/@codegen/kvault/errors/custom.d.ts.map +1 -1
- package/dist/@codegen/kvault/errors/custom.js +108 -9
- package/dist/@codegen/kvault/errors/custom.js.map +1 -1
- package/dist/@codegen/kvault/instructions/addUpdateWhitelistedReserve.d.ts +16 -0
- package/dist/@codegen/kvault/instructions/addUpdateWhitelistedReserve.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/addUpdateWhitelistedReserve.js +66 -0
- package/dist/@codegen/kvault/instructions/addUpdateWhitelistedReserve.js.map +1 -0
- package/dist/@codegen/kvault/instructions/buy.d.ts +24 -0
- package/dist/@codegen/kvault/instructions/buy.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/buy.js +67 -0
- package/dist/@codegen/kvault/instructions/buy.js.map +1 -0
- package/dist/@codegen/kvault/instructions/index.d.ts +12 -0
- package/dist/@codegen/kvault/instructions/index.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/index.js +13 -1
- package/dist/@codegen/kvault/instructions/index.js.map +1 -1
- package/dist/@codegen/kvault/instructions/initGlobalConfig.d.ts +11 -0
- package/dist/@codegen/kvault/instructions/initGlobalConfig.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/initGlobalConfig.js +20 -0
- package/dist/@codegen/kvault/instructions/initGlobalConfig.js.map +1 -0
- package/dist/@codegen/kvault/instructions/invest.d.ts +2 -1
- package/dist/@codegen/kvault/instructions/invest.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/invest.js +5 -0
- package/dist/@codegen/kvault/instructions/invest.js.map +1 -1
- package/dist/@codegen/kvault/instructions/sell.d.ts +40 -0
- package/dist/@codegen/kvault/instructions/sell.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/sell.js +98 -0
- package/dist/@codegen/kvault/instructions/sell.js.map +1 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfig.d.ts +13 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfig.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfig.js +63 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfig.js.map +1 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfigAdmin.d.ts +8 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfigAdmin.d.ts.map +1 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfigAdmin.js +21 -0
- package/dist/@codegen/kvault/instructions/updateGlobalConfigAdmin.js.map +1 -0
- package/dist/@codegen/kvault/instructions/updateReserveAllocation.d.ts +2 -1
- package/dist/@codegen/kvault/instructions/updateReserveAllocation.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/updateReserveAllocation.js +5 -0
- package/dist/@codegen/kvault/instructions/updateReserveAllocation.js.map +1 -1
- package/dist/@codegen/kvault/instructions/updateVaultConfig.d.ts +2 -1
- package/dist/@codegen/kvault/instructions/updateVaultConfig.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/updateVaultConfig.js +2 -5
- package/dist/@codegen/kvault/instructions/updateVaultConfig.js.map +1 -1
- package/dist/@codegen/kvault/instructions/withdraw.d.ts +1 -0
- package/dist/@codegen/kvault/instructions/withdraw.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/withdraw.js +1 -0
- package/dist/@codegen/kvault/instructions/withdraw.js.map +1 -1
- package/dist/@codegen/kvault/instructions/withdrawFromAvailable.d.ts +1 -0
- package/dist/@codegen/kvault/instructions/withdrawFromAvailable.d.ts.map +1 -1
- package/dist/@codegen/kvault/instructions/withdrawFromAvailable.js +1 -0
- package/dist/@codegen/kvault/instructions/withdrawFromAvailable.js.map +1 -1
- package/dist/@codegen/kvault/types/ReserveConfig.d.ts +27 -34
- package/dist/@codegen/kvault/types/ReserveConfig.d.ts.map +1 -1
- package/dist/@codegen/kvault/types/ReserveConfig.js +20 -17
- package/dist/@codegen/kvault/types/ReserveConfig.js.map +1 -1
- package/dist/@codegen/kvault/types/ReserveFees.d.ts +8 -8
- package/dist/@codegen/kvault/types/ReserveFees.d.ts.map +1 -1
- package/dist/@codegen/kvault/types/ReserveFees.js +8 -8
- package/dist/@codegen/kvault/types/ReserveFees.js.map +1 -1
- package/dist/@codegen/kvault/types/UpdateGlobalConfigMode.d.ts +68 -0
- package/dist/@codegen/kvault/types/UpdateGlobalConfigMode.d.ts.map +1 -0
- package/dist/@codegen/kvault/types/UpdateGlobalConfigMode.js +162 -0
- package/dist/@codegen/kvault/types/UpdateGlobalConfigMode.js.map +1 -0
- package/dist/@codegen/kvault/types/UpdateReserveWhitelistMode.d.ts +46 -0
- package/dist/@codegen/kvault/types/UpdateReserveWhitelistMode.d.ts.map +1 -0
- package/dist/@codegen/kvault/types/UpdateReserveWhitelistMode.js +124 -0
- package/dist/@codegen/kvault/types/UpdateReserveWhitelistMode.js.map +1 -0
- package/dist/@codegen/kvault/types/VaultConfigField.d.ts +65 -0
- package/dist/@codegen/kvault/types/VaultConfigField.d.ts.map +1 -1
- package/dist/@codegen/kvault/types/VaultConfigField.js +121 -1
- package/dist/@codegen/kvault/types/VaultConfigField.js.map +1 -1
- package/dist/@codegen/kvault/types/index.d.ts +10 -2
- package/dist/@codegen/kvault/types/index.d.ts.map +1 -1
- package/dist/@codegen/kvault/types/index.js +5 -1
- package/dist/@codegen/kvault/types/index.js.map +1 -1
- package/dist/classes/manager.d.ts +19 -1
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +28 -0
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +7 -4
- package/dist/classes/reserve.js.map +1 -1
- package/dist/classes/vault.d.ts +33 -5
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +379 -48
- package/dist/classes/vault.js.map +1 -1
- package/dist/idl/klend.json +129 -59
- package/dist/lib.d.ts +1 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +4 -2
- package/dist/lib.js.map +1 -1
- package/dist/manager/client_kamino_manager.js +206 -15
- package/dist/manager/client_kamino_manager.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/managerTypes.d.ts +1 -1
- package/dist/utils/managerTypes.d.ts.map +1 -1
- package/dist/utils/managerTypes.js +5 -3
- package/dist/utils/managerTypes.js.map +1 -1
- package/dist/utils/parse.d.ts +10 -0
- package/dist/utils/parse.d.ts.map +1 -0
- package/dist/utils/parse.js +24 -0
- package/dist/utils/parse.js.map +1 -0
- package/dist/utils/seeds.d.ts +5 -5
- package/dist/utils/seeds.d.ts.map +1 -1
- package/dist/utils/seeds.js +13 -13
- package/dist/utils/seeds.js.map +1 -1
- package/dist/utils/vault.d.ts.map +1 -1
- package/dist/utils/vault.js +6 -0
- package/dist/utils/vault.js.map +1 -1
- package/package.json +1 -1
- package/src/@codegen/klend/accounts/LendingMarket.ts +46 -2
- package/src/@codegen/klend/errors/custom.ts +47 -2
- package/src/@codegen/klend/instructions/index.ts +2 -0
- package/src/@codegen/klend/instructions/initReserve.ts +2 -6
- package/src/@codegen/klend/instructions/liquidateObligationAndRedeemReserveCollateralV2.ts +1 -1
- package/src/@codegen/klend/instructions/seedDepositOnInitReserve.ts +50 -0
- package/src/@codegen/klend/instructions/withdrawObligationCollateral.ts +1 -1
- package/src/@codegen/klend/instructions/withdrawObligationCollateralV2.ts +1 -1
- package/src/@codegen/klend/types/ReserveConfig.ts +72 -30
- package/src/@codegen/klend/types/ReserveFees.ts +12 -12
- package/src/@codegen/klend/types/UpdateConfigMode.ts +103 -13
- package/src/@codegen/klend/types/UpdateLendingMarketMode.ts +60 -0
- package/src/@codegen/klend/types/index.ts +12 -2
- package/src/@codegen/kvault/accounts/GlobalConfig.ts +136 -0
- package/src/@codegen/kvault/accounts/Reserve.ts +1 -1
- package/src/@codegen/kvault/accounts/ReserveWhitelistEntry.ts +157 -0
- package/src/@codegen/kvault/accounts/VaultState.ts +57 -1
- package/src/@codegen/kvault/accounts/index.ts +7 -0
- package/src/@codegen/kvault/errors/custom.ts +109 -8
- package/src/@codegen/kvault/instructions/addUpdateWhitelistedReserve.ts +64 -0
- package/src/@codegen/kvault/instructions/buy.ts +74 -0
- package/src/@codegen/kvault/instructions/index.ts +18 -0
- package/src/@codegen/kvault/instructions/initGlobalConfig.ts +44 -0
- package/src/@codegen/kvault/instructions/invest.ts +4 -0
- package/src/@codegen/kvault/instructions/sell.ts +122 -0
- package/src/@codegen/kvault/instructions/updateGlobalConfig.ts +58 -0
- package/src/@codegen/kvault/instructions/updateGlobalConfigAdmin.ts +42 -0
- package/src/@codegen/kvault/instructions/updateReserveAllocation.ts +4 -0
- package/src/@codegen/kvault/instructions/updateVaultConfig.ts +4 -6
- package/src/@codegen/kvault/instructions/withdraw.ts +2 -0
- package/src/@codegen/kvault/instructions/withdrawFromAvailable.ts +2 -0
- package/src/@codegen/kvault/types/ReserveConfig.ts +34 -37
- package/src/@codegen/kvault/types/ReserveFees.ts +12 -12
- package/src/@codegen/kvault/types/UpdateGlobalConfigMode.ts +160 -0
- package/src/@codegen/kvault/types/UpdateReserveWhitelistMode.ts +117 -0
- package/src/@codegen/kvault/types/VaultConfigField.ts +150 -0
- package/src/@codegen/kvault/types/index.ts +31 -0
- package/src/classes/manager.ts +50 -1
- package/src/classes/reserve.ts +7 -5
- package/src/classes/vault.ts +555 -48
- package/src/idl/klend.json +130 -60
- package/src/idl/kvault.json +582 -23
- package/src/lib.ts +2 -1
- package/src/manager/client_kamino_manager.ts +313 -18
- package/src/utils/index.ts +2 -1
- package/src/utils/managerTypes.ts +6 -4
- package/src/utils/parse.ts +18 -0
- package/src/utils/seeds.ts +13 -17
- package/src/utils/vault.ts +6 -0
package/src/classes/vault.ts
CHANGED
|
@@ -23,6 +23,9 @@ import {
|
|
|
23
23
|
AccountInfoWithPubkey,
|
|
24
24
|
AccountInfoBase,
|
|
25
25
|
AccountInfoWithJsonData,
|
|
26
|
+
Option,
|
|
27
|
+
some,
|
|
28
|
+
none,
|
|
26
29
|
} from '@solana/kit';
|
|
27
30
|
import {
|
|
28
31
|
AllOracleAccounts,
|
|
@@ -40,18 +43,28 @@ import {
|
|
|
40
43
|
WRAPPED_SOL_MINT,
|
|
41
44
|
} from '../lib';
|
|
42
45
|
import {
|
|
46
|
+
addUpdateWhitelistedReserve,
|
|
47
|
+
AddUpdateWhitelistedReserveAccounts,
|
|
48
|
+
AddUpdateWhitelistedReserveArgs,
|
|
49
|
+
buy,
|
|
50
|
+
BuyAccounts,
|
|
51
|
+
BuyArgs,
|
|
43
52
|
deposit,
|
|
44
53
|
DepositAccounts,
|
|
45
54
|
DepositArgs,
|
|
46
55
|
giveUpPendingFees,
|
|
47
56
|
GiveUpPendingFeesAccounts,
|
|
48
57
|
GiveUpPendingFeesArgs,
|
|
58
|
+
initKVaultGlobalConfig,
|
|
49
59
|
initVault,
|
|
50
60
|
InitVaultAccounts,
|
|
51
61
|
invest,
|
|
52
62
|
InvestAccounts,
|
|
53
63
|
removeAllocation,
|
|
54
64
|
RemoveAllocationAccounts,
|
|
65
|
+
sell,
|
|
66
|
+
SellAccounts,
|
|
67
|
+
SellArgs,
|
|
55
68
|
updateAdmin,
|
|
56
69
|
UpdateAdminAccounts,
|
|
57
70
|
updateReserveAllocation,
|
|
@@ -69,7 +82,7 @@ import {
|
|
|
69
82
|
withdrawPendingFees,
|
|
70
83
|
WithdrawPendingFeesAccounts,
|
|
71
84
|
} from '../@codegen/kvault/instructions';
|
|
72
|
-
import { VaultConfigField, VaultConfigFieldKind } from '../@codegen/kvault/types';
|
|
85
|
+
import { UpdateReserveWhitelistModeKind, VaultConfigField, VaultConfigFieldKind } from '../@codegen/kvault/types';
|
|
73
86
|
import { VaultState } from '../@codegen/kvault/accounts';
|
|
74
87
|
import Decimal from 'decimal.js';
|
|
75
88
|
import { bpsToPct, decodeVaultName, numberToLamportsDecimal, parseTokenSymbol, pubkeyHashMapToJson } from './utils';
|
|
@@ -85,6 +98,8 @@ import {
|
|
|
85
98
|
getTokenAccountAmount,
|
|
86
99
|
getTokenAccountMint,
|
|
87
100
|
lendingMarketAuthPda,
|
|
101
|
+
parseBooleanFlag,
|
|
102
|
+
programDataPda,
|
|
88
103
|
SECONDS_PER_YEAR,
|
|
89
104
|
U64_MAX,
|
|
90
105
|
VAULT_INITIAL_DEPOSIT,
|
|
@@ -140,6 +155,8 @@ const BASE_VAULT_AUTHORITY_SEED = 'authority';
|
|
|
140
155
|
const SHARES_SEED = 'shares';
|
|
141
156
|
const EVENT_AUTHORITY_SEED = '__event_authority';
|
|
142
157
|
export const METADATA_SEED = 'metadata';
|
|
158
|
+
const GLOBAL_CONFIG_STATE_SEED = 'global_config';
|
|
159
|
+
const WHITELISTED_RESERVES_SEED = 'whitelisted_reserves';
|
|
143
160
|
|
|
144
161
|
export const METADATA_PROGRAM_ID: Address = address('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s');
|
|
145
162
|
|
|
@@ -215,6 +232,29 @@ export class KaminoVaultClient {
|
|
|
215
232
|
console.log('Tokens per share: ', tokensPerShare);
|
|
216
233
|
}
|
|
217
234
|
|
|
235
|
+
/**
|
|
236
|
+
* This method initializes the kvault global config (one off, needs to be signed by program owner)
|
|
237
|
+
* @param admin - the admin of the kvault program
|
|
238
|
+
* @returns - an instruction to initialize the kvault global config
|
|
239
|
+
*/
|
|
240
|
+
async initKvaultGlobalConfigIx(admin: TransactionSigner) {
|
|
241
|
+
const globalConfigAddress = await getKvaultGlobalConfigPda(this.getProgramID());
|
|
242
|
+
|
|
243
|
+
const programData = await programDataPda(this.getProgramID());
|
|
244
|
+
const ix = initKVaultGlobalConfig(
|
|
245
|
+
{
|
|
246
|
+
payer: admin,
|
|
247
|
+
globalConfig: globalConfigAddress,
|
|
248
|
+
programData: programData,
|
|
249
|
+
systemProgram: SYSTEM_PROGRAM_ADDRESS,
|
|
250
|
+
rent: SYSVAR_RENT_ADDRESS,
|
|
251
|
+
},
|
|
252
|
+
undefined,
|
|
253
|
+
this.getProgramID()
|
|
254
|
+
);
|
|
255
|
+
return ix;
|
|
256
|
+
}
|
|
257
|
+
|
|
218
258
|
/**
|
|
219
259
|
* This method will create a vault with a given config. The config can be changed later on, but it is recommended to set it up correctly from the start
|
|
220
260
|
* @param vaultConfig - the config object used to create a vault
|
|
@@ -316,7 +356,7 @@ export class KaminoVaultClient {
|
|
|
316
356
|
[]
|
|
317
357
|
);
|
|
318
358
|
|
|
319
|
-
const setLUTIx = this.updateUninitialisedVaultConfigIx(
|
|
359
|
+
const setLUTIx = await this.updateUninitialisedVaultConfigIx(
|
|
320
360
|
vaultConfig.admin,
|
|
321
361
|
vaultState.address,
|
|
322
362
|
new VaultConfigField.LookupTable(),
|
|
@@ -326,7 +366,7 @@ export class KaminoVaultClient {
|
|
|
326
366
|
const ixs = [createVaultIx, initVaultIx, setLUTIx];
|
|
327
367
|
|
|
328
368
|
if (vaultConfig.getPerformanceFeeBps() > 0) {
|
|
329
|
-
const setPerformanceFeeIx = this.updateUninitialisedVaultConfigIx(
|
|
369
|
+
const setPerformanceFeeIx = await this.updateUninitialisedVaultConfigIx(
|
|
330
370
|
vaultConfig.admin,
|
|
331
371
|
vaultState.address,
|
|
332
372
|
new VaultConfigField.PerformanceFeeBps(),
|
|
@@ -335,7 +375,7 @@ export class KaminoVaultClient {
|
|
|
335
375
|
ixs.push(setPerformanceFeeIx);
|
|
336
376
|
}
|
|
337
377
|
if (vaultConfig.getManagementFeeBps() > 0) {
|
|
338
|
-
const setManagementFeeIx = this.updateUninitialisedVaultConfigIx(
|
|
378
|
+
const setManagementFeeIx = await this.updateUninitialisedVaultConfigIx(
|
|
339
379
|
vaultConfig.admin,
|
|
340
380
|
vaultState.address,
|
|
341
381
|
new VaultConfigField.ManagementFeeBps(),
|
|
@@ -344,7 +384,7 @@ export class KaminoVaultClient {
|
|
|
344
384
|
ixs.push(setManagementFeeIx);
|
|
345
385
|
}
|
|
346
386
|
if (vaultConfig.name && vaultConfig.name.length > 0) {
|
|
347
|
-
const setNameIx = this.updateUninitialisedVaultConfigIx(
|
|
387
|
+
const setNameIx = await this.updateUninitialisedVaultConfigIx(
|
|
348
388
|
vaultConfig.admin,
|
|
349
389
|
vaultState.address,
|
|
350
390
|
new VaultConfigField.Name(),
|
|
@@ -352,7 +392,7 @@ export class KaminoVaultClient {
|
|
|
352
392
|
);
|
|
353
393
|
ixs.push(setNameIx);
|
|
354
394
|
}
|
|
355
|
-
const setFarmIx = this.updateUninitialisedVaultConfigIx(
|
|
395
|
+
const setFarmIx = await this.updateUninitialisedVaultConfigIx(
|
|
356
396
|
vaultConfig.admin,
|
|
357
397
|
vaultState.address,
|
|
358
398
|
new VaultConfigField.Farm(),
|
|
@@ -482,6 +522,12 @@ export class KaminoVaultClient {
|
|
|
482
522
|
this._kaminoVaultProgramId
|
|
483
523
|
);
|
|
484
524
|
|
|
525
|
+
const reserveWhitelistEntryOption = await getReserveWhitelistEntryIfExists(
|
|
526
|
+
reserveAllocationConfig.getReserveAddress(),
|
|
527
|
+
this.getConnection(),
|
|
528
|
+
this._kaminoVaultProgramId
|
|
529
|
+
);
|
|
530
|
+
|
|
485
531
|
const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
|
|
486
532
|
const updateReserveAllocationAccounts: UpdateReserveAllocationAccounts = {
|
|
487
533
|
signer: vaultAdmin,
|
|
@@ -490,6 +536,7 @@ export class KaminoVaultClient {
|
|
|
490
536
|
reserveCollateralMint: reserveState.collateral.mintPubkey,
|
|
491
537
|
reserve: reserveAllocationConfig.getReserveAddress(),
|
|
492
538
|
ctokenVault: cTokenVault,
|
|
539
|
+
reserveWhitelistEntry: reserveWhitelistEntryOption,
|
|
493
540
|
systemProgram: SYSTEM_PROGRAM_ADDRESS,
|
|
494
541
|
rent: SYSVAR_RENT_ADDRESS,
|
|
495
542
|
reserveCollateralTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
@@ -756,7 +803,8 @@ export class KaminoVaultClient {
|
|
|
756
803
|
* @param vault the vault to update
|
|
757
804
|
* @param mode the field to update (based on VaultConfigFieldKind enum)
|
|
758
805
|
* @param value the value to update the field with
|
|
759
|
-
* @param [
|
|
806
|
+
* @param [adminAuthority] the signer of the transaction. Optional. If not provided the admin of the vault will be used. It should be used when changing the admin of the vault if we want to build or batch multiple ixs in the same tx.
|
|
807
|
+
* The global admin should be passed in when wanting to change the AllowAllocationsInWhitelistedReservesOnly or AllowInvestInWhitelistedReservesOnly fields to false
|
|
760
808
|
* @param [lutIxsSigner] the signer of the transaction to be used for the lookup table instructions. Optional. If not provided the admin of the vault will be used. It should be used when changing the admin of the vault if we want to build or batch multiple ixs in the same tx
|
|
761
809
|
* @param [skipLutUpdate] if true, the lookup table instructions will not be included in the returned instructions
|
|
762
810
|
* @returns a struct that contains the instruction to update the field and an optional list of instructions to update the lookup table
|
|
@@ -765,41 +813,26 @@ export class KaminoVaultClient {
|
|
|
765
813
|
vault: KaminoVault,
|
|
766
814
|
mode: VaultConfigFieldKind,
|
|
767
815
|
value: string,
|
|
768
|
-
|
|
816
|
+
adminAuthority?: TransactionSigner,
|
|
769
817
|
lutIxsSigner?: TransactionSigner,
|
|
770
818
|
skipLutUpdate: boolean = false
|
|
771
819
|
): Promise<UpdateVaultConfigIxs> {
|
|
772
820
|
const vaultState: VaultState = await vault.getState();
|
|
773
|
-
const admin = parseVaultAdmin(vaultState,
|
|
821
|
+
const admin = parseVaultAdmin(vaultState, adminAuthority);
|
|
774
822
|
|
|
823
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
775
824
|
const updateVaultConfigAccs: UpdateVaultConfigAccounts = {
|
|
776
|
-
|
|
825
|
+
signer: admin,
|
|
826
|
+
globalConfig: globalConfig,
|
|
777
827
|
vaultState: vault.address,
|
|
778
828
|
klendProgram: this._kaminoLendProgramId,
|
|
779
829
|
};
|
|
780
|
-
if (vaultAdminAuthority) {
|
|
781
|
-
updateVaultConfigAccs.vaultAdminAuthority = vaultAdminAuthority;
|
|
782
|
-
}
|
|
783
830
|
|
|
784
831
|
const updateVaultConfigArgs: UpdateVaultConfigArgs = {
|
|
785
832
|
entry: mode,
|
|
786
|
-
data:
|
|
833
|
+
data: this.getValueForModeAsBuffer(mode, value),
|
|
787
834
|
};
|
|
788
835
|
|
|
789
|
-
if (isNaN(+value) || value === DEFAULT_PUBLIC_KEY) {
|
|
790
|
-
if (mode.kind === new VaultConfigField.Name().kind) {
|
|
791
|
-
const data = Array.from(this.encodeVaultName(value));
|
|
792
|
-
updateVaultConfigArgs.data = Buffer.from(data);
|
|
793
|
-
} else {
|
|
794
|
-
const data = address(value);
|
|
795
|
-
updateVaultConfigArgs.data = Buffer.from(addressEncoder.encode(data));
|
|
796
|
-
}
|
|
797
|
-
} else {
|
|
798
|
-
const buffer = Buffer.alloc(8);
|
|
799
|
-
buffer.writeBigUInt64LE(BigInt(value.toString()));
|
|
800
|
-
updateVaultConfigArgs.data = buffer;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
836
|
const vaultReserves = this.getVaultReserves(vaultState);
|
|
804
837
|
const vaultReservesState = await this.loadVaultReserves(vaultState);
|
|
805
838
|
|
|
@@ -863,6 +896,38 @@ export class KaminoVaultClient {
|
|
|
863
896
|
return updateVaultConfigIxs;
|
|
864
897
|
}
|
|
865
898
|
|
|
899
|
+
/**
|
|
900
|
+
* Add or update a reserve whitelist entry. This controls whether the reserve is whitelisted for adding/updating
|
|
901
|
+
* allocations or for invest, depending on the mode parameter.
|
|
902
|
+
*
|
|
903
|
+
* @param reserve - Address of the reserve to whitelist
|
|
904
|
+
* @param mode - The whitelist mode: either 'Invest' or 'AddAllocation' with a value (1 = allow, 0 = deny)
|
|
905
|
+
* @param globalAdmin - The global admin that signs the transaction
|
|
906
|
+
* @returns - An instruction to add/update the whitelisted reserve
|
|
907
|
+
*/
|
|
908
|
+
async addUpdateWhitelistedReserveIx(
|
|
909
|
+
reserve: Address,
|
|
910
|
+
mode: UpdateReserveWhitelistModeKind,
|
|
911
|
+
globalAdmin: TransactionSigner
|
|
912
|
+
): Promise<Instruction> {
|
|
913
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
914
|
+
const reserveWhitelistEntry = await getReserveWhitelistEntryPda(reserve, this._kaminoVaultProgramId);
|
|
915
|
+
|
|
916
|
+
const accounts: AddUpdateWhitelistedReserveAccounts = {
|
|
917
|
+
globalAdmin,
|
|
918
|
+
globalConfig,
|
|
919
|
+
reserve,
|
|
920
|
+
reserveWhitelistEntry,
|
|
921
|
+
systemProgram: SYSTEM_PROGRAM_ADDRESS,
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
const args: AddUpdateWhitelistedReserveArgs = {
|
|
925
|
+
update: mode,
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
return addUpdateWhitelistedReserve(args, accounts, undefined, this._kaminoVaultProgramId);
|
|
929
|
+
}
|
|
930
|
+
|
|
866
931
|
/** Sets the farm where the shares can be staked. This is store in vault state and a vault can only have one farm, so the new farm will ovveride the old farm
|
|
867
932
|
* @param vault - vault to set the farm for
|
|
868
933
|
* @param farm - the farm where the vault shares can be staked
|
|
@@ -895,44 +960,35 @@ export class KaminoVaultClient {
|
|
|
895
960
|
}
|
|
896
961
|
|
|
897
962
|
/**
|
|
898
|
-
* This method updates the vault config
|
|
899
|
-
*
|
|
963
|
+
* This method updates the vault config during vault initialization, within the same transaction
|
|
964
|
+
* where the vault is created. Use this when the vault state is not yet committed to the chain
|
|
965
|
+
* and cannot be fetched via RPC. For updates to existing vaults, use updateVaultConfigIxs instead.
|
|
966
|
+
*
|
|
967
|
+
* @param admin - the admin that signs the transaction
|
|
900
968
|
* @param vault - address of vault to be updated
|
|
901
969
|
* @param mode - the field to be updated
|
|
902
970
|
* @param value - the new value for the field to be updated (number or pubkey)
|
|
903
971
|
* @returns - an instruction to update the vault config
|
|
904
972
|
*/
|
|
905
|
-
private updateUninitialisedVaultConfigIx(
|
|
973
|
+
private async updateUninitialisedVaultConfigIx(
|
|
906
974
|
admin: TransactionSigner,
|
|
907
975
|
vault: Address,
|
|
908
976
|
mode: VaultConfigFieldKind,
|
|
909
977
|
value: string
|
|
910
|
-
): Instruction {
|
|
978
|
+
): Promise<Instruction> {
|
|
979
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
911
980
|
const updateVaultConfigAccs: UpdateVaultConfigAccounts = {
|
|
912
|
-
|
|
981
|
+
signer: admin,
|
|
982
|
+
globalConfig: globalConfig,
|
|
913
983
|
vaultState: vault,
|
|
914
984
|
klendProgram: this._kaminoLendProgramId,
|
|
915
985
|
};
|
|
916
986
|
|
|
917
987
|
const updateVaultConfigArgs: UpdateVaultConfigArgs = {
|
|
918
988
|
entry: mode,
|
|
919
|
-
data:
|
|
989
|
+
data: this.getValueForModeAsBuffer(mode, value),
|
|
920
990
|
};
|
|
921
991
|
|
|
922
|
-
if (isNaN(+value)) {
|
|
923
|
-
if (mode.kind === new VaultConfigField.Name().kind) {
|
|
924
|
-
const data = Array.from(this.encodeVaultName(value));
|
|
925
|
-
updateVaultConfigArgs.data = Buffer.from(data);
|
|
926
|
-
} else {
|
|
927
|
-
const data = address(value);
|
|
928
|
-
updateVaultConfigArgs.data = Buffer.from(addressEncoder.encode(data));
|
|
929
|
-
}
|
|
930
|
-
} else {
|
|
931
|
-
const buffer = Buffer.alloc(8);
|
|
932
|
-
buffer.writeBigUInt64LE(BigInt(value.toString()));
|
|
933
|
-
updateVaultConfigArgs.data = buffer;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
992
|
const updateVaultConfigIx = updateVaultConfig(
|
|
937
993
|
updateVaultConfigArgs,
|
|
938
994
|
updateVaultConfigAccs,
|
|
@@ -1220,6 +1276,92 @@ export class KaminoVaultClient {
|
|
|
1220
1276
|
return depositIxs;
|
|
1221
1277
|
}
|
|
1222
1278
|
|
|
1279
|
+
// todo (silviu): after all tx indexing works for buy/sell ixs remove this function and use the buyIx in the deposit function above
|
|
1280
|
+
async buySharesIxs(
|
|
1281
|
+
user: TransactionSigner,
|
|
1282
|
+
vault: KaminoVault,
|
|
1283
|
+
tokenAmount: Decimal,
|
|
1284
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1285
|
+
farmState?: FarmState
|
|
1286
|
+
): Promise<DepositIxs> {
|
|
1287
|
+
const vaultState = await vault.getState();
|
|
1288
|
+
|
|
1289
|
+
const tokenProgramID = vaultState.tokenProgram;
|
|
1290
|
+
const userTokenAta = await getAssociatedTokenAddress(vaultState.tokenMint, user.address, tokenProgramID);
|
|
1291
|
+
const createAtasIxs: Instruction[] = [];
|
|
1292
|
+
const closeAtasIxs: Instruction[] = [];
|
|
1293
|
+
if (vaultState.tokenMint === WRAPPED_SOL_MINT) {
|
|
1294
|
+
const [{ ata: wsolAta, createAtaIx: createWsolAtaIxn }] = await createAtasIdempotent(user, [
|
|
1295
|
+
{
|
|
1296
|
+
mint: WRAPPED_SOL_MINT,
|
|
1297
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1298
|
+
},
|
|
1299
|
+
]);
|
|
1300
|
+
createAtasIxs.push(createWsolAtaIxn);
|
|
1301
|
+
const transferWsolIxs = getTransferWsolIxs(
|
|
1302
|
+
user,
|
|
1303
|
+
wsolAta,
|
|
1304
|
+
lamports(
|
|
1305
|
+
BigInt(numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).ceil().toString())
|
|
1306
|
+
)
|
|
1307
|
+
);
|
|
1308
|
+
createAtasIxs.push(...transferWsolIxs);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
const [{ ata: userSharesAta, createAtaIx: createSharesAtaIxs }] = await createAtasIdempotent(user, [
|
|
1312
|
+
{
|
|
1313
|
+
mint: vaultState.sharesMint,
|
|
1314
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1315
|
+
},
|
|
1316
|
+
]);
|
|
1317
|
+
createAtasIxs.push(createSharesAtaIxs);
|
|
1318
|
+
|
|
1319
|
+
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1320
|
+
const buyAccounts: BuyAccounts = {
|
|
1321
|
+
user: user,
|
|
1322
|
+
vaultState: vault.address,
|
|
1323
|
+
tokenVault: vaultState.tokenVault,
|
|
1324
|
+
tokenMint: vaultState.tokenMint,
|
|
1325
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1326
|
+
sharesMint: vaultState.sharesMint,
|
|
1327
|
+
userTokenAta: userTokenAta,
|
|
1328
|
+
userSharesAta: userSharesAta,
|
|
1329
|
+
tokenProgram: tokenProgramID,
|
|
1330
|
+
klendProgram: this._kaminoLendProgramId,
|
|
1331
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1332
|
+
eventAuthority: eventAuthority,
|
|
1333
|
+
program: this._kaminoVaultProgramId,
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
const buyArgs: BuyArgs = {
|
|
1337
|
+
maxAmount: new BN(
|
|
1338
|
+
numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).floor().toString()
|
|
1339
|
+
),
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
let buyIx = buy(buyArgs, buyAccounts, undefined, this._kaminoVaultProgramId);
|
|
1343
|
+
|
|
1344
|
+
const vaultReserves = this.getVaultReserves(vaultState);
|
|
1345
|
+
|
|
1346
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1347
|
+
buyIx = this.appendRemainingAccountsForVaultReserves(buyIx, vaultReserves, vaultReservesState);
|
|
1348
|
+
|
|
1349
|
+
const depositIxs: DepositIxs = {
|
|
1350
|
+
depositIxs: [...createAtasIxs, buyIx, ...closeAtasIxs],
|
|
1351
|
+
stakeInFarmIfNeededIxs: [],
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
// if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
|
|
1355
|
+
if (!(await vault.hasFarm())) {
|
|
1356
|
+
return depositIxs;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// if there is a farm, stake the shares
|
|
1360
|
+
const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
|
|
1361
|
+
depositIxs.stakeInFarmIfNeededIxs = stakeSharesIxs;
|
|
1362
|
+
return depositIxs;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1223
1365
|
/**
|
|
1224
1366
|
* This function creates instructions to stake the shares in the vault farm if the vault has a farm
|
|
1225
1367
|
* @param user - user to stake
|
|
@@ -1389,6 +1531,135 @@ export class KaminoVaultClient {
|
|
|
1389
1531
|
return withdrawIxs;
|
|
1390
1532
|
}
|
|
1391
1533
|
|
|
1534
|
+
async sellSharesIxs(
|
|
1535
|
+
user: TransactionSigner,
|
|
1536
|
+
vault: KaminoVault,
|
|
1537
|
+
shareAmountToWithdraw: Decimal,
|
|
1538
|
+
slot: Slot,
|
|
1539
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1540
|
+
farmState?: FarmState
|
|
1541
|
+
): Promise<WithdrawIxs> {
|
|
1542
|
+
const vaultState = await vault.getState();
|
|
1543
|
+
const hasFarm = await vault.hasFarm();
|
|
1544
|
+
|
|
1545
|
+
const withdrawIxs: WithdrawIxs = {
|
|
1546
|
+
unstakeFromFarmIfNeededIxs: [],
|
|
1547
|
+
withdrawIxs: [],
|
|
1548
|
+
postWithdrawIxs: [],
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// compute the total shares the user has (in ATA + in farm) and check if they want to withdraw everything or just a part
|
|
1552
|
+
let userSharesAtaBalance = new Decimal(0);
|
|
1553
|
+
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1554
|
+
const userSharesAtaState = await fetchMaybeToken(this.getConnection(), userSharesAta);
|
|
1555
|
+
if (userSharesAtaState.exists) {
|
|
1556
|
+
const userSharesAtaBalanceInLamports = getTokenBalanceFromAccountInfoLamports(userSharesAtaState);
|
|
1557
|
+
userSharesAtaBalance = userSharesAtaBalanceInLamports.div(
|
|
1558
|
+
new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
let userSharesInFarm = new Decimal(0);
|
|
1563
|
+
if (hasFarm) {
|
|
1564
|
+
userSharesInFarm = await getUserSharesInTokensStakedInFarm(
|
|
1565
|
+
this.getConnection(),
|
|
1566
|
+
user.address,
|
|
1567
|
+
vaultState.vaultFarm,
|
|
1568
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
let sharesToWithdraw = shareAmountToWithdraw;
|
|
1573
|
+
const totalUserShares = userSharesAtaBalance.add(userSharesInFarm);
|
|
1574
|
+
let withdrawAllShares = false;
|
|
1575
|
+
if (sharesToWithdraw.gt(totalUserShares)) {
|
|
1576
|
+
sharesToWithdraw = new Decimal(U64_MAX.toString()).div(
|
|
1577
|
+
new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
|
|
1578
|
+
);
|
|
1579
|
+
withdrawAllShares = true;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// if not enough shares in ATA unstake from farm
|
|
1583
|
+
const sharesInAtaAreEnoughForWithdraw = sharesToWithdraw.lte(userSharesAtaBalance);
|
|
1584
|
+
if (hasFarm && !sharesInAtaAreEnoughForWithdraw && userSharesInFarm.gt(0)) {
|
|
1585
|
+
// if we need to unstake we need to make sure share ata is created
|
|
1586
|
+
const [{ createAtaIx }] = await createAtasIdempotent(user, [
|
|
1587
|
+
{
|
|
1588
|
+
mint: vaultState.sharesMint,
|
|
1589
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1590
|
+
},
|
|
1591
|
+
]);
|
|
1592
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(createAtaIx);
|
|
1593
|
+
let shareLamportsToWithdraw = new Decimal(U64_MAX.toString());
|
|
1594
|
+
if (!withdrawAllShares) {
|
|
1595
|
+
const sharesToWithdrawFromFarm = sharesToWithdraw.sub(userSharesAtaBalance);
|
|
1596
|
+
shareLamportsToWithdraw = collToLamportsDecimal(
|
|
1597
|
+
sharesToWithdrawFromFarm,
|
|
1598
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
const unstakeAndWithdrawFromFarmIxs = await getFarmUnstakeAndWithdrawIxs(
|
|
1602
|
+
this.getConnection(),
|
|
1603
|
+
user,
|
|
1604
|
+
shareLamportsToWithdraw,
|
|
1605
|
+
vaultState.vaultFarm,
|
|
1606
|
+
farmState
|
|
1607
|
+
);
|
|
1608
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.unstakeIx);
|
|
1609
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// if the vault has allocations withdraw otherwise wtihdraw from available ix
|
|
1613
|
+
const vaultAllocation = vaultState.vaultAllocationStrategy.find(
|
|
1614
|
+
(allocation) => allocation.reserve !== DEFAULT_PUBLIC_KEY
|
|
1615
|
+
);
|
|
1616
|
+
|
|
1617
|
+
if (vaultAllocation) {
|
|
1618
|
+
const withdrawFromVaultIxs = await this.sellSharesWithReserveIxs(
|
|
1619
|
+
user,
|
|
1620
|
+
vault,
|
|
1621
|
+
sharesToWithdraw,
|
|
1622
|
+
totalUserShares,
|
|
1623
|
+
slot,
|
|
1624
|
+
vaultReservesMap
|
|
1625
|
+
);
|
|
1626
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1627
|
+
} else {
|
|
1628
|
+
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
|
|
1629
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// if the vault is for SOL return the ix to unwrap the SOL
|
|
1633
|
+
if (vaultState.tokenMint === WRAPPED_SOL_MINT) {
|
|
1634
|
+
const userWsolAta = await getAssociatedTokenAddress(WRAPPED_SOL_MINT, user.address);
|
|
1635
|
+
const unwrapIx = getCloseAccountInstruction(
|
|
1636
|
+
{
|
|
1637
|
+
account: userWsolAta,
|
|
1638
|
+
owner: user,
|
|
1639
|
+
destination: user.address,
|
|
1640
|
+
},
|
|
1641
|
+
{ programAddress: TOKEN_PROGRAM_ADDRESS }
|
|
1642
|
+
);
|
|
1643
|
+
withdrawIxs.postWithdrawIxs.push(unwrapIx);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// if we burn all of user's shares close its shares ATA
|
|
1647
|
+
const burnAllUserShares = sharesToWithdraw.gt(totalUserShares);
|
|
1648
|
+
if (burnAllUserShares) {
|
|
1649
|
+
const closeAtaIx = getCloseAccountInstruction(
|
|
1650
|
+
{
|
|
1651
|
+
account: userSharesAta,
|
|
1652
|
+
owner: user,
|
|
1653
|
+
destination: user.address,
|
|
1654
|
+
},
|
|
1655
|
+
{ programAddress: TOKEN_PROGRAM_ADDRESS }
|
|
1656
|
+
);
|
|
1657
|
+
withdrawIxs.postWithdrawIxs.push(closeAtaIx);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
return withdrawIxs;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1392
1663
|
private async withdrawFromAvailableIxs(
|
|
1393
1664
|
user: TransactionSigner,
|
|
1394
1665
|
vault: KaminoVault,
|
|
@@ -1417,6 +1688,115 @@ export class KaminoVaultClient {
|
|
|
1417
1688
|
return [createAtaIx, withdrawFromAvailableIxn];
|
|
1418
1689
|
}
|
|
1419
1690
|
|
|
1691
|
+
private async sellSharesWithReserveIxs(
|
|
1692
|
+
user: TransactionSigner,
|
|
1693
|
+
vault: KaminoVault,
|
|
1694
|
+
shareAmount: Decimal,
|
|
1695
|
+
allUserShares: Decimal,
|
|
1696
|
+
slot: Slot,
|
|
1697
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
1698
|
+
): Promise<Instruction[]> {
|
|
1699
|
+
const vaultState = await vault.getState();
|
|
1700
|
+
|
|
1701
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1702
|
+
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1703
|
+
const [{ ata: userTokenAta, createAtaIx }] = await createAtasIdempotent(user, [
|
|
1704
|
+
{
|
|
1705
|
+
mint: vaultState.tokenMint,
|
|
1706
|
+
tokenProgram: vaultState.tokenProgram,
|
|
1707
|
+
},
|
|
1708
|
+
]);
|
|
1709
|
+
|
|
1710
|
+
const withdrawAllShares = shareAmount.gte(allUserShares);
|
|
1711
|
+
const actualSharesToWithdraw = shareAmount.lte(allUserShares) ? shareAmount : allUserShares;
|
|
1712
|
+
const shareLamportsToWithdraw = collToLamportsDecimal(
|
|
1713
|
+
actualSharesToWithdraw,
|
|
1714
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1715
|
+
);
|
|
1716
|
+
const tokensPerShare = await this.getTokensPerShareSingleVault(vault, slot);
|
|
1717
|
+
const sharesPerToken = new Decimal(1).div(tokensPerShare);
|
|
1718
|
+
const tokensToWithdraw = shareLamportsToWithdraw.mul(tokensPerShare);
|
|
1719
|
+
let tokenLeftToWithdraw = tokensToWithdraw;
|
|
1720
|
+
const availableTokens = new Decimal(vaultState.tokenAvailable.toString());
|
|
1721
|
+
tokenLeftToWithdraw = tokenLeftToWithdraw.sub(availableTokens);
|
|
1722
|
+
|
|
1723
|
+
type ReserveWithTokensToWithdraw = { reserve: Address; shares: Decimal };
|
|
1724
|
+
|
|
1725
|
+
const reserveWithSharesAmountToWithdraw: ReserveWithTokensToWithdraw[] = [];
|
|
1726
|
+
let isFirstWithdraw = true;
|
|
1727
|
+
|
|
1728
|
+
if (tokenLeftToWithdraw.lte(0)) {
|
|
1729
|
+
// Availabe enough to withdraw all - using the first existent reserve
|
|
1730
|
+
const firstReserve = vaultState.vaultAllocationStrategy.find((reserve) => reserve.reserve !== DEFAULT_PUBLIC_KEY);
|
|
1731
|
+
if (withdrawAllShares) {
|
|
1732
|
+
reserveWithSharesAmountToWithdraw.push({
|
|
1733
|
+
reserve: firstReserve!.reserve,
|
|
1734
|
+
shares: new Decimal(U64_MAX.toString()),
|
|
1735
|
+
});
|
|
1736
|
+
} else {
|
|
1737
|
+
reserveWithSharesAmountToWithdraw.push({
|
|
1738
|
+
reserve: firstReserve!.reserve,
|
|
1739
|
+
shares: shareLamportsToWithdraw,
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
} else {
|
|
1743
|
+
// Get decreasing order sorted available liquidity to withdraw from each reserve allocated to
|
|
1744
|
+
const reserveAllocationAvailableLiquidityToWithdraw = await this.getReserveAllocationAvailableLiquidityToWithdraw(
|
|
1745
|
+
vault,
|
|
1746
|
+
slot,
|
|
1747
|
+
vaultReservesState
|
|
1748
|
+
);
|
|
1749
|
+
// sort
|
|
1750
|
+
const reserveAllocationAvailableLiquidityToWithdrawSorted = [
|
|
1751
|
+
...reserveAllocationAvailableLiquidityToWithdraw.entries(),
|
|
1752
|
+
].sort((a, b) => b[1].sub(a[1]).toNumber());
|
|
1753
|
+
|
|
1754
|
+
reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw], _) => {
|
|
1755
|
+
if (tokenLeftToWithdraw.gt(0)) {
|
|
1756
|
+
let tokensToWithdrawFromReserve = Decimal.min(tokenLeftToWithdraw, availableLiquidityToWithdraw);
|
|
1757
|
+
if (isFirstWithdraw) {
|
|
1758
|
+
tokensToWithdrawFromReserve = tokensToWithdrawFromReserve.add(availableTokens);
|
|
1759
|
+
isFirstWithdraw = false;
|
|
1760
|
+
}
|
|
1761
|
+
if (withdrawAllShares) {
|
|
1762
|
+
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: new Decimal(U64_MAX.toString()) });
|
|
1763
|
+
} else {
|
|
1764
|
+
// round up to the nearest integer the shares to withdraw
|
|
1765
|
+
const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).floor();
|
|
1766
|
+
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: sharesToWithdrawFromReserve });
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
tokenLeftToWithdraw = tokenLeftToWithdraw.sub(tokensToWithdrawFromReserve);
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
const withdrawIxs: Instruction[] = [];
|
|
1775
|
+
withdrawIxs.push(createAtaIx);
|
|
1776
|
+
for (let reserveIndex = 0; reserveIndex < reserveWithSharesAmountToWithdraw.length; reserveIndex++) {
|
|
1777
|
+
const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
|
|
1778
|
+
const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
|
|
1779
|
+
if (reserveState === undefined) {
|
|
1780
|
+
throw new Error(`Reserve ${reserveWithTokens.reserve} not found in vault reserves map`);
|
|
1781
|
+
}
|
|
1782
|
+
const marketAddress = reserveState.state.lendingMarket;
|
|
1783
|
+
|
|
1784
|
+
const withdrawFromReserveIx = await this.sellIx(
|
|
1785
|
+
user,
|
|
1786
|
+
vault,
|
|
1787
|
+
vaultState,
|
|
1788
|
+
marketAddress,
|
|
1789
|
+
{ address: reserveWithTokens.reserve, state: reserveState.state },
|
|
1790
|
+
userSharesAta,
|
|
1791
|
+
userTokenAta,
|
|
1792
|
+
reserveWithTokens.shares,
|
|
1793
|
+
vaultReservesState
|
|
1794
|
+
);
|
|
1795
|
+
withdrawIxs.push(withdrawFromReserveIx);
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
return withdrawIxs;
|
|
1799
|
+
}
|
|
1420
1800
|
private async withdrawWithReserveIxs(
|
|
1421
1801
|
user: TransactionSigner,
|
|
1422
1802
|
vault: KaminoVault,
|
|
@@ -1666,6 +2046,12 @@ export class KaminoVaultClient {
|
|
|
1666
2046
|
ixs.push(createAtaIx);
|
|
1667
2047
|
}
|
|
1668
2048
|
|
|
2049
|
+
const reserveWhitelistEntryOption = await getReserveWhitelistEntryIfExists(
|
|
2050
|
+
reserve.address,
|
|
2051
|
+
this.getConnection(),
|
|
2052
|
+
this._kaminoVaultProgramId
|
|
2053
|
+
);
|
|
2054
|
+
|
|
1669
2055
|
const investAccounts: InvestAccounts = {
|
|
1670
2056
|
payer,
|
|
1671
2057
|
vaultState: vault.address,
|
|
@@ -1678,6 +2064,7 @@ export class KaminoVaultClient {
|
|
|
1678
2064
|
lendingMarketAuthority: lendingMarketAuth,
|
|
1679
2065
|
reserveLiquiditySupply: reserve.state.liquidity.supplyVault,
|
|
1680
2066
|
reserveCollateralMint: reserve.state.collateral.mintPubkey,
|
|
2067
|
+
reserveWhitelistEntry: reserveWhitelistEntryOption,
|
|
1681
2068
|
klendProgram: this._kaminoLendProgramId,
|
|
1682
2069
|
instructionSysvarAccount: SYSVAR_INSTRUCTIONS_ADDRESS,
|
|
1683
2070
|
tokenProgram: tokenProgram,
|
|
@@ -1707,6 +2094,89 @@ export class KaminoVaultClient {
|
|
|
1707
2094
|
return decodeVaultName(token);
|
|
1708
2095
|
}
|
|
1709
2096
|
|
|
2097
|
+
/** Helper to serialize value as Buffer for updateVaultConfig instruction */
|
|
2098
|
+
private getValueForModeAsBuffer(mode: VaultConfigFieldKind, value: string): Buffer {
|
|
2099
|
+
const isWhitelistOnlyFlag =
|
|
2100
|
+
mode.kind === new VaultConfigField.AllowInvestInWhitelistedReservesOnly().kind ||
|
|
2101
|
+
mode.kind === new VaultConfigField.AllowAllocationsInWhitelistedReservesOnly().kind;
|
|
2102
|
+
|
|
2103
|
+
if (isWhitelistOnlyFlag) {
|
|
2104
|
+
const flag = parseBooleanFlag(value);
|
|
2105
|
+
return Buffer.from([flag]);
|
|
2106
|
+
} else if (isNaN(+value)) {
|
|
2107
|
+
if (mode.kind === new VaultConfigField.Name().kind) {
|
|
2108
|
+
const data = Array.from(this.encodeVaultName(value));
|
|
2109
|
+
return Buffer.from(data);
|
|
2110
|
+
} else {
|
|
2111
|
+
const data = address(value);
|
|
2112
|
+
return Buffer.from(addressEncoder.encode(data));
|
|
2113
|
+
}
|
|
2114
|
+
} else {
|
|
2115
|
+
const buffer = Buffer.alloc(8);
|
|
2116
|
+
buffer.writeBigUInt64LE(BigInt(value.toString()));
|
|
2117
|
+
return buffer;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
private async sellIx(
|
|
2122
|
+
user: TransactionSigner,
|
|
2123
|
+
vault: KaminoVault,
|
|
2124
|
+
vaultState: VaultState,
|
|
2125
|
+
marketAddress: Address,
|
|
2126
|
+
reserve: ReserveWithAddress,
|
|
2127
|
+
userSharesAta: Address,
|
|
2128
|
+
userTokenAta: Address,
|
|
2129
|
+
shareAmountLamports: Decimal,
|
|
2130
|
+
vaultReservesState: Map<Address, KaminoReserve>
|
|
2131
|
+
): Promise<Instruction> {
|
|
2132
|
+
const [lendingMarketAuth] = await lendingMarketAuthPda(marketAddress, this._kaminoLendProgramId);
|
|
2133
|
+
|
|
2134
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
2135
|
+
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
2136
|
+
const sellAccounts: SellAccounts = {
|
|
2137
|
+
withdrawFromAvailable: {
|
|
2138
|
+
user,
|
|
2139
|
+
vaultState: vault.address,
|
|
2140
|
+
globalConfig: globalConfig,
|
|
2141
|
+
tokenVault: vaultState.tokenVault,
|
|
2142
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
2143
|
+
userTokenAta: userTokenAta,
|
|
2144
|
+
tokenMint: vaultState.tokenMint,
|
|
2145
|
+
userSharesAta: userSharesAta,
|
|
2146
|
+
sharesMint: vaultState.sharesMint,
|
|
2147
|
+
tokenProgram: vaultState.tokenProgram,
|
|
2148
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
2149
|
+
klendProgram: this._kaminoLendProgramId,
|
|
2150
|
+
eventAuthority: eventAuthority,
|
|
2151
|
+
program: this._kaminoVaultProgramId,
|
|
2152
|
+
},
|
|
2153
|
+
withdrawFromReserveAccounts: {
|
|
2154
|
+
vaultState: vault.address,
|
|
2155
|
+
reserve: reserve.address,
|
|
2156
|
+
ctokenVault: await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId),
|
|
2157
|
+
lendingMarket: marketAddress,
|
|
2158
|
+
lendingMarketAuthority: lendingMarketAuth,
|
|
2159
|
+
reserveLiquiditySupply: reserve.state.liquidity.supplyVault,
|
|
2160
|
+
reserveCollateralMint: reserve.state.collateral.mintPubkey,
|
|
2161
|
+
reserveCollateralTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
2162
|
+
instructionSysvarAccount: SYSVAR_INSTRUCTIONS_ADDRESS,
|
|
2163
|
+
},
|
|
2164
|
+
eventAuthority: eventAuthority,
|
|
2165
|
+
program: this._kaminoVaultProgramId,
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2168
|
+
const sellArgs: SellArgs = {
|
|
2169
|
+
sharesAmount: new BN(shareAmountLamports.floor().toString()),
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
let sellIxn = sell(sellArgs, sellAccounts, undefined, this._kaminoVaultProgramId);
|
|
2173
|
+
|
|
2174
|
+
const vaultReserves = this.getVaultReserves(vaultState);
|
|
2175
|
+
sellIxn = this.appendRemainingAccountsForVaultReserves(sellIxn, vaultReserves, vaultReservesState);
|
|
2176
|
+
|
|
2177
|
+
return sellIxn;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
1710
2180
|
private async withdrawIx(
|
|
1711
2181
|
user: TransactionSigner,
|
|
1712
2182
|
vault: KaminoVault,
|
|
@@ -1720,11 +2190,13 @@ export class KaminoVaultClient {
|
|
|
1720
2190
|
): Promise<Instruction> {
|
|
1721
2191
|
const [lendingMarketAuth] = await lendingMarketAuthPda(marketAddress, this._kaminoLendProgramId);
|
|
1722
2192
|
|
|
2193
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
1723
2194
|
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1724
2195
|
const withdrawAccounts: WithdrawAccounts = {
|
|
1725
2196
|
withdrawFromAvailable: {
|
|
1726
2197
|
user,
|
|
1727
2198
|
vaultState: vault.address,
|
|
2199
|
+
globalConfig: globalConfig,
|
|
1728
2200
|
tokenVault: vaultState.tokenVault,
|
|
1729
2201
|
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1730
2202
|
userTokenAta: userTokenAta,
|
|
@@ -1772,10 +2244,12 @@ export class KaminoVaultClient {
|
|
|
1772
2244
|
userTokenAta: Address,
|
|
1773
2245
|
shareAmountLamports: Decimal
|
|
1774
2246
|
): Promise<Instruction> {
|
|
2247
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
1775
2248
|
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1776
2249
|
const withdrawFromAvailableAccounts: WithdrawFromAvailableAccounts = {
|
|
1777
2250
|
user,
|
|
1778
2251
|
vaultState: vault.address,
|
|
2252
|
+
globalConfig: globalConfig,
|
|
1779
2253
|
tokenVault: vaultState.tokenVault,
|
|
1780
2254
|
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1781
2255
|
userTokenAta,
|
|
@@ -4162,6 +4636,39 @@ export async function getEventAuthorityPda(kaminoVaultProgramId: Address): Promi
|
|
|
4162
4636
|
)[0];
|
|
4163
4637
|
}
|
|
4164
4638
|
|
|
4639
|
+
export async function getKvaultGlobalConfigPda(kaminoVaultProgramId: Address): Promise<Address> {
|
|
4640
|
+
return (
|
|
4641
|
+
await getProgramDerivedAddress({
|
|
4642
|
+
seeds: [Buffer.from(GLOBAL_CONFIG_STATE_SEED)],
|
|
4643
|
+
programAddress: kaminoVaultProgramId,
|
|
4644
|
+
})
|
|
4645
|
+
)[0];
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4648
|
+
export async function getReserveWhitelistEntryPda(
|
|
4649
|
+
reserveAddress: Address,
|
|
4650
|
+
kaminoVaultProgramId: Address
|
|
4651
|
+
): Promise<Address> {
|
|
4652
|
+
return (
|
|
4653
|
+
await getProgramDerivedAddress({
|
|
4654
|
+
seeds: [Buffer.from(WHITELISTED_RESERVES_SEED), addressEncoder.encode(reserveAddress)],
|
|
4655
|
+
programAddress: kaminoVaultProgramId,
|
|
4656
|
+
})
|
|
4657
|
+
)[0];
|
|
4658
|
+
}
|
|
4659
|
+
|
|
4660
|
+
async function getReserveWhitelistEntryIfExists(
|
|
4661
|
+
reserveAddress: Address,
|
|
4662
|
+
rpc: Rpc<SolanaRpcApi>,
|
|
4663
|
+
kaminoVaultProgramId: Address
|
|
4664
|
+
): Promise<Option<Address>> {
|
|
4665
|
+
const reserveWhitelistEntry = await getReserveWhitelistEntryPda(reserveAddress, kaminoVaultProgramId);
|
|
4666
|
+
const reserveWhitelistEntryAccount = await fetchEncodedAccount(rpc, reserveWhitelistEntry, {
|
|
4667
|
+
commitment: 'processed',
|
|
4668
|
+
});
|
|
4669
|
+
return reserveWhitelistEntryAccount.exists ? some(reserveWhitelistEntry) : none<Address>();
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4165
4672
|
function parseVaultAdmin(vault: VaultState, signer?: TransactionSigner) {
|
|
4166
4673
|
return signer ?? noopSigner(vault.vaultAdminAuthority);
|
|
4167
4674
|
}
|