From 36f32037d46c26090e8793841bf1f2461fcfe7c4 Mon Sep 17 00:00:00 2001 From: Marco van Dijk Date: Sat, 16 Apr 2022 18:31:15 +0200 Subject: [PATCH] Added winning ticket viewer --- package.json | 12 +- src/App.js | 2 + src/actions/livepeer.js | 10 +- src/components/OrchAddressViewer.js | 1 - src/pages/home.js | 11 ++ src/pages/tickets.js | 201 +++++++++++++++++++++++++ src/reducers/livepeer/livepeerstate.js | 6 +- 7 files changed, 236 insertions(+), 7 deletions(-) create mode 100644 src/pages/tickets.js diff --git a/package.json b/package.json index c185bc0..e3ecf9f 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,23 @@ "version": "0.1.0", "private": true, "dependencies": { + "@mantine/core": "^4.1.3", + "@mantine/dates": "^4.1.3", + "@mantine/form": "^4.1.3", + "@mantine/hooks": "^4.1.3", + "@mantine/modals": "^4.1.3", + "@mantine/next": "^4.1.3", + "@mantine/notifications": "^4.1.3", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", + "dayjs": "^1.11.1", "ethers": "^5.4.4", "http": "^0.0.1-security", "https": "^1.0.0", "md5": "^2.3.0", - "react": "^16.12.0", - "react-dom": "^16.12.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", "react-indiana-drag-scroll": "^2.1.0", "react-markdown": "^7.1.1", "react-paginate": "^8.1.2", diff --git a/src/App.js b/src/App.js index 3dec16b..84d08f6 100644 --- a/src/App.js +++ b/src/App.js @@ -3,6 +3,7 @@ import Home from './pages/home.js'; import Startup from './pages/loadingScreen.js'; import Grafana from './pages/grafana.js'; import Livepeer from './pages/livepeer.js'; +import Tickets from './pages/tickets.js'; import { BrowserRouter as Router, @@ -16,6 +17,7 @@ export default function App() { } /> + } /> } /> } /> diff --git a/src/actions/livepeer.js b/src/actions/livepeer.js index 350617a..b986f04 100644 --- a/src/actions/livepeer.js +++ b/src/actions/livepeer.js @@ -24,6 +24,7 @@ export const RECEIVE_CURRENT_ORCHESTRATOR = "RECEIVE_CURRENT_ORCHESTRATOR"; export const RECEIVE_ORCHESTRATOR = "RECEIVE_ORCHESTRATOR"; export const CLEAR_ORCHESTRATOR = "CLEAR_ORCHESTRATOR"; export const RECEIVE_TICKETS = "RECEIVE_TICKETS"; +export const RECEIVE_WINNING_TICKETS = "RECEIVE_WINNING_TICKETS"; export const SET_ALL_ENS_INFO = "SET_ALL_ENS_INFO"; export const SET_ALL_ENS_DOMAINS = "SET_ALL_ENS_DOMAINS"; export const SET_ALL_THREEBOX_INFO = "SET_ALL_THREEBOX_INFO"; @@ -49,6 +50,9 @@ const clearOrchestratorInfo = () => ({ const setTickets = message => ({ type: RECEIVE_TICKETS, message }); +const setWinningTickets = message => ({ + type: RECEIVE_WINNING_TICKETS, message +}); const setAllEnsInfo = message => ({ type: SET_ALL_ENS_INFO, message }); @@ -428,6 +432,7 @@ export const getTickets = () => async dispatch => { // Combine raw list of events into a list of useful Events if (response.ok) { let finalTicketList = []; + let winningTicketList = []; // Current transaction we are processing let txCounter = 0; let currentTx = ""; @@ -475,11 +480,9 @@ export const getTickets = () => async dispatch => { eventValue: amount }); } else if (eventObj.name === "WinningTicketTransfer") { - // For now lets just ignore these, they are boring - continue; const amount = parseFloat(eventObj.data.amount) / 1000000000000000000; const txt = " broadcaster payed out " + amount.toFixed(4) + " Eth"; - finalTicketList.push({ + winningTicketList.push({ eventType: "TransferTicket", eventDescription: txt, eventCaller: "", @@ -499,6 +502,7 @@ export const getTickets = () => async dispatch => { } // NOTE: We are throwing away the very oldest Ticket now, which should be fine. // We can fix this once above wall of text becomes a separate function + dispatch(setWinningTickets(winningTicketList)); return dispatch(setTickets(finalTicketList)); } return dispatch(receiveErrors(data)); diff --git a/src/components/OrchAddressViewer.js b/src/components/OrchAddressViewer.js index 6f3dc6b..bc2370e 100644 --- a/src/components/OrchAddressViewer.js +++ b/src/components/OrchAddressViewer.js @@ -75,7 +75,6 @@ const Address = (obj) => { let thisIcon; if (hasENS) { thisName = thisInfo.domain; - console.log(thisInfo.avatar); if (thisInfo.avatar) { thisIcon = diff --git a/src/pages/home.js b/src/pages/home.js index 0462c3a..fec62e1 100644 --- a/src/pages/home.js +++ b/src/pages/home.js @@ -11,12 +11,16 @@ const Home = (obj) => { const userstate = useSelector((state) => state.userstate); const [redirectToGrafana, setRedirectToGrafana] = useState(false); const [redirectToLPT, setRedirectToLPT] = useState(false); + const [redirectToTickets, setRedirectToTickets] = useState(false); if (redirectToGrafana) { return ; } if (redirectToLPT) { return ; } + if (redirectToTickets) { + return ; + } // Get amount of unique IP's which have visited this website var totalVisitorCount = 0; if (userstate.visitorStats) { @@ -57,6 +61,13 @@ const Home = (obj) => {

🔎 Blockchain 🕵️

+
+ +
diff --git a/src/pages/tickets.js b/src/pages/tickets.js new file mode 100644 index 0000000..cfb27b4 --- /dev/null +++ b/src/pages/tickets.js @@ -0,0 +1,201 @@ +import React, { useState, useEffect } from 'react' +import '../style.css'; +import { Navigate } from "react-router-dom"; +import { useSelector, useDispatch } from 'react-redux'; +import { Accordion } from '@mantine/core'; +import ScrollContainer from 'react-indiana-drag-scroll'; +import Address from '../components/OrchAddressViewer'; + +const Tickets = (obj) => { + const livepeer = useSelector((state) => state.livepeerstate); + const [ticketsPerMonth, setTicketsPerMonth] = useState([]); + const [redirectToHome, setRedirectToHome] = useState(false); + + console.log("Rendering Winning Ticket Viewer"); + + useEffect(() => { + // Process Winning tickets as: + // List of Months containing + // List of Orchestrators (sorted by earnings) containing + // List of winning tickets + let ticketsPerMonth = []; + let ticketIdx = livepeer.winningTickets.length - 1; + let currentMonth = 99; + let currentYear = 99; + let currentOrchCounter = []; + while (ticketIdx >= 0) { + const thisTicket = livepeer.winningTickets[ticketIdx]; + const thisTime = new Date(thisTicket.transactionTime * 1000); + const thisYear = thisTime.getFullYear(); + const thisMonth = thisTime.getMonth(); + ticketIdx -= 1; + + // On a new month + if (thisMonth != currentMonth) { + // Push this months data + if (currentOrchCounter.length) { + // Sort this months data + let sortedList = [] + while (currentOrchCounter.length) { + let ticketIdx2 = currentOrchCounter.length - 1; + let largestIdx = 0; + let largestValue = 0; + // Find current O with most ticket wins in Eth + while (ticketIdx2 >= 0) { + const currentOrch = currentOrchCounter[ticketIdx2]; + if (currentOrch.sum > largestValue) { + largestIdx = ticketIdx2; + largestValue = currentOrch.sum; + } + ticketIdx2 -= 1; + } + // Push current biggest list + sortedList.push(currentOrchCounter[largestIdx]); + // Remove from list + currentOrchCounter.splice(largestIdx, 1); + } + ticketsPerMonth.push( + { + year: currentYear, + month: currentMonth, + orchestrators: sortedList + } + ); + } + // clear data + currentMonth = thisMonth; + currentYear = thisYear; + currentOrchCounter = []; + } + // Find orch in list + let thisIdx = 0; + let thisFound = false; + let ticketIdx2 = currentOrchCounter.length - 1; + while (ticketIdx2 >= 0) { + const currentOrch = currentOrchCounter[ticketIdx2]; + if (currentOrch.address == thisTicket.eventTo) { + thisFound = true; + thisIdx = ticketIdx2; + break; + } + ticketIdx2 -= 1; + } + // If not in list, append at the end + if (!thisFound) { + currentOrchCounter.push({ + address: thisTicket.eventTo, + sum: thisTicket.eventValue + }); + } else { + // Else update that entry + currentOrchCounter[thisIdx].sum += thisTicket.eventValue; + } + } + + setTicketsPerMonth(ticketsPerMonth); + }, [livepeer.winningTickets]); + + if (redirectToHome) { + return ; + } + + return ( +
+ +
+
+
+
+
+
+ +
+
+ +
+ { + ticketsPerMonth.map(function (data) { + let thisMonth = ""; + let monthAsNum = data.month; + if (monthAsNum == 0) { + thisMonth = "Januari";; + } else if (monthAsNum == 1) { + thisMonth = "Februari";; + } else if (monthAsNum == 2) { + thisMonth = "March";; + } else if (monthAsNum == 3) { + thisMonth = "April"; + } else if (monthAsNum == 4) { + thisMonth = "May"; + } else if (monthAsNum == 5) { + thisMonth = "June"; + } else if (monthAsNum == 6) { + thisMonth = "July"; + } else if (monthAsNum == 7) { + thisMonth = "August"; + } else if (monthAsNum == 8) { + thisMonth = "September"; + } else if (monthAsNum == 9) { + thisMonth = "October"; + } else if (monthAsNum == 10) { + thisMonth = "November"; + } else if (monthAsNum == 11) { + thisMonth = "December";; + } + return ( + +
+ { + data.orchestrators.map(function (orch) { + return ( +
+
+
+
+
+

{orch.sum} Eth

+
+
+ ) + }) + } +
+
+ + ) + }) + } + +
+
+ +
+
+
+
+
+
+
+ ); +} + +export default Tickets; \ No newline at end of file diff --git a/src/reducers/livepeer/livepeerstate.js b/src/reducers/livepeer/livepeerstate.js index c7a2f3a..a5e96f4 100644 --- a/src/reducers/livepeer/livepeerstate.js +++ b/src/reducers/livepeer/livepeerstate.js @@ -6,6 +6,7 @@ import { RECEIVE_CURRENT_ORCHESTRATOR, CLEAR_ORCHESTRATOR, RECEIVE_TICKETS, + RECEIVE_WINNING_TICKETS, SET_ALL_ENS_INFO, SET_ALL_ENS_DOMAINS, SET_ALL_THREEBOX_INFO @@ -19,7 +20,8 @@ export default (state = { selectedOrchestrator: null, tickets: [], ensInfoMapping: [], - ensDomainMapping: [] + ensDomainMapping: [], + winningTickets: [] }, { type, message }) => { Object.freeze(state); switch (type) { @@ -37,6 +39,8 @@ export default (state = { return { ...state, selectedOrchestrator: null }; case RECEIVE_TICKETS: return { ...state, tickets: message }; + case RECEIVE_WINNING_TICKETS: + return { ...state, winningTickets: message }; case SET_ALL_ENS_INFO: return { ...state, ensInfoMapping: message }; case SET_ALL_ENS_DOMAINS: