diff --git a/frontend/package.json b/frontend/package.json
index 711aa01a..187160a0 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,6 +15,7 @@
"@emotion/react": "^11.4.0",
"@emotion/styled": "^11.3.0",
"@nivo/bar": "^0.73.1",
+ "@nivo/core": "^0.73.0",
"@stripe/stripe-js": "^1.16.0",
"axios": "^0.21.1",
"focus-visible": "^5.2.0",
diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js
index b4e2894c..f265fa60 100644
--- a/frontend/pages/_app.js
+++ b/frontend/pages/_app.js
@@ -6,6 +6,7 @@ import "highlight.js/styles/github.css";
import "focus-visible/dist/focus-visible";
import dynamic from "next/dynamic";
import { QueryClient, QueryClientProvider } from "react-query";
+import { ReactQueryDevtools } from "react-query/devtools";
const HeadSEO = dynamic(() => import("../src/components/HeadSEO"), {
ssr: false,
@@ -69,6 +70,7 @@ export default function CachingApp({ Component, pageProps }) {
{pageProps.metaTags && }
+
{getLayout()}
>
diff --git a/frontend/pages/nft.js b/frontend/pages/nft.js
index 94da0bd9..3e7251c9 100644
--- a/frontend/pages/nft.js
+++ b/frontend/pages/nft.js
@@ -6,12 +6,13 @@ import React, {
useState,
} from "react";
import { getLayout } from "../src/layouts/AppLayout";
-import { Spinner, Flex, Heading, Stack } from "@chakra-ui/react";
+import { Spinner, Flex, Heading, Stack, Text, Spacer } from "@chakra-ui/react";
import Scrollable from "../src/components/Scrollable";
import useNFTs from "../src/core/hooks/useNFTs";
import RangeSelector from "../src/components/RangeSelector";
import StatsCard from "../src/components/StatsCard";
import useWindowSize from "../src/core/hooks/useWindowSize";
+import NFTChart from "../src/components/NFTChart";
const HOUR_KEY = "Hourly";
const DAY_KEY = "Daily";
@@ -25,7 +26,7 @@ const Analytics = () => {
const windowSize = useWindowSize();
useEffect(() => {
if (typeof window !== "undefined") {
- document.title = `Analytics: Page under construction`;
+ document.title = `NFT Analytics`;
}
}, []);
@@ -33,11 +34,15 @@ const Analytics = () => {
ntx: false,
values: false,
mints: false,
+ NFTOwners: false,
+ minters: false,
});
const nTxRef_ = useRef();
const valueRef_ = useRef();
const mintsRef_ = useRef();
+ const uniqueNFTOwnersRef_ = useRef();
+ const mintersRef_ = useRef();
const nTxRef = useCallback(
(node) => {
@@ -67,13 +72,40 @@ const Analytics = () => {
[nodesReady]
);
+ const uniqueNFTOwnersRef = useCallback(
+ (node) => {
+ if (node !== null && !nodesReady.NFTOwners) {
+ setNodeReady({ ...nodesReady, NFTOwners: true });
+ uniqueNFTOwnersRef_.current = node;
+ }
+ },
+ [nodesReady]
+ );
+
+ const mintersRef = useCallback(
+ (node) => {
+ if (node !== null && !nodesReady.minters) {
+ setNodeReady({ ...nodesReady, minters: true });
+ mintersRef_.current = node;
+ }
+ },
+ [nodesReady]
+ );
+
const [timeRange, setTimeRange] = useState(HOUR_KEY);
const { nftCache } = useNFTs();
useLayoutEffect(() => {
- const items = [nTxRef_, valueRef_, mintsRef_];
+ const items = [
+ nTxRef_,
+ valueRef_,
+ mintsRef_,
+ uniqueNFTOwnersRef_,
+ mintersRef_,
+ ];
console.log("useeffect fired");
- if (nTxRef_.current) {
+ if (items.some((item) => !!item.current)) {
+ console.log("brder fun");
var firstItemInCurrentRow = items[0];
items.forEach((item) => {
if (item.current) {
@@ -99,7 +131,12 @@ const Analytics = () => {
}
}, [nodesReady, windowSize]);
+ const keys = ["NFTs", "Other"];
+
if (nftCache.isLoading) return ;
+
+ const plotMinW = "500px";
+
return (
{
alignItems="center"
minH="100vh"
>
-
- NFT market analysis
-
- setTimeRange(e)}
- />
+
+
+ NFT market analysis
+
+
+ setTimeRange(e)}
+ />
+
{
boxShadow="md"
borderRadius="lg"
bgColor="gray.100"
- // divider={}
>
nTxRef(node)}
- // borderTopLeftRadius="inherit"
- labelKey="transactions"
+ labelKey="nft_transfers"
+ totalKey="num_transactions"
timeRange={timeMap[timeRange]}
netLabel="Ethereum mainnet"
label="Number of transactions"
/>
valueRef(node)}
- labelKey="values"
+ labelKey="nft_transfer_value"
+ totalKey="total_value"
timeRange={timeMap[timeRange]}
netLabel="Ethereum mainnet"
label="Value of transactions"
/>
mintsRef(node)}
- // borderTopRightRadius="inherit"
- // borderRightWidth="0"
- labelKey="mints"
+ labelKey="nft_mints"
timeRange={timeMap[timeRange]}
netLabel="Ethereum mainnet"
label="Minted NFTs"
/>
+ uniqueNFTOwnersRef(node)}
+ labelKey="nft_owners"
+ timeRange={timeMap[timeRange]}
+ netLabel="Ethereum mainnet"
+ label="NFTs owners"
+ />
+
+ mintersRef(node)}
+ labelKey="nft_minters"
+ timeRange={timeMap[timeRange]}
+ netLabel="Ethereum mainnet"
+ label="NFTs minters"
+ />
+
+
+
+ NFT owners dynamic
+
+
+
+
+
+ NFT values compared to total
+
+
+
+
+
+ NFT Minting activity
+
+
+
+
+
+ Unique minters number
+
+
+
+
+
+ Number of NFT owners accounts
+
+
+
+
+
+ NFT transactions vs all Ethereum
+
+
+
+
+
+ NFT transfers vs all Ethereum
+
+
+
+
);
diff --git a/frontend/src/components/NFTChart.js b/frontend/src/components/NFTChart.js
new file mode 100644
index 00000000..cb23b05a
--- /dev/null
+++ b/frontend/src/components/NFTChart.js
@@ -0,0 +1,176 @@
+import React, { useCallback } from "react";
+import { Spinner } from "@chakra-ui/react";
+import useNFTs from "../core/hooks/useNFTs";
+import { ResponsiveBarCanvas } from "@nivo/bar";
+import moment from "moment";
+
+const HOUR_KEY = "Hourly";
+const DAY_KEY = "Daily";
+const WEEK_KEY = "Weekly";
+let timeMap = {};
+timeMap[HOUR_KEY] = "hour";
+timeMap[DAY_KEY] = "day";
+timeMap[WEEK_KEY] = "week";
+
+const NFTChart = ({ timeRange, keyPosition, keyTotal }) => {
+ const { nftCache } = useNFTs();
+
+ const getHourlyData = useCallback(
+ (keyPosition, keyTotal) => {
+ const retval = [];
+ nftCache?.data?.forEach((block, idx) => {
+ let diff =
+ keyTotal && Number(block[keyTotal]) - Number(block[keyPosition]);
+
+ let date = moment(block.crawled_at).format(`HH`);
+ //group by days if not hour key
+ if (idx < 23) {
+ retval.push({
+ date: date,
+ NFTs: Number(block[keyPosition]),
+ Other: keyTotal && diff,
+ });
+ }
+ });
+
+ return retval;
+ },
+ [nftCache.data]
+ );
+
+ const getDailyData = useCallback(
+ (keyPosition, keyTotal) => {
+ const retval = [];
+ nftCache?.data?.forEach((block, idx) => {
+ if (idx < 7 * 24) {
+ let diff =
+ keyTotal && Number(block[keyTotal]) - Number(block[keyPosition]);
+
+ let date = moment(block.crawled_at).format(`l`);
+ let existingIdx = retval.findIndex(
+ (element) => element.date === date
+ );
+ if (existingIdx !== -1) {
+ const prevValue = retval[existingIdx];
+ const newValue = {
+ date: prevValue.date,
+ NFTs: prevValue.NFTs + Number(block[keyPosition]),
+ Other: prevValue.Other + Number(block[keyPosition]),
+ };
+ retval[existingIdx] = { ...newValue };
+ } else {
+ retval.push({
+ date: date,
+
+ NFTs: Number(block[keyPosition]),
+ Other: keyTotal && diff,
+ });
+ }
+ }
+ });
+
+ return retval;
+ },
+ [nftCache.data]
+ );
+
+ const getWeeklyData = useCallback(
+ (keyPosition, keyTotal) => {
+ const retval = [];
+ nftCache?.data?.forEach((block, idx) => {
+ if (idx < 28 * 24) {
+ let diff =
+ keyTotal && Number(block[keyTotal]) - Number(block[keyPosition]);
+
+ let date = moment(block.crawled_at).format(`l`);
+ let existingIdx = retval.findIndex(
+ (element) => element.date === date
+ );
+ if (existingIdx !== -1) {
+ const prevValue = retval[existingIdx];
+ const newValue = {
+ date: prevValue.date,
+ NFTs: prevValue.NFTs + Number(block[keyPosition]),
+ Other: prevValue.Other + Number(block[keyPosition]),
+ };
+ retval[existingIdx] = { ...newValue };
+ } else {
+ retval.push({
+ date: date,
+ NFTs: Number(block[keyPosition]),
+ Other: keyTotal && diff,
+ });
+ }
+ }
+ });
+
+ return retval;
+ },
+ [nftCache.data]
+ );
+
+ const plotData =
+ timeRange === HOUR_KEY
+ ? getHourlyData(keyPosition, keyTotal)
+ : timeRange === DAY_KEY
+ ? getDailyData(keyPosition, keyTotal)
+ : getWeeklyData(keyPosition, keyTotal);
+
+ plotData.forEach((item, index) => {
+ plotData[index].NFTs = plotData[index].NFTs / 1e18;
+ plotData[index].Other = plotData[index].Other / 1e18;
+ });
+ if (nftCache.isLoading) return ;
+ return (
+ labelLookup[d.id]}
+ // tooltipLabel={(d) => labelLookup[d.id]}
+ legends={[
+ {
+ anchor: "bottom-right",
+ direction: "column",
+ translateX: 100,
+ itemWidth: 80,
+ itemHeight: 20,
+ itemTextColor: "#999999",
+ symbolSize: 12,
+ symbolShape: "circle",
+ effects: [
+ {
+ on: "hover",
+ style: {
+ itemTextColor: "#000000",
+ },
+ },
+ ],
+ },
+ ]}
+ />
+ );
+};
+
+export default NFTChart;
diff --git a/frontend/src/components/RangeSelector.js b/frontend/src/components/RangeSelector.js
index cf4ef35a..72eceb58 100644
--- a/frontend/src/components/RangeSelector.js
+++ b/frontend/src/components/RangeSelector.js
@@ -20,7 +20,7 @@ const RangeSelector_ = ({
}, [range, onChange]);
return (
-
+
{ranges.map((item, idx) => {
const isActive = item === range ? true : false;
return (
@@ -37,6 +37,7 @@ const RangeSelector_ = ({
bgColor: isActive ? "secondary.900" : "secondary.50",
}}
cursor="pointer"
+ py="2px"
>
{item}
diff --git a/frontend/src/components/StatsCard.js b/frontend/src/components/StatsCard.js
index 2e941268..31ce9c8c 100644
--- a/frontend/src/components/StatsCard.js
+++ b/frontend/src/components/StatsCard.js
@@ -4,11 +4,6 @@ import { TriangleDownIcon, TriangleUpIcon } from "@chakra-ui/icons";
import useNFTs from "../core/hooks/useNFTs";
import { fromWei } from "web3-utils";
-const TIME_PERIOD = {
- current: 0,
- previous: 1,
-};
-
const isNumberNonzeroAndFinite = (str) => {
return !(isNaN(Number(str)) || Number(str) === 0);
};
@@ -39,6 +34,7 @@ const nFormatter = (num, digits) => {
};
const getChange = (a, b) => {
+ console.log(`change:`, a, b);
if (isNumberNonzeroAndFinite(a) && isNumberNonzeroAndFinite(b)) {
let retval = (Math.abs(Number(a) - Number(b)) * 100) / Number(b);
retval =
@@ -53,7 +49,7 @@ const getDiff = (a, b) => {
if (isNaN(a) || isNaN(b)) {
return "-";
} else {
- return Number(a) - Number(b);
+ return Number(Number(a) - Number(b)).toFixed(2);
}
};
@@ -67,26 +63,61 @@ const StatsCard_ = ({
label,
netLabel,
labelKey,
+ totalKey,
timeRange,
innerRef,
}) => {
+ console.log("stats card");
const { nftCache } = useNFTs();
const [nftData, setData] = useState();
useEffect(() => {
- if (nftCache.data[TIME_PERIOD.current][labelKey][timeRange]) {
- const cacheData = nftCache.data[TIME_PERIOD.current][labelKey][timeRange];
- const prevCacheData =
- nftCache.data[TIME_PERIOD.previous][labelKey][timeRange];
- const valueChange = getChange(cacheData.amount, prevCacheData.amount);
- const share = isNaN(cacheData.percentage)
- ? "-"
- : Number(cacheData.percentage).toFixed(2);
- const shareChange = getDiff(
- cacheData.percentage,
- prevCacheData.percentage
+ if (nftCache.data) {
+ const resolution =
+ timeRange === "hour" ? 1 : timeRange === "day" ? 24 : 24 * 7;
+
+ let currentPeriod = 0,
+ previousPeriod = 0,
+ currentTotalPeriod = 0,
+ previousTotalPeriod = 0;
+ for (let i = 0; i < resolution; i++) {
+ currentPeriod += Number(nftCache.data[i][labelKey]);
+ previousPeriod += Number(nftCache.data[resolution + i][labelKey]);
+ if (totalKey) {
+ currentTotalPeriod += Number(nftCache.data[i][totalKey]);
+ previousTotalPeriod += Number(
+ nftCache.data[resolution + i][totalKey]
+ );
+ }
+ }
+ console.log(
+ "card,",
+ totalKey,
+ labelKey,
+ currentPeriod,
+ currentTotalPeriod
);
+ // percentage =
+ // const cacheData = nftCache.data[TIME_PERIOD.current][labelKey][timeRange];
+ // const prevCacheData =
+ // nftCache.data[TIME_PERIOD.previous][labelKey][timeRange];
+ const valueChange = getChange(currentPeriod, previousPeriod);
+ totalKey &&
+ console.log(
+ "getting change in share",
+ currentPeriod,
+ currentTotalPeriod
+ );
+
+ const share = !totalKey
+ ? "-"
+ : getChange(currentPeriod, currentTotalPeriod);
+ const shareChange = getDiff(
+ share,
+ getChange(previousPeriod, previousTotalPeriod)
+ );
+ totalKey && console.log("share", share);
setData({
dimension: labelKey === "values" ? "Eth" : "#",
@@ -96,12 +127,13 @@ const StatsCard_ = ({
shareChange,
share,
value:
- labelKey === "values"
- ? getEthValue(cacheData.amount)
- : nFormatter(cacheData.amount, 2),
+ labelKey === "total_value"
+ ? getEthValue(currentPeriod)
+ : nFormatter(currentPeriod, 2),
});
}
- }, [nftCache?.data, nftCache.isLoading, labelKey, timeRange]);
+ }, [nftCache?.data, nftCache.isLoading, labelKey, totalKey, timeRange]);
+ console.log("nftData", nftData);
if (nftCache.isLoading || !nftData) return "";
return (
diff --git a/frontend/src/core/utils/mockupRequests.js b/frontend/src/core/utils/mockupRequests.js
index 5e7a8a1d..0a727af0 100644
--- a/frontend/src/core/utils/mockupRequests.js
+++ b/frontend/src/core/utils/mockupRequests.js
@@ -19,6 +19,9 @@ export const makenum = (length) => {
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
+ if (result[0] === "0") {
+ result = "1" + result.slice(1, result.length);
+ }
return result;
};
@@ -27,6 +30,28 @@ const randDate = () => {
new Date(+new Date() - Math.floor(Math.random() * 10000000000))
).format("MM/DD/YYYY");
};
+
+const generateMockNFTData = (days) => {
+ const retArr = [];
+ console.log("calculating array...");
+ for (let i = 0; i < days * 24; i++) {
+ let total_value = makenum(23);
+ let nft_transfer_value = makenum(22);
+ retArr.push({
+ num_transactions: makenum(5),
+ total_value: total_value.toString(),
+ nft_transfers: makenum(4),
+ nft_transfer_value: nft_transfer_value.toString(),
+ nft_mints: makenum(4),
+ nft_owners: makenum(4),
+ nft_minters: makenum(4),
+ crawled_at: moment.utc().subtract(i, "hours"),
+ });
+ }
+ return retArr;
+};
+
+const mockNFTData = generateMockNFTData(100);
export let MockSubscriptions = [
{
label: "Bobs wallet",
@@ -74,132 +99,7 @@ const enableMockupRequests = (axiosInstance) => {
//assume all currency units are in wei
mock.onGet(`${MOCK_API}/nft`).reply(200, {
- data: [
- {
- crawled_at: "2021-09-06T06:10:10.889073+00:00",
- blocks: {
- hour: {
- start: 13170228,
- end: 13271506,
- },
- day: {
- start: 13164032,
- end: 14270506,
- },
- week: {
- start: 13154612,
- end: 14270508,
- },
- },
- transactions: {
- hour: {
- total: "50017",
- amount: "1076",
- percentage: "6.323468771476769",
- },
- day: {
- total: "1534628",
- amount: "68423",
- percentage: "4.149088511829428",
- },
- week: {
- total: "3036720",
- amount: "252081",
- percentage: "2.3611565469979405",
- },
- },
- values: {
- hour: {
- total: "32108237248132871265869",
- amount: "902575483711416563753",
- percentage: "3.222693614745530439610725634",
- },
- day: {
- total: "1248742881687945808996123",
- amount: "36532034623835761073277",
- percentage: "2.967167722185197815518956241",
- },
- week: {
- total: "4496907645654832424013847",
- amount: "171796514135927551452190",
- percentage: "4.053142988352582169869986652",
- },
- },
- mints: {
- hour: {
- amount: 1884,
- },
- day: {
- amount: 45131,
- },
- week: {
- amount: 1281978,
- },
- },
- },
- {
- crawled_at: "2021-09-06T06:10:10.889073+00:00",
- blocks: {
- hour: {
- start: 13170228,
- end: 13170506,
- },
- day: {
- start: 13164032,
- end: 13170506,
- },
- week: {
- start: 13154612,
- end: 13170508,
- },
- },
- transactions: {
- hour: {
- total: "48017",
- amount: "2076",
- percentage: "4.323468771476769",
- },
- day: {
- total: "1134628",
- amount: "58423",
- percentage: "5.149088511829428",
- },
- week: {
- total: "2836720",
- amount: "152081",
- percentage: "5.3611565469979405",
- },
- },
- values: {
- hour: {
- total: "36108237248132871265869",
- amount: "802575483711416563753",
- percentage: "2.222693614745530439610725634",
- },
- day: {
- total: "1348742881687945808996123",
- amount: "26532034623835761073277",
- percentage: "1.967167722185197815518956241",
- },
- week: {
- total: "3496907645654832424013847",
- amount: "71796514135927551452190",
- percentage: "2.053142988352582169869986652",
- },
- },
- mints: {
- hour: {
- amount: 2884,
- },
- day: {
- amount: 95131,
- },
- week: {
- amount: 281978,
- },
- },
- },
- ],
+ data: [...mockNFTData],
});
// mock.onGet(`${MOCK_API}/subscription_types/`).reply(200, {
@@ -245,7 +145,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -257,7 +157,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -269,7 +169,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -281,7 +181,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -293,7 +193,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -305,7 +205,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -317,7 +217,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -329,7 +229,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -341,7 +241,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
@@ -353,7 +253,7 @@ const enableMockupRequests = (axiosInstance) => {
// gas: 2265656,
// gasPrice: 1000000000,
// hash: "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6",
- // value: 0,
+ // values: 0,
// input:
// "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca",
// },
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 2ad192e4..381d638a 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1299,6 +1299,24 @@
lodash "^4.17.21"
react-motion "^0.5.2"
+"@nivo/core@^0.73.0":
+ version "0.73.0"
+ resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.73.0.tgz#58fac20c8cd7eac12bfdc96619554764ca225cdf"
+ integrity sha512-NFKSk5NQgC2NB3olG8hltN4b4Ri0rB0vt3q1yGmQj+RdGRS4f82Dtwt5Ratxu6QeZD8lt0DhqN9Q7TJ+j/kt0g==
+ dependencies:
+ "@nivo/recompose" "0.73.0"
+ "@react-spring/web" "9.2.4"
+ d3-color "^2.0.0"
+ d3-format "^1.4.4"
+ d3-hierarchy "^1.1.8"
+ d3-interpolate "^2.0.1"
+ d3-scale "^3.2.3"
+ d3-scale-chromatic "^2.0.0"
+ d3-shape "^1.3.5"
+ d3-time-format "^3.0.0"
+ lodash "^4.17.21"
+ resize-observer-polyfill "^1.5.1"
+
"@nivo/legends@0.73.0":
version "0.73.0"
resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.73.0.tgz#ef344038c4ff03249ffffebaf14412d012004fda"
@@ -2596,7 +2614,12 @@ d3-format@^1.4.4:
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
-"d3-interpolate@1 - 2", "d3-interpolate@1.2.0 - 2":
+d3-hierarchy@^1.1.8:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83"
+ integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==
+
+"d3-interpolate@1 - 2", "d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163"
integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==
@@ -2627,7 +2650,7 @@ d3-scale@^3.2.3:
d3-time "^2.1.1"
d3-time-format "2 - 3"
-d3-shape@^1.2.2:
+d3-shape@^1.2.2, d3-shape@^1.3.5:
version "1.3.7"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==