forked from vfat-io/vfat-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
|
||
$(function() { | ||
consoleInit(main) | ||
}); | ||
|
||
const Yogurt_CHEF_ABI = [{"type":"constructor","inputs":[{"type":"address","name":"_Yogurt","internalType":"contract YogurtToken"},{"type":"address","name":"_devaddr","internalType":"address"},{"type":"address","name":"_feeAddress1","internalType":"address"},{"type":"uint256","name":"_YogurtPerBlock","internalType":"uint256"},{"type":"uint256","name":"_startBlock","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BONUS_MULTIPLIER","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract YogurtToken"}],"name":"Yogurt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"YogurtPerBlock","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"add","inputs":[{"type":"uint256","name":"_allocPoint","internalType":"uint256"},{"type":"address","name":"_lpToken","internalType":"contract IERC20"},{"type":"uint16","name":"_depositFeeBP","internalType":"uint16"},{"type":"bool","name":"_withUpdate","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deposit","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"depositReferral","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"address","name":"referral","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"dev","inputs":[{"type":"address","name":"_devaddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"devaddr","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdraw","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeAddress","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getMultiplier","inputs":[{"type":"uint256","name":"_from","internalType":"uint256"},{"type":"uint256","name":"_to","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"massUpdatePools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingYogurt","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"lpToken","internalType":"contract IERC20"},{"type":"uint256","name":"allocPoint","internalType":"uint256"},{"type":"uint256","name":"lastRewardBlock","internalType":"uint256"},{"type":"uint256","name":"accYogurtPerShare","internalType":"uint256"},{"type":"uint16","name":"depositFeeBP","internalType":"uint16"}],"name":"poolInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_allocPoint","internalType":"uint256"},{"type":"uint16","name":"_depositFeeBP","internalType":"uint16"},{"type":"bool","name":"_withUpdate","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeAddress1","inputs":[{"type":"address","name":"_feeAddress1","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"startBlock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAllocPoint","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateEmissionRate","inputs":[{"type":"uint256","name":"_YogurtPerBlock","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePool","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"rewardDebt","internalType":"uint256"}],"name":"userInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"user","indexed":true},{"type":"uint256","name":"pid","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyWithdraw","inputs":[{"type":"address","name":"user","indexed":true},{"type":"uint256","name":"pid","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"user","indexed":true},{"type":"uint256","name":"pid","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false}] | ||
|
||
async function main() { | ||
const App = await init_ethers(); | ||
|
||
_print(`Initialized ${App.YOUR_ADDRESS}\n`); | ||
_print("Reading smart contracts...\n"); | ||
|
||
const Yogurt_CHEF_ADDR = "0xca3E704Bd09B979170D76d34880c7A72fda51B63"; | ||
const rewardTokenTicker = "YOGURT"; | ||
const Yogurt_CHEF = new ethers.Contract(Yogurt_CHEF_ADDR, Yogurt_CHEF_ABI, App.provider); | ||
|
||
const blocksPerSeconds = await getAverageBlockTime(App); | ||
|
||
const rewardsPerWeek = await Yogurt_CHEF.YogurtPerBlock() /1e18 * 604800 / blocksPerSeconds; | ||
|
||
const tokens = {}; | ||
const prices = await getPulsePrices(); | ||
|
||
await loadYogurtChefContract(App, tokens, prices, Yogurt_CHEF, Yogurt_CHEF_ADDR, Yogurt_CHEF_ABI, rewardTokenTicker, | ||
"Yogurt", null, rewardsPerWeek, "pendingYogurt", [7, 10], "pulse"); | ||
|
||
hideLoading(); | ||
} | ||
|
||
async function loadYogurtChefContract(App, tokens, prices, chef, chefAddress, chefAbi, rewardTokenTicker, | ||
rewardTokenFunction, rewardsPerBlockFunction, rewardsPerWeekFixed, pendingRewardsFunction, | ||
deathPoolIndices, chain) { | ||
const chefContract = chef ?? new ethers.Contract(chefAddress, chefAbi, App.provider); | ||
|
||
const poolCount = parseInt(await chefContract.poolLength(), 10); | ||
const totalAllocPoints = await chefContract.totalAllocPoint(); | ||
_print(`<a href='https://scan.pulsechain.com/address/${chefAddress}' target='_blank'>Staking Contract</a>`); | ||
_print(`Found ${poolCount} pools.\n`) | ||
|
||
_print(`Showing incentivized pools only.\n`); | ||
|
||
const rewardTokenAddress = await chefContract.callStatic[rewardTokenFunction](); | ||
const rewardToken = await getGeneralToken(App, rewardTokenAddress, chefAddress); | ||
const rewardsPerWeek = rewardsPerWeekFixed ?? | ||
await chefContract.callStatic[rewardsPerBlockFunction]() | ||
/ 10 ** rewardToken.decimals * 604800 / 3 | ||
|
||
const poolInfos = await Promise.all([...Array(poolCount).keys()].map(async (x) => | ||
await getYogurtPoolInfo(App, chefContract, chefAddress, x, pendingRewardsFunction))); | ||
|
||
var tokenAddresses = [].concat.apply([], poolInfos.filter(x => x.poolToken).map(x => x.poolToken.tokens)); | ||
|
||
await Promise.all(tokenAddresses.map(async (address) => { | ||
tokens[address] = await getGeneralToken(App, address, chefAddress); | ||
})); | ||
|
||
if (deathPoolIndices) { //load prices for the deathpool assets | ||
deathPoolIndices.map(i => poolInfos[i]) | ||
.map(poolInfo => | ||
poolInfo.poolToken ? getPoolPrices(tokens, prices, poolInfo.poolToken, chain) : undefined); | ||
} | ||
|
||
const poolPrices = poolInfos.map(poolInfo => poolInfo.poolToken ? getPoolPrices(tokens, prices, poolInfo.poolToken, chain) : undefined); | ||
|
||
|
||
_print("Finished reading smart contracts.\n"); | ||
|
||
let aprs = [] | ||
for (i = 0; i < poolCount; i++) { | ||
if (poolPrices[i]) { | ||
const apr = printYogurtPool(App, chefAbi, chefAddress, prices, tokens, poolInfos[i], i, poolPrices[i], | ||
totalAllocPoints, rewardsPerWeek, rewardTokenTicker, rewardTokenAddress, | ||
pendingRewardsFunction, null, null, chain, poolInfos[i].depositFee, poolInfos[i].withdrawFee) | ||
aprs.push(apr); | ||
} | ||
} | ||
let totalUserStaked=0, totalStaked=0, averageApr=0; | ||
for (const a of aprs) { | ||
if (!isNaN(a.totalStakedUsd)) { | ||
totalStaked += a.totalStakedUsd; | ||
} | ||
if (a.userStakedUsd > 0) { | ||
totalUserStaked += a.userStakedUsd; | ||
averageApr += a.userStakedUsd * a.yearlyAPR / 100; | ||
} | ||
} | ||
averageApr = averageApr / totalUserStaked; | ||
_print_bold(`Total Staked: $${formatMoney(totalStaked)}`); | ||
if (totalUserStaked > 0) { | ||
_print_bold(`\nYou are staking a total of $${formatMoney(totalUserStaked)} at an average APR of ${(averageApr * 100).toFixed(2)}%`) | ||
_print(`Estimated earnings:` | ||
+ ` Day $${formatMoney(totalUserStaked*averageApr/365)}` | ||
+ ` Week $${formatMoney(totalUserStaked*averageApr/52)}` | ||
+ ` Year $${formatMoney(totalUserStaked*averageApr)}\n`); | ||
} | ||
return { prices, totalUserStaked, totalStaked, averageApr } | ||
} | ||
|
||
function printYogurtPool(App, chefAbi, chefAddr, prices, tokens, poolInfo, poolIndex, poolPrices, | ||
totalAllocPoints, rewardsPerWeek, rewardTokenTicker, rewardTokenAddress, | ||
pendingRewardsFunction, fixedDecimals, claimFunction, chain="eth", depositFee=0, withdrawFee=0) { | ||
fixedDecimals = fixedDecimals ?? 2; | ||
const sp = (poolInfo.stakedToken == null) ? null : getPoolPrices(tokens, prices, poolInfo.stakedToken, chain); | ||
var poolRewardsPerWeek = poolInfo.allocPoints / totalAllocPoints * rewardsPerWeek; | ||
if (poolRewardsPerWeek == 0 && rewardsPerWeek != 0) return; | ||
const userStaked = poolInfo.userLPStaked ?? poolInfo.userStaked; | ||
const rewardPrice = getParameterCaseInsensitive(prices, rewardTokenAddress)?.usd; | ||
const staked_tvl = sp?.staked_tvl ?? poolPrices.staked_tvl; | ||
_print_inline(`${poolIndex} - `); | ||
poolPrices.print_price(chain); | ||
sp?.print_price(chain); | ||
const apr = printAPR(rewardTokenTicker, rewardPrice, poolRewardsPerWeek, poolPrices.stakeTokenTicker, | ||
staked_tvl, userStaked, poolPrices.price, fixedDecimals); | ||
if (poolInfo.userLPStaked > 0) sp?.print_contained_price(userStaked); | ||
if (poolInfo.userStaked > 0) poolPrices.print_contained_price(userStaked); | ||
printYogurtContractLinks(App, chefAbi, chefAddr, poolIndex, poolInfo.address, pendingRewardsFunction, | ||
rewardTokenTicker, poolPrices.stakeTokenTicker, poolInfo.poolToken.unstaked, | ||
poolInfo.userStaked, poolInfo.pendingRewardTokens, fixedDecimals, claimFunction, rewardPrice, chain, depositFee, withdrawFee); | ||
return apr; | ||
} | ||
|
||
function printYogurtContractLinks(App, chefAbi, chefAddr, poolIndex, poolAddress, pendingRewardsFunction, | ||
rewardTokenTicker, stakeTokenTicker, unstaked, userStaked, pendingRewardTokens, fixedDecimals, | ||
claimFunction, rewardTokenPrice, chain, depositFee, withdrawFee) { | ||
fixedDecimals = fixedDecimals ?? 2; | ||
const approveAndStake = async function() { | ||
return chefContract_stake(chefAbi, chefAddr, poolIndex, poolAddress, App) | ||
} | ||
const unstake = async function() { | ||
return chefContract_unstake(chefAbi, chefAddr, poolIndex, App, pendingRewardsFunction) | ||
} | ||
const emergencyWithdraw = async function() { | ||
return YogurtContract_emergencyWithdraw(chefAbi, chefAddr, poolIndex, App) | ||
} | ||
const claim = async function() { | ||
return chefContract_claim(chefAbi, chefAddr, poolIndex, App, pendingRewardsFunction, claimFunction) | ||
} | ||
if(depositFee > 0){ | ||
_print_link(`Stake ${unstaked.toFixed(fixedDecimals)} ${stakeTokenTicker} - Fee ${depositFee}%`, approveAndStake) | ||
}else{ | ||
_print_link(`Stake ${unstaked.toFixed(fixedDecimals)} ${stakeTokenTicker}`, approveAndStake) | ||
} | ||
if(withdrawFee > 0){ | ||
_print_link(`Unstake ${userStaked.toFixed(fixedDecimals)} ${stakeTokenTicker} - Fee ${withdrawFee}%`, unstake) | ||
}else{ | ||
_print_link(`Unstake ${userStaked.toFixed(fixedDecimals)} ${stakeTokenTicker}`, unstake) | ||
} | ||
_print_link(`Claim ${pendingRewardTokens.toFixed(fixedDecimals)} ${rewardTokenTicker} ($${formatMoney(pendingRewardTokens*rewardTokenPrice)})`, claim) | ||
_print(`Staking or unstaking also claims rewards.`) | ||
_print_link(`Emergency Withdraw ${userStaked.toFixed(fixedDecimals)} ${stakeTokenTicker}`, emergencyWithdraw) | ||
_print(""); | ||
} | ||
|
||
const YogurtContract_emergencyWithdraw = async function(chefAbi, chefAddress, poolIndex, App) { | ||
const signer = App.provider.getSigner() | ||
|
||
const CHEF_CONTRACT = new ethers.Contract(chefAddress, chefAbi, signer) | ||
|
||
const currentStakedAmount = (await CHEF_CONTRACT.userInfo(poolIndex, App.YOUR_ADDRESS)).amount | ||
|
||
if (currentStakedAmount > 0) { | ||
showLoading() | ||
CHEF_CONTRACT.emergencyWithdraw(poolIndex, {gasLimit: 500000}) | ||
.then(function(t) { | ||
return App.provider.waitForTransaction(t.hash) | ||
}) | ||
.catch(function() { | ||
hideLoading() | ||
}) | ||
} | ||
} | ||
|
||
async function getYogurtPoolInfo(app, chefContract, chefAddress, poolIndex, pendingRewardsFunction) { | ||
const poolInfo = await chefContract.poolInfo(poolIndex); | ||
if (poolInfo.allocPoint == 0 || poolIndex == 8) { | ||
return { | ||
address: poolInfo.lpToken ?? poolInfo.stakingToken ?? poolInfo.token, | ||
allocPoints: poolInfo.allocPoint ?? 1, | ||
poolToken: null, | ||
userStaked : 0, | ||
pendingRewardTokens : 0, | ||
}; | ||
} | ||
const poolToken = await getGeneralToken(app, poolInfo.lpToken ?? poolInfo.stakingToken ?? poolInfo.token, chefAddress); | ||
const userInfo = await chefContract.userInfo(poolIndex, app.YOUR_ADDRESS); | ||
const pendingRewardTokens = await chefContract.callStatic[pendingRewardsFunction](poolIndex, app.YOUR_ADDRESS); | ||
const staked = userInfo.amount / 10 ** poolToken.decimals; | ||
return { | ||
address: poolInfo.lpToken ?? poolInfo.stakingToken ?? poolInfo.token, | ||
allocPoints: poolInfo.allocPoint ?? 1, | ||
poolToken: poolToken, | ||
userStaked : staked, | ||
pendingRewardTokens : pendingRewardTokens / 10 ** 18, | ||
depositFee : (poolInfo.depositFeeBP ?? poolInfo.depositFee ?? 0) / 100, | ||
withdrawFee : (poolInfo.withdrawFeeBP ?? 0) / 100 | ||
}; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<%- include(`${partials}/head`); -%> | ||
|
||
<body> | ||
<%- include(`${partials}/header_main`); -%> | ||
<pre id="log"> | ||
*************** 👨🌾 UNOFFICIAL YOGURTFINANCE FARMING CALCULATOR 👨🌾 *************** | ||
INFO : https://yogurtfinance.com/ | ||
******************************************************************************** | ||
|
||
</pre> | ||
<div class="loader--1"></div> | ||
<%- include(`${partials}/scripts`, {scriptname: 'pulse_yogurtfinance'}); -%> | ||
</body> | ||
</html> |