@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
830 lines • 91.4 kB
JavaScript
"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',