Skip to content

Commit

Permalink
add calculate apr
Browse files Browse the repository at this point in the history
  • Loading branch information
rudy5348 committed Nov 15, 2023
1 parent d02b9f5 commit 40d3af2
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/calculateClmmApr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ApiClmmPoolsItem, MathUtil, PoolInfoLayout } from "@raydium-io/raydium-sdk"
import { ParsedAccountData, PublicKey } from "@solana/web3.js"
import Decimal from "decimal.js"
import { ENDPOINT, RAYDIUM_MAINNET_API, connection } from "../config"


async function calculateClmmApr() {
const poolId = ''

const poolAccountInfo = await connection.getAccountInfo(new PublicKey(poolId))

if (poolAccountInfo === null) throw Error('get pool account data error')

const mintPrice: { [mint: string]: number } = {}
for (const [mint, price] of Object.entries(await (await fetch(ENDPOINT + RAYDIUM_MAINNET_API.price)).json()) as [string, number][]) mintPrice[mint] = price

const poolApiInfo: { [poolId: string]: ApiClmmPoolsItem } = {}
for (const item of (await (await fetch(ENDPOINT + RAYDIUM_MAINNET_API.clmmPools)).json()).data) poolApiInfo[item.id] = item

const apiPoolInfo = poolApiInfo[poolId]
if (apiPoolInfo === undefined) throw Error('api pool info check error')

const poolInfo = PoolInfoLayout.decode(poolAccountInfo.data)

const chainTime = await connection.getBlockTime(await connection.getSlot())
if (chainTime === null) throw Error('get chain time error')

const formatRewardInfo: {
mint: string,
price: number,
sendCountYear: number,
sendCountYearToU: number,
tvl: number,
apr: number,
}[] = []

for (const rewardInfo of poolInfo.rewardInfos) {
if (rewardInfo.tokenMint.equals(PublicKey.default)) continue

const rewardVaultAdress = rewardInfo.tokenVault
const rewardVaultAccount = await connection.getParsedAccountInfo(rewardVaultAdress)
const rewardVaultAccountData = rewardVaultAccount.value?.data as ParsedAccountData
if (rewardVaultAccountData.program !== 'spl-token') continue

const rewardPerSecond = (rewardInfo.openTime.toNumber() < chainTime && rewardInfo.endTime.toNumber() > chainTime) ? MathUtil.x64ToDecimal(rewardInfo.emissionsPerSecondX64) : new Decimal(0)

const sendCountYear = new Decimal(rewardPerSecond.mul(3600 * 24 * 365).toString()).div(10 ** rewardVaultAccountData.parsed.info.tokenAmount.decimals)
const sendCountYearToU = sendCountYear.mul(mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0)

const tvl = apiPoolInfo.tvl

formatRewardInfo.push({
mint: rewardVaultAccountData.parsed.info.mint,
price: mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0,
sendCountYear: sendCountYear.toNumber(),
sendCountYearToU: sendCountYearToU.toNumber(),
tvl,
apr: tvl !== 0 ? sendCountYearToU.div(tvl).toNumber() : 0,
})
}

console.log(formatRewardInfo)
}

calculateClmmApr()
94 changes: 94 additions & 0 deletions src/calculateFarmApr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { FARM_STATE_LAYOUT_V3, FARM_STATE_LAYOUT_V5, FARM_STATE_LAYOUT_V6 } from "@raydium-io/raydium-sdk"
import { ParsedAccountData, PublicKey } from "@solana/web3.js"
import { BN } from "bn.js"
import Decimal from "decimal.js"
import { ENDPOINT, PROGRAMIDS, RAYDIUM_MAINNET_API, connection } from "../config"


async function calculateFarmApr() {
const poolId = ''

const poolAccountInfo = await connection.getAccountInfo(new PublicKey(poolId))

if (poolAccountInfo === null) throw Error('get pool account data error')

const mintPrice: { [mint: string]: number } = {}
for (const [mint, price] of Object.entries(await (await fetch(ENDPOINT + RAYDIUM_MAINNET_API.price)).json()) as [string, number][]) mintPrice[mint] = price

const poolTvl: { [poolId: string]: number } = {}
for (const info of (await (await fetch(ENDPOINT + RAYDIUM_MAINNET_API.farmApr)).json()).data) poolTvl[info.id] = info.tvl

const rewardInfo: { mint: string, price: number, sendCountYear: number, sendCountYearToU: number, tvl: number, apr: number }[] = []

switch (poolAccountInfo.owner.toString()) {
case PROGRAMIDS.FarmV3.toString():
case PROGRAMIDS.FarmV5.toString(): {
const layout = PROGRAMIDS.FarmV3.toString() === poolAccountInfo.owner.toString() ? FARM_STATE_LAYOUT_V3 : FARM_STATE_LAYOUT_V5
const poolInfo = layout.decode(poolAccountInfo.data)

const poolVaultAccount = await connection.getParsedAccountInfo(poolInfo.lpVault)
const poolVaultAccountData = poolVaultAccount.value?.data as ParsedAccountData
if (poolVaultAccountData.program !== 'spl-token') break

for (const itemRewardInfo of poolInfo.rewardInfos) {
const rewardVaultAdress = itemRewardInfo.rewardVault
const rewardVaultAccount = await connection.getParsedAccountInfo(rewardVaultAdress)
const rewardVaultAccountData = rewardVaultAccount.value?.data as ParsedAccountData
if (rewardVaultAccountData.program !== 'spl-token') continue

const sendCountYear = new Decimal(itemRewardInfo.perSlotReward.mul(new BN(2.5 * 3600 * 24 * 365)).toString()).div(10 ** rewardVaultAccountData.parsed.info.tokenAmount.decimals) // one slot -> 400ms
const sendCountYearToU = sendCountYear.mul(mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0)

const tvl = poolTvl[poolId] !== undefined ? poolTvl[poolId] : poolVaultAccountData.parsed.info.tokenAmount.uiAmount * (mintPrice[poolVaultAccountData.parsed.info.mint] ?? 0)

rewardInfo.push({
mint: rewardVaultAccountData.parsed.info.mint,
price: mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0,
sendCountYear: sendCountYear.toNumber(),
sendCountYearToU: sendCountYearToU.toNumber(),
tvl,
apr: tvl !== 0 ? sendCountYearToU.div(tvl).toNumber() : 0,
})
}
break
}
case PROGRAMIDS.FarmV6.toString(): {
const layout = FARM_STATE_LAYOUT_V6
const poolInfo = layout.decode(poolAccountInfo.data)

const chainTime = await connection.getBlockTime(await connection.getSlot())
if (chainTime === null) throw Error('get chain time error')

const poolVaultAccount = await connection.getParsedAccountInfo(poolInfo.lpVault)
const poolVaultAccountData = poolVaultAccount.value?.data as ParsedAccountData
if (poolVaultAccountData.program !== 'spl-token') break

for (const itemRewardInfo of poolInfo.rewardInfos) {
const rewardVaultAdress = itemRewardInfo.rewardVault
const rewardVaultAccount = await connection.getParsedAccountInfo(rewardVaultAdress)
const rewardVaultAccountData = rewardVaultAccount.value?.data as ParsedAccountData
if (rewardVaultAccountData.program !== 'spl-token') continue

const rewardPerSecond = (itemRewardInfo.rewardOpenTime.toNumber() < chainTime && itemRewardInfo.rewardEndTime.toNumber() > chainTime) ? itemRewardInfo.rewardPerSecond : new BN(0)

const sendCountYear = new Decimal(rewardPerSecond.mul(new BN(3600 * 24 * 365)).toString()).div(10 ** rewardVaultAccountData.parsed.info.tokenAmount.decimals)
const sendCountYearToU = sendCountYear.mul(mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0)

const tvl = poolTvl[poolId] !== undefined ? poolTvl[poolId] : poolVaultAccountData.parsed.info.tokenAmount.uiAmount * (mintPrice[poolVaultAccountData.parsed.info.mint] ?? 0)

rewardInfo.push({
mint: rewardVaultAccountData.parsed.info.mint,
price: mintPrice[rewardVaultAccountData.parsed.info.mint] ?? 0,
sendCountYear: sendCountYear.toNumber(),
sendCountYearToU: sendCountYearToU.toNumber(),
tvl,
apr: tvl !== 0 ? sendCountYearToU.div(tvl).toNumber() : 0,
})
}
break
}
default:
throw Error('program Id check error')
}
console.log(rewardInfo)
}

0 comments on commit 40d3af2

Please sign in to comment.