UNPKG

@kamino-finance/klend-sdk

Version:

Typescript SDK for interacting with the Kamino Lending (klend) protocol

830 lines 91.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const dotenv_1 = __importDefault(require("dotenv")); const commander_1 = require("commander"); const kit_1 = require("@solana/kit"); const lib_1 = require("../lib"); const types_1 = require("../@codegen/klend/types"); const fraction_1 = require("../classes/fraction"); const decimal_js_1 = __importDefault(require("decimal.js")); const bn_js_1 = __importDefault(require("bn.js")); const types_2 = require("../@codegen/kvault/types"); const fs = __importStar(require("fs")); const VaultConfigField_1 = require("../@codegen/kvault/types/VaultConfigField"); const rpc_1 = require("../utils/rpc"); const token_2022_1 = require("@solana-program/token-2022"); const ManagerEnv_1 = require("./tx/ManagerEnv"); const processor_1 = require("./tx/processor"); const priorityFee_1 = require("../client/tx/priorityFee"); const address_lookup_table_1 = require("@solana-program/address-lookup-table"); const signer_1 = require("../utils/signer"); dotenv_1.default.config({ path: `.env${process.env.ENV ? '.' + process.env.ENV : ''}`, }); async function main() { const commands = new commander_1.Command(); commands.name('kamino-manager-cli').description('CLI to interact with the kvaults and klend programs'); commands .command('create-market') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig pubkey is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(ms, staging); const admin = await env.getSigner(); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const { market: marketKp, ixs: createMarketIxs } = await kaminoManager.createMarketIxs({ admin, }); await (0, processor_1.processTx)(env.c, admin, [ ...createMarketIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Market created:', marketKp.address); }); commands .command('add-asset-to-market') .requiredOption('--market <string>', 'Market address to add asset to') .requiredOption('--mint <string>', 'Reserve liquidity token mint') .requiredOption('--reserve-config-path <string>', 'Path for the reserve config') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ market, mint, reserveConfigPath, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(undefined, staging); const tokenMint = (0, kit_1.address)(mint); const marketAddress = (0, kit_1.address)(market); const existingMarket = await lib_1.KaminoMarket.load(env.c.rpc, marketAddress, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, false); if (existingMarket === null) { throw new Error(`Market ${marketAddress} does not exist`); } const signer = await env.getSigner({ market: existingMarket }); const mintAccount = await (0, token_2022_1.fetchMint)(env.c.rpc, mint); const tokenMintProgramId = mintAccount.programAddress; const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const reserveConfigFromFile = JSON.parse(fs.readFileSync(reserveConfigPath, 'utf8')); const reserveConfig = parseReserveConfigFromFile(reserveConfigFromFile); const assetConfig = new lib_1.AssetReserveConfigCli(tokenMint, tokenMintProgramId, reserveConfig); const [adminAta] = await (0, token_2022_1.findAssociatedTokenPda)({ mint: tokenMint, owner: signer.address, tokenProgram: tokenMintProgramId, }); const { reserve, txnIxs } = await kaminoManager.addAssetToMarketIxs({ admin: signer, adminLiquiditySource: adminAta, marketAddress: marketAddress, assetConfig: assetConfig, }); console.log('reserve: ', reserve.address); const _createReserveSig = await (0, processor_1.processTx)(env.c, signer, [ ...txnIxs[0], ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); const [lut, createLutIxs] = await createUpdateReserveConfigLutIxs(env, marketAddress, reserve.address); await (0, processor_1.processTx)(env.c, signer, [ ...createLutIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode); const lutAcc = await (0, address_lookup_table_1.fetchAddressLookupTable)(env.c.rpc, lut); const _updateReserveSig = await (0, processor_1.processTx)(env.c, signer, [ ...txnIxs[1], ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 400_000, }), ], mode, [lutAcc]); mode === 'execute' && console.log('Reserve Created with config:', JSON.parse(JSON.stringify(reserveConfig)), '\nreserve address:', reserve.address); }); commands .command('update-reserve-config') .requiredOption('--reserve <string>', 'Reserve address') .requiredOption('--reserve-config-path <string>', 'Path for the reserve config') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option('--update-entire-config', 'If set, it will update entire reserve config in 1 instruction') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ reserve, reserveConfigPath, mode, updateEntireConfig, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(undefined, staging); const reserveAddress = (0, kit_1.address)(reserve); const reserveState = await lib_1.Reserve.fetch(env.c.rpc, reserveAddress, env.klendProgramId); if (reserveState === null) { throw new Error(`Reserve ${reserveAddress} not found`); } const marketAddress = reserveState.lendingMarket; const marketState = await lib_1.KaminoMarket.load(env.c.rpc, marketAddress, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, false); if (marketState === null) { throw new Error(`Market ${marketAddress} not found`); } const signer = await env.getSigner({ market: marketState }); const marketWithAddress = { address: marketAddress, state: marketState.state, }; const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const reserveConfigFromFile = JSON.parse(fs.readFileSync(reserveConfigPath, 'utf8')); const reserveConfig = parseReserveConfigFromFile(reserveConfigFromFile); const ixs = await kaminoManager.updateReserveIxs(signer, marketWithAddress, reserveAddress, reserveConfig, reserveState, updateEntireConfig); await (0, processor_1.processTx)(env.c, signer, [ ...ixs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 400_000, }), ], mode, []); mode === 'execute' && console.log('Reserve Updated with config -> ', JSON.parse(JSON.stringify(reserveConfig))); }); commands .command('download-reserve-config') .requiredOption('--reserve <string>', 'Reserve address') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ reserve, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(undefined, staging); const reserveAddress = (0, kit_1.address)(reserve); const reserveState = await lib_1.Reserve.fetch(env.c.rpc, reserveAddress, env.klendProgramId); if (!reserveState) { throw new Error('Reserve not found'); } fs.mkdirSync('./configs/' + reserveState.lendingMarket, { recursive: true }); const decoder = new TextDecoder('utf-8'); const reserveName = decoder.decode(Uint8Array.from(reserveState.config.tokenInfo.name)).replace(/\0/g, ''); const reserveConfigDisplay = parseReserveConfigToFile(reserveState.config); fs.writeFileSync('./configs/' + reserveState.lendingMarket + '/' + reserveName + '.json', JSON.stringify(reserveConfigDisplay, null, 2)); }); commands .command('create-vault') .requiredOption('--mint <string>', 'Vault token mint') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .requiredOption('--name <string>', 'The onchain name of the strat') .requiredOption('--tokenName <string>', 'The name of the token in the vault') .requiredOption('--extraTokenName <string>', 'The extra string appended to the token symbol') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ mint, mode, name, tokenName, extraTokenName, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(staging, ms); const tokenMint = (0, kit_1.address)(mint); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const admin = await env.getSigner(); const tokenProgramID = await (0, rpc_1.getAccountOwner)(env.c.rpc, tokenMint); const kaminoVaultConfig = new lib_1.KaminoVaultConfig({ admin, tokenMint: tokenMint, tokenMintProgramId: tokenProgramID, performanceFeeRatePercentage: new decimal_js_1.default(0.0), managementFeeRatePercentage: new decimal_js_1.default(0.0), name, vaultTokenSymbol: tokenName, vaultTokenName: extraTokenName, }); const { vault: vaultKp, initVaultIxs: instructions } = await kaminoManager.createVaultIxs(kaminoVaultConfig); await (0, processor_1.processTx)(env.c, admin, [ ...instructions.createAtaIfNeededIxs, ...instructions.initVaultIxs, instructions.createLUTIx, instructions.setFarmToVaultIx, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); await (0, lib_1.sleep)(2000); // create the farm await (0, processor_1.processTx)(env.c, admin, [ ...instructions.createVaultFarm.setupFarmIxs, ...instructions.createVaultFarm.updateFarmIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); await (0, lib_1.sleep)(2000); await (0, processor_1.processTx)(env.c, admin, [ ...instructions.populateLUTIxs, ...instructions.cleanupIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); await (0, processor_1.processTx)(env.c, admin, [ instructions.initSharesMetadataIx, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Vault created:', vaultKp.address); }); commands .command('set-shares-metadata') .requiredOption('--vault <string>', 'Vault address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .requiredOption('--symbol <string>', 'The symbol of the kVault token') .requiredOption('--extraName <string>', 'The name of the kVault token, appended to the symbol') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, mode, symbol, extraName, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(undefined, staging); const kVault = new lib_1.KaminoVault(env.c.rpc, (0, kit_1.address)(vault)); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const vaultState = await kVault.getState(); const signer = await env.getSigner({ vaultState }); const ix = await kaminoManager.getSetSharesMetadataIx(signer, kVault, symbol, extraName); await (0, processor_1.processTx)(env.c, signer, [ ix, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); }); commands .command('update-vault-pending-admin') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--new-admin <string>', 'Pubkey of the new admin') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, newAdmin, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.PendingVaultAdmin(), newAdmin, signer, undefined, true); await (0, processor_1.processTx)(env.c, signer, [ instructions.updateVaultConfigIx, ...instructions.updateLUTIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log(`Pending admin updated to ${newAdmin}`); }); commands .command('update-vault-config') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--field <string>', 'The field to update') .requiredOption('--value <string>', 'The value to update the field to') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--skip-lut-update`, 'If set, it will skip the LUT update') .option(`--lutSigner <string>`, 'If set, it will use the provided signer instead of the default one for the LUT update') .action(async ({ vault, field, value, mode, staging, skipLutUpdate, lutSigner }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); let lutSignerOrUndefined = undefined; if (lutSigner) { lutSignerOrUndefined = await (0, signer_1.parseKeypairFile)(lutSigner); } const shouldSkipLutUpdate = !!skipLutUpdate; const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, field, value, signer, lutSignerOrUndefined, shouldSkipLutUpdate); await (0, processor_1.processTx)(env.c, signer, [ instructions.updateVaultConfigIx, ...instructions.updateLUTIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Vault updated'); }); commands .command('update-vault-mgmt-fee') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--fee-bps <string>', 'Pubkey of the new admin') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, feeBps, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.ManagementFeeBps(), feeBps, signer); await (0, processor_1.processTx)(env.c, signer, [ instructions.updateVaultConfigIx, ...instructions.updateLUTIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Management fee updated'); }); commands .command('insert-into-lut') .requiredOption('--lut <string>', 'Lookup table address') .requiredOption('--addresses <string>', 'The addresses to insert into the LUT, space separated') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .option(`--signer <string>`, 'If set, it will use the provided signer instead of the default one') .action(async ({ lut, addresses, mode, staging, multisig, signer }) => { const env = await (0, ManagerEnv_1.initEnv)(multisig, staging); const lutAddress = (0, kit_1.address)(lut); let txSigner = await env.getSigner(); // if the signer is provided (path to a keypair) we use it, otherwise we use the default one if (signer) { txSigner = await (0, signer_1.parseKeypairFile)(signer); } const addressesArr = addresses.split(' ').map((a) => (0, kit_1.address)(a)); if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const instructions = await kaminoManager.insertIntoLutIxs(txSigner, lutAddress, addressesArr); await (0, processor_1.processTx)(env.c, txSigner, [ ...instructions, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Management fee updated'); }); commands.command('create-lut').action(async () => { const env = await (0, ManagerEnv_1.initEnv)(false); const signer = await env.getSigner(); const [initLutIx, lutAddress] = await (0, lib_1.initLookupTableIx)(signer, await env.c.rpc.getSlot().send()); await (0, processor_1.processTx)(env.c, signer, [ initLutIx, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], 'execute', []); console.log(`LUT created: ${lutAddress}`); }); commands .command('sync-vault-lut') .requiredOption('--vault <string>', 'The vault address to sync') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--signer <string>`, 'If set, it will use the provided signer instead of the default one') .action(async ({ vault, mode, staging, signer }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); let txSigner = await env.getSigner({ vaultState }); // if the signer is provided (path to a keypair) we use it, otherwise we use the default one if (signer) { txSigner = await (0, signer_1.parseKeypairFile)(signer); } const syncLUTIxs = await kaminoManager.syncVaultLUTIxs(txSigner, kaminoVault); // if we need to create the LUT we have to do that in a separate tx and wait a little bit after if (syncLUTIxs.setupLUTIfNeededIxs.length > 0) { await (0, processor_1.processTx)(env.c, txSigner, [ ...syncLUTIxs.setupLUTIfNeededIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); await (0, lib_1.sleep)(2000); mode === 'execute' && console.log('LUT created and set to the vault'); } // if there are accounts to be added to the LUT we have to do that in a separate tx for (const ix of syncLUTIxs.syncLUTIxs) { await (0, processor_1.processTx)(env.c, txSigner, [ ix, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Accounts added to the LUT'); } }); commands .command('update-vault-perf-fee') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--fee-bps <string>', 'Pubkey of the new admin') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, feeBps, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.PerformanceFeeBps(), feeBps, signer); await (0, processor_1.processTx)(env.c, signer, [ instructions.updateVaultConfigIx, ...instructions.updateLUTIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Performance fee updated'); }); commands .command('accept-vault-ownership') .requiredOption('--vault <string>', 'Vault address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const pendingAdmin = await env.getSigner({ vaultState, useVaultPendingAdmin: true, }); const instructions = await kaminoManager.acceptVaultOwnershipIxs(kaminoVault, pendingAdmin); await (0, processor_1.processTx)(env.c, pendingAdmin, [ instructions.acceptVaultOwnershipIx, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log(`Vault ownership accepted by ${pendingAdmin.address}`); await (0, processor_1.processTx)(env.c, pendingAdmin, [ instructions.initNewLUTIx, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Initialized new LUT and updated vault config'); // send the LUT mgmt ixs one by one const lutIxs = [...instructions.updateLUTIxs]; for (let i = 0; i < lutIxs.length; i++) { const lutIxsGroup = lutIxs.slice(i, i + 1); await (0, processor_1.processTx)(env.c, pendingAdmin, [ ...lutIxsGroup, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('LUT updated'); } }); commands .command('give-up-pending-fees') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--max-amount-to-give-up <string>', 'Max amount to give up') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, maxAmountToGiveUp, mode, staging, multisig }) => { const env = await (0, ManagerEnv_1.initEnv)(multisig, staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const instruction = await kaminoManager.giveUpPendingFeesIx(kaminoVault, new decimal_js_1.default(maxAmountToGiveUp), signer); await (0, processor_1.processTx)(env.c, signer, [ instruction, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Gave up pending fees'); }); commands .command('withdraw-pending-fees') .requiredOption('--vault <string>', 'Vault address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const instructions = await kaminoManager.withdrawPendingFeesIxs(kaminoVault, await env.c.rpc.getSlot({ commitment: 'confirmed' }).send(), signer); await (0, processor_1.processTx)(env.c, signer, [ ...instructions, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Pending fees withdrawn'); }); commands .command('remove-vault-allocation') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--reserve <string>', 'Reserve address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, reserve, mode, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const reserveAddress = (0, kit_1.address)(reserve); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const ixs = await kaminoManager.fullRemoveReserveFromVaultIxs(signer, kaminoVault, reserveAddress); const transactionIxs = [ ...ixs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 1_000_000, }), ]; const lookupTableAddresses = []; if (vaultState.vaultLookupTable !== lib_1.DEFAULT_PUBLIC_KEY) { lookupTableAddresses.push(vaultState.vaultLookupTable); } const lookupTables = await (0, address_lookup_table_1.fetchAllAddressLookupTable)(env.c.rpc, lookupTableAddresses); await (0, processor_1.processTx)(env.c, signer, transactionIxs, mode, lookupTables); mode === 'execute' && console.log('Vault allocation removed'); }); commands .command('stake') .requiredOption('--vault <string>', 'Vault address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ vault, mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(staging, ms); const user = await env.getSigner(); const vaultAddress = (0, kit_1.address)(vault); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const stakeIxs = await new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId).stakeSharesIxs(user, kaminoVault); await (0, processor_1.processTx)(env.c, user, [ ...stakeIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ], mode, []); mode === 'execute' && console.log('Staked into vault farm'); }); commands .command('update-vault-reserve-allocation') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--reserve <string>', 'Reserve address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option('--allocation-weight <number>', 'Allocation weight') .option('--allocation-cap <string>', 'Allocation cap decimal value') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .option(`--skip-lut-update`, 'If set, it will skip the LUT update') .action(async ({ vault, reserve, mode, allocationWeight, allocationCap, staging, multisig, skipLutUpdate }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(staging, ms); const reserveAddress = (0, kit_1.address)(reserve); const vaultAddress = (0, kit_1.address)(vault); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const signer = await env.getSigner({ vaultState }); const shouldUpdateLut = skipLutUpdate ? false : true; let allocationWeightValue; let allocationCapDecimal; const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const reserveState = await lib_1.Reserve.fetch(env.c.rpc, reserveAddress, env.klendProgramId); if (!reserveState) { throw new Error('Reserve not found'); } const existentAllocation = kaminoManager.getVaultAllocations(vaultState).get(reserveAddress); if (allocationWeight) { allocationWeightValue = Number(allocationWeight); } else if (existentAllocation) { allocationWeightValue = existentAllocation.targetWeight.toNumber(); } else { throw new Error('Allocation weight is required'); } if (allocationCap) { allocationCapDecimal = new decimal_js_1.default(allocationCap); } else if (existentAllocation) { allocationCapDecimal = existentAllocation.tokenAllocationCap.div(new decimal_js_1.default(10).pow(Number(vaultState.tokenMintDecimals.toString()))); } else { throw new Error('Allocation cap is required'); } console.log('allocationWeightValue', allocationWeightValue); console.log('allocationCapDecimal', allocationCapDecimal.toString()); const reserveWithAddress = { address: reserveAddress, state: reserveState, }; const firstReserveAllocationConfig = new lib_1.ReserveAllocationConfig(reserveWithAddress, allocationWeightValue, allocationCapDecimal); const instructions = await kaminoManager.updateVaultReserveAllocationIxs(kaminoVault, firstReserveAllocationConfig, signer); const txInstructions = [ instructions.updateReserveAllocationIx, ...instructions.updateLUTIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, }), ]; if (shouldUpdateLut) { txInstructions.push(...instructions.updateLUTIxs); } await (0, processor_1.processTx)(env.c, signer, txInstructions, mode, []); mode === 'execute' && console.log('Vault allocation updated'); }); commands .command('deposit') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--amount <number>', 'Token amount to deposit, in decimals') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ vault, amount, mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const env = await (0, ManagerEnv_1.initEnv)(staging, multisig); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const payer = await env.getSigner(); const depositInstructions = await kaminoManager.depositToVaultIxs(payer, kaminoVault, amount); const instructions = [...depositInstructions.depositIxs, ...depositInstructions.stakeInFarmIfNeededIxs]; await (0, processor_1.processTx)(env.c, payer, [ ...instructions, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 800_000, }), ], mode, []); mode === 'execute' && console.log('User deposited'); }); commands .command('withdraw') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--amount <number>', 'Shares amount to withdraw') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ vault, amount, mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const env = await (0, ManagerEnv_1.initEnv)(multisig, staging); const signer = await env.getSigner(); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const vaultState = await kaminoVault.getState(); const lookupTableAddresses = []; if (vaultState.vaultLookupTable !== lib_1.DEFAULT_PUBLIC_KEY) { lookupTableAddresses.push(vaultState.vaultLookupTable); } const lookupTables = await (0, address_lookup_table_1.fetchAllAddressLookupTable)(env.c.rpc, lookupTableAddresses); const withdrawIxs = await kaminoManager.withdrawFromVaultIxs(signer, kaminoVault, new decimal_js_1.default(amount), await env.c.rpc.getSlot({ commitment: 'confirmed' }).send()); await (0, processor_1.processTx)(env.c, signer, [ ...withdrawIxs.unstakeFromFarmIfNeededIxs, ...withdrawIxs.withdrawIxs, ...withdrawIxs.postWithdrawIxs, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 800_000, }), ], mode, lookupTables); mode === 'execute' && console.log('User withdrew'); }); commands .command('invest-all-reserves') .requiredOption('--vault <string>', 'Vault address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ vault, mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(staging, ms); const payer = await env.getSigner(); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const instructions = await kaminoManager.investAllReservesIxs(payer, kaminoVault); for (let i = 0; i < instructions.length; i++) { const txInstructions = []; txInstructions.push(); await (0, processor_1.processTx)(env.c, payer, [ instructions[i], ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 800_000, }), ], mode, []); mode === 'execute' && console.log('Reserves invested'); } }); commands .command('invest-single-reserve') .requiredOption('--vault <string>', 'Vault address') .requiredOption('--reserve <string>', 'Reserve address') .requiredOption(`--mode <string>`, 'simulate|multisig|execute - simulate - to print txn simulation and to get tx simulation link in explorer, execute - execute tx, multisig - to get bs58 tx for multisig usage') .option(`--staging`, 'If true, will use the staging programs') .option(`--multisig <string>`, 'If using multisig mode this is required, otherwise will be ignored') .action(async ({ vault, reserve, mode, staging, multisig }) => { if (mode === 'multisig' && !multisig) { throw new Error('If using multisig mode, multisig is required'); } const ms = multisig ? (0, kit_1.address)(multisig) : undefined; const env = await (0, ManagerEnv_1.initEnv)(staging, ms); const vaultAddress = (0, kit_1.address)(vault); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.klendProgramId, env.kvaultProgramId); const kaminoVault = new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId); const reserveAddress = (0, kit_1.address)(reserve); const reserveState = await lib_1.Reserve.fetch(env.c.rpc, reserveAddress, env.klendProgramId); if (!reserveState) { throw new Error('Reserve not found'); } const reserveWithAddress = { address: reserveAddress, state: reserveState, }; const payer = await env.getSigner(); const instructions = await kaminoManager.investSingleReserveIxs(payer, kaminoVault, reserveWithAddress); await (0, processor_1.processTx)(env.c, payer, [ ...instructions, ...(0, priorityFee_1.getPriorityFeeAndCuIxs)({ priorityFeeMultiplier: 2500, computeUnits: 800_000, }), ], mode, []); mode === 'execute' && console.log(`Reserve ${reserveAddress} invested`); }); // commands // .command('close-vault') // .requiredOption('--vault <string>', 'Vault address') // .option(`--staging`, 'If true, will use the staging programs') // .action(async ({vault, staging}) => { // const env = await initEnv(false, staging); // const vaultAddress = address(vault); // const kaminoManager = new KaminoManager(env.connection, env.klendProgramId, env.kvaultProgramId); // const kaminoVault = new KaminoVault(vaultAddress, undefined, env.kvaultProgramId); // const instructions = await kaminoManager.closeVault(kaminoVault); // const closeVaultSig = await processTxn(env.client, env.payer, [instructions], 'execute', 2500, []); // console.log('Vault closed:', closeVaultSig); // }); commands .command('get-vault-colls') .requiredOption('--vault <string>', 'Vault address') .option(`--staging`, 'If true, will use the staging programs') .action(async ({ vault, staging }) => { const env = await (0, ManagerEnv_1.initEnv)(staging); const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)(); const kaminoManager = new lib_1.KaminoManager(env.c.rpc, slotDuration, env.klendProgramId, env.kvaultProgramId); const vaultAddress = (0, kit_1.address)(vault); const vaultState = await new lib_1.KaminoVault(env.c.rpc, vaultAddress, undefined, env.kvaultProgramId).getState(); const vaultCollaterals = await kaminoManager.getVaultCollaterals(vaultState, await env.c.rpc.getSlot({ commitment: 'confirmed' }).send()); vaultCollaterals.forEach((collateral) => { console.log('reserve ', collateral.address); console.log('market overview', collateral.reservesAsCollateral); console.log('min LTV', collateral.minLTVPct); console.log('max LTV',