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; return thisBlock;
} }
/*
SMART CONTRACT EVENTS
*/
// Set special flag to make sure also get blocks that pass us by while we are syncing // Set special flag to make sure also get blocks that pass us by while we are syncing
let isSyncing = true; let isSyncing = true;
let isEventSyncing = false; let isEventSyncing = false;
@ -157,6 +163,13 @@ let isTicketSyncing = false;
// Start Listening for live updates // Start Listening for live updates
var BondingManagerProxyListener; var BondingManagerProxyListener;
var TicketBrokerProxyListener; var TicketBrokerProxyListener;
/*
SMART CONTRACT EVENTS - LIVE DATA
*/
if (!CONF_SIMPLE_MODE) { if (!CONF_SIMPLE_MODE) {
BondingManagerProxyListener = bondingManagerContract.events.allEvents(async (error, event) => { BondingManagerProxyListener = bondingManagerContract.events.allEvents(async (error, event) => {
try { try {
@ -232,6 +245,12 @@ if (!CONF_SIMPLE_MODE) {
console.log("Listening for tickets on " + TicketBrokerTargetAddr); console.log("Listening for tickets on " + TicketBrokerTargetAddr);
} }
/*
SMART CONTRACT EVENTS - SYNC OF MISSED BLOCKS
*/
// Syncs events database // Syncs events database
const syncEvents = function () { const syncEvents = function () {
console.log("Starting sync process for Bonding Manager events"); console.log("Starting sync process for Bonding Manager events");
@ -412,6 +431,30 @@ if (!isEventSyncing && !CONF_SIMPLE_MODE && !CONF_DISABLE_SYNC) {
handleSync(); 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 // Splits of raw CMC object into coin quote data
const parseCmc = async function () { const parseCmc = async function () {
try { 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 // Queries Alchemy for block info and gas fees
const parseL1Blockchain = async function () { const parseL1Blockchain = async function () {
const l1Wei = await web3layer1.eth.getGasPrice(); const l1Wei = await web3layer1.eth.getGasPrice();
@ -463,62 +542,6 @@ const parseEthBlockchain = async function () {
await Promise.all([parseL1Blockchain(), parseL2Blockchain()]); 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 // Exports gas fees and contract prices
apiRouter.get("/blockchains", async (req, res) => { apiRouter.get("/blockchains", async (req, res) => {
try { 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 THEGRAPH - ORCHESTRATOR
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);
}
});
// Gets info on a given Orchestrator // Gets info on a given Orchestrator
const parseOrchestrator = async function (reqAddr) { 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 // Gets info on a given Delegator
const parseDelegator = async function (reqAddr) { 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 // Export livepeer and eth coin prices and L1 Eth gas price
apiRouter.get("/prometheus/:orchAddr", async (req, res) => { 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 getEnsDomain = async function (addr) {
const now = new Date().getTime(); const now = new Date().getTime();
let wasInCache = false; let wasInCache = false;
@ -1093,17 +1165,18 @@ apiRouter.get("/getEnsInfo", async (req, res) => {
}); });
/*
3BOX DATA
*/
const getThreeBoxInfo = async function (addr) { const getThreeBoxInfo = async function (addr) {
const now = new Date().getTime(); const now = new Date().getTime();
let wasInCache = false;
// See if it is cached // See if it is cached
for (const thisAddr of threeboxCache) { for (const thisAddr of threeboxCache) {
if (thisAddr.address === addr) { if (thisAddr.address === addr) {
// Check timeout return thisAddr;
if (now - thisAddr.timestamp < CONF_TIMEOUT_ENS_INFO) {
return thisAddr;
}
wasInCache = true;
} }
} }
// Else get it and cache it // Else get it and cache it
@ -1124,18 +1197,8 @@ const getThreeBoxInfo = async function (addr) {
image: data.image, image: data.image,
timestamp: now timestamp: now
} }
if (wasInCache) { console.log("Caching new 3box info " + threeBoxObj.address + " @ " + threeBoxObj.timestamp);
for (var idx = 0; idx < threeboxCache.length; idx++) { threeboxCache.push(threeBoxObj);
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);
}
} catch (error) { } catch (error) {
console.error(error.message); 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 zeroPad = (num, places) => String(num).padStart(places, '0')
const getScoreAtMonthYear = async function (month, year) { 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 { RESERVED
res.send(delegatorCache);
} catch (err) { */
res.status(400).send(err);
}
});

View File

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

View File

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

View File

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