Skip to content

Commit

Permalink
add yogurt finance
Browse files Browse the repository at this point in the history
  • Loading branch information
devsceth committed Jul 29, 2023
1 parent 7e23bf2 commit 8fb50c1
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/static/js/pulse.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const main = async() => {
"title":"Pulse Network",
"heading":["Pool Provider","LP", "Reward Tokens", "INFO"],
"rows": [
["Yogurtfinance ", `<a href="yogurtfinance" >Various</a>`,"YOGURTFINANCE ","https://yogurtfinance.com/"],
["Pulsex ", `<a href="pulsex" >Various</a>`,"INC ","https://app.pulsex.com"],
["Daytona Finance ", `<a href="daytona" >Various</a>`,"TONI ","https://www.daytona.finance"],
["Velocimeter ", `<a href="velocimeter" >Various</a>`,"FLOW ","https://pulse.velocimeter.xyz"],
Expand Down
198 changes: 198 additions & 0 deletions src/static/js/pulse_yogurtfinance.js
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
};
}
16 changes: 16 additions & 0 deletions src/views/pages/pulse/yogurtfinance/index.ejs
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>

0 comments on commit 8fb50c1

Please sign in to comment.