@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
710 lines • 79.3 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 });
exports.parseKeypairFile = parseKeypairFile;
const dotenv_1 = __importDefault(require("dotenv"));
const commander_1 = require("commander");
const web3_js_1 = require("@solana/web3.js");
const lib_1 = require("./lib");
const anchor = __importStar(require("@coral-xyz/anchor"));
const base58_js_1 = require("base58-js");
const types_1 = require("./idl_codegen/types");
const fraction_1 = require("./classes/fraction");
const decimal_js_1 = __importDefault(require("decimal.js"));
const anchor_1 = require("@coral-xyz/anchor");
const types_2 = require("./idl_codegen_kamino_vault/types");
const fs = __importStar(require("fs"));
const VaultConfigField_1 = require("./idl_codegen_kamino_vault/types/VaultConfigField");
const rpc_1 = require("./utils/rpc");
const spl_token_1 = require("@solana/spl-token");
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 - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig pubkey is required');
}
const multisigPk = multisig ? new web3_js_1.PublicKey(multisig) : web3_js_1.PublicKey.default;
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const { market: marketKp, ixs: createMarketIxs } = await kaminoManager.createMarketIxs({
admin: mode === 'multisig' ? multisigPk : env.payer.publicKey,
});
await processTxn(env.client, env.payer, createMarketIxs, mode, 2500, [marketKp]);
mode === 'execute' && console.log('Market created:', marketKp.publicKey.toBase58());
});
commands
.command('add-asset-to-market')
.requiredOption('--market <string>', 'Market address to add asset to')
.requiredOption('--mint <string>', 'Reserve liquidity token mint')
.requiredOption('--mint-program-id <string>', 'Reserve liquidity token mint program id')
.requiredOption('--reserve-config-path <string>', 'Path for the reserve config')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 ({ market, mint, mintProgramId, reserveConfigPath, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const tokenMint = new web3_js_1.PublicKey(mint);
const tokenMintProgramId = new web3_js_1.PublicKey(mintProgramId);
const marketAddress = new web3_js_1.PublicKey(market);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const multisigPk = multisig ? new web3_js_1.PublicKey(multisig) : web3_js_1.PublicKey.default;
const kaminoManager = new lib_1.KaminoManager(env.connection, 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 = mode === 'multisig'
? (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, multisigPk)
: (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, env.payer.publicKey);
const { reserve, txnIxs } = await kaminoManager.addAssetToMarketIxs({
admin: mode === 'multisig' ? multisigPk : env.payer.publicKey,
adminLiquiditySource: adminAta,
marketAddress: marketAddress,
assetConfig: assetConfig,
});
console.log('reserve: ', reserve.publicKey);
const _createReserveSig = await processTxn(env.client, env.payer, txnIxs[0], mode, 2500, [reserve]);
const [lut, createLutIxs] = await createUpdateReserveConfigLutIxs(env, marketAddress, reserve.publicKey);
await processTxn(env.client, env.payer, createLutIxs, mode, 2500, []);
const _updateSig = await processTxn(env.client, env.payer, txnIxs[1], mode, 2500, [], 400_000, 1000, [lut]);
mode === 'execute' &&
console.log('Reserve Created with config:', JSON.parse(JSON.stringify(reserveConfig)), '\nreserve address:', reserve.publicKey.toBase58());
});
commands
.command('update-reserve-config')
.requiredOption('--reserve <string>', 'Reserve address')
.requiredOption('--reserve-config-path <string>', 'Path for the reserve config')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const reserveAddress = new web3_js_1.PublicKey(reserve);
const reserveState = await lib_1.Reserve.fetch(env.connection, reserveAddress, env.kLendProgramId);
if (!reserveState) {
throw new Error('Reserve not found');
}
const marketAddress = reserveState.lendingMarket;
const marketState = await lib_1.LendingMarket.fetch(env.connection, marketAddress, env.kLendProgramId);
if (!marketState) {
throw new Error('Market not found');
}
const marketWithAddress = {
address: marketAddress,
state: marketState,
};
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, 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(marketWithAddress, reserveAddress, reserveConfig, reserveState, updateEntireConfig);
const _updateReserveSig = await processTxn(env.client, env.payer, ixs, mode, 2500, [], 400_000);
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 = initializeClient(false, staging);
const reserveAddress = new web3_js_1.PublicKey(reserve);
const reserveState = await lib_1.Reserve.fetch(env.connection, reserveAddress, env.kLendProgramId);
if (!reserveState) {
throw new Error('Reserve not found');
}
fs.mkdirSync('./configs/' + reserveState.lendingMarket.toBase58(), { 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.toBase58() + '/' + reserveName + '.json', JSON.stringify(reserveConfigDisplay, null, 2));
});
commands
.command('create-vault')
.requiredOption('--mint <string>', 'Vault token mint')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const tokenMint = new web3_js_1.PublicKey(mint);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const multisigPk = multisig ? new web3_js_1.PublicKey(multisig) : web3_js_1.PublicKey.default;
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const tokenProgramID = await (0, rpc_1.getAccountOwner)(env.connection, tokenMint);
const kaminoVaultConfig = new lib_1.KaminoVaultConfig({
admin: mode === 'multisig' ? multisigPk : env.payer.publicKey,
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);
const _createVaultSig = await processTxn(env.client, env.payer, [...instructions.createAtaIfNeededIxs, ...instructions.initVaultIxs, instructions.createLUTIx], mode, 2500, [vaultKp]);
await (0, lib_1.sleep)(2000);
const _populateLUTSig = await processTxn(env.client, env.payer, [...instructions.populateLUTIxs, ...instructions.cleanupIxs], mode, 2500, []);
const _setSharesMetadataSig = await processTxn(env.client, env.payer, [instructions.initSharesMetadataIx], mode, 2500, []);
mode === 'execute' && console.log('Vault created:', vaultKp.publicKey.toBase58());
});
commands
.command('set-shares-metadata')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--symbol <string>', 'The symbol of the kVault token')
.requiredOption('--extraName <string>', 'The name of the kVault token, appended to the symbol')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn for multisig usage')
.action(async ({ vault, symbol, extraName, mode }) => {
const env = initializeClient(false, false);
const kVault = new lib_1.KaminoVault(new web3_js_1.PublicKey(vault));
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const ix = await kaminoManager.getSetSharesMetadataIx(kVault, symbol, extraName);
await processTxn(env.client, env.payer, [ix], mode, 2500, []);
});
commands
.command('update-vault-pending-admin')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--new-admin <string>', 'Pubkey of the new admin')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, newAdmin, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.PendingVaultAdmin(), newAdmin);
const updateVaultPendingAdminSig = await processTxn(env.client, env.payer, [instructions.updateVaultConfigIx, ...instructions.updateLUTIxs], mode, 2500, []);
mode === 'execute' && console.log('Pending admin updated:', updateVaultPendingAdminSig);
});
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 - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, field, value, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, field, value);
const updateVaultPendingAdminSig = await processTxn(env.client, env.payer, [instructions.updateVaultConfigIx, ...instructions.updateLUTIxs], mode, 2500, []);
mode === 'execute' && console.log('Vault updated:', updateVaultPendingAdminSig);
});
commands
.command('update-vault-mgmt-fee')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--fee-bps <string>', 'Pubkey of the new admin')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, feeBps, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.ManagementFeeBps(), feeBps);
const updateVaultConfigSig = await processTxn(env.client, env.payer, [instructions.updateVaultConfigIx, ...instructions.updateLUTIxs], mode, 2500, []);
mode === 'execute' && console.log('Management fee updated:', updateVaultConfigSig);
});
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 - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 ({ lut, addresses, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const lutAddress = new web3_js_1.PublicKey(lut);
const addressesArr = addresses.split(' ').map((address) => new web3_js_1.PublicKey(address));
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const instructions = await kaminoManager.insertIntoLUTIxs(env.payer.publicKey, lutAddress, addressesArr);
const updateVaultConfigSig = await processTxn(env.client, env.payer, instructions, mode, 2500, []);
mode === 'execute' && console.log('Management fee updated:', updateVaultConfigSig);
});
commands.command('create-lut').action(async () => {
const env = initializeClient(false, false);
const initLutIx = (0, lib_1.initLookupTableIx)(env.payer.publicKey, await env.connection.getSlot());
const updateVaultConfigSig = await processTxn(env.client, env.payer, [initLutIx[0]], 'execute', 2500, []);
console.log(`LUT created: ${initLutIx[1].toString()} tx id: ${updateVaultConfigSig}`);
});
commands
.command('sync-vault-lut')
.requiredOption('--vault <string>', 'The vault address to sync')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const syncLUTIxs = await kaminoManager.syncVaultLUTIxs(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) {
const setupLUTSig = await processTxn(env.client, env.payer, syncLUTIxs.setupLUTIfNeededIxs, mode, 2500, []);
await (0, lib_1.sleep)(2000);
mode === 'execute' && console.log('LUT created and set to the vault:', setupLUTSig);
}
// 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) {
const insertIntoLUTSig = await processTxn(env.client, env.payer, [ix], mode, 2500, []);
mode === 'execute' && console.log('Accounts added to the LUT:', insertIntoLUTSig);
}
});
commands
.command('update-vault-perf-fee')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--fee-bps <string>', 'Pubkey of the new admin')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, feeBps, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.updateVaultConfigIxs(kaminoVault, new VaultConfigField_1.PerformanceFeeBps(), feeBps);
const updateVaultPerfFeeSig = await processTxn(env.client, env.payer, [instructions.updateVaultConfigIx, ...instructions.updateLUTIxs], mode, 2500, []);
mode === 'execute' && console.log('Performance fee updated:', updateVaultPerfFeeSig);
});
commands
.command('accept-vault-ownership')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.acceptVaultOwnershipIxs(kaminoVault);
const acceptVaultOwnershipSig = await processTxn(env.client, env.payer, [instructions.acceptVaultOwnershipIx], mode, 2500, []);
mode === 'execute' && console.log('Vault ownership accepted:', acceptVaultOwnershipSig);
// 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);
const lutIxsSig = await processTxn(env.client, env.payer, lutIxsGroup, mode, 2500, []);
mode === 'execute' && console.log('LUT updated:', lutIxsSig);
}
});
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 - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, maxAmountToGiveUp, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instruction = await kaminoManager.giveUpPendingFeesIx(kaminoVault, new decimal_js_1.default(maxAmountToGiveUp));
const giveUpPendingFeesSig = await processTxn(env.client, env.payer, [instruction], mode, 2500, []);
mode === 'execute' && console.log('Give up pending fees tx:', giveUpPendingFeesSig);
});
commands
.command('withdraw-pending-fees')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.withdrawPendingFeesIxs(kaminoVault, await env.connection.getSlot('confirmed'));
const withdrawPendingFeesSig = await processTxn(env.client, env.payer, instructions, mode, 2500, []);
mode === 'execute' && console.log('Pending fees withdrawn:', withdrawPendingFeesSig);
});
commands
.command('remove-vault-allocation')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--reserve <string>', 'Reserve address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const reserveAddress = new web3_js_1.PublicKey(reserve);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instruction = await kaminoManager.removeReserveFromAllocationIx(kaminoVault, reserveAddress);
if (instruction) {
const updateVaultAllocationSig = await processTxn(env.client, env.payer, [instruction], mode, 2500, []);
mode === 'execute' && console.log('Vault allocation updated:', updateVaultAllocationSig);
}
});
commands
.command('stake')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const stakeIxs = await new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId).stakeSharesIxs(env.payer.publicKey, kaminoVault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const withdrawPendingFeesSig = await processTxn(env.client, env.payer, stakeIxs, mode, 2500, []);
mode === 'execute' && console.log('Stake into vault farm:', withdrawPendingFeesSig);
});
commands
.command('update-vault-reserve-allocation')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--reserve <string>', 'Reserve address')
.requiredOption('--allocation-weight <number>', 'Allocation weight')
.requiredOption('--allocation-cap <string>', 'Allocation cap decimal value')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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, allocationWeight, allocationCap, mode, staging, multisig }) => {
const env = initializeClient(mode === 'multisig', staging);
const reserveAddress = new web3_js_1.PublicKey(reserve);
const vaultAddress = new web3_js_1.PublicKey(vault);
const allocationWeightValue = Number(allocationWeight);
const allocationCapDecimal = new decimal_js_1.default(allocationCap);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const reserveState = await lib_1.Reserve.fetch(env.connection, reserveAddress, env.kLendProgramId);
if (!reserveState) {
throw new Error('Reserve not found');
}
const reserveWithAddress = {
address: reserveAddress,
state: reserveState,
};
const firstReserveAllocationConfig = new lib_1.ReserveAllocationConfig(reserveWithAddress, allocationWeightValue, allocationCapDecimal);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.updateVaultReserveAllocationIxs(kaminoVault, firstReserveAllocationConfig);
const updateVaultAllocationSig = await processTxn(env.client, env.payer, [instructions.updateReserveAllocationIx, ...instructions.updateLUTIxs], mode, 2500, []);
mode === 'execute' && console.log('Vault allocation updated:', updateVaultAllocationSig);
});
commands
.command('deposit')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--amount <number>', 'Token amount to deposit, in decimals')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const depositInstructions = await kaminoManager.depositToVaultIxs(env.payer.publicKey, kaminoVault, amount);
const instructions = [...depositInstructions.depositIxs, ...depositInstructions.stakeInFarmIfNeededIxs];
const depositSig = await processTxn(env.client, env.payer, instructions, mode, 2500, [], 800_000);
mode === 'execute' && console.log('User deposit:', depositSig);
});
commands
.command('withdraw')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--amount <number>', 'Shares amount to withdraw')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const withdrawIxs = await kaminoManager.withdrawFromVaultIxs(env.payer.publicKey, kaminoVault, new decimal_js_1.default(amount), await env.connection.getSlot('confirmed'));
const withdrawSig = await processTxn(env.client, env.payer, [...withdrawIxs.unstakeFromFarmIfNeededIxs, ...withdrawIxs.withdrawIxs, ...withdrawIxs.postWithdrawIxs], mode, 2500, [], 800_000);
mode === 'execute' && console.log('User withdraw:', withdrawSig);
});
commands
.command('invest-all-reserves')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const instructions = await kaminoManager.investAllReservesIxs(env.payer.publicKey, kaminoVault);
for (let i = 0; i < instructions.length; i++) {
const txInstructions = [];
txInstructions.push(instructions[i]);
const investReserveSig = await processTxn(env.client, env.payer, txInstructions, mode, 2500, [], 800000);
mode === 'execute' && console.log('Reserve invested:', investReserveSig);
}
});
commands
.command('invest-single-reserve')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--reserve <string>', 'Reserve address')
.requiredOption(`--mode <string>`, 'simulate - to print txn simulation, inspect - to get txn simulation in explorer, execute - execute txn, multisig - to get bs58 txn 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 }) => {
const env = initializeClient(mode === 'multisig', staging);
const vaultAddress = new web3_js_1.PublicKey(vault);
if (mode === 'multisig' && !multisig) {
throw new Error('If using multisig mode, multisig is required');
}
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const reserveState = await lib_1.Reserve.fetch(env.connection, new web3_js_1.PublicKey(reserve), env.kLendProgramId);
if (!reserveState) {
throw new Error('Reserve not found');
}
const reserveWithAddress = {
address: new web3_js_1.PublicKey(reserve),
state: reserveState,
};
const instructions = await kaminoManager.investSingleReserveIxs(env.payer.publicKey, kaminoVault, reserveWithAddress);
const investReserveSig = await processTxn(env.client, env.payer, instructions, mode, 2500, [], 800_000);
mode === 'execute' && console.log('Reserve invested:', investReserveSig);
});
// commands
// .command('close-vault')
// .requiredOption('--vault <string>', 'Vault address')
// .option(`--staging`, 'If true, will use the staging programs')
// .action(async ({vault, staging}) => {
// const env = initializeClient(false, staging);
// const vaultAddress = new PublicKey(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')
.action(async ({ vault }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const vaultState = await new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId).getState(env.connection);
const vaultCollaterals = await kaminoManager.getVaultCollaterals(vaultState, await env.connection.getSlot('confirmed'));
vaultCollaterals.forEach((collateral) => {
console.log('reserve ', collateral.address);
console.log('market overview', collateral.reservesAsCollateral);
console.log('min LTV', collateral.minLTVPct);
console.log('max LTV', collateral.maxLTVPct);
});
});
commands
.command('get-vault-overview')
.requiredOption('--vault <string>', 'Vault address')
.action(async ({ vault }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const vaultState = await new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId).getState(env.connection);
const vaultOverview = await kaminoManager.getVaultOverview(vaultState, new decimal_js_1.default(1.0), await env.connection.getSlot('confirmed'));
console.log('vaultOverview', vaultOverview);
});
commands
.command('get-vault-allocation-distribution')
.requiredOption('--vault <string>', 'Vault address')
.action(async ({ vault }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const vaultState = await new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId).getState(env.connection);
const allocationDistribution = kaminoManager.getAllocationsDistribuionPct(vaultState);
allocationDistribution.forEach((allocation, reserveAddress) => {
console.log('reserve ', reserveAddress);
console.log('allocation', allocation);
});
});
commands
.command('get-user-shares-for-vault')
.requiredOption('--vault <string>', 'Vault address')
.requiredOption('--wallet <string>', 'User wailt address')
.action(async ({ vault, wallet }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const walletAddress = new web3_js_1.PublicKey(wallet);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const userShares = await kaminoManager.getUserSharesBalanceSingleVault(walletAddress, kaminoVault);
console.log(`User shares for vault ${vaultAddress.toBase58()}: unstaked shares: ${userShares.unstakedShares} staked shares: ${userShares.stakedShares} total shares: ${userShares.totalShares}`);
});
commands
.command('get-user-shares-all-vaults')
.requiredOption('--wallet <string>', 'User wailt address')
.action(async ({ wallet }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const walletAddress = new web3_js_1.PublicKey(wallet);
const userShares = await kaminoManager.getUserSharesBalanceAllVaults(walletAddress);
userShares.forEach((userShares, vaultAddress) => {
console.log(`User shares for vault ${vaultAddress}: staked shares ${userShares.stakedShares} unstaked shares ${userShares.unstakedShares} total shares ${userShares.totalShares}`);
});
});
commands
.command('get-tokens-per-share')
.requiredOption('--vault <string>', 'Vault address')
.action(async ({ vault }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
const tokensPerShare = await kaminoManager.getTokensPerShareSingleVault(kaminoVault, await env.connection.getSlot('confirmed'));
console.log(`Tokens per share for vault ${vaultAddress.toBase58()}: ${tokensPerShare}`);
});
commands
.command('print-vault')
.requiredOption('--vault <string>', 'Vault address')
.action(async ({ vault }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const vaultAddress = new web3_js_1.PublicKey(vault);
const kaminoVault = new lib_1.KaminoVault(vaultAddress, undefined, env.kVaultProgramId);
await kaminoVault.getState(env.connection);
const slot = await env.connection.getSlot('confirmed');
const tokensPerShare = await kaminoManager.getTokensPerShareSingleVault(kaminoVault, slot);
const holdings = await kaminoManager.getVaultHoldings(kaminoVault.state, slot);
const vaultState = kaminoVault.state;
const sharesIssued = (0, lib_1.lamportsToDecimal)(vaultState.sharesIssued.toString(), vaultState.sharesMintDecimals.toString());
const vaultOverview = await kaminoManager.getVaultOverview(vaultState, new decimal_js_1.default(1.0), slot);
console.log('farm', vaultState.vaultFarm.toString());
console.log('vault token mint', vaultState.tokenMint.toBase58());
console.log('Name: ', kaminoManager.getDecodedVaultName(kaminoVault.state));
console.log('Shares issued: ', sharesIssued);
(0, lib_1.printHoldings)(holdings);
console.log(`Tokens per share for vault ${vaultAddress.toBase58()}: ${tokensPerShare}`);
console.log('vaultOverview', vaultOverview);
for (const [reserveAddress, reserveOverview] of vaultOverview.reservesOverview) {
console.log(`reserve ${reserveAddress.toBase58()} supplyAPY ${reserveOverview.supplyAPY}`);
}
});
commands.command('get-oracle-mappings').action(async () => {
const env = initializeClient(false, false);
const kaminoManager = new lib_1.KaminoManager(env.connection, lib_1.DEFAULT_RECENT_SLOT_DURATION_MS, env.kLendProgramId, env.kVaultProgramId);
console.log('Getting oracle mappings');
const oracleConfigs = await kaminoManager.getScopeOracleConfigs();
console.log('oracleConfigs', JSON.parse(JSON.stringify(oracleConfigs)));
});
commands.command('get-all-vaults').action(async () => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new lib_1.KaminoManager(env.connection, slotDuration, env.kLendProgramId, env.kVaultProgramId);
const allVaults = await kaminoManager.getAllVaults();
console.log('all vaults', allVaults);
});
commands
.command('get-all-vaults-for-token')
.requiredOption('--token <string>', 'Token address')
.action(async ({ token }) => {
const env = initializeClient(false, false);
const slotDuration = await (0, lib_1.getMedianSlotDurationInMsFromLastEpochs)();
const kaminoManager = new