diff --git a/public/deployments/dashboard.json b/public/deployments/dashboard.json
index 3b6d098..ef077a9 100644
--- a/public/deployments/dashboard.json
+++ b/public/deployments/dashboard.json
@@ -158,6 +158,7 @@
"fn": "balanceOf",
"args": ["MinipoolManager"],
"title": "MinipoolManager Balance (AVAX)",
+ "desc": "Includes 'withdrawable' and 'pending' minipool funds",
"formatter": "formatEther"
},
{
diff --git a/public/home.html b/public/home.html
index 5691a01..3ef6a94 100644
--- a/public/home.html
+++ b/public/home.html
@@ -34,7 +34,8 @@
⚠️ These numbers are all estimates of next cycle's rewards, based on the information in the smart contracts, and may
not be accurate.
- Not Financial Advice, Do Your Own Research, WAGMI.
+ GGP buys required to get everyone to 150% collateralization ratio:
+ Not Financial Advice, Do Your Own Research, WAGMI.
@@ -102,6 +103,10 @@
Contracts
.addEventListener("click", () => tableMinipools.download("csv", "GoGoPool_Minipools.csv"));
GGP.refreshDataLoop(() => {
+ document.getElementById("buy-pressure").innerHTML = GGP.buyPressure().toLocaleString(undefined, {
+ maximumFractionDigits: 0,
+ });
+
tableDashboard.blockRedraw();
tableMinipools.blockRedraw();
tableStakers.blockRedraw();
diff --git a/public/js/gogopool.js b/public/js/gogopool.js
index a51aa41..1a3bad3 100644
--- a/public/js/gogopool.js
+++ b/public/js/gogopool.js
@@ -8,20 +8,21 @@ import { minipoolsTransformer } from "/js/transformers.js";
// Hard-code reward cycle amounts
// Note we show the rewards for the *next* cycle amount
const REWARDS_TOTAL_NODEOP_POOL_AMT = {
- 0: BigNumber.from("50629343838906640213406"),
- 1: BigNumber.from("50832782764109674639470"),
- 2: BigNumber.from("51037039147986861608379"),
- 3: BigNumber.from("51242116275252192212662"),
- 4: BigNumber.from("51448017443818301518451"),
- 5: BigNumber.from("51654745964849503381680"),
- 6: BigNumber.from("51862305162815038368864"),
- 7: BigNumber.from("52070698375542535638786"),
- 8: BigNumber.from("52279928954271689644796"),
- 9: BigNumber.from("52490000263708152520974"),
- 10: BigNumber.from("52700915682077643018745"),
- 11: BigNumber.from("52912678601180272864145"),
+ 1: BigNumber.from("50629343838906640213406"),
+ 2: BigNumber.from("50832782764109674639470"),
+ 3: BigNumber.from("51037039147986861608379"),
+ 4: BigNumber.from("51242116275252192212662"),
+ 5: BigNumber.from("51448017443818301518451"),
+ 6: BigNumber.from("51654745964849503381680"),
+ 7: BigNumber.from("51862305162815038368864"),
+ 8: BigNumber.from("52070698375542535638786"),
+ 9: BigNumber.from("52279928954271689644796"),
+ 10: BigNumber.from("52490000263708152520974"),
+ 11: BigNumber.from("52700915682077643018745"),
+ 12: BigNumber.from("52912678601180272864145"),
};
+const REWARDS_CYCLE_DURATION = 2592000; // 30 days
// Convert to eth
for (const k in REWARDS_TOTAL_NODEOP_POOL_AMT) {
REWARDS_TOTAL_NODEOP_POOL_AMT[k] =
@@ -225,6 +226,12 @@ class GoGoPool {
return cycle.value.toNumber();
}
+ rewardsCycleStartTime() {
+ const ctrct = this.dashboard.filter((r) => r.contract === "RewardsPool")[0];
+ const cycle = ctrct.metrics.filter((r) => r.fn === "getRewardsCycleStartTime")[0];
+ return cycle.value.toNumber();
+ }
+
// Reformat data shape to fit Tabulator table
dashboardAsTabulatorData() {
this.dashboardData = [];
@@ -266,12 +273,18 @@ class GoGoPool {
async fetchStakers({ status } = { status: Object.keys(MINIPOOL_STATUS_MAP) }) {
await this.until((_) => this.isLoaded);
+ const rewardsCycleStartTime = (await this.contracts.RewardsPool.contract.getRewardsCycleStartTime()).toNumber();
+ const rewardsCycleEndTime = rewardsCycleStartTime + REWARDS_CYCLE_DURATION;
+
let allStakers = await this.contracts.Staking.contract.getStakers(0, 0);
allStakers = allStakers.map(unfuckEthersObj);
- console.log("allStakers", allStakers);
+ // console.log("allStakers", allStakers);
+ // Filter out people not running minipools at all
let eligibleStakers = allStakers.filter((s) => s.rewardsStartTime > 0 && s.avaxValidatingHighWater > 0);
- // console.log("eligibleStakers (pre enrichment)", eligibleStakers);
+ // Calc eligibility based on if they *will* be eligible for the next cycle
+ eligibleStakers.forEach((s) => (s.isEligible = rewardsCycleEndTime - s.rewardsStartTime >= REWARDS_CYCLE_DURATION));
+ console.log("eligibleStakers (pre enrichment)", eligibleStakers);
// Define similiar structure as used in dashboard.js. Consolidate somehow, someday.
const ethAsFloat = (v) => parseFloat(ethersUtils.formatEther(v || 0));
@@ -289,10 +302,6 @@ class GoGoPool {
contract: "TokenGGP",
metrics: [{ fn: "balanceOf", formatter: ethAsFloat }],
},
- {
- contract: "ClaimNodeOp",
- metrics: [{ fn: "isEligible" }],
- },
];
// For each ELIGIBLE staker we want to call a couple contract funcs, so mush them all together for speed into batches
@@ -323,10 +332,7 @@ class GoGoPool {
}
}
- console.log("results", results);
-
const metrics = enrichments.map((e) => e.metrics).flat();
- console.log(metrics);
// Now add the results of the batch to each staker
const idFn = (v) => v;
@@ -338,12 +344,13 @@ class GoGoPool {
});
}
- console.log("eligibleStakers", eligibleStakers);
-
// So, I still want to show recently created minipool owners in the list, but since they are not yet eligible
// we will nerf their rewards to zero
eligibleStakers.forEach((s) => {
+ // If they were eligible by time but their collat ratio is < 10%, then set them to not eligible
+ if (s.getCollateralizationRatio < 0.1) s.isEligible = false;
if (!s.isEligible) {
+ console.log("notEligible", s);
s.getEffectiveGGPStaked = 0;
s.getEffectiveRewardsRatio = 0;
}
@@ -363,22 +370,31 @@ class GoGoPool {
const investors = eligibleStakers.filter((s) => INVESTOR_ADDRS[s.stakerAddr]);
const users = eligibleStakers.filter((s) => !INVESTOR_ADDRS[s.stakerAddr]);
- // Investors share 10% of rewards pie
+ // Investors share INVESTOR_REWARDS_SHARE % of rewards pie
const investorTotalGGPStaked = investors.reduce((acc, s) => acc + s.getEffectiveGGPStaked, 0);
investors.map((s) => {
s.ggpInvestorRewardsPoolPct = s.getEffectiveGGPStaked / investorTotalGGPStaked;
s.ggpRewardsPoolAmt = REWARDS_POOL_AMT * INVESTOR_REWARDS_SHARE * s.ggpInvestorRewardsPoolPct;
s.ggpRewardsPoolPct = s.ggpRewardsPoolAmt / REWARDS_POOL_AMT;
+ s.ggpReqToMax = 0; // N/A to investors
});
- // Users share 90% of rewards pie
+ // Users share remainder of rewards pie
const userTotalGGPStaked = users.reduce((acc, s) => acc + s.getEffectiveGGPStaked, 0);
users.map((s) => {
s.ggpUserRewardsPoolPct = s.getEffectiveGGPStaked / userTotalGGPStaked;
s.ggpRewardsPoolAmt = REWARDS_POOL_AMT * (1 - INVESTOR_REWARDS_SHARE) * s.ggpUserRewardsPoolPct;
s.ggpRewardsPoolPct = s.ggpRewardsPoolAmt / REWARDS_POOL_AMT;
+ // Lets calc how much GGP they would need to buy to max out rewards
+ s.ggpReqToMax = 0;
+ if (s.getCollateralizationRatio < 1.5) {
+ s.ggpReqToMax = s.ggpStaked * (1.5 / s.getCollateralizationRatio) - s.ggpStaked - s.balanceOf - s.ggpRewards;
+ if (s.ggpReqToMax < 0) s.ggpReqToMax = 0;
+ }
});
+ console.log("eligibleStakers (post-enrichment)", eligibleStakers);
+
const totalRewardsCheck = eligibleStakers.reduce((acc, s) => acc + s.ggpRewardsPoolAmt, 0);
console.log("totalRewardsCheck", totalRewardsCheck);
@@ -386,6 +402,10 @@ class GoGoPool {
return this.stakersData;
}
+ buyPressure() {
+ return this.stakersData.reduce((acc, s) => acc + s.ggpReqToMax, 0);
+ }
+
stakersAsTabulatorData() {
return this.stakersData;
}