Skip to content

Instantly share code, notes, and snippets.

@codewithgun
Last active August 1, 2025 16:09
Show Gist options
  • Save codewithgun/ff6c201af1e9e9b86f1d4987981359f8 to your computer and use it in GitHub Desktop.
Save codewithgun/ff6c201af1e9e9b86f1d4987981359f8 to your computer and use it in GitHub Desktop.
Fetch meteora vault details
import VaultImpl from "@meteora-ag/vault-sdk";
import { Mint, unpackMint } from "@solana/spl-token";
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
const keeperBaseUrl = "https://merv2-api.meteora.ag";
const lendingProgramIdsToName = new Map<string, string>([
["MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA", "MarginFi"],
["So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo", "Solend"],
["KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD", "Kamino"],
]);
async function getVaultApy(tokenMint: PublicKey): Promise<number> {
const response = await fetch(
`${keeperBaseUrl}/vault_state/${tokenMint.toBase58()}`
);
return response
.json()
.then((data) => Math.ceil(Number(data.closest_apy) * 100) / 100);
}
async function showVaultDetails() {
const mintAddresses = [
new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"),
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
new PublicKey("So11111111111111111111111111111111111111112"),
];
const mintAccounts = await connection.getMultipleAccountsInfo(mintAddresses);
const mintMap = new Map<string, Mint>();
for (let i = 0; i < mintAddresses.length; i++) {
const mintAddress = mintAddresses[i];
const mintAccount = mintAccounts[i];
const mintState = unpackMint(mintAddress, mintAccount);
mintMap.set(mintAddress.toBase58(), mintState);
}
const vaults = await VaultImpl.createMultiple(connection, mintAddresses);
for (const vault of vaults) {
const mintState = mintMap.get(vault.vaultState.tokenMint.toBase58());
console.log(`Vault for mint ${vault.vaultState.tokenMint.toBase58()}`);
console.log(`Vault address: ${vault.vaultPda.toBase58()}`);
// Total amount in vault
const totalAmount = Number(vault.vaultState.totalAmount.toString());
const vaultTotalUiAmount = totalAmount / 10 ** mintState.decimals;
console.log(`Total amount in vault: ${vaultTotalUiAmount}`);
const lpMintSupply = Number(vault.tokenLpMint.supply.toString());
const virtualPrice = totalAmount / lpMintSupply;
// Vault LP to token amount exchange rate
console.log(`Virtual Price: ${virtualPrice}`);
// This is the current max withdrawable amount from the vault after deduct locked to drip profits + token allocated to strategies
const withdrawableAmount = await vault.getWithdrawableAmount();
const withdrawableUiAmount = withdrawableAmount / 10 ** mintState.decimals;
console.log(`Withdrawable amount: ${withdrawableUiAmount}`);
// The only way to get the current APY is to fetch it from the keeper API
const apy = await getVaultApy(vault.vaultState.tokenMint);
console.log(`APY: ${apy}%`);
// Lending that the vault deposited to. This retrieve the info from onchain. User can get it from API https://merv2-api.meteora.ag/vault_state as well.
const strategyAddresses = vault.vaultState.strategies.filter(
(s) => !s.equals(PublicKey.default)
);
const strategyAccounts = await connection.getMultipleAccountsInfo(
strategyAddresses
);
const strategyReserveLiquidityMap = new Map<string, number>();
for (const strategy of strategyAccounts) {
// TODO: Fix the SDK
const reserveBytes = strategy.data.slice(8, 8 + 32);
const reserveAddress = new PublicKey(reserveBytes);
const liquidity = strategy.data.readBigInt64LE(8 + 32 + 32 + 1);
const liquidityAmount =
Number(liquidity.toString()) / 10 ** mintState.decimals;
strategyReserveLiquidityMap.set(
reserveAddress.toBase58(),
liquidityAmount
);
}
const reserveAddresses = Array.from(strategyReserveLiquidityMap.keys());
const reserveAccounts = await connection.getMultipleAccountsInfo(
reserveAddresses.map((addr) => new PublicKey(addr))
);
for (let i = 0; i < reserveAddresses.length; i++) {
const reserveAddress = reserveAddresses[i];
const reserveAccount = reserveAccounts[i];
console.log(`Reserve: ${reserveAddress}`);
console.log(
`Liquidity: ${strategyReserveLiquidityMap.get(reserveAddress)}`
);
console.log(
`Lending Program: ${
lendingProgramIdsToName.get(reserveAccount.owner.toBase58()) ||
"Unknown"
}`
);
}
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
}
}
showVaultDetails().catch((error) => {
console.error("Error fetching vault details:", error);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment