diff --git a/deploy/trade-mining/paradeen-feed-pyth.ts b/deploy/trade-mining/paradeen-feed-pyth.ts new file mode 100644 index 0000000..80f5a59 --- /dev/null +++ b/deploy/trade-mining/paradeen-feed-pyth.ts @@ -0,0 +1,125 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; +import { ethers } from "hardhat"; +import { getConfig } from "../utils/config"; +import { BigNumber } from "ethers"; +import { AP__factory, Paradeen__factory } from "../../typechain"; +import * as readlineSync from "readline-sync"; +import { getCoinGeckoPriceUSD } from "../utils/price"; +import { formatEther } from "ethers/lib/utils"; + +interface FeedParadeenParams { + weekTimestamp: BigNumber; + amount: BigNumber; +} + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const config = getConfig(); + const signer = (await ethers.getSigners())[0]; + const pythExponent = BigNumber.from(10).pow(6); + + // contracts + const ap = AP__factory.connect(config.TradeMining.AP, ethers.provider); + const paradeen = Paradeen__factory.connect( + config.TradeMining.paradeen, + signer + ); + + // constants + const E18 = BigNumber.from(10).pow(18); + const WEEK = BigNumber.from(604800); + + // configs + const tradingFeeBps = 9; + const weeklyFeeThreshold = BigNumber.from(20000).mul(E18); + + console.log(`> Prepare data...`); + + const currentBlock = await ethers.provider.getBlock("latest"); + const weekCursor = BigNumber.from(currentBlock.timestamp).div(WEEK).mul(WEEK); + + const weeklyTradingVolume = await ap.weeklyTotalSupply(weekCursor); + const tradingFeeCollected = weeklyTradingVolume + .mul(tradingFeeBps) + .mul(2) // account closing volume assure + .div(10000); + const pythPrice = await getCoinGeckoPriceUSD("pyth-network"); + + console.log(`> Weekly trading volume: ${formatEther(weeklyTradingVolume)}`); + console.log(`> Trading fee collected: ${formatEther(tradingFeeCollected)}`); + console.log(`> Pyth price: ${formatEther(pythPrice)}\n`); + + let amountToFeed = BigNumber.from(0); + + if (tradingFeeCollected.lt(weeklyFeeThreshold)) { + console.log( + `> Trading fee collected is < ${formatEther(weeklyFeeThreshold)} USD` + ); + amountToFeed = tradingFeeCollected.mul(E18).div(pythPrice); + } else { + console.log( + `> Trading fee collected is > ${formatEther(weeklyFeeThreshold)} USD` + ); + amountToFeed = weeklyFeeThreshold.mul(E18).div(pythPrice); + } + + console.log(`> Amount to feed: ${formatEther(amountToFeed)} Pyth`); + + const PARAMS_INPUT: Array = [ + { + weekTimestamp: weekCursor, + amount: amountToFeed.mul(pythExponent).div(E18), + }, + ]; + + // Check feed timestamp + const weeklyReward = await paradeen.tokensPerWeek(weekCursor); + if (weeklyReward.gt(0)) { + console.log( + `> Weekly reward for ${weekCursor}: ${formatEther(weeklyReward)}` + ); + console.log(`> Already fed for this week`); + const goNext = readlineSync.question("Confirm to re-feed? (y/n): "); + switch (goNext.toLowerCase()) { + case "y": + break; + case "n": + console.log("Aborting"); + return; + default: + console.log("Invalid input"); + return; + } + } + + // Ask for confirmation + console.table(PARAMS_INPUT); + const confirm = readlineSync.question("Confirm? (y/n): "); + switch (confirm.toLowerCase()) { + case "y": + break; + case "n": + console.log("Aborting"); + return; + default: + console.log("Invalid input"); + return; + } + + const timestamps = PARAMS_INPUT.map((p) => + p.weekTimestamp.div(WEEK).mul(WEEK) + ); + const amounts = PARAMS_INPUT.map((p) => p.amount); + + console.log("> Feeding rewards to Paradeen"); + const tx = await paradeen.feed(timestamps, amounts, { + gasLimit: 10000000000, + }); + console.log(`> ⛓ Tx submitted: ${tx.hash}`); + console.log(`> Waiting tx to be mined...`); + await tx.wait(); + console.log(`> Tx mined!`); +}; + +export default func; +func.tags = ["FeedParadeenPyth"]; diff --git a/deploy/utils/price.ts b/deploy/utils/price.ts new file mode 100644 index 0000000..b67ffe9 --- /dev/null +++ b/deploy/utils/price.ts @@ -0,0 +1,19 @@ +import axios from "axios"; +import { BigNumber } from "ethers"; +import { parseEther } from "ethers/lib/utils"; + +export async function getCoinGeckoPriceUSD( + assetId: string +): Promise { + let tokenPrice = BigNumber.from(0); + try { + const response = await axios.get( + `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${assetId}` + ); + tokenPrice = parseEther(response.data[0]["current_price"].toString()); + } catch (error) { + throw new Error(`Error fetching price for ${assetId}: ${error}`); + } + + return tokenPrice; +} diff --git a/package.json b/package.json index f45c1e2..bbeb0c4 100644 --- a/package.json +++ b/package.json @@ -184,6 +184,7 @@ "deploy:mainnet:trade-mining:ap-token:upgrade:ap-token": "hardhat --network mainnet deploy --no-compile --reset --tags UpgradeAPToken", "deploy:mainnet:trade-mining:paradeen": "hardhat --network mainnet deploy --no-compile --reset --tags Paradeen", "deploy:mainnet:trade-mining:feed-paradeen": "hardhat --network mainnet deploy --no-compile --reset --tags FeedParadeen", + "deploy:mainnet:trade-mining:feed-paradeen-pyth": "hardhat --network mainnet deploy --no-compile --reset --tags FeedParadeenPyth", "deploy:mainnet:trade-mining:set_mineable": "hardhat --network mainnet deploy --no-compile --reset --tags SetMiningManagerMinable", "deploy:mainnet:trade-mining:set_miner_manager_auth": "hardhat --network mainnet deploy --no-compile --reset --tags SetMiningManagerAuth", "deploy:mainnet:trade-mining:set_miner_manager_point": "hardhat --network mainnet deploy --no-compile --reset --tags SetMiningManagerPoint",