Last active
August 1, 2025 16:09
-
-
Save codewithgun/ff6c201af1e9e9b86f1d4987981359f8 to your computer and use it in GitHub Desktop.
Fetch meteora vault details
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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