Frontend ready, time to debug all the things

This commit is contained in:
Marco van Dijk 2022-04-21 14:40:43 +02:00
parent f6238bfc32
commit 9b4e3455f3
5 changed files with 257 additions and 355 deletions

View File

@ -1078,11 +1078,8 @@ const syncEvents = function (toBlock) {
console.log("Starting sync process for Bonding Manager events to block " + toBlock);
isEventSyncing = true;
let lastTxSynced = 0;
if (lastBlockTickets != 'latest'){
lastBlockTickets += 1;
}
// Then do a sync from last found until latest known
bondingManagerContract.getPastEvents("allEvents", { fromBlock: lastBlockEvents, toBlock: toBlock }, async (error, events) => {
bondingManagerContract.getPastEvents("allEvents", { fromBlock: lastBlockEvents + 1, toBlock: toBlock }, async (error, events) => {
try {
if (error) {
throw error
@ -1135,11 +1132,8 @@ const syncEvents = function (toBlock) {
const syncTickets = function (toBlock) {
console.log("Starting sync process for Ticket Broker events to block " + toBlock);
isTicketSyncing = true;
if (lastBlockTickets != 'latest'){
lastBlockTickets += 1;
}
// Then do a sync from last found until latest known
ticketBrokerContract.getPastEvents("allEvents", { fromBlock: lastBlockTickets, toBlock: toBlock }, async (error, events) => {
ticketBrokerContract.getPastEvents("allEvents", { fromBlock: lastBlockTickets + 1, toBlock: toBlock }, async (error, events) => {
try {
if (error) {
throw error

View File

@ -1,233 +0,0 @@
import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { VictoryPie } from 'victory';
import Address from '../components/OrchAddressViewer';
import {
getOrchestratorScores
} from "../actions/livepeer";
const StakeOverview = (obj) => {
const livepeer = useSelector((state) => state.livepeerstate);
const dispatch = useDispatch();
const [thisScores, setThisScores] = useState(null);
const [removeOnlyStakers, setRemoveOnlyStakers] = useState(false);
useEffect(() => {
const now = new Date().getTime();
let wasInCache = false;
// See if it is cached
for (const thisScore of livepeer.orchScores) {
if (thisScore.year === obj.year && thisScore.month === obj.month) {
// Check timeout
if (now - thisScore.timestamp < 360000) {
wasInCache = true;
}
if (!thisScores) {
setThisScores(thisScore);
}
}
}
if (!wasInCache) {
dispatch(getOrchestratorScores(obj.year, obj.month));
}
}, [livepeer.orchScores]);
const getName = (address) => {
let thisDomain = null;
// Lookup domain in cache
if (livepeer.ensDomainMapping) {
for (const thisAddr of livepeer.ensDomainMapping) {
if (thisAddr.address === address) {
thisDomain = thisAddr;
break;
}
}
}
// Lookup current info in cache only if this addr has a mapped ENS domain
if (thisDomain && thisDomain.domain) {
for (const thisAddr of livepeer.ensInfoMapping) {
if (thisAddr.domain === thisDomain.domain) {
return thisAddr.domain;
}
}
}
if (livepeer.threeBoxInfo) {
for (const thisAddr of livepeer.threeBoxInfo) {
if (thisAddr.address === address) {
if (thisAddr.name) {
return thisAddr.name;
} else {
return (address.substring(0, 10) + "..");
}
break;
}
}
}
return (address.substring(0, 10) + "..");
}
let orchList = [];
let pieList = [];
let otherSum = 0;
let pieObj = null;
if (livepeer.orchInfo) {
let orchIdx = livepeer.orchInfo.length - 1;
// calc sum of stake
let totalStake = 0;
let totalEarnings = 0;
while (orchIdx >= 0) {
const thisOrch = livepeer.orchInfo[orchIdx];
orchIdx -= 1;
if (removeOnlyStakers && !parseFloat(thisOrch.totalVolumeUSD)) {
continue;
}
totalStake += parseFloat(thisOrch.totalStake);
totalEarnings += parseFloat(thisOrch.totalVolumeETH);
}
// create slices
orchIdx = livepeer.orchInfo.length - 1;
while (orchIdx >= 0) {
const thisOrch = livepeer.orchInfo[orchIdx];
const thisStake = parseFloat(thisOrch.totalStake);
const thisEarnings = parseFloat(thisOrch.totalVolumeETH);
orchIdx -= 1;
if (removeOnlyStakers && !parseFloat(thisOrch.totalVolumeUSD)) {
continue;
}
// Add orch stat descending
let idx = orchList.length - 1;
while (idx >= 0) {
const sel = orchList[idx];
if (sel.sum < thisStake) {
idx--;
continue;
} else {
break;
}
}
if (idx == orchList.length - 1) {
orchList.push({
address: thisOrch.id,
sum: thisStake,
ratio: (thisStake / totalStake) * 100,
earnings: thisEarnings,
earningsRatio: (thisEarnings / totalEarnings) * 100
});
} else {
orchList.splice(idx + 1, 0, {
address: thisOrch.id,
sum: thisStake,
ratio: (thisStake / totalStake) * 100,
earnings: thisEarnings,
earningsRatio: (thisEarnings / totalEarnings) * 100
});
}
// Add slice
if ((thisStake / totalStake) < 0.04) {
otherSum += thisStake;
} else {
pieList.push({
address: getName(thisOrch.id),
sum: thisStake
});
}
}
pieList.push({
address: "Other",
sum: otherSum
});
pieObj = <div className="stroke">
<h4>Active Orchestrators by Stake</h4>
<div className='row'>
<p>Only Transcoding?</p>
<div className="toggle-container" onClick={() => setRemoveOnlyStakers(!removeOnlyStakers)}>
<div className={`dialog-button ${removeOnlyStakers ? "" : "disabled"}`}>
{removeOnlyStakers ? "1" : "0"}
</div>
</div>
</div>
<VictoryPie padding={100} data={pieList} x="address" y="sum"
sortOrder="descending"
sortKey="sum"
colorScale={[
"#003f5c",
"#2f4b7c",
"#665191",
"#ff7c43",
"#ffa600",
"#5c3446",
"#83424e",
"#a6544e",
"#c16d46",
"#d18d3c",
"#d3b136",
"#c5d843",
"#a3ff69",
]}
style={{
data: {
fillOpacity: 0.9, stroke: "#636363", strokeWidth: 2
},
labels: {
fontSize: 10, zIndex: 999
}
}} />
</div>
}
return (
<div className="stroke">
{pieObj}
<div className="flexContainer forceWrap">
<div className="row">
<div className="rowAlignLeft">
<h4>Orchestrator</h4>
</div>
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>Stake</h4>
</div>
</div>
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>Earnings</h4>
</div>
</div>
</div>
{
orchList.map(function (orch) {
return (
<div className="row" key={"staker" + orch.address + orch.sum}>
<div className="rowAlignLeft">
<Address address={orch.address} seed={"stake" + orch.address + orch.sum} />
</div>
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>{orch.sum.toFixed(2)} LPT</h4>
</div>
<div className="rowAlignRight" >
<span>({orch.ratio.toFixed(2)} %)</span>
</div>
</div>
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>{orch.earnings.toFixed(2)} Eth</h4>
</div>
<div className="rowAlignRight" >
<span>({orch.earningsRatio.toFixed(2)} %)</span>
</div>
</div>
</div>
)
})
}
</div>
<div className="verticalDivider" />
</div>
)
}
export default StakeOverview;

View File

@ -15,8 +15,8 @@ const WinnerMonth = (obj) => {
const now = new Date().getTime();
let wasInCache = false;
// See if it is cached
for (const thisScore of livepeer.orchScores) {
if (thisScore.year === obj.year && thisScore.month === obj.month) {
for (const thisScore of obj.data.testScores) {
if (thisScore.year === obj.data.year && thisScore.month === obj.data.month) {
// Check timeout
if (now - thisScore.timestamp < 360000) {
wasInCache = true;
@ -28,8 +28,9 @@ const WinnerMonth = (obj) => {
}
if (!wasInCache) {
dispatch(getOrchestratorScores(obj.year, obj.month));
dispatch(getAllMonthlyStats());
}
}, [livepeer.orchScores]);
}, []);
const getName = (address) => {
let thisDomain = null;
@ -67,30 +68,44 @@ const WinnerMonth = (obj) => {
return (address.substring(0, 10) + "..");
}
let pieList = [];
let otherSum = 0;
let ticketIdx = obj.orchestrators.length - 1;
while (ticketIdx >= 0) {
const thisTicket = obj.orchestrators[ticketIdx];
ticketIdx -= 1;
if ((thisTicket.sum / obj.total) < 0.04) {
otherSum += thisTicket.sum;
} else {
pieList.push({
address: getName(thisTicket.address),
sum: thisTicket.sum
});
// Show all orchs (if latestTotalStake exists) or show only those in winningTicketsReceived
let orchList;
// Pies for stake overview, if have stake data for that month saved
let stakeObj;
let totalStakeSum = 0;
if (obj.data.latestTotalStake && obj.data.latestTotalStake.length) {
orchList = obj.data.latestTotalStake;
let pieList = [];
let otherSum = 0;
let ticketIdx = obj.data.latestTotalStake.length - 1;
// Calc total stake at that time
while (ticketIdx >= 0) {
const thisTicket = obj.data.latestTotalStake[ticketIdx];
ticketIdx -= 1;
totalStakeSum += thisTicket.totalStake;
}
}
pieList.push({
address: "Other",
sum: otherSum
});
ticketIdx = obj.data.latestTotalStake.length - 1;
// Create pie chart
while (ticketIdx >= 0) {
const thisTicket = obj.data.latestTotalStake[ticketIdx];
ticketIdx -= 1;
if ((thisTicket.totalStake / totalStakeSum) < 0.04) {
otherSum += thisTicket.totalStake;
} else {
pieList.push({
address: getName(thisTicket.address),
sum: thisTicket.totalStake
});
}
}
pieList.push({
address: "Other",
sum: otherSum
});
return (
<div className="stroke">
<h4>Top Earners</h4>
stakeObj = <div className="stroke">
<h4>Stake Distribution</h4>
<div className="row">
<VictoryPie padding={100} data={pieList} x="address" y="sum"
sortOrder="descending"
@ -119,10 +134,159 @@ const WinnerMonth = (obj) => {
}
}} />
</div>
</div>;
} else {
orchList = obj.data.winningTicketsReceived;
}
// Pies for earnings overview
let earningsObj;
if (obj.data.winningTicketsReceived && obj.data.winningTicketsReceived.length) {
let otherSum = 0;
let pieList = [];
let ticketIdx = obj.data.winningTicketsReceived.length - 1;
// Create pie chart
while (ticketIdx >= 0) {
const thisTicket = obj.data.winningTicketsReceived[ticketIdx];
ticketIdx -= 1;
if ((thisTicket.sum / obj.data.winningTicketsReceivedSum) < 0.04) {
otherSum += thisTicket.sum;
} else {
pieList.push({
address: getName(thisTicket.address),
sum: thisTicket.sum
});
}
}
pieList.push({
address: "Other",
sum: otherSum
});
stakeObj = <div className="stroke">
<h4>Stake Distribution</h4>
<div className="row">
<VictoryPie padding={100} data={pieList} x="address" y="sum"
sortOrder="descending"
sortKey="sum"
colorScale={[
"#003f5c",
"#2f4b7c",
"#665191",
"#ff7c43",
"#ffa600",
"#5c3446",
"#83424e",
"#a6544e",
"#c16d46",
"#d18d3c",
"#d3b136",
"#c5d843",
"#a3ff69",
]}
style={{
data: {
fillOpacity: 0.9, stroke: "#636363", strokeWidth: 2
},
labels: {
fontSize: 10, zIndex: 999
}
}} />
</div>
</div>;
}
return (
<div className="stroke">
{stakeObj}
{earningsObj}
{obj.data.reactivationCount ?
<div className="row">
<p className="darkText">{obj.data.reactivationCount} Orchestrator reactivated</p>
</div> : null
}
{obj.data.activationCount ?
<div className="row">
<p className="darkText">{obj.data.activationCount} Orchestrator activated with an initial stake of {obj.data.activationInitialSum} LPT</p>
</div> : null
}
{obj.data.unbondCount ?
<div className="row">
<p className="darkText">{obj.data.unbondCount} delegators unbonded {obj.data.unbondStakeSum} LPT</p>
</div> : null
}
{obj.data.rewardCount ?
<div className="row">
<p className="darkText">{obj.data.rewardCount} reward calls were made worth {obj.data.rewardAmountSum} LPT</p>
</div> : null
}
{obj.data.claimCount ?
<div className="row">
<p className="darkText">{obj.data.claimCount} reward claims were made worth {obj.data.claimRewardSum} LPT and {obj.data.claimFeeSum} ETH</p>
</div> : null
}
{obj.data.withdrawStakeCount ?
<div className="row">
<p className="darkText">{obj.data.withdrawStakeCount} withdraw stake calls were made worth {obj.data.withdrawStakeAmountSum} LPT</p>
</div> : null
}
{obj.data.withdrawFeesCount ?
<div className="row">
<p className="darkText">{obj.data.withdrawFeesCount} withdraw fees calls were made worth {obj.data.withdrawFeesAmountSum} ETH</p>
</div> : null
}
{obj.data.bondCount ?
<div className="row">
<p className="darkText">{obj.data.bondCount} delegators delegated their first stake worth {obj.data.bondStakeSum} LPT</p>
</div> : null
}
{obj.data.moveStakeCount ?
<div className="row">
<p className="darkText">Stake got moved around {obj.data.moveStakeCount} times worth {obj.data.moveStakeSum} LPT</p>
</div> : null
}
{obj.data.winningTicketsReceivedCount ?
<div className="row">
<p className="darkText">{obj.data.winningTicketsReceivedCount} winning tickets were sent out worth {obj.data.winningTicketsReceivedSum} ETH</p>
</div> : null
}
{obj.data.winningTicketsRedeemedCount ?
<div className="row">
<p className="darkText">{obj.data.winningTicketsRedeemedCount} winning tickets were redeemed worth {obj.data.winningTicketsRedeemedSum} ETH</p>
</div> : null
}
<div className="flexContainer forceWrap">
{
obj.orchestrators.map(function (orch) {
return (<Winner stats={thisScores} address={orch.address} sum={orch.sum} total={obj.total} key={"delegator" + orch.address + orch.sum} />)
orchList.map(function (orch, i) {
let thisCommission = null;
let thisStake = null;
let thisEarnings = null;
for (const obj in obj.data.winningTicketsReceived) {
if (obj.address == orch.address){
thisEarnings = obj;
}
}
for (const obj in obj.data.latestCommission) {
if (obj.address == orch.address){
thisCommission = obj;
}
}
for (const obj in obj.data.latestTotalStake) {
if (obj.address == orch.address){
thisStake = obj;
}
}
return (<Winner
thisScore={thisScores[obj.address]}
totalEarnings={obj.data.winningTicketsReceivedSum}
thisEarnings={thisEarnings}
totalStake={totalStakeSum}
thisStake={thisStake}
thisCommission={thisCommission}
address={orch.address}
key={orch.address + i}
seed={"win" + orch.address + i}
/>)
})
}
</div>

View File

@ -6,55 +6,48 @@ import { CircularProgressbar } from 'react-circular-progressbar';
import 'react-circular-progressbar/dist/styles.css';
const Winner = (obj) => {
const [thisScore, setThisScore] = useState(0);
const [opened, setOpened] = useState(false);
useEffect(() => {
// Get score of this Orch
let thisScore = null;
if (obj.stats) {
thisScore = obj.stats.scores[obj.address];
}
let score = 0;
if (thisScore) {
score = (thisScore["FRA"].score + thisScore["LAX"].score + thisScore["LON"].score + thisScore["MDW"].score + thisScore["NYC"].score + thisScore["PRG"].score + thisScore["SIN"].score) / 7;
if (thisScore != score) {
setThisScore(score);
if (obj.thisScore) {
score = (obj.thisScore["FRA"].score + obj.thisScore["LAX"].score + obj.thisScore["LON"].score + obj.thisScore["MDW"].score + obj.thisScore["NYC"].score + obj.thisScore["PRG"].score + obj.thisScore["SIN"].score) / 7;
if (obj.thisScore != score) {
setobj.thisScore(score);
}
}
}, [obj.stats]);
let scoreObj = null;
if (thisScore) {
if (obj.thisScore) {
scoreObj =
<Popover className="strokeSmollLeft" style={{ cursor: 'pointer', marginTop: '0.2em', marginBottom: '0.2em' }}
<Popover className="strokeSmollLeft" style={{ cursor: 'pointer', marginTop: '0.2em', marginBottom: '0.2em' }}
opened={opened}
onClose={() => setOpened(false)}
target={
<div className="strokeSmollLeft" style={{ width: '4em', height: '4em', marginLeft: '2em' }} onClick={() => setOpened((o) => !o)} >
<CircularProgressbar value={thisScore} maxValue={1} text={`${((thisScore * 10).toFixed(1))}`}
styles={{
root: {},
path: {
stroke: `rgba(20, 153, 53, ${thisScore})`,
strokeLinecap: 'round',
transition: 'stroke-dashoffset 0.5s ease 0s',
transformOrigin: 'center center',
},
trail: {
stroke: '#d66400',
strokeLinecap: 'rounnd',
transformOrigin: 'center center',
},
text: {
fill: 'rgba(0, 0, 0, 0.875)',
fontSize: '32px',
},
background: {
fill: '#3e98c7',
},
}}/>
<CircularProgressbar value={obj.thisScore} maxValue={1} text={`${((obj.thisScore * 10).toFixed(1))}`}
styles={{
root: {},
path: {
stroke: `rgba(20, 153, 53, ${obj.thisScore})`,
strokeLinecap: 'round',
transition: 'stroke-dashoffset 0.5s ease 0s',
transformOrigin: 'center center',
},
trail: {
stroke: '#d66400',
strokeLinecap: 'rounnd',
transformOrigin: 'center center',
},
text: {
fill: 'rgba(0, 0, 0, 0.875)',
fontSize: '32px',
},
background: {
fill: '#3e98c7',
},
}} />
</div>
}
width={260}
@ -68,16 +61,36 @@ const Winner = (obj) => {
return (
<div className="row">
<div className="rowAlignLeft">
<Address address={obj.address} seed={"delegator" + obj.address + obj.sum} />
<Address address={obj.address} seed={obj.seed} />
</div>
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>{obj.sum.toFixed(4)} Eth</h4>
<h4>{obj.thisEarnings.sum.toFixed(4)} Eth</h4>
</div>
<div className="rowAlignRight" >
<span>({((obj.sum / obj.total) * 100).toFixed(2)} %)</span>
<span>({((obj.thisEarnings.sum / obj.totalEarnings) * 100).toFixed(2)} %)</span>
</div>
</div>
{obj.thisStake ?
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<h4>{obj.thisStake.totalStake.toFixed(4)} LPT</h4>
</div>
<div className="rowAlignRight" >
<span>({((obj.thisStake.totalStake / obj.totalStake) * 100).toFixed(2)} %)</span>
</div>
</div> : null
}
{obj.thisCommission ?
<div className="strokeSmollLeft" style={{ minWidth: '100px' }} >
<div className="rowAlignLeft" >
<span>{obj.thisCommission.rewardCommission.toFixed(2)}% Reward</span>
</div>
<div className="rowAlignRight" >
<span>{obj.thisCommission.feeCommission.toFixed(2)}% Fee</span>
</div>
</div> : null
}
{scoreObj}
</div>
)

View File

@ -5,12 +5,11 @@ import { useSelector, useDispatch } from 'react-redux';
import { Accordion } from '@mantine/core';
import ScrollContainer from 'react-indiana-drag-scroll';
import WinnerMonth from '../components/WinnerMonth';
import StakeOverview from '../components/StakeOverview';
const Stats = (obj) => {
const livepeer = useSelector((state) => state.livepeerstate);
const [ticketsPerMonth, setTicketsPerMonth] = useState([]);
const [redirectToHome, setRedirectToHome] = useState(false);
const [removeOnlyStakers, setRemoveOnlyStakers] = useState(false);
console.log("Rendering Stats Viewer");
@ -18,42 +17,6 @@ const Stats = (obj) => {
return <Navigate push to="/" />;
}
const getName = (address) => {
let thisDomain = null;
// Lookup domain in cache
if (livepeer.ensDomainMapping) {
for (const thisAddr of livepeer.ensDomainMapping) {
if (thisAddr.address === address) {
thisDomain = thisAddr;
break;
}
}
}
// Lookup current info in cache only if this addr has a mapped ENS domain
if (thisDomain && thisDomain.domain) {
for (const thisAddr of livepeer.ensInfoMapping) {
if (thisAddr.domain === thisDomain.domain) {
return thisAddr.domain;
}
}
}
if (livepeer.threeBoxInfo) {
for (const thisAddr of livepeer.threeBoxInfo) {
if (thisAddr.address === address) {
if (thisAddr.name) {
return thisAddr.name;
} else {
return (address.substring(0, 10) + "..");
}
break;
}
}
}
return (address.substring(0, 10) + "..");
}
return (
<div style={{ margin: 0, padding: 0, height: '100%', width: '100%', overflow: 'hidden' }}>
<div id='header'>
@ -65,6 +28,14 @@ const Stats = (obj) => {
</button>
<h4 className="rowAlignLeft withWrap showNeverOnMobile">Statistics</h4>
</div>
{/* <div className='rowAlignRight'>
<p>Filter</p>
<div className="toggle-container" onClick={() => setRemoveOnlyStakers(!removeOnlyStakers)}>
<div className={`dialog-button ${removeOnlyStakers ? "" : "disabled"}`}>
{removeOnlyStakers ? "Show" : "Hide"}
</div>
</div>
</div> */}
</div>
<div id='bodyContent'>
<div className="mainContent">
@ -86,13 +57,8 @@ const Stats = (obj) => {
content: { padding: 0, paddingTop: '1em', paddingBottom: '1em' },
contentInner: { padding: 0 },
}}>
<Accordion.Item
label={"Current Stake Overview"}
className="stroke">
<StakeOverview />
</Accordion.Item>
{
ticketsPerMonth.map(function (data) {
livepeer.monthlyStats.map(function (data) {
let thisMonth = "";
let monthAsNum = data.month;
if (monthAsNum == 0) {
@ -123,14 +89,12 @@ const Stats = (obj) => {
return (
<Accordion.Item
label={data.year + "-" + thisMonth + ": " + data.orchestrators.length + " orchestrators earned " + data.total.toFixed(2) + " Eth"}
label={data.year + "-" + thisMonth + ": " + data.winningTicketsReceived.length + " orchestrators earned " + data.winningTicketsReceivedSum.toFixed(2) + " Eth"}
className="stroke"
key={data.year + "-" + data.month + "-" + data.total}>
<WinnerMonth
year={data.year}
month={data.month}
orchestrators={data.orchestrators}
total={data.total}
data={data}
removeOnlyStakers={removeOnlyStakers}
/>
</Accordion.Item>
)