mirror of
https://github.com/stronk-dev/LivepeerEvents.git
synced 2025-07-05 18:55:09 +02:00
ENS support and other stuff
This commit is contained in:
parent
8dc1d2b2c0
commit
114147cdcd
@ -20,6 +20,7 @@
|
|||||||
"connect-mongo": "^3.1.2",
|
"connect-mongo": "^3.1.2",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
"esm": "^3.2.20",
|
"esm": "^3.2.20",
|
||||||
|
"ethers": "^5.6.1",
|
||||||
"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",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
//Server configuration variables
|
|
||||||
export const {
|
export const {
|
||||||
NODE_PORT = 42609,
|
NODE_PORT = 42609,
|
||||||
NODE_ENV = 'local',
|
NODE_ENV = 'local',
|
||||||
@ -17,7 +16,10 @@ export const {
|
|||||||
CONF_TIMEOUT_CMC = 360000,
|
CONF_TIMEOUT_CMC = 360000,
|
||||||
CONF_TIMEOUT_ALCHEMY = 2000,
|
CONF_TIMEOUT_ALCHEMY = 2000,
|
||||||
CONF_TIMEOUT_LIVEPEER = 60000,
|
CONF_TIMEOUT_LIVEPEER = 60000,
|
||||||
|
CONF_TIMEOUT_ENS_DOMAIN = 86400000,
|
||||||
|
CONF_TIMEOUT_ENS_INFO = 3600000,
|
||||||
CONF_DISABLE_SYNC = false,
|
CONF_DISABLE_SYNC = false,
|
||||||
CONF_DISABLE_DB = false,
|
CONF_DISABLE_DB = false,
|
||||||
CONF_DISABLE_CMC = false
|
CONF_DISABLE_CMC = false,
|
||||||
|
CONF_DISABLE_ENS = false
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
@ -8,9 +8,10 @@ import {
|
|||||||
API_CMC, API_L1_HTTP, API_L2_HTTP, API_L2_WS,
|
API_CMC, API_L1_HTTP, API_L2_HTTP, API_L2_WS,
|
||||||
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_DISABLE_SYNC,
|
CONF_TIMEOUT_ALCHEMY, CONF_TIMEOUT_LIVEPEER, CONF_DISABLE_SYNC,
|
||||||
CONF_DISABLE_DB,
|
CONF_DISABLE_DB, CONF_DISABLE_CMC, CONF_TIMEOUT_ENS_DOMAIN,
|
||||||
CONF_DISABLE_CMC
|
CONF_TIMEOUT_ENS_INFO, CONF_DISABLE_ENS
|
||||||
} from "../config";
|
} from "../config";
|
||||||
|
|
||||||
// Do API requests to other API's
|
// Do API requests to other API's
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
// Read ABI files
|
// Read ABI files
|
||||||
@ -45,8 +46,14 @@ if (!CONF_SIMPLE_MODE) {
|
|||||||
}
|
}
|
||||||
// For listening to blockchain events
|
// For listening to blockchain events
|
||||||
|
|
||||||
|
// ENS stuff TODO: CONF_DISABLE_ENS
|
||||||
|
const { ethers } = require("ethers");
|
||||||
|
const provider = new ethers.providers.JsonRpcProvider(API_L1_HTTP);
|
||||||
|
// const ens = new ENS({ provider: web3layer1, ensAddress: getEnsAddress('1') });
|
||||||
|
let ensDomainCache = [];
|
||||||
|
let ensInfoCache = [];
|
||||||
|
|
||||||
// Update CoinMarketCap related api calls every 5 minutes
|
// Update CoinMarketCap related api calls every 5 minutes
|
||||||
const timeoutCMC = CONF_TIMEOUT_CMC;
|
|
||||||
let cmcPriceGet = 0;
|
let cmcPriceGet = 0;
|
||||||
let ethPrice = 0;
|
let ethPrice = 0;
|
||||||
let lptPrice = 0;
|
let lptPrice = 0;
|
||||||
@ -54,7 +61,6 @@ let cmcQuotes = {};
|
|||||||
let cmcCache = {};
|
let cmcCache = {};
|
||||||
|
|
||||||
// Update Alchemy related API calls every 2 seconds
|
// Update Alchemy related API calls every 2 seconds
|
||||||
const timeoutAlchemy = CONF_TIMEOUT_ALCHEMY;
|
|
||||||
let l2Gwei = 0;
|
let l2Gwei = 0;
|
||||||
let l1Gwei = 0;
|
let l1Gwei = 0;
|
||||||
let l2block = 0;
|
let l2block = 0;
|
||||||
@ -82,8 +88,6 @@ let commissionFeeCostL2 = 0;
|
|||||||
let serviceUriFeeCostL1 = 0;
|
let serviceUriFeeCostL1 = 0;
|
||||||
let serviceUriFeeCostL2 = 0;
|
let serviceUriFeeCostL2 = 0;
|
||||||
|
|
||||||
// Update O info from thegraph every 1 minute
|
|
||||||
const timeoutTheGraph = CONF_TIMEOUT_LIVEPEER;
|
|
||||||
// Will contain addr, lastGet, and obj of any requested O's
|
// Will contain addr, lastGet, and obj of any requested O's
|
||||||
let orchestratorCache = [];
|
let orchestratorCache = [];
|
||||||
// Contains delegator addr and the address of the O they are bounded to
|
// Contains delegator addr and the address of the O they are bounded to
|
||||||
@ -461,12 +465,12 @@ apiRouter.get("/grafana", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
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 > timeoutAlchemy) {
|
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
|
||||||
await parseEthBlockchain();
|
await parseEthBlockchain();
|
||||||
arbGet = now;
|
arbGet = now;
|
||||||
}
|
}
|
||||||
// Update coin prices once their data has expired
|
// Update coin prices once their data has expired
|
||||||
if (now - cmcPriceGet > timeoutCMC) {
|
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
|
||||||
await parseCmc();
|
await parseCmc();
|
||||||
cmcPriceGet = now;
|
cmcPriceGet = now;
|
||||||
}
|
}
|
||||||
@ -502,7 +506,7 @@ apiRouter.get("/cmc", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
// Update cmc once their data has expired
|
// Update cmc once their data has expired
|
||||||
if (now - cmcPriceGet > timeoutCMC) {
|
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
|
||||||
cmcPriceGet = now;
|
cmcPriceGet = now;
|
||||||
await parseCmc();
|
await parseCmc();
|
||||||
}
|
}
|
||||||
@ -517,7 +521,7 @@ apiRouter.get("/blockchains", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
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 > timeoutAlchemy) {
|
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
|
||||||
arbGet = now;
|
arbGet = now;
|
||||||
await parseEthBlockchain();
|
await parseEthBlockchain();
|
||||||
}
|
}
|
||||||
@ -551,7 +555,7 @@ apiRouter.get("/quotes", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
// Update cmc once their data has expired
|
// Update cmc once their data has expired
|
||||||
if (now - cmcPriceGet > timeoutCMC) {
|
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
|
||||||
cmcPriceGet = now;
|
cmcPriceGet = now;
|
||||||
await parseCmc();
|
await parseCmc();
|
||||||
}
|
}
|
||||||
@ -596,17 +600,18 @@ const parseOrchestrator = async function (reqAddr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wasCached) {
|
if (wasCached) {
|
||||||
if (now - orchestratorObj.lastGet < timeoutTheGraph) {
|
if (now - orchestratorObj.lastGet < CONF_TIMEOUT_LIVEPEER) {
|
||||||
needsUpdate = false;
|
needsUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!wasCached || needsUpdate) {
|
if (!wasCached || needsUpdate) {
|
||||||
const orchQuery = gql`{
|
const orchQuery = gql`{
|
||||||
transcoders(where: {id: "${reqAddr}"}) {
|
transcoder(id: "${reqAddr}") {
|
||||||
id
|
id
|
||||||
activationRound
|
activationRound
|
||||||
deactivationRound
|
deactivationRound
|
||||||
active
|
active
|
||||||
|
status
|
||||||
lastRewardRound {
|
lastRewardRound {
|
||||||
id
|
id
|
||||||
length
|
length
|
||||||
@ -629,7 +634,7 @@ const parseOrchestrator = async function (reqAddr) {
|
|||||||
totalVolumeETH
|
totalVolumeETH
|
||||||
totalVolumeUSD
|
totalVolumeUSD
|
||||||
serviceURI
|
serviceURI
|
||||||
delegators {
|
delegators(first: 1000) {
|
||||||
id
|
id
|
||||||
bondedAmount
|
bondedAmount
|
||||||
startRound
|
startRound
|
||||||
@ -643,20 +648,22 @@ const parseOrchestrator = async function (reqAddr) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
orchestratorObj = await request("https://api.thegraph.com/subgraphs/name/livepeer/arbitrum-one", orchQuery);
|
orchestratorObj = await request("https://api.thegraph.com/subgraphs/name/livepeer/arbitrum-one", orchQuery);
|
||||||
orchestratorObj = orchestratorObj.transcoders[0];
|
orchestratorObj = orchestratorObj.transcoder;
|
||||||
// Not found
|
// Not found
|
||||||
if (!orchestratorObj) {
|
if (!orchestratorObj) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
orchestratorObj.lastGet = now;
|
orchestratorObj.lastGet = now;
|
||||||
if (wasCached) {
|
if (wasCached) {
|
||||||
for (var orch of orchestratorCache) {
|
for (var idx = 0; idx < orchestratorCache.length; idx++) {
|
||||||
if (orch.id == reqAddr) {
|
if (orchestratorCache[idx].id == reqAddr) {
|
||||||
orch = orchestratorObj;
|
console.log("Updating outdated orchestrator " + orchestratorObj.id + " @ " + now);
|
||||||
|
orchestratorCache[idx] = orchestratorObj;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
console.log("Pushing new orchestrator " + orchestratorObj.id + " @ " + now);
|
||||||
orchestratorCache.push(orchestratorObj);
|
orchestratorCache.push(orchestratorObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +721,7 @@ const parseDelegator = async function (reqAddr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wasCached) {
|
if (wasCached) {
|
||||||
if (now - delegatorObj.lastGet < timeoutTheGraph) {
|
if (now - delegatorObj.lastGet < CONF_TIMEOUT_LIVEPEER) {
|
||||||
needsUpdate = false;
|
needsUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -738,13 +745,15 @@ const parseDelegator = async function (reqAddr) {
|
|||||||
}
|
}
|
||||||
delegatorObj.lastGet = now;
|
delegatorObj.lastGet = now;
|
||||||
if (wasCached) {
|
if (wasCached) {
|
||||||
for (var delegator of delegatorCache) {
|
for (var idx = 0; idx < delegatorCache.length; idx++) {
|
||||||
if (delegator.id == reqAddr) {
|
if (delegatorCache[idx].id == reqAddr) {
|
||||||
delegator = delegatorObj;
|
console.log("Updating outdated delegator " + delegatorObj.id + " @ " + now);
|
||||||
|
delegatorCache[idx] = delegatorObj;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
console.log("Pushing new delegator " + delegatorObj.id + " @ " + now);
|
||||||
delegatorCache.push(delegatorObj);
|
delegatorCache.push(delegatorObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -804,12 +813,12 @@ apiRouter.get("/prometheus/:orchAddr", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
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 > timeoutAlchemy) {
|
if (now - arbGet > CONF_TIMEOUT_ALCHEMY) {
|
||||||
await parseEthBlockchain();
|
await parseEthBlockchain();
|
||||||
arbGet = now;
|
arbGet = now;
|
||||||
}
|
}
|
||||||
// Update coin prices once their data has expired
|
// Update coin prices once their data has expired
|
||||||
if (now - cmcPriceGet > timeoutCMC) {
|
if (now - cmcPriceGet > CONF_TIMEOUT_CMC) {
|
||||||
await parseCmc();
|
await parseCmc();
|
||||||
cmcPriceGet = now;
|
cmcPriceGet = now;
|
||||||
}
|
}
|
||||||
@ -950,4 +959,121 @@ apiRouter.get("/prometheus/:orchAddr", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getEnsDomain = async function (addr) {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
let wasInCache = false;
|
||||||
|
// See if it is cached
|
||||||
|
for (const thisAddr of ensDomainCache) {
|
||||||
|
if (thisAddr.address === addr) {
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < CONF_TIMEOUT_ENS_DOMAIN ){
|
||||||
|
return thisAddr.domain;
|
||||||
|
}
|
||||||
|
wasInCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Else get it and cache it
|
||||||
|
const ensDomain = await provider.lookupAddress(addr.toLowerCase());
|
||||||
|
let ensObj;
|
||||||
|
if (!ensDomain){
|
||||||
|
ensObj = {
|
||||||
|
domain: null,
|
||||||
|
address: addr,
|
||||||
|
timestamp: now
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ensObj = {
|
||||||
|
domain: ensDomain,
|
||||||
|
address: addr,
|
||||||
|
timestamp: now
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (wasInCache){
|
||||||
|
for (var idx = 0; idx < ensDomainCache.length; idx++) {
|
||||||
|
if (ensDomainCache[idx].address == addr) {
|
||||||
|
console.log("Updating outdated domain " + ensObj.domain + " owned by " + ensObj.address + " @ " + ensObj.timestamp);
|
||||||
|
ensDomainCache[idx] = ensObj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Caching new domain " + ensObj.domain + " owned by " + ensObj.address + " @ " + ensObj.timestamp);
|
||||||
|
ensDomainCache.push(ensObj);
|
||||||
|
}
|
||||||
|
return ensObj.domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEnsInfo = async function (addr) {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
let wasInCache = false;
|
||||||
|
// See if it is cached
|
||||||
|
for (const thisAddr of ensInfoCache) {
|
||||||
|
if (thisAddr.domain === addr) {
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < CONF_TIMEOUT_ENS_INFO ){
|
||||||
|
return thisAddr;
|
||||||
|
}
|
||||||
|
wasInCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Else get it and cache it
|
||||||
|
const resolver = await provider.getResolver(addr);
|
||||||
|
const description = await resolver.getText("description");
|
||||||
|
const url = await resolver.getText("url");
|
||||||
|
const avatar = await resolver.getAvatar();
|
||||||
|
const ensObj = {
|
||||||
|
domain: addr,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
avatar,
|
||||||
|
timestamp: now
|
||||||
|
};
|
||||||
|
if (wasInCache){
|
||||||
|
for (var idx = 0; idx < ensInfoCache.length; idx++) {
|
||||||
|
if (ensInfoCache[idx].domain == addr) {
|
||||||
|
console.log("Updating outdated info " + ensObj.domain + " @ " + ensObj.timestamp);
|
||||||
|
ensInfoCache[idx] = ensObj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Caching new info " + ensObj.domain + " @ " + ensObj.timestamp);
|
||||||
|
ensInfoCache.push(ensObj);
|
||||||
|
}
|
||||||
|
return ensObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets and caches info for a single address
|
||||||
|
apiRouter.get("/getENS/:orch", async (req, res) => {
|
||||||
|
try {
|
||||||
|
// First resolve addr => domain name
|
||||||
|
const ensDomain = await getEnsDomain(req.params.orch);
|
||||||
|
if (!ensDomain){
|
||||||
|
res.send({domain: null});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Then resolve address to info
|
||||||
|
const ensInfo = await getEnsInfo(ensDomain);
|
||||||
|
res.send(ensInfo);
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).send(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Returns entire ENS domain mapping cache
|
||||||
|
apiRouter.get("/getEnsDomains", async (req, res) => {
|
||||||
|
try {
|
||||||
|
res.send(ensDomainCache);
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).send(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Returns entire ENS info mapping cache
|
||||||
|
apiRouter.get("/getEnsInfo", async (req, res) => {
|
||||||
|
try {
|
||||||
|
res.send(ensInfoCache);
|
||||||
|
} catch (err) {
|
||||||
|
res.status(400).send(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default apiRouter;
|
export default apiRouter;
|
BIN
public/ens.png
Normal file
BIN
public/ens.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
@ -24,6 +24,8 @@ export const RECEIVE_CURRENT_ORCHESTRATOR = "RECEIVE_CURRENT_ORCHESTRATOR";
|
|||||||
export const RECEIVE_ORCHESTRATOR = "RECEIVE_ORCHESTRATOR";
|
export const RECEIVE_ORCHESTRATOR = "RECEIVE_ORCHESTRATOR";
|
||||||
export const CLEAR_ORCHESTRATOR = "CLEAR_ORCHESTRATOR";
|
export const CLEAR_ORCHESTRATOR = "CLEAR_ORCHESTRATOR";
|
||||||
export const RECEIVE_TICKETS = "RECEIVE_TICKETS";
|
export const RECEIVE_TICKETS = "RECEIVE_TICKETS";
|
||||||
|
export const SET_ALL_ENS_INFO = "SET_ALL_ENS_INFO";
|
||||||
|
export const SET_ALL_ENS_DOMAINS = "SET_ALL_ENS_DOMAINS";
|
||||||
|
|
||||||
const setQuotes = message => ({
|
const setQuotes = message => ({
|
||||||
type: RECEIVE_QUOTES, message
|
type: RECEIVE_QUOTES, message
|
||||||
@ -46,6 +48,13 @@ const clearOrchestratorInfo = () => ({
|
|||||||
const setTickets = message => ({
|
const setTickets = message => ({
|
||||||
type: RECEIVE_TICKETS, message
|
type: RECEIVE_TICKETS, message
|
||||||
});
|
});
|
||||||
|
const setAllEnsInfo = message => ({
|
||||||
|
type: SET_ALL_ENS_INFO, message
|
||||||
|
});
|
||||||
|
const setAllEnsDomains = message => ({
|
||||||
|
type: SET_ALL_ENS_DOMAINS, message
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
export const getQuotes = () => async dispatch => {
|
export const getQuotes = () => async dispatch => {
|
||||||
const response = await apiUtil.getQuotes();
|
const response = await apiUtil.getQuotes();
|
||||||
@ -523,3 +532,27 @@ export const getOrchestratorInfo = (orchAddr) => async dispatch => {
|
|||||||
export const clearOrchestrator = () => async dispatch => {
|
export const clearOrchestrator = () => async dispatch => {
|
||||||
return dispatch(clearOrchestratorInfo({}));
|
return dispatch(clearOrchestratorInfo({}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAllEnsDomains = () => async dispatch => {
|
||||||
|
const response = await apiUtil.getAllEnsDomains();
|
||||||
|
const data = await response.json();
|
||||||
|
if (response.ok) {
|
||||||
|
return dispatch(setAllEnsDomains(data));
|
||||||
|
}
|
||||||
|
return dispatch(receiveErrors(data));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllEnsInfo = () => async dispatch => {
|
||||||
|
const response = await apiUtil.getAllEnsInfo();
|
||||||
|
const data = await response.json();
|
||||||
|
if (response.ok) {
|
||||||
|
return dispatch(setAllEnsInfo(data));
|
||||||
|
}
|
||||||
|
return dispatch(receiveErrors(data));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getEnsInfo = async (addr) => {
|
||||||
|
const response = await apiUtil.getEnsInfo(addr);
|
||||||
|
const data = await response.json();
|
||||||
|
};
|
||||||
|
|
@ -1,14 +1,94 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { getEnsInfo } from "../actions/livepeer";
|
||||||
|
import {
|
||||||
|
getOrchestratorInfo
|
||||||
|
} from "../actions/livepeer";
|
||||||
|
|
||||||
const Address = (obj) => {
|
const Address = (obj) => {
|
||||||
|
const livepeer = useSelector((state) => state.livepeerstate);
|
||||||
|
const [hasRefreshed, setRefresh] = useState(false);
|
||||||
|
let thisDomain = null;
|
||||||
|
let thisInfo = null;
|
||||||
|
const now = new Date().getTime();
|
||||||
|
// Lookup domain in cache
|
||||||
|
if (livepeer.ensDomainMapping){
|
||||||
|
for (const thisAddr of livepeer.ensDomainMapping) {
|
||||||
|
if (thisAddr.address === obj.address) {
|
||||||
|
thisDomain = thisAddr;
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < 86400000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Is outdated
|
||||||
|
if (!hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it was not cached at all
|
||||||
|
if (thisDomain == null && !hasRefreshed) {
|
||||||
|
setRefresh(true);
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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) {
|
||||||
|
thisInfo = thisAddr;
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < 86400000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Is outdated
|
||||||
|
if (!hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it was not cached at all
|
||||||
|
if (thisInfo == null && !hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let thisName;
|
||||||
|
let thisIcon;
|
||||||
|
if (thisInfo) {
|
||||||
|
thisName = thisInfo.domain;
|
||||||
|
if (thisInfo.avatar) {
|
||||||
|
thisIcon =
|
||||||
|
<a className="selectOrchLight" style={{cursor: 'alias'}} target="_blank" rel="noopener noreferrer" href={"https://app.ens.domains/name/" + thisInfo.domain + "/details"} >
|
||||||
|
<div className="rowAlignLeft">
|
||||||
|
<img alt="" src={thisInfo.avatar} width="20" height="20" />
|
||||||
|
</div>
|
||||||
|
</a >
|
||||||
|
} else {
|
||||||
|
thisIcon =
|
||||||
|
<a className="selectOrchLight" style={{cursor: 'alias'}} target="_blank" rel="noopener noreferrer" href={"https://app.ens.domains/name/" + thisInfo.domain + "/details"} >
|
||||||
|
<div className="rowAlignLeft">
|
||||||
|
<img alt="" src="ens.png" width="20" height="20" />
|
||||||
|
</div>
|
||||||
|
</a >
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thisName = obj.address;
|
||||||
|
thisIcon = null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rowAlignLeft">
|
<div className="rowAlignLeft">
|
||||||
<a className="selectOrchLight" target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/" + obj.address} >
|
<a className="selectOrchLight" style={{cursor: 'alias'}} target="_blank" rel="noopener noreferrer" href={"https://explorer.livepeer.org/accounts/" + obj.address} >
|
||||||
<div className="rowAlignLeft">
|
<div className="rowAlignLeft">
|
||||||
<img alt="" src="livepeer.png" width="20" height="20" />
|
<img alt="" src="livepeer.png" width="20" height="20" />
|
||||||
<span className="elipsText elipsOnMobile">{obj.address}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
{thisIcon}
|
||||||
|
<span className="elipsText elipsOnMobile">{thisName}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,9 @@ const EventButton = (obj) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="strokeSmollLeft">
|
<div className="strokeSmollLeft" style={{ width: '100%', minWidth: '200px', maxWidth: '500px'}}>
|
||||||
{blockNumber}
|
{blockNumber}
|
||||||
<div className="strokeSmollLeft" style={{ borderRadius: "1.2em", backgroundColor: obj.eventObj.eventColour, opacity: 0.9, border: '0.1em solid rgba(54, 46, 46, 0.1)', boxShadow: "4px 2px 3px 2px rgba(54, 46, 46, 0.1)" }}>
|
<div className="strokeSmollLeft" style={{ width: "100%", borderRadius: "1.2em", backgroundColor: obj.eventObj.eventColour, opacity: 0.9, border: '0.1em solid rgba(54, 46, 46, 0.1)', boxShadow: "4px 2px 3px 2px rgba(54, 46, 46, 0.1)" }}>
|
||||||
<div className="halfVerticalDivider" />
|
<div className="halfVerticalDivider" />
|
||||||
<div className="rowAlignLeft">
|
<div className="rowAlignLeft">
|
||||||
{eventCaller}
|
{eventCaller}
|
||||||
|
@ -1,14 +1,85 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
getOrchestratorInfo
|
getOrchestratorInfo
|
||||||
} from "../actions/livepeer";
|
} from "../actions/livepeer";
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { getEnsInfo } from "../actions/livepeer";
|
||||||
|
|
||||||
const EventButtonAddress = (obj) => {
|
const EventButtonAddress = (obj) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const livepeer = useSelector((state) => state.livepeerstate);
|
||||||
|
const [hasRefreshed, setRefresh] = useState(false);
|
||||||
|
let thisDomain = null;
|
||||||
|
let thisInfo = null;
|
||||||
|
const now = new Date().getTime();
|
||||||
|
// Lookup domain in cache
|
||||||
|
if (livepeer.ensDomainMapping) {
|
||||||
|
for (const thisAddr of livepeer.ensDomainMapping) {
|
||||||
|
if (thisAddr.address === obj.address) {
|
||||||
|
thisDomain = thisAddr;
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < 86400000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Is outdated
|
||||||
|
if (!hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it was not cached at all
|
||||||
|
if (thisDomain == null && !hasRefreshed) {
|
||||||
|
setRefresh(true);
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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) {
|
||||||
|
thisInfo = thisAddr;
|
||||||
|
// Check timeout
|
||||||
|
if (now - thisAddr.timestamp < 86400000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Is outdated
|
||||||
|
if (!hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it was not cached at all
|
||||||
|
if (thisInfo == null && !hasRefreshed) {
|
||||||
|
getEnsInfo(obj.address);
|
||||||
|
setRefresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let thisName;
|
||||||
|
let thisIcon;
|
||||||
|
if (thisInfo) {
|
||||||
|
thisName = <h4 className="elipsText elipsOnMobileExtra">{thisInfo.domain}</h4>;
|
||||||
|
if (thisInfo.avatar) {
|
||||||
|
thisIcon =
|
||||||
|
<a className="selectOrch" style={{ cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://app.ens.domains/name/" + thisInfo.domain + "/details"} >
|
||||||
|
<img alt="" src={thisInfo.avatar} width="20em" height="20em" style={{ margin: 0 }} />
|
||||||
|
</a >
|
||||||
|
} else {
|
||||||
|
thisIcon =
|
||||||
|
<a className="selectOrch" style={{ cursor: 'alias' }} target="_blank" rel="noopener noreferrer" href={"https://app.ens.domains/name/" + thisInfo.domain + "/details"} >
|
||||||
|
<img alt="" src="ens.png" width="20em" height="20em" style={{ margin: 0 }} />
|
||||||
|
</a >
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thisName = <span className="elipsText elipsOnMobileExtra">{obj.address}</span>;
|
||||||
|
thisIcon = null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rowAlignLeft" style={{ width: '100%' }}>
|
<div className="rowAlignLeft" style={{ width: '100%' }}>
|
||||||
|
{thisIcon}
|
||||||
<a className="selectOrch" style={{ cursor: 'alias' }} rel="noopener noreferrer" target="_blank" href={"https://explorer.livepeer.org/accounts/" + obj.address}>
|
<a className="selectOrch" style={{ cursor: 'alias' }} rel="noopener noreferrer" target="_blank" href={"https://explorer.livepeer.org/accounts/" + obj.address}>
|
||||||
<img alt="" src="livepeer.png" width="20em" height="20em" style={{ margin: 0 }} />
|
<img alt="" src="livepeer.png" width="20em" height="20em" style={{ margin: 0 }} />
|
||||||
</a>
|
</a>
|
||||||
@ -17,7 +88,7 @@ const EventButtonAddress = (obj) => {
|
|||||||
</button>
|
</button>
|
||||||
<span>{obj.name}</span>
|
<span>{obj.name}</span>
|
||||||
<button className="selectOrch" style={{ padding: '0.5em', cursor: 'help' }} onClick={() => { dispatch(getOrchestratorInfo(obj.address)) }} >
|
<button className="selectOrch" style={{ padding: '0.5em', cursor: 'help' }} onClick={() => { dispatch(getOrchestratorInfo(obj.address)) }} >
|
||||||
<span className="elipsText elipsOnMobileExtra">{obj.address}</span>
|
{thisName}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import '../style.css';
|
import '../style.css';
|
||||||
import { Navigate, useSearchParams } from "react-router-dom";
|
import { Navigate, useSearchParams } from "react-router-dom";
|
||||||
import { useSelector, useDispatch } from 'react-redux'
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { getOrchestratorInfo, clearOrchestrator } from "../actions/livepeer";
|
import { getOrchestratorInfo, clearOrchestrator } from "../actions/livepeer";
|
||||||
import EventViewer from "../components/eventViewer";
|
import EventViewer from "../components/eventViewer";
|
||||||
import Orchestrator from "../components/orchestratorViewer";
|
import Orchestrator from "../components/orchestratorViewer";
|
||||||
|
@ -4,7 +4,8 @@ import {
|
|||||||
getVisitorStats
|
getVisitorStats
|
||||||
} from "../actions/user";
|
} from "../actions/user";
|
||||||
import {
|
import {
|
||||||
getQuotes, getBlockchainData, getEvents, getCurrentOrchestratorInfo, getTickets
|
getQuotes, getBlockchainData, getEvents, getCurrentOrchestratorInfo, getTickets,
|
||||||
|
getAllEnsDomains, getAllEnsInfo
|
||||||
} from "../actions/livepeer";
|
} from "../actions/livepeer";
|
||||||
import { login } from "../actions/session";
|
import { login } from "../actions/session";
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ const Startup = (obj) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const refreshAllZeData = () => {
|
const refreshAllZeData = () => {
|
||||||
console.log("Refreshing data...");
|
console.log("Refreshing Livepeer data...");
|
||||||
batch(() => {
|
batch(() => {
|
||||||
dispatch(getQuotes());
|
dispatch(getQuotes());
|
||||||
dispatch(getEvents());
|
dispatch(getEvents());
|
||||||
@ -36,9 +37,18 @@ const Startup = (obj) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refreshENS = () => {
|
||||||
|
console.log("Refreshing ENS data...");
|
||||||
|
batch(() => {
|
||||||
|
dispatch(getAllEnsDomains());
|
||||||
|
dispatch(getAllEnsInfo());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshLogin();
|
refreshLogin();
|
||||||
refreshAllZeData();
|
refreshAllZeData();
|
||||||
|
refreshENS();
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
if (refreshInterval) {
|
if (refreshInterval) {
|
||||||
const interval = setInterval(refreshAllZeData, refreshInterval);
|
const interval = setInterval(refreshAllZeData, refreshInterval);
|
||||||
|
@ -5,10 +5,21 @@ import {
|
|||||||
RECEIVE_ORCHESTRATOR,
|
RECEIVE_ORCHESTRATOR,
|
||||||
RECEIVE_CURRENT_ORCHESTRATOR,
|
RECEIVE_CURRENT_ORCHESTRATOR,
|
||||||
CLEAR_ORCHESTRATOR,
|
CLEAR_ORCHESTRATOR,
|
||||||
RECEIVE_TICKETS
|
RECEIVE_TICKETS,
|
||||||
|
SET_ALL_ENS_INFO,
|
||||||
|
SET_ALL_ENS_DOMAINS
|
||||||
} from "../../actions/livepeer";
|
} from "../../actions/livepeer";
|
||||||
|
|
||||||
export default (state = {}, { type, message }) => {
|
export default (state = {
|
||||||
|
quotes: [],
|
||||||
|
blockchains: [],
|
||||||
|
events: [],
|
||||||
|
thisOrchestrator: null,
|
||||||
|
selectedOrchestrator: null,
|
||||||
|
tickets: [],
|
||||||
|
ensInfoMapping: [],
|
||||||
|
ensDomainMapping: []
|
||||||
|
}, { type, message }) => {
|
||||||
Object.freeze(state);
|
Object.freeze(state);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RECEIVE_QUOTES:
|
case RECEIVE_QUOTES:
|
||||||
@ -25,6 +36,10 @@ export default (state = {}, { type, message }) => {
|
|||||||
return { ...state, selectedOrchestrator: null };
|
return { ...state, selectedOrchestrator: null };
|
||||||
case RECEIVE_TICKETS:
|
case RECEIVE_TICKETS:
|
||||||
return { ...state, tickets: message };
|
return { ...state, tickets: message };
|
||||||
|
case SET_ALL_ENS_INFO:
|
||||||
|
return { ...state, ensInfoMapping: message };
|
||||||
|
case SET_ALL_ENS_DOMAINS:
|
||||||
|
return { ...state, ensDomainMapping: message };
|
||||||
default:
|
default:
|
||||||
return { ...state };
|
return { ...state };
|
||||||
}
|
}
|
||||||
|
@ -62,3 +62,30 @@ export const getOrchestratorByDelegator = (delAddr) => (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getAllEnsDomains = () => (
|
||||||
|
fetch("api/livepeer/getEnsDomains/", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getAllEnsInfo = () => (
|
||||||
|
fetch("api/livepeer/getEnsInfo/", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getEnsInfo = (addr) => (
|
||||||
|
fetch("api/livepeer/getENS/" + addr, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user