Created
January 19, 2022 13:28
-
-
Save kassandraoftroy/14cf5accdaf5b3b3e7d63e816afa5bf7 to your computer and use it in GitHub Desktop.
This file contains 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 { 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