Compare commits

...

13 Commits

23 changed files with 171 additions and 162 deletions

View File

@ -2,7 +2,7 @@ module.exports = {
apps : [{ apps : [{
name : "backend", name : "backend",
script : "./src/index.js", script : "./src/index.js",
cwd : "/var/www/backend", cwd : "/var/www/nframe/backend",
env_production: { env_production: {
NODE_ENV: "production" NODE_ENV: "production"
}, },

View File

@ -14,22 +14,24 @@
"author": "Marco van Dijk", "author": "Marco van Dijk",
"license": "WTFPL", "license": "WTFPL",
"dependencies": { "dependencies": {
"@alch/alchemy-web3": "^1.2.4", "@alch/alchemy-web3": "^1.4.7",
"alchemy-api": "^1.3.3", "alchemy-api": "^1.3.3",
"alchemy-sdk": "^2.2.4",
"coinmarketcap-api": "^3.1.1", "coinmarketcap-api": "^3.1.1",
"connect-mongo": "^3.1.2", "connect-mongo": "^4.6.0",
"crypto-js": "^3.1.9-1", "connect-mongodb-session": "^3.1.1",
"esm": "^3.2.20", "crypto-js": "^4.1.1",
"ethers": "^5.6.1", "esm": "^3.2.25",
"ethers": "^5.7.2",
"express": "^4.17.1", "express": "^4.17.1",
"express-session": "^1.17.0", "express-session": "^1.17.0",
"graphql-request": "^4.0.0", "graphql-request": "^4.0.0",
"install": "^0.13.0", "install": "^0.13.0",
"joi": "^14.3.1", "joi": "^14.3.1",
"mongoose": "^5.12.3", "mongoose": "^6.8.0",
"npm": "^8.5.2", "npm": "^8.5.2",
"prom-client": "^14.0.1", "prom-client": "^14.1.0",
"web3": "^1.7.0" "web3": "^1.8.1"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^1.18.10" "nodemon": "^1.18.10"

View File

@ -8,9 +8,10 @@ export const {
SESS_SECRET = 'secret!session', SESS_SECRET = 'secret!session',
SESS_LIFETIME = (1000 * 60 * 60) * 24 * 365, SESS_LIFETIME = (1000 * 60 * 60) * 24 * 365,
API_CMC = "Coinmarketcap API key", API_CMC = "Coinmarketcap API key",
API_L1_HTTP = "ETH L1 HTTP API KEY", API_L1_HTTP = "ETH L1 HTTP API URL",
API_L2_HTTP = "ETH L2 HTTP API KEY", API_L2_HTTP = "ETH L2 HTTP API URL",
API_L2_WS = "ETH L2 WSS API KEY", API_L1_KEY = "ETH L1 HTTP API KEY",
API_L2_KEY = "ETH L@ HTTP API KEY",
CONF_DEFAULT_ORCH = "YOUR OWN ORCHESTRATORS PUBLIC ADDRESS", CONF_DEFAULT_ORCH = "YOUR OWN ORCHESTRATORS PUBLIC ADDRESS",
CONF_SIMPLE_MODE = false, CONF_SIMPLE_MODE = false,
CONF_TIMEOUT_CMC = 360000, CONF_TIMEOUT_CMC = 360000,

View File

@ -19,7 +19,7 @@ import TotalStakeDataPoint from "../models/TotalStakeDataPoint";
const apiRouter = express.Router(); const apiRouter = express.Router();
import { import {
API_CMC, API_L1_HTTP, API_L2_HTTP, API_CMC, API_L1_KEY, API_L2_KEY, API_L2_HTTP, API_L1_HTTP,
CONF_DEFAULT_ORCH, CONF_SIMPLE_MODE, CONF_TIMEOUT_CMC, CONF_DEFAULT_ORCH, CONF_SIMPLE_MODE, CONF_TIMEOUT_CMC,
CONF_TIMEOUT_ALCHEMY, CONF_TIMEOUT_LIVEPEER, CONF_TIMEOUT_ALCHEMY, CONF_TIMEOUT_LIVEPEER,
CONF_DISABLE_DB, CONF_DISABLE_CMC, CONF_TIMEOUT_ENS_DOMAIN, CONF_DISABLE_DB, CONF_DISABLE_CMC, CONF_TIMEOUT_ENS_DOMAIN,
@ -60,17 +60,21 @@ if (!CONF_DISABLE_CMC) {
} }
// Gets blockchain data // Gets blockchain data
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
console.log("Connecting to HTTP RPC's");
const web3layer1 = createAlchemyWeb3(API_L1_HTTP);
const web3layer2 = createAlchemyWeb3(API_L2_HTTP);
// ENS stuff TODO: CONF_DISABLE_ENS // ENS stuff TODO: CONF_DISABLE_ENS
const { ethers } = require("ethers"); const { ethers } = require("ethers");
const provider = new ethers.providers.JsonRpcProvider(API_L1_HTTP); const l1provider = new ethers.providers.JsonRpcProvider(API_L1_HTTP + API_L1_KEY);
// const l1provider = new ethers.providers.AlchemyProvider("mainnet", API_L1_KEY);
import { Network, Alchemy } from 'alchemy-sdk';
console.log("Connecting to HTTP RPC's");
const web3layer1 = new Alchemy({apiKey: API_L1_KEY, network: Network.ETH_MAINNET});
const web3layer2 = new Alchemy({apiKey: API_L2_KEY, network: Network.ARB_MAINNET});
// Smart contract event stuff // Smart contract event stuff
// https://arbiscan.io/address/0x35Bcf3c30594191d53231E4FF333E8A770453e40#events const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const deprWeb3main = createAlchemyWeb3(API_L1_HTTP + API_L1_KEY);
const deprWeb3 = createAlchemyWeb3(API_L2_HTTP + API_L2_KEY);
let BondingManagerTargetJson; let BondingManagerTargetJson;
let BondingManagerTargetAbi; let BondingManagerTargetAbi;
let BondingManagerProxyAddr; let BondingManagerProxyAddr;
@ -89,17 +93,17 @@ if (!CONF_SIMPLE_MODE) {
BondingManagerTargetJson = fs.readFileSync('src/abi/BondingManagerTarget.json'); BondingManagerTargetJson = fs.readFileSync('src/abi/BondingManagerTarget.json');
BondingManagerTargetAbi = JSON.parse(BondingManagerTargetJson); BondingManagerTargetAbi = JSON.parse(BondingManagerTargetJson);
BondingManagerProxyAddr = "0x35Bcf3c30594191d53231E4FF333E8A770453e40"; BondingManagerProxyAddr = "0x35Bcf3c30594191d53231E4FF333E8A770453e40";
bondingManagerContract = new web3layer2.eth.Contract(BondingManagerTargetAbi.abi, BondingManagerProxyAddr); bondingManagerContract = new deprWeb3.eth.Contract(BondingManagerTargetAbi.abi, BondingManagerProxyAddr);
// Listen for events on the ticket broker contract // Listen for events on the ticket broker contract
TicketBrokerTargetJson = fs.readFileSync('src/abi/TicketBrokerTarget.json'); TicketBrokerTargetJson = fs.readFileSync('src/abi/TicketBrokerTarget.json');
TicketBrokerTargetAbi = JSON.parse(TicketBrokerTargetJson); TicketBrokerTargetAbi = JSON.parse(TicketBrokerTargetJson);
TicketBrokerTargetAddr = "0xa8bB618B1520E284046F3dFc448851A1Ff26e41B"; TicketBrokerTargetAddr = "0xa8bB618B1520E284046F3dFc448851A1Ff26e41B";
ticketBrokerContract = new web3layer2.eth.Contract(TicketBrokerTargetAbi.abi, TicketBrokerTargetAddr); ticketBrokerContract = new deprWeb3.eth.Contract(TicketBrokerTargetAbi.abi, TicketBrokerTargetAddr);
// Listen for events on the rounds manager contract // Listen for events on the rounds manager contract
RoundsManagerTargetJson = fs.readFileSync('src/abi/RoundsManagerTarget.json'); RoundsManagerTargetJson = fs.readFileSync('src/abi/RoundsManagerTarget.json');
RoundsManagerTargetAbi = JSON.parse(RoundsManagerTargetJson); RoundsManagerTargetAbi = JSON.parse(RoundsManagerTargetJson);
RoundsManagerTargetAddr = "0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f"; RoundsManagerTargetAddr = "0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f";
roundsManagerContract = new web3layer2.eth.Contract(RoundsManagerTargetAbi.abi, RoundsManagerTargetAddr); roundsManagerContract = new deprWeb3.eth.Contract(RoundsManagerTargetAbi.abi, RoundsManagerTargetAddr);
} }
/* /*
@ -136,7 +140,7 @@ const getBlock = async function (blockNumber) {
} }
} }
// Else get it and cache it // Else get it and cache it
const thisBlock = await web3layer2.eth.getBlock(blockNumber); const thisBlock = await web3layer2.core.getBlock(blockNumber);
console.log("Caching new block " + thisBlock.number + " mined at " + thisBlock.timestamp); console.log("Caching new block " + thisBlock.number + " mined at " + thisBlock.timestamp);
const blockObj = { const blockObj = {
@ -216,14 +220,14 @@ let totalStakeDataPoint = [];
apiRouter.post("/getAllMonthlyStats", async (req, res) => { apiRouter.post("/getAllMonthlyStats", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasMonthlyStatRefresh[req.session.user.ip]) { if (alreadyHasMonthlyStatRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(monthlyStatCache); res.send(monthlyStatCache);
if (req.session.user.ip) { if (req.session.user && req.session.user.ip) {
alreadyHasMonthlyStatRefresh[req.session.user.ip] = true; alreadyHasMonthlyStatRefresh[req.session.user.ip] = true;
} }
} catch (err) { } catch (err) {
@ -250,17 +254,17 @@ apiRouter.get("/getAllTotalStakes", async (req, res) => {
apiRouter.post("/getAllUpdateEvents", async (req, res) => { apiRouter.post("/getAllUpdateEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasUpdateRefresh[req.session.user.ip]) { if (alreadyHasUpdateRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(updateEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasUpdateRefresh[req.session.user.ip] = true; alreadyHasUpdateRefresh[req.session.user.ip] = true;
} }
res.send(updateEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -269,17 +273,17 @@ apiRouter.post("/getAllUpdateEvents", async (req, res) => {
apiRouter.post("/getAllRewardEvents", async (req, res) => { apiRouter.post("/getAllRewardEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user &&req.session.user.ip) {
if (alreadyHasRewardRefresh[req.session.user.ip]) { if (alreadyHasRewardRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(rewardEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasRewardRefresh[req.session.user.ip] = true; alreadyHasRewardRefresh[req.session.user.ip] = true;
} }
res.send(rewardEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -288,17 +292,17 @@ apiRouter.post("/getAllRewardEvents", async (req, res) => {
apiRouter.post("/getAllClaimEvents", async (req, res) => { apiRouter.post("/getAllClaimEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasClaimRefresh[req.session.user.ip]) { if (alreadyHasClaimRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(claimEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasClaimRefresh[req.session.user.ip] = true; alreadyHasClaimRefresh[req.session.user.ip] = true;
} }
res.send(claimEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -307,17 +311,17 @@ apiRouter.post("/getAllClaimEvents", async (req, res) => {
apiRouter.post("/getAllWithdrawStakeEvents", async (req, res) => { apiRouter.post("/getAllWithdrawStakeEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasWithdrawStakeRefresh[req.session.user.ip]) { if (alreadyHasWithdrawStakeRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(withdrawStakeEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasWithdrawStakeRefresh[req.session.user.ip] = true; alreadyHasWithdrawStakeRefresh[req.session.user.ip] = true;
} }
res.send(withdrawStakeEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -326,17 +330,17 @@ apiRouter.post("/getAllWithdrawStakeEvents", async (req, res) => {
apiRouter.post("/getAllWithdrawFeesEvents", async (req, res) => { apiRouter.post("/getAllWithdrawFeesEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasWithdrawFeesRefresh[req.session.user.ip]) { if (alreadyHasWithdrawFeesRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(withdrawFeesEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasWithdrawFeesRefresh[req.session.user.ip] = true; alreadyHasWithdrawFeesRefresh[req.session.user.ip] = true;
} }
res.send(withdrawFeesEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -345,17 +349,17 @@ apiRouter.post("/getAllWithdrawFeesEvents", async (req, res) => {
apiRouter.post("/getAllTransferTicketEvents", async (req, res) => { apiRouter.post("/getAllTransferTicketEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasTransferTicketRefresh[req.session.user.ip]) { if (alreadyHasTransferTicketRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(transferTicketEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasTransferTicketRefresh[req.session.user.ip] = true; alreadyHasTransferTicketRefresh[req.session.user.ip] = true;
} }
res.send(transferTicketEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -364,17 +368,17 @@ apiRouter.post("/getAllTransferTicketEvents", async (req, res) => {
apiRouter.post("/getAllRedeemTicketEvents", async (req, res) => { apiRouter.post("/getAllRedeemTicketEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasRedeemTicketRefresh[req.session.user.ip]) { if (alreadyHasRedeemTicketRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(redeemTicketEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasRedeemTicketRefresh[req.session.user.ip] = true; alreadyHasRedeemTicketRefresh[req.session.user.ip] = true;
} }
res.send(redeemTicketEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -391,17 +395,17 @@ apiRouter.get("/getAllWinningTickets", async (req, res) => {
apiRouter.post("/getAllActivateEvents", async (req, res) => { apiRouter.post("/getAllActivateEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasActivateRefresh[req.session.user.ip]) { if (alreadyHasActivateRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(activateEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasActivateRefresh[req.session.user.ip] = true; alreadyHasActivateRefresh[req.session.user.ip] = true;
} }
res.send(activateEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -410,17 +414,17 @@ apiRouter.post("/getAllActivateEvents", async (req, res) => {
apiRouter.post("/getAllUnbondEvents", async (req, res) => { apiRouter.post("/getAllUnbondEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasUnbondRefresh[req.session.user.ip]) { if (alreadyHasUnbondRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(unbondEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasUnbondRefresh[req.session.user.ip] = true; alreadyHasUnbondRefresh[req.session.user.ip] = true;
} }
res.send(unbondEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -429,17 +433,17 @@ apiRouter.post("/getAllUnbondEvents", async (req, res) => {
apiRouter.post("/getAllStakeEvents", async (req, res) => { apiRouter.post("/getAllStakeEvents", async (req, res) => {
try { try {
const { smartUpdate } = req.body; const { smartUpdate } = req.body;
if (smartUpdate && req.session.user.ip) { if (smartUpdate && req.session.user && req.session.user.ip) {
if (alreadyHasStakeRefresh[req.session.user.ip]) { if (alreadyHasStakeRefresh[req.session.user.ip]) {
res.send({ noop: true }); res.send({ noop: true });
return; return;
} }
} }
res.send(stakeEventCache); if (req.session.user && req.session.user.ip) {
if (req.session.user.ip) {
alreadyHasAnyRefresh[req.session.user.ip] = true; alreadyHasAnyRefresh[req.session.user.ip] = true;
alreadyHasStakeRefresh[req.session.user.ip] = true; alreadyHasStakeRefresh[req.session.user.ip] = true;
} }
res.send(stakeEventCache);
} catch (err) { } catch (err) {
res.status(400).send(err); res.status(400).send(err);
} }
@ -447,7 +451,7 @@ apiRouter.post("/getAllStakeEvents", async (req, res) => {
apiRouter.get("/hasAnyRefresh", async (req, res) => { apiRouter.get("/hasAnyRefresh", async (req, res) => {
try { try {
if (req.session.user.ip) { if (req.session.user && req.session.user.ip) {
console.log(req.session.user.ip + " is checking for new Events"); console.log(req.session.user.ip + " is checking for new Events");
if (alreadyHasAnyRefresh[req.session.user.ip]) { if (alreadyHasAnyRefresh[req.session.user.ip]) {
console.log(req.session.user.ip + " is still up to date"); console.log(req.session.user.ip + " is still up to date");
@ -2044,12 +2048,12 @@ const handleSync = async function () {
console.log('Starting new sync cycle #' + cycle); console.log('Starting new sync cycle #' + cycle);
isSyncing = true; isSyncing = true;
// Get latest blocks in chain // Get latest blocks in chain
var latestBlock = await web3layer1.eth.getBlockNumber(); var latestBlock = await deprWeb3main.eth.getBlockNumber();
if (latestBlock > latestL1Block) { if (latestBlock > latestL1Block) {
latestL1Block = latestBlock; latestL1Block = latestBlock;
console.log("Latest L1 Eth block changed to " + latestL1Block); console.log("Latest L1 Eth block changed to " + latestL1Block);
} }
latestBlock = await web3layer2.eth.getBlockNumber(); latestBlock = await deprWeb3.eth.getBlockNumber();
if (latestBlock > latestBlockInChain) { if (latestBlock > latestBlockInChain) {
latestBlockInChain = latestBlock; latestBlockInChain = latestBlock;
console.log("Latest L2 Eth block changed to " + latestBlockInChain); console.log("Latest L2 Eth block changed to " + latestBlockInChain);
@ -2141,6 +2145,7 @@ const handleSync = async function () {
return; return;
} }
catch (err) { catch (err) {
console.log(err);
hasError = false; hasError = false;
console.log("Error while syncing. Retrying in 30 seconds"); console.log("Error while syncing. Retrying in 30 seconds");
console.log("latestBlockInChain " + latestBlockInChain); console.log("latestBlockInChain " + latestBlockInChain);
@ -2280,8 +2285,9 @@ let serviceUriFeeCostL2 = 0;
// 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(); try {
l1block = await web3layer1.eth.getBlockNumber(); const l1Wei = await deprWeb3main.eth.getGasPrice();
l1block = await deprWeb3main.eth.getBlockNumber();
l1Gwei = l1Wei / 1000000000; l1Gwei = l1Wei / 1000000000;
redeemRewardCostL1 = (redeemRewardGwei * l1Gwei) / 1000000000; redeemRewardCostL1 = (redeemRewardGwei * l1Gwei) / 1000000000;
claimTicketCostL1 = (claimTicketGwei * l1Gwei) / 1000000000; claimTicketCostL1 = (claimTicketGwei * l1Gwei) / 1000000000;
@ -2289,10 +2295,14 @@ const parseL1Blockchain = async function () {
stakeFeeCostL1 = (stakeFeeGwei * l1Gwei) / 1000000000; stakeFeeCostL1 = (stakeFeeGwei * l1Gwei) / 1000000000;
commissionFeeCostL1 = (commissionFeeGwei * l1Gwei) / 1000000000; commissionFeeCostL1 = (commissionFeeGwei * l1Gwei) / 1000000000;
serviceUriFeeCostL1 = (serviceUriFee * l1Gwei) / 1000000000; serviceUriFeeCostL1 = (serviceUriFee * l1Gwei) / 1000000000;
} catch (err) {
console.log(err);
}
} }
const parseL2Blockchain = async function () { const parseL2Blockchain = async function () {
const l2Wei = await web3layer2.eth.getGasPrice(); try {
l2block = await web3layer2.eth.getBlockNumber(); const l2Wei = await deprWeb3.eth.getGasPrice();
l2block = await deprWeb3.eth.getBlockNumber();
l2Gwei = l2Wei / 1000000000; l2Gwei = l2Wei / 1000000000;
redeemRewardCostL2 = (redeemRewardGwei * l2Gwei) / 1000000000; redeemRewardCostL2 = (redeemRewardGwei * l2Gwei) / 1000000000;
claimTicketCostL2 = (claimTicketGwei * l2Gwei) / 1000000000; claimTicketCostL2 = (claimTicketGwei * l2Gwei) / 1000000000;
@ -2300,10 +2310,17 @@ const parseL2Blockchain = async function () {
stakeFeeCostL2 = (stakeFeeGwei * l2Gwei) / 1000000000; stakeFeeCostL2 = (stakeFeeGwei * l2Gwei) / 1000000000;
commissionFeeCostL2 = (commissionFeeGwei * l2Gwei) / 1000000000; commissionFeeCostL2 = (commissionFeeGwei * l2Gwei) / 1000000000;
serviceUriFeeCostL2 = (serviceUriFee * l2Gwei) / 1000000000; serviceUriFeeCostL2 = (serviceUriFee * l2Gwei) / 1000000000;
} catch (err) {
console.log(err);
}
} }
const parseEthBlockchain = async function () { const parseEthBlockchain = async function () {
console.log("Getting new blockchain data"); console.log("Getting new blockchain data");
await Promise.all([parseL1Blockchain(), parseL2Blockchain()]); const l1Promise = parseL1Blockchain();
const l2Promise = parseL2Blockchain();
await Promise.all([l1Promise, l2Promise]);
console.log("done getting blockchain data");
} }
// Exports gas fees and contract prices // Exports gas fees and contract prices
@ -2840,8 +2857,8 @@ apiRouter.get("/grafana", async (req, res) => {
const now = new Date().getTime(); const now = new Date().getTime();
// Update blockchain data if the cached data has expired // Update blockchain data if the cached data has expired
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) { if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
await parseEthBlockchain(); arbGet = now;
arbGet = now; await parseEthBlockchain();
} }
// Update coin prices once their data has expired // Update coin prices once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) { if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
@ -2883,9 +2900,9 @@ apiRouter.get("/prometheus/:orchAddr", async (req, res) => {
const now = new Date().getTime(); const now = new Date().getTime();
// Update blockchain data if the cached data has expired // Update blockchain data if the cached data has expired
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) { if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
await parseEthBlockchain(); arbGet = now;
arbGet = now; await parseEthBlockchain();
} }
// Update coin prices once their data has expired // Update coin prices once their data has expired
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) { if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
await parseCmc(); await parseCmc();
@ -3061,7 +3078,7 @@ const getEnsDomain = async function (addr) {
} }
} }
// Else get it and cache it // Else get it and cache it
const ensDomain = await provider.lookupAddress(addr.toLowerCase()); const ensDomain = await l1provider.lookupAddress(addr.toLowerCase());
let ensObj; let ensObj;
if (!ensDomain) { if (!ensDomain) {
ensObj = { ensObj = {
@ -3106,7 +3123,7 @@ const getEnsInfo = async function (addr) {
} }
} }
// Else get it and cache it // Else get it and cache it
const resolver = await provider.getResolver(addr); const resolver = await l1provider.getResolver(addr);
const description = await resolver.getText("description"); const description = await resolver.getText("description");
const url = await resolver.getText("url"); const url = await resolver.getText("url");
const avatar = await resolver.getAvatar(); const avatar = await resolver.getAvatar();
@ -3284,4 +3301,4 @@ apiRouter.get("/getAllOrchScores", async (req, res) => {
}); });
export default apiRouter; export default apiRouter;

View File

@ -2,7 +2,7 @@
import express from 'express'; import express from 'express';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import session from "express-session"; import session from "express-session";
import connectStore from "connect-mongo"; import MongoStore from "connect-mongo";
import { userRouter, sessionRouter, livepeerRouter } from './routes/index'; import { userRouter, sessionRouter, livepeerRouter } from './routes/index';
import { import {
NODE_PORT, NODE_ENV, MONGO_URI, SESS_NAME, SESS_SECRET, NODE_PORT, NODE_ENV, MONGO_URI, SESS_NAME, SESS_SECRET,
@ -15,20 +15,22 @@ const { NODE_ENV: mode } = process.env;
(async () => { (async () => {
try { try {
// Make DB connection if needed // Make DB connection if needed
let clientP;
if (!CONF_SIMPLE_MODE && !CONF_DISABLE_DB){ if (!CONF_SIMPLE_MODE && !CONF_DISABLE_DB){
if (mode == "production"){ if (mode == "production"){
await mongoose.connect(MONGO_URI, { useNewUrlParser: true, useFindAndModify: false}); clientP = mongoose.connect(MONGO_URI, { useNewUrlParser: true}).then(m => m.connection.getClient());
}else if (mode == "development"){ }else if (mode == "development"){
await mongoose.connect(MONGO_URI_DEV, { useNewUrlParser: true, useFindAndModify: false}); clientP = mongoose.connect(MONGO_URI_DEV, { useNewUrlParser: true}).then(m => m.connection.getClient());
}else if (mode == "local"){ }else if (mode == "local"){
await mongoose.connect(MONGO_URI_LOCAL, { useNewUrlParser: true, useFindAndModify: false}); clientP = mongoose.connect(MONGO_URI_LOCAL, { useNewUrlParser: true}).then(m => m.connection.getClient());
}else{ }else{
await mongoose.connect(MONGO_URI, { useNewUrlParser: true, useFindAndModify: false}); clientP = mongoose.connect(MONGO_URI, { useNewUrlParser: true}).then(m => m.connection.getClient());
} }
console.log('MongoDB connected on ' + mode); console.log('MongoDB connected on ' + mode);
}else{ }else{
console.log('Running without a database connection' ); console.log('Running without a database connection' );
} }
// Web application framework // Web application framework
const app = express(); const app = express();
app.disable('x-powered-by'); app.disable('x-powered-by');
@ -36,19 +38,16 @@ const { NODE_ENV: mode } = process.env;
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
app.use(express.json()); app.use(express.json());
let MongoStore;
if (!CONF_SIMPLE_MODE && !CONF_DISABLE_DB){ if (!CONF_SIMPLE_MODE && !CONF_DISABLE_DB){
// Import session module
MongoStore = connectStore(session);
// Declare session data // Declare session data
app.use(session({ app.use(session({
name: SESS_NAME, name: SESS_NAME,
//TODO: change secret in config file //TODO: change secret in config file
secret: SESS_SECRET, secret: SESS_SECRET,
//define where to store them //define where to store them
store: new MongoStore({ store: MongoStore.create({
mongooseConnection: mongoose.connection, clientPromise: clientP,
collection: 'session', collectionName: 'session',
ttl: parseInt(SESS_LIFETIME) / 1000, ttl: parseInt(SESS_LIFETIME) / 1000,
}), }),
saveUninitialized: false, saveUninitialized: false,
@ -56,8 +55,8 @@ const { NODE_ENV: mode } = process.env;
resave: false, resave: false,
//cookie to send to users //cookie to send to users
cookie: { cookie: {
sameSite: true, sameSite: false,
secure: NODE_ENV === 'production', secure: false,
maxAge: parseInt(SESS_LIFETIME) maxAge: parseInt(SESS_LIFETIME)
} }
})); }));
@ -88,4 +87,4 @@ const { NODE_ENV: mode } = process.env;
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} }
})(); })();

View File

@ -3,31 +3,32 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@mantine/core": "^4.1.3", "@emotion/react": "^11.10.5",
"@mantine/dates": "^4.1.3", "@mantine/core": "^4.2.12",
"@mantine/form": "^4.1.3", "@mantine/dates": "^4.2.12",
"@mantine/hooks": "^4.1.3", "@mantine/form": "^4.2.12",
"@mantine/modals": "^4.1.3", "@mantine/hooks": "^4.2.12",
"@mantine/modals": "^4.2.12",
"@mantine/next": "^4.1.3", "@mantine/next": "^4.1.3",
"@mantine/notifications": "^4.1.3", "@mantine/notifications": "^4.2.12",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
"dayjs": "^1.11.1", "dayjs": "^1.11.7",
"ethers": "^5.4.4", "ethers": "^5.4.4",
"http": "^0.0.1-security", "http": "^0.0.1-security",
"https": "^1.0.0", "https": "^1.0.0",
"md5": "^2.3.0", "md5": "^2.3.0",
"react": "^17.0.2", "react": "^18.2.0",
"react-circular-progressbar": "^2.0.4", "react-circular-progressbar": "^2.0.4",
"react-dom": "^17.0.2", "react-dom": "^18.2.0",
"react-indiana-drag-scroll": "^2.1.0", "react-indiana-drag-scroll": "^2.1.0",
"react-markdown": "^7.1.1", "react-markdown": "^7.1.1",
"react-paginate": "^8.1.2", "react-paginate": "^8.1.2",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"react-retro-hit-counter": "^1.0.1", "react-retro-hit-counter": "^1.0.1",
"react-router-dom": "^6.0.2", "react-router-dom": "^6.0.2",
"react-scripts": "3.2.0", "react-scripts": "^5.0.1",
"redux": "^4.1.2", "redux": "^4.1.2",
"redux-thunk": "^2.4.1", "redux-thunk": "^2.4.1",
"styled-components": "^5.3.3", "styled-components": "^5.3.3",

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
public/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@ -2,16 +2,16 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#855dfe" /> <meta name="theme-color" content="#855dfe" />
<meta <meta
name="LivepeerEvents" name="LivepeerEvents"
content="marco@stronk.tech" content="marco@stronk.rocks"
/> />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Livepeer Supplementary Explorer</title> <title>Livepeer Supplementary Explorer</title>
<meta name="title" content="Captain Chad's supplementary explorer for Livepeer" /> <meta name="title" content="Captain Stronk's supplementary explorer for Livepeer" />
<meta name="description" content="Frontend + API which aggregates and caches in one central location: coin prices, blockchain data, ENS data, Livepeer smart contract events and monthly statistics. Also contains statistics for the Captain Chad orchestrator on the Livepeer network" /> <meta name="description" content="Frontend + API which aggregates and caches in one central location: coin prices, blockchain data, ENS data, Livepeer smart contract events and monthly statistics. Also contains statistics for the Captain Chad orchestrator on the Livepeer network" />
</head> </head>
<body> <body>

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 KiB

View File

@ -1,10 +1,10 @@
{ {
"short_name": "LivepeerEvents", "short_name": "LivepeerEvents",
"name": "nframe.nl", "name": "stronk.rocks",
"icons": [ "icons": [
{ {
"src": "favicon.png", "src": "favicon.ico",
"type": "image/png" "type": "image/x-icon"
} }
], ],
"start_url": ".", "start_url": ".",

View File

@ -107,8 +107,8 @@ const EventButtonAddress = (obj) => {
// Hardcoded Chad substitution // Hardcoded Chad substitution
if (thisAvatar == "" && orchInfo.avatar){ if (thisAvatar == "" && orchInfo.avatar){
let thisUrl = orchInfo.avatar.url; let thisUrl = orchInfo.avatar.url;
if (thisUrl == "https://nframe.nl/avatar.png"){ if (thisUrl == "https://stronk.rocks/avatar.png"){
thisUrl = "https://nframe.nl/avatar.png?" + performance.now(); thisUrl = "https://stronk.rocks/avatar.png?" + performance.now();
} }
setAvatar(thisUrl); setAvatar(thisUrl);
} }

View File

@ -34,25 +34,25 @@ const ScoreView = (obj) => {
<h4>Success</h4> <h4>Success</h4>
</div> </div>
<div className="row"> <div className="row">
{(obj.score["FRA"].success_rate * 10).toFixed(1)} {(obj.score["FRA"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LAX"].success_rate * 10).toFixed(1)} {(obj.score["LAX"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LON"].success_rate * 10).toFixed(1)} {(obj.score["LON"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["MDW"].success_rate * 10).toFixed(1)} {(obj.score["MDW"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["NYC"].success_rate * 10).toFixed(1)} {(obj.score["NYC"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["PRG"].success_rate * 10).toFixed(1)} {(obj.score["PRG"]?.success_rate * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["SIN"].success_rate * 10).toFixed(1)} {(obj.score["SIN"]?.success_rate * 10).toFixed(1)}
</div> </div>
</div> </div>
<div className="stroke"> <div className="stroke">
@ -60,25 +60,25 @@ const ScoreView = (obj) => {
<h4>Speed</h4> <h4>Speed</h4>
</div> </div>
<div className="row"> <div className="row">
{(obj.score["FRA"].round_trip_score * 10).toFixed(1)} {(obj.score["FRA"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LAX"].round_trip_score * 10).toFixed(1)} {(obj.score["LAX"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LON"].round_trip_score * 10).toFixed(1)} {(obj.score["LON"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["MDW"].round_trip_score * 10).toFixed(1)} {(obj.score["MDW"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["NYC"].round_trip_score * 10).toFixed(1)} {(obj.score["NYC"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["PRG"].round_trip_score * 10).toFixed(1)} {(obj.score["PRG"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["SIN"].round_trip_score * 10).toFixed(1)} {(obj.score["SIN"]?.round_trip_score * 10).toFixed(1)}
</div> </div>
</div> </div>
<div className="stroke"> <div className="stroke">
@ -86,25 +86,25 @@ const ScoreView = (obj) => {
<h4>Score</h4> <h4>Score</h4>
</div> </div>
<div className="row"> <div className="row">
{(obj.score["FRA"].score * 10).toFixed(1)} {(obj.score["FRA"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LAX"].score * 10).toFixed(1)} {(obj.score["LAX"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["LON"].score * 10).toFixed(1)} {(obj.score["LON"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["MDW"].score * 10).toFixed(1)} {(obj.score["MDW"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["NYC"].score * 10).toFixed(1)} {(obj.score["NYC"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["PRG"].score * 10).toFixed(1)} {(obj.score["PRG"]?.score * 10).toFixed(1)}
</div> </div>
<div className="row"> <div className="row">
{(obj.score["SIN"].score * 10).toFixed(1)} {(obj.score["SIN"]?.score * 10).toFixed(1)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -19,7 +19,7 @@ const Grafana = (obj) => {
if (thisChad == ""){ if (thisChad == ""){
const randomChad = performance.now(); const randomChad = performance.now();
const chadSource = "https://nframe.nl/avatar.png?" + randomChad; const chadSource = "https://stronk.rocks/avatar.png?" + randomChad;
setChad(chadSource); setChad(chadSource);
} }
@ -30,7 +30,7 @@ const Grafana = (obj) => {
<button className="homeButton" onClick={() => { <button className="homeButton" onClick={() => {
setRedirectToHome(true); setRedirectToHome(true);
}}> }}>
<div style={{fontSize: '4em'}}>🏠</div> <img alt="" src="android-chrome-512x512.png" width="100em" style={{ zIndex: 10 }} />
</button> </button>
</div> </div>
<div className="verticalDivider" /> <div className="verticalDivider" />
@ -57,7 +57,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -75,7 +75,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -84,7 +84,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -96,7 +96,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -108,7 +108,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -120,7 +120,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
<div className="flexContainer stretchAndPad"> <div className="flexContainer stretchAndPad">
@ -132,7 +132,7 @@ const Grafana = (obj) => {
<div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}> <div className="row" style={{ width: 'unset', marginTop: '1em', marginBottom: '1em' }}>
<a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} > <a className="selectOrch" style={{ padding: '0.2em', cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/0x847791cbf03be716a7fe9dc8c9affe17bd49ae5e/delegating"} >
<img alt="" src="livepeer.png" width="20em" height="20em" /> <img alt="" src="livepeer.png" width="20em" height="20em" />
<span className="lightTextAlt">Stake with captain-chad.eth</span> <span className="lightTextAlt">Stake with captain-stronk.eth</span>
</a> </a>
</div> </div>
</div> </div>

View File

@ -39,7 +39,7 @@ const Home = (obj) => {
if (thisChad == ""){ if (thisChad == ""){
const randomChad = performance.now(); const randomChad = performance.now();
const chadSource = "https://nframe.nl/avatar.png?" + randomChad; const chadSource = "https://stronk.rocks/avatar.png?" + randomChad;
setChad(chadSource); setChad(chadSource);
} }
@ -47,7 +47,7 @@ const Home = (obj) => {
<div className="stroke"> <div className="stroke">
<div className="verticalDivider" /> <div className="verticalDivider" />
<div className="row"> <div className="row">
<img alt="" src="livepeer.png" width="100em" height="100em" style={{ zIndex: 10 }} /> <img alt="" src="android-chrome-512x512.png" width="100em" style={{ zIndex: 10 }} />
</div> </div>
<div className="verticalDivider" /> <div className="verticalDivider" />
<div className="stroke roundedOpaque" style={{ maxWidth: '400px' }}> <div className="stroke roundedOpaque" style={{ maxWidth: '400px' }}>
@ -90,6 +90,14 @@ const Home = (obj) => {
<div className="row"> <div className="row">
<p>External Links:</p> <p>External Links:</p>
</div> </div>
<a href="https://forum.livepeer.org/t/transcoder-campaign-captain-stronk">
<button className="waveButton">
<div className="row">
<img alt="" src="livepeer.png" width="20em" height="20em" style={{ margin: 0 }} />
<p style={{ padding: '0.3em', flex: 1, flexGrow: 3 }}>Transcoder Campaign</p>
</div>
</button>
</a>
<a href="https://github.com/stronk-dev/LivepeerEvents"> <a href="https://github.com/stronk-dev/LivepeerEvents">
<button className="waveButton"> <button className="waveButton">
<div className="row"> <div className="row">
@ -123,26 +131,6 @@ const Home = (obj) => {
</button> </button>
</a> </a>
<div className="verticalDivider" /> <div className="verticalDivider" />
<div className="row">
<p>Contact me on:</p>
</div>
<a href="https://discordapp.com/users/303504235927044097">
<button className="waveButton">
<div className="row">
<img alt="" src="discord.svg" width="20em" height="20em" style={{ margin: 0 }} />
<p style={{ padding: '0.3em', flex: 1, flexGrow: 3 }}>Discord</p>
</div>
</button>
</a>
<a href="mailto:marco@livepeer.org">
<button className="waveButton">
<div className="row">
<img alt="" src="email.png" width="20em" height="20em" style={{ margin: 0 }} />
<p style={{ padding: '0.3em', flex: 1, flexGrow: 3 }}>Email</p>
</div>
</button>
</a>
<div className="verticalDivider" />
<div className="row"> <div className="row">
<ContractPrices quotes={livepeer.quotes} blockchains={livepeer.blockchains} /> <ContractPrices quotes={livepeer.quotes} blockchains={livepeer.blockchains} />
</div> </div>
@ -175,7 +163,7 @@ const Home = (obj) => {
/> />
</div> </div>
<h6 className="lightText"> <h6 className="lightText">
nframe.nl stronk.rocks
</h6> </h6>
</div> </div>
</div> </div>

View File

@ -49,7 +49,7 @@ const Livepeer = (obj) => {
if (thisChad == ""){ if (thisChad == ""){
const randomChad = performance.now(); const randomChad = performance.now();
const chadSource = "https://nframe.nl/avatar.png?" + randomChad; const chadSource = "https://stronk.rocks/avatar.png?" + randomChad;
setChad(chadSource); setChad(chadSource);
} }
@ -61,9 +61,8 @@ const Livepeer = (obj) => {
setRedirectToHome(true); setRedirectToHome(true);
}}> }}>
<div className="row"> <div className="row">
<img alt="" src={thisChad} width="40em" height="40em" /> <img alt="" src="apple-touch-icon.png" width="40em" height="40em" />
</div> </div>
<h1>🏠</h1>
</button> </button>
<h4 className="rowAlignLeft withWrap showNeverOnMobile">{headerString}</h4> <h4 className="rowAlignLeft withWrap showNeverOnMobile">{headerString}</h4>
</div> </div>

View File

@ -175,7 +175,9 @@ const Stats = (obj) => {
<button className="homeButton" onClick={() => { <button className="homeButton" onClick={() => {
setRedirectToHome(true); setRedirectToHome(true);
}}> }}>
<h1>🏠</h1> <div className="row">
<img alt="" src="apple-touch-icon.png" width="40em" height="40em" />
</div>
</button> </button>
<h4 className="rowAlignLeft withWrap showNeverOnMobile">Statistics</h4> <h4 className="rowAlignLeft withWrap showNeverOnMobile">Statistics</h4>
</div> </div>

View File

@ -29,7 +29,7 @@ body {
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
background-image: url("/background.jpg"); background-image: url("../public/background.jpg");
background-repeat: no-repeat center center fixed; background-repeat: no-repeat center center fixed;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
@ -750,4 +750,4 @@ svg {
.main-container { .main-container {
height: calc(100vh - 60px); height: calc(100vh - 60px);
} }
} }