diff --git a/scripts/curve.ts b/scripts/curve.ts index 64085b9..1432292 100644 --- a/scripts/curve.ts +++ b/scripts/curve.ts @@ -1,8 +1,9 @@ import { ethers } from "hardhat" -import { FeeAmount, v3PartyFactory, deployContracts, bnbPartyFactory, BNBPositionManager, v3Factory, positionManager, maxAndMinWBNB } from "../test/helper" +import {FeeAmount, v3PartyFactory, deployContracts, bnbPartyFactory, positionManager, BNBPositionManager, v3Factory, maxAndMinWBNB} from "../test/helper" import { IUniswapV3Pool } from "../typechain-types" import BigNumber from "bignumber.js" import * as csvWriter from "csv-writer" +import { getPrice } from "./get-price" const BNB_PRICE = 600 // BNB price in USD let lpContract: IUniswapV3Pool @@ -15,8 +16,8 @@ const csv = createCsvWriter({ { id: "MEMEAmount", title: "MEME Amount" }, { id: "WBNBAmount", title: "WBNB Amount" }, { id: "SqrtPriceX96", title: "sqrtPriceX96" }, - { id: "priceMemeInWbnb", title: "Price of MEME in WBNB" }, - { id: "priceWbnbInMeme", title: "Price of WBNB in MEME" }, + { id: "priceMemeInWbnb", title: "Amount of WBNB required to purchase one unit of the MEME" }, + { id: "priceWbnbInMeme", title: "Amount of MEME tokens required to purchase one unit of WBNB" }, { id: "wbnbValueInLp", title: "WBNB Value in USD" }, { id: "memeValueInLp", title: "MEME Value in USD" }, { id: "marketCap", title: "Market Cap in USD" }, @@ -35,34 +36,25 @@ async function createLiquidityPool(wbnbAddress: string) { return { MEME, position } } -function calculatePrices(sqrtPriceX96: BigNumber, token0: string, token1: string, meme: string) { - const priceX96 = sqrtPriceX96.pow(2) - const priceToken0InToken1 = priceX96.dividedBy(new BigNumber(2).pow(192)) - const priceToken1InToken0 = new BigNumber(1).div(priceToken0InToken1) - return token0 === meme - ? { priceMemeInWbnb: priceToken0InToken1, priceWbnbInMeme: priceToken1InToken0 } - : { priceMemeInWbnb: priceToken1InToken0, priceWbnbInMeme: priceToken0InToken1 } -} - async function getTokenBalances(lpAddress: string, token: any, wbnbAddress: string) { const wbnb = await ethers.getContractAt("IWBNB", wbnbAddress) - const [MEMEAmount, WBNBAmount, wethAddress] = await Promise.all([ - token.balanceOf(lpAddress), - wbnb.balanceOf(lpAddress), - wbnb.getAddress(), - ]) + const [MEMEAmount, WBNBAmount] = await Promise.all([token.balanceOf(lpAddress), wbnb.balanceOf(lpAddress)]) const lpPool = await ethers.getContractAt("UniswapV3Pool", lpAddress) const token0 = await lpPool.token0() - const isPartyPool = await bnbPartyFactory.isTokenOnPartyLP(token0 === wethAddress ? await token.getAddress() : token0) + const isPartyPool = await bnbPartyFactory.isTokenOnPartyLP( + token0 === wbnbAddress ? await token.getAddress() : token0 + ) + const [feeGrowthGlobal0X128, feeGrowthGlobal1X128, liquidity, getFeeGlobal] = await Promise.all([ lpPool.feeGrowthGlobal0X128(), lpPool.feeGrowthGlobal1X128(), lpPool.liquidity(), bnbPartyFactory.getFeeGrowthInsideLastX128(lpAddress, isPartyPool ? BNBPositionManager : positionManager), ]) + let wbnbFee, memeFee - if (token0 === wethAddress) { + if (token0 === wbnbAddress) { wbnbFee = await bnbPartyFactory.calculateFees(liquidity, feeGrowthGlobal0X128 - getFeeGlobal.feeGrowthInside0LastX128) memeFee = await bnbPartyFactory.calculateFees(liquidity, feeGrowthGlobal1X128 - getFeeGlobal.feeGrowthInside1LastX128) } else { @@ -70,7 +62,10 @@ async function getTokenBalances(lpAddress: string, token: any, wbnbAddress: stri wbnbFee = await bnbPartyFactory.calculateFees(liquidity, feeGrowthGlobal1X128 - getFeeGlobal.feeGrowthInside1LastX128) } - return { WBNBAmount: new BigNumber((WBNBAmount - wbnbFee).toString()), MEMEAmount: new BigNumber((MEMEAmount - memeFee).toString()) } + return { + WBNBAmount: new BigNumber((WBNBAmount - wbnbFee).toString()), + MEMEAmount: new BigNumber((MEMEAmount - memeFee).toString()), + } } async function logData( @@ -84,7 +79,10 @@ async function logData( ) { const wbnbValueUSD = WBNBAmount.div(new BigNumber(10).pow(18)).multipliedBy(BNB_PRICE) const memeValueUSD = MEMEAmount.div(new BigNumber(10).pow(18)).multipliedBy(priceMemeInWbnb).multipliedBy(BNB_PRICE) - const marketCap = initialMEMEAmount.div(new BigNumber(10).pow(18)).multipliedBy(priceMemeInWbnb).multipliedBy(BNB_PRICE) + const marketCap = initialMEMEAmount + .div(new BigNumber(10).pow(18)) + .multipliedBy(priceMemeInWbnb) + .multipliedBy(BNB_PRICE) const remainingMEMEPercentage = MEMEAmount.div(initialMEMEAmount).multipliedBy(100).toFixed(2) const memeMarketCapInBnb = initialMEMEAmount.div(new BigNumber(10).pow(18)).multipliedBy(priceMemeInWbnb) @@ -93,8 +91,8 @@ async function logData( MEMEAmount: MEMEAmount.toString(), WBNBAmount: WBNBAmount.toString(), SqrtPriceX96: sqrtPriceX96.toString(), - priceMemeInWbnb: priceMemeInWbnb.toString(), - priceWbnbInMeme: priceWbnbInMeme.toString(), + priceMemeInWbnb: priceMemeInWbnb.toString(10), + priceWbnbInMeme: priceWbnbInMeme.toString(10), wbnbValueInLp: wbnbValueUSD.toString(), memeValueInLp: memeValueUSD.toString(), marketCap: marketCap.toString(), @@ -109,32 +107,43 @@ async function logData( async function test() { const target = ethers.parseEther("13") const wbnbAddresses = await maxAndMinWBNB() - const wbnbAddress = wbnbAddresses.maxAddress + const wbnbAddress = wbnbAddresses.minAddress await deployContracts(target, wbnbAddress) const { MEME, position } = await createLiquidityPool(wbnbAddress) const token = await ethers.getContractAt("ERC20Token", MEME) const lpAddress = await v3PartyFactory.getPool(position.token0, position.token1, FeeAmount.HIGH) lpContract = (await ethers.getContractAt("UniswapV3Pool", lpAddress)) as any as IUniswapV3Pool - const { MEMEAmount: initialMEMEAmount, } = await getTokenBalances(lpAddress, token, wbnbAddress) + const { MEMEAmount: initialMEMEAmount } = await getTokenBalances(lpAddress, token, wbnbAddress) const segments = 26 for (let i = 0; i <= segments; ++i) { const swapAmount = ethers.parseUnits("5.06", 17) - if( i !== 0) await bnbPartyFactory.joinParty(MEME, 0, { value: swapAmount }) + if (i !== 0) await bnbPartyFactory.joinParty(MEME, 0, { value: swapAmount }) const isParty = await bnbPartyFactory.isTokenOnPartyLP(MEME) if (isParty) { const { MEMEAmount, WBNBAmount } = await getTokenBalances(lpAddress, token, wbnbAddress) const slot0 = await lpContract.slot0() const sqrtPriceX96 = new BigNumber(slot0.sqrtPriceX96.toString()) - const { priceMemeInWbnb, priceWbnbInMeme } = calculatePrices(sqrtPriceX96, await lpContract.token0(), await lpContract.token1(), MEME) + let { priceToken0InToken1: priceMemeInWbnb, priceToken1InToken0: priceWbnbInMeme } = getPrice(sqrtPriceX96) + if (wbnbAddress === wbnbAddresses.minAddress) { + // replace the price of MEME in WBNB with the price of WBNB in MEME + const temp = priceMemeInWbnb + priceMemeInWbnb = priceWbnbInMeme + priceWbnbInMeme = temp + } await logData(i, MEMEAmount, WBNBAmount, sqrtPriceX96, priceMemeInWbnb, priceWbnbInMeme, initialMEMEAmount) - } - else { + } else { const newLPPool = await v3Factory.getPool(wbnbAddress, MEME, FeeAmount.HIGH) const lpContract = (await ethers.getContractAt("UniswapV3Pool", newLPPool)) as any as IUniswapV3Pool const slot0 = await lpContract.slot0() const sqrtPriceX96 = new BigNumber(slot0.sqrtPriceX96.toString()) - const { priceMemeInWbnb, priceWbnbInMeme } = calculatePrices(sqrtPriceX96, await lpContract.token0(), await lpContract.token1(), MEME) + let { priceToken0InToken1: priceMemeInWbnb, priceToken1InToken0: priceWbnbInMeme } = getPrice(sqrtPriceX96) + if (wbnbAddress === wbnbAddresses.minAddress) { + // replace the price of MEME in WBNB with the price of WBNB in MEME + const temp = priceMemeInWbnb + priceMemeInWbnb = priceWbnbInMeme + priceWbnbInMeme = temp + } const { MEMEAmount, WBNBAmount } = await getTokenBalances(newLPPool, token, wbnbAddress) await logData(i, MEMEAmount, WBNBAmount, sqrtPriceX96, priceMemeInWbnb, priceWbnbInMeme, initialMEMEAmount) } diff --git a/scripts/encodePrice.ts b/scripts/encodePrice.ts new file mode 100644 index 0000000..18b4a61 --- /dev/null +++ b/scripts/encodePrice.ts @@ -0,0 +1,16 @@ +import BigNumber from "bignumber.js" // Import BigNumber.js for precise calculations + +// Configure BigNumber.js for high precision +BigNumber.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }) + +// Function to calculate sqrtPriceX96 +export function encodePriceSqrt(reserve1: string, reserve0: string): bigint { + return BigInt( + new BigNumber(reserve1) // Convert reserve1 to a BigNumber + .div(reserve0) // Divide by reserve0 + .sqrt() // Take the square root of the result + .multipliedBy(new BigNumber(2).pow(96)) // Multiply by 2^96 + .integerValue(BigNumber.ROUND_DOWN) // Round down to the nearest integer + .toString() // Convert to string + ) +} diff --git a/scripts/get-price.ts b/scripts/get-price.ts new file mode 100644 index 0000000..5951fee --- /dev/null +++ b/scripts/get-price.ts @@ -0,0 +1,20 @@ +import BigNumber from "bignumber.js" + +export function getPrice(sqrtPriceX96: BigNumber) { + // Calculate price of token0 in terms of token1 + const buyOneOfToken0 = sqrtPriceX96.dividedBy(new BigNumber(2).pow(96)).pow(2) + + // Calculate price of token1 in terms of token0 + const buyOneOfToken1 = new BigNumber(1).dividedBy(buyOneOfToken0) + + // Convert to smallest unit (wei) + const buyOneOfToken0Wei = buyOneOfToken0.multipliedBy(new BigNumber(10).pow(18)).integerValue(BigNumber.ROUND_DOWN).toString(10) + const buyOneOfToken1Wei = buyOneOfToken1.multipliedBy(new BigNumber(10).pow(18)).integerValue(BigNumber.ROUND_DOWN).toString(10) + + return { + priceToken0InToken1: buyOneOfToken0, // Price of token0 in terms of token1 + priceToken1InToken0: buyOneOfToken1, // Price of token1 in terms of token0 + priceToken0InToken1Wei: buyOneOfToken0Wei, // Price of token0 in lowest decimal (wei) + priceToken1InToken0Wei: buyOneOfToken1Wei, // Price of token1 in lowest decimal (wei) + } +}