Prep for new event parsing in backend

This commit is contained in:
Marco van Dijk 2022-04-19 08:27:44 +02:00
parent 387d581bba
commit 8f61f40061
15 changed files with 633 additions and 129 deletions

View File

@ -0,0 +1,32 @@
import mongoose from 'mongoose';
const ActivateEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
initialStake: {
type: Number,
required: true
},
round: {
type: Number,
required: false,
default: null
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const ActivateEvent = mongoose.model('ActivateEvent', ActivateEventSchema);
export default ActivateEvent;

View File

@ -0,0 +1,31 @@
import mongoose from 'mongoose';
const ClaimEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
fees: {
type: Number,
required: true
},
rewards: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const ClaimEvent = mongoose.model('ClaimEvent', ClaimEventSchema);
export default ClaimEvent;

View File

@ -0,0 +1,27 @@
import mongoose from 'mongoose';
const RedeemEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const RedeemEvent = mongoose.model('RedeemEvent', RedeemEventSchema);
export default RedeemEvent;

View File

@ -0,0 +1,27 @@
import mongoose from 'mongoose';
const RewardEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const RewardEvent = mongoose.model('RewardEvent', RewardEventSchema);
export default RewardEvent;

View File

@ -0,0 +1,35 @@
import mongoose from 'mongoose';
const StakeEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
from: {
type: String,
required: false
},
to: {
type: String,
required: false
},
stake: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const StakeEvent = mongoose.model('StakeEvent', StakeEventSchema);
export default StakeEvent;

View File

@ -0,0 +1,31 @@
import mongoose from 'mongoose';
const TransferEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
to: {
type: String,
required: true
},
amount: {
type: number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const TransferEvent = mongoose.model('TransferEvent', TransferEventSchema);
export default TransferEvent;

View File

@ -0,0 +1,27 @@
import mongoose from 'mongoose';
const UnbondEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
stake: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const UnbondEvent = mongoose.model('UnbondEvent', UnbondEventSchema);
export default UnbondEvent;

View File

@ -0,0 +1,31 @@
import mongoose from 'mongoose';
const UpdateEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
rewardCommission: {
type: Number,
required: true
},
feeCommission: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const UpdateEvent = mongoose.model('UpdateEvent', UpdateEventSchema);
export default UpdateEvent;

View File

@ -0,0 +1,31 @@
import mongoose from 'mongoose';
const WithdrawEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
from: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const WithdrawEvent = mongoose.model('WithdrawEvent', WithdrawEventSchema);
export default WithdrawEvent;

View File

@ -0,0 +1,35 @@
import mongoose from 'mongoose';
const WithdrawEventSchema = new mongoose.Schema({
address: {
type: String,
required: true
},
from: {
type: String,
required: true
},
round: {
type: Number,
required: true
},
amount: {
type: Number,
required: true
},
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
}
}, { timestamps: false });
const WithdrawEvent = mongoose.model('WithdrawEvent', WithdrawEventSchema);
export default WithdrawEvent;

View File

@ -0,0 +1,148 @@
import mongoose from 'mongoose';
const MonthlyStatSchema = new mongoose.Schema({
// Static props
year: {
type: Number,
required: true
},
month: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
// Counters based on Smart Contract Events
// Any TranscoderUpdate event: commission rates are done with thegraph query of current data, no historical data
// Any TranscoderActivated event
activationCount: {
type: Number,
required: false,
default: 0
},
activationInitialSum: {
type: Number,
required: false,
default: 0
},
// Lone Unbond event
unbondCount: {
type: Number,
required: false,
default: 0
},
unbondStakeSum: {
type: Number,
required: false,
default: 0
},
// Any Reward event
rewardCount: {
type: Number,
required: false,
default: 0
},
rewardAmountSum: {
type: Number,
required: false,
default: 0
},
// Any EarningsClaimed event
claimCount: {
type: Number,
required: false,
default: 0
},
claimRewardSum: {
type: Number,
required: false,
default: 0
},
claimFeeSum: {
type: Number,
required: false,
default: 0
},
// Any WithdrawStake event
withdrawStakeCount: {
type: Number,
required: false,
default: 0
},
withdrawStakeAmountSum: {
type: Number,
required: false,
default: 0
},
// Any WithdrawFees event
withdrawFeesCount: {
type: Number,
required: false,
default: 0
},
withdrawFeesAmountSum: {
type: Number,
required: false,
default: 0
},
// Lone Bond event
bondCount: {
type: Number,
required: false,
default: 0
},
bondStakeSum: {
type: Number,
required: false,
default: 0
},
// Unbond->TransferBond->Rebond event
moveStakeCount: {
type: Number,
required: false,
default: 0
},
moveStakeSum: {
type: Number,
required: false,
default: 0
},
// Any TransferTicket event
winningTicketsReceivedCount: {
type: Number,
required: false,
default: 0
},
winningTicketsReceivedSum: {
type: Number,
required: false,
default: 0
},
// Any RedeemTicket event
winningTicketsRedeemedCount: {
type: Number,
required: false,
default: 0
},
winningTicketsRedeemedSum: {
type: Number,
required: false,
default: 0
},
// Dynamic stats (until the month has passed)
orchestratorStats: {
type: [Object],
required: false,
default: null
},
testScores: {
type: Object,
required: false,
default: null
},
}, { timestamps: false });
const MonthlyStat = mongoose.model('MonthlyStat', MonthlyStatSchema);
export default MonthlyStat;

View File

@ -150,6 +150,12 @@ const getBlock = async function (blockNumber) {
return thisBlock;
}
/*
SMART CONTRACT EVENTS
*/
// Set special flag to make sure also get blocks that pass us by while we are syncing
let isSyncing = true;
let isEventSyncing = false;
@ -157,6 +163,13 @@ let isTicketSyncing = false;
// Start Listening for live updates
var BondingManagerProxyListener;
var TicketBrokerProxyListener;
/*
SMART CONTRACT EVENTS - LIVE DATA
*/
if (!CONF_SIMPLE_MODE) {
BondingManagerProxyListener = bondingManagerContract.events.allEvents(async (error, event) => {
try {
@ -232,6 +245,12 @@ if (!CONF_SIMPLE_MODE) {
console.log("Listening for tickets on " + TicketBrokerTargetAddr);
}
/*
SMART CONTRACT EVENTS - SYNC OF MISSED BLOCKS
*/
// Syncs events database
const syncEvents = function () {
console.log("Starting sync process for Bonding Manager events");
@ -412,6 +431,30 @@ if (!isEventSyncing && !CONF_SIMPLE_MODE && !CONF_DISABLE_SYNC) {
handleSync();
}
// Exports list of smart contract events
apiRouter.get("/getEvents", async (req, res) => {
try {
res.send(eventsCache);
} catch (err) {
res.status(400).send(err);
}
});
// Exports list of smart contract ticket events
apiRouter.get("/getTickets", async (req, res) => {
try {
res.send(ticketsCache);
} catch (err) {
res.status(400).send(err);
}
});
/*
COINMARKETCAP
*/
// Splits of raw CMC object into coin quote data
const parseCmc = async function () {
try {
@ -436,6 +479,42 @@ const parseCmc = async function () {
}
}
// Exports raw CoinMarketCap info
apiRouter.get("/cmc", async (req, res) => {
try {
const now = new Date().getTime();
// Update cmc once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
cmcPriceGet = now;
await parseCmc();
}
res.send(cmcCache);
} catch (err) {
res.status(400).send(err);
}
});
// Exports top 200 coin quotes
apiRouter.get("/quotes", async (req, res) => {
try {
const now = new Date().getTime();
// Update cmc once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
cmcPriceGet = now;
await parseCmc();
}
res.send(cmcQuotes);
} catch (err) {
res.status(400).send(err);
}
});
/*
ARBITRUM DATA
*/
// Queries Alchemy for block info and gas fees
const parseL1Blockchain = async function () {
const l1Wei = await web3layer1.eth.getGasPrice();
@ -463,62 +542,6 @@ const parseEthBlockchain = async function () {
await Promise.all([parseL1Blockchain(), parseL2Blockchain()]);
}
// Export livepeer and eth coin prices and L1 Eth gas price
apiRouter.get("/grafana", async (req, res) => {
try {
const now = new Date().getTime();
// Update blockchain data if the cached data has expired
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
await parseEthBlockchain();
arbGet = now;
}
// Update coin prices once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
await parseCmc();
cmcPriceGet = now;
}
res.send({
timestamp: now,
cmcTime: cmcPriceGet,
blockchainTime: arbGet,
l1GasFeeInGwei: l1Gwei,
l2GasFeeInGwei: l2Gwei,
ethPriceInDollar: ethPrice,
lptPriceInDollar: lptPrice,
redeemRewardCostL1,
redeemRewardCostL2,
claimTicketCostL1,
claimTicketCostL2,
withdrawFeeCostL1,
withdrawFeeCostL2,
stakeFeeCostL1,
stakeFeeCostL2,
commissionFeeCostL1,
commissionFeeCostL2,
serviceUriFeeCostL1,
serviceUriFeeCostL2,
quotes: cmcQuotes
});
} catch (err) {
res.status(400).send(err);
}
});
// Exports raw CoinMarketCap info
apiRouter.get("/cmc", async (req, res) => {
try {
const now = new Date().getTime();
// Update cmc once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
cmcPriceGet = now;
await parseCmc();
}
res.send(cmcCache);
} catch (err) {
res.status(400).send(err);
}
});
// Exports gas fees and contract prices
apiRouter.get("/blockchains", async (req, res) => {
try {
@ -553,38 +576,11 @@ apiRouter.get("/blockchains", async (req, res) => {
}
});
// Exports top 200 coin quotes
apiRouter.get("/quotes", async (req, res) => {
try {
const now = new Date().getTime();
// Update cmc once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
cmcPriceGet = now;
await parseCmc();
}
res.send(cmcQuotes);
} catch (err) {
res.status(400).send(err);
}
});
/*
// Exports list of smart contract events
apiRouter.get("/getEvents", async (req, res) => {
try {
res.send(eventsCache);
} catch (err) {
res.status(400).send(err);
}
});
THEGRAPH - ORCHESTRATOR
// Exports list of smart contract ticket events
apiRouter.get("/getTickets", async (req, res) => {
try {
res.send(ticketsCache);
} catch (err) {
res.status(400).send(err);
}
});
*/
// Gets info on a given Orchestrator
const parseOrchestrator = async function (reqAddr) {
@ -720,6 +716,20 @@ apiRouter.post("/getOrchestrator", async (req, res) => {
}
});
// Returns entire orch info cache
apiRouter.get("/getAllOrchInfo", async (req, res) => {
try {
res.send(orchestratorCache);
} catch (err) {
res.status(400).send(err);
}
});
/*
THEGRAPH - DELEGATOR
*/
// Gets info on a given Delegator
const parseDelegator = async function (reqAddr) {
@ -824,6 +834,61 @@ apiRouter.post("/getOrchestratorByDelegator", async (req, res) => {
}
});
// Returns entire delegator info cache
apiRouter.get("/getAllDelInfo", async (req, res) => {
try {
res.send(delegatorCache);
} catch (err) {
res.status(400).send(err);
}
});
/*
PROMETHEUS - GRAFANA
*/
// Export livepeer and eth coin prices and L1 Eth gas price
apiRouter.get("/grafana", async (req, res) => {
try {
const now = new Date().getTime();
// Update blockchain data if the cached data has expired
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
await parseEthBlockchain();
arbGet = now;
}
// Update coin prices once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
await parseCmc();
cmcPriceGet = now;
}
res.send({
timestamp: now,
cmcTime: cmcPriceGet,
blockchainTime: arbGet,
l1GasFeeInGwei: l1Gwei,
l2GasFeeInGwei: l2Gwei,
ethPriceInDollar: ethPrice,
lptPriceInDollar: lptPrice,
redeemRewardCostL1,
redeemRewardCostL2,
claimTicketCostL1,
claimTicketCostL2,
withdrawFeeCostL1,
withdrawFeeCostL2,
stakeFeeCostL1,
stakeFeeCostL2,
commissionFeeCostL1,
commissionFeeCostL2,
serviceUriFeeCostL1,
serviceUriFeeCostL2,
quotes: cmcQuotes
});
} catch (err) {
res.status(400).send(err);
}
});
// Export livepeer and eth coin prices and L1 Eth gas price
apiRouter.get("/prometheus/:orchAddr", async (req, res) => {
@ -976,6 +1041,13 @@ apiRouter.get("/prometheus/:orchAddr", async (req, res) => {
}
});
/*
ENS DATA
*/
const getEnsDomain = async function (addr) {
const now = new Date().getTime();
let wasInCache = false;
@ -1093,17 +1165,18 @@ apiRouter.get("/getEnsInfo", async (req, res) => {
});
/*
3BOX DATA
*/
const getThreeBoxInfo = async function (addr) {
const now = new Date().getTime();
let wasInCache = false;
// See if it is cached
for (const thisAddr of threeboxCache) {
if (thisAddr.address === addr) {
// Check timeout
if (now - thisAddr.timestamp < CONF_TIMEOUT_ENS_INFO) {
return thisAddr;
}
wasInCache = true;
return thisAddr;
}
}
// Else get it and cache it
@ -1124,18 +1197,8 @@ const getThreeBoxInfo = async function (addr) {
image: data.image,
timestamp: now
}
if (wasInCache) {
for (var idx = 0; idx < threeboxCache.length; idx++) {
if (threeboxCache[idx].address == addr) {
console.log("Updating outdated 3box info " + threeBoxObj.address + " @ " + threeBoxObj.timestamp);
threeboxCache[idx] = threeBoxObj;
break;
}
}
} else {
console.log("Caching new 3box info " + threeBoxObj.address + " @ " + threeBoxObj.timestamp);
threeboxCache.push(threeBoxObj);
}
console.log("Caching new 3box info " + threeBoxObj.address + " @ " + threeBoxObj.timestamp);
threeboxCache.push(threeBoxObj);
} catch (error) {
console.error(error.message);
};
@ -1163,6 +1226,11 @@ apiRouter.get("/getAllThreeBox", async (req, res) => {
}
});
/*
LEADERBOARD TEST SCORES
*/
const zeroPad = (num, places) => String(num).padStart(places, '0')
const getScoreAtMonthYear = async function (month, year) {
@ -1251,23 +1319,12 @@ apiRouter.get("/getAllOrchScores", async (req, res) => {
}
});
// Returns entire orch info cache
apiRouter.get("/getAllOrchInfo", async (req, res) => {
try {
res.send(orchestratorCache);
} catch (err) {
res.status(400).send(err);
}
});
// Returns entire delegator info cache
apiRouter.get("/getAllDelInfo", async (req, res) => {
try {
res.send(delegatorCache);
} catch (err) {
res.status(400).send(err);
}
});
/*
RESERVED
*/

View File

@ -124,8 +124,6 @@ export const getEvents = () => async dispatch => {
let eventContainsUnbond = false;
let eventContainsRebond = false;
let eventContainsTransferBond = false;
let eventContainsTranscoderUpdate = false;
let eventContainsEarningsClaimed = false;
let eventContainsReward = false;
// Temp vars for the current Event we are processing
let tmpAmount = 0;
@ -256,8 +254,6 @@ export const getEvents = () => async dispatch => {
eventContainsUnbond = false;
eventContainsRebond = false;
eventContainsTransferBond = false;
eventContainsTranscoderUpdate = false;
eventContainsEarningsClaimed = false;
eventContainsReward = false;
txCounter++;
currentTx = eventObj.transactionHash;
@ -318,7 +314,6 @@ export const getEvents = () => async dispatch => {
}
// Always split off TranscoderUpdate as a separate Update Event
else if (eventObj.name === "TranscoderUpdate") {
eventContainsTranscoderUpdate = true;
const amount1 = parseFloat(eventObj.data.rewardCut) / 10000;
const amount2 = 100 - (eventObj.data.feeShare / 10000);
const subtext = "changed commission";
@ -344,7 +339,6 @@ export const getEvents = () => async dispatch => {
}
// Always split off EarningsClaimed as a separate Claim Event
else if (eventObj.name === "EarningsClaimed") {
eventContainsEarningsClaimed = true;
const amount1 = parseFloat(eventObj.data.rewards) / 1000000000000000000;
const amount2 = parseFloat(eventObj.data.fees) / 1000000000000000000;
if (amount1 < thresholdStaking && amount2 < thresholdFees) {

View File

@ -1,8 +1,6 @@
import React from "react";
const ScoreView = (obj) => {
console.log(obj.score);
return (
<div className="row">
<div className="stroke">

View File

@ -58,7 +58,7 @@ const Home = (obj) => {
<button className="waveButton" onClick={() => {
setRedirectToLPT(true);
}}>
<p>🔎 Blockchain 🕵</p>
<p>🔎 Contract Events 🕵</p>
</button>
</div>
<div className="row">