Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kassandraoftroy/14cf5accdaf5b3b3e7d63e816afa5bf7 to your computer and use it in GitHub Desktop.
Save kassandraoftroy/14cf5accdaf5b3b3e7d63e816afa5bf7 to your computer and use it in GitHub Desktop.
import { BigNumber } from '@ethersproject/bignumber';
import { ethers } from 'ethers';
type APRType = {
apr: number
feesEarned0: BigNumber
feesEarned1: BigNumber
}
const X96 = BigNumber.from(2).pow(BigNumber.from(96))
const BLOCKS_PER_YEAR = 2102400
const computeAverageReserves = (snapshots: any, firstBlock: number, lastBlock: number) => {
let cumulativeBlocks = BigNumber.from(0)
let cumulativeReserves = BigNumber.from(0)
for (let i=1; i < snapshots.length+1; i++) {
if (Number(snapshots[i-1].block) < lastBlock) {
if (i == snapshots.length || Number(snapshots[i].block) >= firstBlock) {
const reserves0 = BigNumber.from(snapshots[i-1].reserves0)
const reserves1 = BigNumber.from(snapshots[i-1].reserves1)
const priceX96X96 = BigNumber.from(snapshots[i-1].sqrtPriceX96).mul(BigNumber.from(snapshots[i-1].sqrtPriceX96))
const reserves0As1X96 = reserves0.mul(priceX96X96).div(X96)
const reserves0As1 = reserves0As1X96.div(X96)
const reserves = reserves1.add(reserves0As1)
let blockDifferential: BigNumber
if (i<snapshots.length) {
blockDifferential = BigNumber.from(snapshots[i].block).sub(BigNumber.from(snapshots[i-1].block))
} else {
blockDifferential = BigNumber.from(lastBlock).sub(BigNumber.from(snapshots[i-1].block))
}
cumulativeReserves = cumulativeReserves.add(reserves.mul(blockDifferential))
cumulativeBlocks = cumulativeBlocks.add(blockDifferential)
}
}
}
if (cumulativeBlocks.gt(ethers.constants.Zero)) {
return cumulativeReserves.div(cumulativeBlocks)
} else {
return ethers.constants.Zero
}
}
const computeTotalFeesEarned = (snapshots: any, sqrtPriceX96: BigNumber, firstBlock: number): BigNumber[] => {
let feesEarned0 = BigNumber.from(0)
let feesEarned1 = BigNumber.from(0)
let totalFeesEarned0 = BigNumber.from(0)
let totalFeesEarned1 = BigNumber.from(0)
for (let i=0; i<snapshots.length; i++) {
if (Number(snapshots[i].block) >= firstBlock) {
feesEarned0 = feesEarned0.add(BigNumber.from(snapshots[i].feesEarned0))
feesEarned1 = feesEarned1.add(BigNumber.from(snapshots[i].feesEarned1))
}
totalFeesEarned0 = totalFeesEarned0.add(BigNumber.from(snapshots[i].feesEarned0))
totalFeesEarned1 = totalFeesEarned1.add(BigNumber.from(snapshots[i].feesEarned1))
}
const priceX96X96 = sqrtPriceX96.mul(sqrtPriceX96)
const fees0As1X96 = feesEarned0.mul(priceX96X96).div(X96)
const fees0As1 = fees0As1X96.div(X96)
return [feesEarned1.add(fees0As1), totalFeesEarned0, totalFeesEarned1]
}
export const getAPR = (poolData: any, sqrtPriceX96: BigNumber, currentFees0: BigNumber, currentFees1: BigNumber, lastBlock: number): APRType => {
if (poolData.supplySnapshots.length == 0) {
return {
apr: 0,
feesEarned0: ethers.constants.Zero,
feesEarned1: ethers.constants.Zero,
}
}
let snapshots = [];
if (poolData.feeSnapshots.length != 0) {
snapshots = [...poolData.feeSnapshots].sort((a: any, b:any) => (a.block > b.block) ? 1: -1)
}
const supplySnaps = [...poolData.supplySnapshots].sort((a: any, b: any) => (a.block > b.block) ? 1: -1)
let firstBlock = (Number(lastBlock) - 40320*4).toString()
if (Number(firstBlock) < Number(poolData.blockCreated)) {
firstBlock = poolData.blockCreated
}
snapshots.push({
feesEarned0: currentFees0.toString(),
feesEarned1: currentFees1.toString(),
block: lastBlock
});
if (snapshots.length == 0 || supplySnaps.length == 0) {
return {
apr: 0,
feesEarned0: ethers.constants.Zero,
feesEarned1: ethers.constants.Zero,
}
}
const [totalFeeValue, feesTotal0, feesTotal1] = computeTotalFeesEarned(snapshots, sqrtPriceX96, Number(firstBlock))
const averageReserves = computeAverageReserves(supplySnaps, Number(firstBlock), Number(lastBlock))
let apr = 0
if (averageReserves.gt(ethers.constants.Zero)) {
let averagePrincipal = averageReserves.sub(totalFeeValue)
if (averagePrincipal.lte(ethers.constants.Zero)) {
averagePrincipal = averageReserves
}
const totalBlocks = Number(lastBlock) - Number(firstBlock)
apr = (Number(ethers.utils.formatEther(totalFeeValue)) * BLOCKS_PER_YEAR) / (Number(ethers.utils.formatEther(averagePrincipal)) * totalBlocks)
}
return {
apr: apr > 0 ? apr : 0,
feesEarned0: feesTotal0,
feesEarned1: feesTotal1
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment