From 733af071f894bcfd943e0cba0d6868590b9f0be6 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Wed, 23 Jun 2021 12:59:06 +0200 Subject: [PATCH 01/28] Refactoring to context --- .env.template | 2 + .gitignore | 2 + components/Bundles.tsx | 42 ++-- context/BundleData/BundleDataProvider.tsx | 116 ++++++++++ context/TokenData/TokenDataProvider.tsx | 199 ++++++++++++++++++ .../tokensList}/fetchTokensApiByDex.js | 0 .../TokenData/tokensList}/jsonCOINGECKO.json | 0 .../tokensList}/tokensCOINGECKO.json | 0 lib/ABILogs.js | 67 ------ lib/api.ts | 25 --- lib/getReceipts.js | 33 --- lib/getToken.ts | 36 ---- lib/uniswapV2SubGraph.ts | 34 --- package.json | 1 + pages/Home.tsx | 11 + pages/{index.js => index.tsx} | 57 ++--- yarn.lock | 5 + 17 files changed, 379 insertions(+), 251 deletions(-) create mode 100644 .env.template create mode 100644 context/BundleData/BundleDataProvider.tsx create mode 100644 context/TokenData/TokenDataProvider.tsx rename {tokensList => context/TokenData/tokensList}/fetchTokensApiByDex.js (100%) rename {tokensList => context/TokenData/tokensList}/jsonCOINGECKO.json (100%) rename {tokensList => context/TokenData/tokensList}/tokensCOINGECKO.json (100%) delete mode 100644 lib/ABILogs.js delete mode 100644 lib/api.ts delete mode 100644 lib/getReceipts.js delete mode 100644 lib/getToken.ts delete mode 100644 lib/uniswapV2SubGraph.ts create mode 100644 pages/Home.tsx rename pages/{index.js => index.tsx} (50%) diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..415f2cf --- /dev/null +++ b/.env.template @@ -0,0 +1,2 @@ +NEXT_PUBLIC_INFURA_ID= +FLASHBOTS_API_URL=https://blocks.flashbots.net/v1/blocks \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1437c53..3f21c02 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files +.env .env.local .env.development.local .env.test.local @@ -32,3 +33,4 @@ yarn-error.log* # vercel .vercel + diff --git a/components/Bundles.tsx b/components/Bundles.tsx index dfc0813..d051d83 100644 --- a/components/Bundles.tsx +++ b/components/Bundles.tsx @@ -2,19 +2,35 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import BundleModal from './BundleModal'; import styles from '../styles/Home.module.css'; -import { getBlocks } from '../lib/api'; +import { useBundleData } from '../context/BundleData/BundleDataProvider'; -export default function Bundles({ bundles }) { +export default function Bundles({ }) { const router = useRouter(); + const { blocks, setFilters, filters } = useBundleData() const [openModal, setOpenModal] = useState(false); const [bundle, setBundle] = useState(undefined); const [searchValue, setSearch] = useState(undefined); useEffect(() => { - if (router.query.block) { - findBundleAndOpen(router.query.block as unknown as string); + if (router.query.block && blocks.length > 0) { + const blockNumber = router.query.block as unknown as string + const local = blocks.find(b => b.block_number == blockNumber); + if (local) { + setBundleAndOpen(local); + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: blockNumber + }) + } + } else if (filters.block_number) { + setBundleAndOpen(undefined) + setFilters({ + ...filters, + block_number: undefined + }) } - }, [router.query.block]); + }, [router.query.block, blocks]); const setBundleAndOpen = bundle => { if (bundle !== undefined) { @@ -25,19 +41,7 @@ export default function Bundles({ bundles }) { }; const findBundleAndOpen = async (blockNumber: string) => { - const local = bundles.find(b => b.block_number == blockNumber); - if (local) { - setBundleAndOpen(local); - } else { - try { - const blocks = await getBlocks({ block_number: blockNumber }) - if (blocks) { - setBundleAndOpen(blocks[0]); - } - } catch (e) { - setBundleAndOpen(undefined); - } - } + }; const submit = e => { @@ -67,7 +71,7 @@ export default function Bundles({ bundles }) { - { bundles?.sort(sortBlocks).map((b, i) => ) } + { blocks?.sort(sortBlocks).map((b, i) => ) } diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx new file mode 100644 index 0000000..7d61e1a --- /dev/null +++ b/context/BundleData/BundleDataProvider.tsx @@ -0,0 +1,116 @@ +import { useRouter } from "next/router" +import * as React from "react" +import { useCallback, useEffect } from "react" +import { useState } from "react" + +type BundleDataContextProps = { + children: React.ReactNode | React.ReactNode[] +} + +// TODO Update +export type Block = { + hash: string + block_number: string +} + +export interface IBundleFilters { + from?: string | string[] + to?: string + block_number?: string + limit: number +} + +interface IBundleDataContext { + blocks: Block[] + page: number + setPage: (page: number) => void + filters: IBundleFilters + setFilters: (newFilter: IBundleFilters) => void +} + +const BundleDataContext = React.createContext(undefined) + +const BundleDataProvider = ({ children }: BundleDataContextProps) => { + const { query } = useRouter(); + const [blocks, setBlocks] = useState([]) + const [page, setPage] = useState(1) + const [filters, _setFilters] = useState({ + limit: 10 + }) + + // Update filter from query + useEffect(() => { + const { from } = query; + if (from && filters.from != from) { + _setFilters({ + ...filters, + from: from + }) + } + }, [query.from]); + + useEffect(() => { + // Change page back to first if filters are changed + setPage(1) + }, [filters, setPage]) + + function getSubBundles(bundle) { + return bundle.transactions.reduce((acc, curr) => { + if (acc[curr.bundle_index]) { + acc[curr.bundle_index].push(curr); + } else { + acc[curr.bundle_index] = [curr]; + } + return acc; + }, []); + } + + function transformBundle(bundle) { + bundle.transactions = getSubBundles(bundle); + return bundle; + } + + const getBlocks = useCallback(async () => { + // TODO: Type Safety + let params: Record = {} + Object.keys(filters).map(key => params[key] = filters[key]) + + const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` + const res = await fetch(url) + const { blocks } = await res.json() + setBlocks(blocks.map(block => transformBundle(block))) + }, []) + + // Automatically update when view is changed + useEffect(() => { + getBlocks() + }, [filters, page]) + + const setFilters = useCallback((filter: IBundleFilters) => { + + }, []) + + return ( + + {children} + + ) +} + +const useBundleData = () => { + const context = React.useContext(BundleDataContext) + if (context === undefined) { + throw new Error("useBundleData must be used within a BundleDataProvider") + } + return context +} + +export { BundleDataProvider, useBundleData } diff --git a/context/TokenData/TokenDataProvider.tsx b/context/TokenData/TokenDataProvider.tsx new file mode 100644 index 0000000..0ebdc9e --- /dev/null +++ b/context/TokenData/TokenDataProvider.tsx @@ -0,0 +1,199 @@ +import * as React from "react" +import { useCallback, useEffect } from "react" +import { useState } from "react" +import { addABI, decodeLogs } from "abi-decoder"; +import { Interface } from "@ethersproject/abi"; +const DEXES = ["COINGECKO"]; + +export const eventsJson = [ + //erc20 + { "text_signature": "event Transfer(address indexed from, address indexed to, uint256 value)", }, + { "text_signature": "event Approval(address indexed owner, address indexed spender, uint256 value)", }, + //WETH + { "text_signature": "event Deposit(address indexed dst, uint wad)", }, + { "text_signature": "event Withdrawal(address indexed src, uint wad)", }, + //IUniswapExchange + { "text_signature": "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)" }, + { "text_signature": "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" }, + { "text_signature": "event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, + { "text_signature": "event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, + //IUniswapV2Pair + { "text_signature": "event Mint(address indexed sender, uint amount0, uint amount1)" }, + { "text_signature": "event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)" }, + { "text_signature": "event Swap(address indexed sender, uint amount0, uint amount1, uint amount0Out, uint amount1Out, address indexed to)" }, + { "text_signature": "event Sync(uint112 reserve0, uint112 reserve1)" } +]; + + +// const USDC = { +// "chainId": 1, +// "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", +// "name": "USD Coin", +// "symbol": "USDC", +// "decimals": 6, +// "logoURI": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" +// }; + +const uniswapV2GQL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2"; +const ethQL = `{ + bundles (first:1) { + ethPrice + } +}`; + + +type TokenDataContextProps = { + children: React.ReactNode | React.ReactNode[] +} + +// TODO Update +export type Token = { + address: string + coin: string + logo: string + decimals: number +} + +export type Log = { + +} + +interface ITokenDataContextProps { + tokens: Token[] + getReceipts: (transaction: object) => Promise +} + + +const TokenDataContext = React.createContext(undefined) + +const TokenDataProvider = ({ children }: TokenDataContextProps) => { + const [tokens, setTokens] = useState([]) + + const loadTokens = useCallback(async () => { + DEXES.map(d => { + let { tokens } = require(`./tokensList/json${d}.json`) + console.log(tokens) + setTokens(tokens) + }) + }, []) + + const addEvents = async () => { + eventsJson.map(async e => { + let { text_signature } = e; + try { + let i = new Interface([text_signature]); + await addABI(i.fragments); + } catch (e) { + console.log(e); + } + }); + }; + + const getEthPrice = async () => { + const res = await fetch(uniswapV2GQL, { + method: 'POST', + headers: { + 'Accept': 'api_version=2', + 'Content-Type': 'application/graphql' + }, + body: JSON.stringify({ query : ethQL }) + }); + + const { data: { bundles } } = await res.json(); + + if (bundles.length > 0) { + return parseFloat(bundles[0].ethPrice).toFixed(6); + } + + return "1"; + } + + const getAllLogs = async (_logs) =>{ + const ethPrice = await getEthPrice(); + return decodeLogs(_logs).map(log => { + const { coin, logo, decimals } = tokens.find(token => token.address === log.address) + let ethValue = "0"; + let value; + + log.events.map(e => { + if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { + value = parseFloat(`${e.value / 10 ** decimals}`).toFixed(2); + if (coin === 'WETH') { + ethValue = parseFloat(`${value * parseFloat(ethPrice)}`).toFixed(2); + } + } + }); + + log.coin = { + address: log.address, + name: coin, + event: log.name, + logo, + decimals, + value, + ethValue + }; + + return log; + }); + } + + const getReceipts = useCallback(async (transaction) => { + const jsonrpc = { + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [], + "id": 1 + }; + + const params = { + method: "POST", + headers: { + "Accept": "application/json", + "Content-Type": "application/json" + }, + body: "" + }; + + const { transaction_hash } = transaction; + jsonrpc.params = [transaction_hash]; + params.body = JSON.stringify(jsonrpc); + + try { + const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params); + const { result : { logs } } = await res.json(); + return getAllLogs(logs) + } catch(e) { + console.log(e); + } + + return [] + }, []) + + // Fetch initial + useEffect(() => { + addEvents() + loadTokens() + }, []) + + return ( + + {children} + + ) +} + +const useTokenData = () => { + const context = React.useContext(TokenDataContext) + if (context === undefined) { + throw new Error("useTokenData must be used within a TokenDataContextProvider") + } + return context +} + +export { TokenDataProvider, useTokenData } diff --git a/tokensList/fetchTokensApiByDex.js b/context/TokenData/tokensList/fetchTokensApiByDex.js similarity index 100% rename from tokensList/fetchTokensApiByDex.js rename to context/TokenData/tokensList/fetchTokensApiByDex.js diff --git a/tokensList/jsonCOINGECKO.json b/context/TokenData/tokensList/jsonCOINGECKO.json similarity index 100% rename from tokensList/jsonCOINGECKO.json rename to context/TokenData/tokensList/jsonCOINGECKO.json diff --git a/tokensList/tokensCOINGECKO.json b/context/TokenData/tokensList/tokensCOINGECKO.json similarity index 100% rename from tokensList/tokensCOINGECKO.json rename to context/TokenData/tokensList/tokensCOINGECKO.json diff --git a/lib/ABILogs.js b/lib/ABILogs.js deleted file mode 100644 index 49a4dae..0000000 --- a/lib/ABILogs.js +++ /dev/null @@ -1,67 +0,0 @@ -import { addABI, decodeLogs } from "abi-decoder"; -import { Interface } from "@ethersproject/abi"; -import { getToken } from "./getToken"; -import { getEthPrice } from "./uniswapV2SubGraph"; - -const eventsJson = [ - //erc20 - { "text_signature": "event Transfer(address indexed from, address indexed to, uint256 value)", }, - { "text_signature": "event Approval(address indexed owner, address indexed spender, uint256 value)", }, - //WETH - { "text_signature": "event Deposit(address indexed dst, uint wad)", }, - { "text_signature": "event Withdrawal(address indexed src, uint wad)", }, - //IUniswapExchange - { "text_signature": "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)" }, - { "text_signature": "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" }, - { "text_signature": "event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, - { "text_signature": "event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, - //IUniswapV2Pair - { "text_signature": "event Mint(address indexed sender, uint amount0, uint amount1)" }, - { "text_signature": "event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)" }, - { "text_signature": "event Swap(address indexed sender, uint amount0, uint amount1, uint amount0Out, uint amount1Out, address indexed to)" }, - { "text_signature": "event Sync(uint112 reserve0, uint112 reserve1)" } -]; - -const addEvents = async () => { - eventsJson.map(async e => { - let { text_signature } = e; - try { - let i = new Interface([text_signature]); - await addABI(i.fragments); - } catch (e) { - console.log(e); - } - }); -}; - -addEvents(); - -export async function getAllLogs(_logs) { - const ethPrice = await getEthPrice(); - return decodeLogs(_logs).map(log => { - const { coin, logo, decimals } = getToken(log.address); - let ethValue = 0; - let value; - - log.events.map(e => { - if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { - value = parseFloat(e.value / 10 ** decimals).toFixed(2); - if (coin === 'WETH') { - ethValue = parseFloat(value * ethPrice).toFixed(2); - } - } - }); - - log.coin = { - address: log.address, - name: coin, - event: log.name, - logo, - decimals, - value, - ethValue - }; - - return log; - }); -} diff --git a/lib/api.ts b/lib/api.ts deleted file mode 100644 index b408d87..0000000 --- a/lib/api.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const API_URL = 'https://blocks.flashbots.net/v1/blocks'; - -export async function getBlocks(params: Record = {}) { - params.limit = '10'; - const url = `${API_URL}/?${new URLSearchParams(params)}`; - const res = await fetch(url); - const { blocks } = await res.json(); - return blocks.map(block => transformBundle(block)); -} - -function getSubBundles(bundle) { - return bundle.transactions.reduce((acc, curr) => { - if (acc[curr.bundle_index]) { - acc[curr.bundle_index].push(curr); - } else { - acc[curr.bundle_index] = [curr]; - } - return acc; - }, []); -} - -function transformBundle(bundle) { - bundle.transactions = getSubBundles(bundle); - return bundle; -} diff --git a/lib/getReceipts.js b/lib/getReceipts.js deleted file mode 100644 index 120d546..0000000 --- a/lib/getReceipts.js +++ /dev/null @@ -1,33 +0,0 @@ -import { getAllLogs } from '../lib/ABILogs'; - -export async function getReceipts(transaction) { - const jsonrpc = { - "jsonrpc": "2.0", - "method": "eth_getTransactionReceipt", - "params": [], - "id": 1 - }; - - const params = { - method: "POST", - headers: { - "Accept": "application/json", - "Content-Type": "application/json" - }, - body: "" - }; - - const { transaction_hash } = transaction; - jsonrpc.params = [transaction_hash]; - params.body = JSON.stringify(jsonrpc); - - try { - const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params); - const { result : { logs } } = await res.json(); - return getAllLogs(logs); - } catch(e) { - console.log(e); - } - - return []; -} diff --git a/lib/getToken.ts b/lib/getToken.ts deleted file mode 100644 index 4af8341..0000000 --- a/lib/getToken.ts +++ /dev/null @@ -1,36 +0,0 @@ -const DEXES = ["COINGECKO"]; - -let tokensList = []; -async function getTokens() { - DEXES.map(d => { - let { tokens } = require(`../tokensList/json${d}.json`) - tokensList.push(tokens); - }) -} - -getTokens(); - -export function getToken(_address: string) { - let c = { - coin: "", - logo: "", - decimals: 18 - }; - - for (let d in tokensList) { - for (let t in tokensList[d]) { - let o = tokensList[d][t]; - if (o.address === _address) { - c.coin = o.symbol; - c.logo = o.logoURI ? o.logoURI : ""; - c.decimals = o.decimals ? o.decimals : 0; - break; - } - } - - if (c.coin !== "") { - break; - } - } - return c; -} diff --git a/lib/uniswapV2SubGraph.ts b/lib/uniswapV2SubGraph.ts deleted file mode 100644 index 1ae9aff..0000000 --- a/lib/uniswapV2SubGraph.ts +++ /dev/null @@ -1,34 +0,0 @@ -// const USDC = { -// "chainId": 1, -// "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", -// "name": "USD Coin", -// "symbol": "USDC", -// "decimals": 6, -// "logoURI": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" -// }; - -const uniswapV2GQL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2"; -const ethQL = `{ - bundles (first:1) { - ethPrice - } -}`; - -export async function getEthPrice() { - const res = await fetch(uniswapV2GQL, { - method: 'POST', - headers: { - 'Accept': 'api_version=2', - 'Content-Type': 'application/graphql' - }, - body: JSON.stringify({ query : ethQL }) - }); - - const { data: { bundles } } = await res.json(); - - if (bundles.length > 0) { - return parseFloat(bundles[0].ethPrice).toFixed(6); - } - - return 1; -} diff --git a/package.json b/package.json index 078c9a3..29b15d1 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@headlessui/react": "^1.1.1", "abi-decoder": "^2.4.0", "csvtojson": "^2.0.10", + "dotenv": "^10.0.0", "fs": "^0.0.1-security", "next": "^10.2.3", "react": "17.0.2", diff --git a/pages/Home.tsx b/pages/Home.tsx new file mode 100644 index 0000000..3d4a46a --- /dev/null +++ b/pages/Home.tsx @@ -0,0 +1,11 @@ +import { useEffect } from 'react'; +import Bundles from '../components/Bundles'; +import * as ga from '../lib/ga'; + +export default function Home({}) { + useEffect(ga.pageview); + // TODO: Move query logic to + return ( + + ) +} diff --git a/pages/index.js b/pages/index.tsx similarity index 50% rename from pages/index.js rename to pages/index.tsx index 55871a4..f396a87 100644 --- a/pages/index.js +++ b/pages/index.tsx @@ -1,25 +1,16 @@ import Head from 'next/head'; -import { useEffect, useState } from 'react'; +import React, { useEffect} from 'react'; import { useRouter } from 'next/router'; -import Bundles from '../components/Bundles'; -import styles from '../styles/Home.module.css'; import * as ga from '../lib/ga'; -import { getBlocks } from '../lib/api'; +import { BundleDataProvider } from '../context/BundleDataProvider'; +import styles from '../styles/Home.module.css'; +import Home from './Home'; +require('dotenv').config() -export default function Home({ initialBlocks }) { +export default function App() { useEffect(ga.pageview); - const [blocks, setBlocks] = useState(initialBlocks); - const router = useRouter(); - useEffect(() => { - const { from } = router.query; - if (from) { - const fetchFrom = async () => setBlocks(await getBlocks({ from })); - fetchFrom(); - } - }, [router.query.from]); - useEffect(() => { const handleRouteChange = (url) => { ga.pageview(url); @@ -32,35 +23,27 @@ export default function Home({ initialBlocks }) { }, [router.events]); return ( -
- + +
+ Contribute in GitHub +

+ + Flashbots Bundle Explorer + 🤖 +

+ 🤖 Flashbots Bundle Explorer ⚡ - Contribute in GitHub - -

- - Flashbots Bundle Explorer - 🤖 -

- - + {/* */} +
brewed with ⚡ by marto.lol ❤️ tip jar: 0x87122a7385fd61720d72290a6f2ed25b7eca7af7 💸
-
+ + ) -} - -export async function getServerSideProps({ query }) { - const { from } = query; - return { - props: { - initialBlocks: await getBlocks(from ? { from } : undefined) - }, - } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2dea298..1654fa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -972,6 +972,11 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + electron-to-chromium@^1.3.723: version "1.3.725" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz#04fc83f9189169aff50f0a00c6b4090b910cba85" From d76142506f1185c5520d6d3cb7998e5937289e60 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Wed, 23 Jun 2021 22:32:06 +0200 Subject: [PATCH 02/28] Working pagination --- components/BundleModal.tsx | 1 - pages/index.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/BundleModal.tsx b/components/BundleModal.tsx index 4d7b25c..fff28ed 100644 --- a/components/BundleModal.tsx +++ b/components/BundleModal.tsx @@ -2,7 +2,6 @@ import { Fragment, useRef, useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { Dialog, Transition } from '@headlessui/react'; -import { getReceipts } from '../lib/getReceipts'; export default function BundleModal({ open, bundle, setOpen }) { const cancelButtonRef = useRef(); diff --git a/pages/index.tsx b/pages/index.tsx index f396a87..3d125bd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,11 +1,11 @@ +require('dotenv').config() import Head from 'next/head'; import React, { useEffect} from 'react'; import { useRouter } from 'next/router'; import * as ga from '../lib/ga'; -import { BundleDataProvider } from '../context/BundleDataProvider'; import styles from '../styles/Home.module.css'; import Home from './Home'; -require('dotenv').config() +import { BundleDataProvider } from '../context/BundleData/BundleDataProvider'; export default function App() { useEffect(ga.pageview); From 1cc289f3d0a006bc8754310c06031a2d01828ac6 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Fri, 25 Jun 2021 17:08:53 +0200 Subject: [PATCH 03/28] Environment vars working --- context/BundleData/BundleDataProvider.tsx | 1 - next.config.js | 15 ++++++++++++++ package.json | 4 +++- pages/index.tsx | 1 - tsconfig.json | 2 +- yarn.lock | 24 ++++++++++++++++++----- 6 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 next.config.js diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 7d61e1a..9ee32d4 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -74,7 +74,6 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // TODO: Type Safety let params: Record = {} Object.keys(filters).map(key => params[key] = filters[key]) - const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` const res = await fetch(url) const { blocks } = await res.json() diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..508524f --- /dev/null +++ b/next.config.js @@ -0,0 +1,15 @@ +require('dotenv').config() +module.exports = { + env: { + NEXT_PUBLIC_INFURA_ID: process.env.NEXT_PUBLIC_INFURA_ID, + FLASHBOTS_API_URL: process.env.FLASHBOTS_API_URL + }, + future: { + webpack5: true, + }, + webpack: (config) => { + config.resolve.fallback = { fs: false }; + + return config; + }, +}; \ No newline at end of file diff --git a/package.json b/package.json index 29b15d1..2fa3f69 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "abi-decoder": "^2.4.0", "csvtojson": "^2.0.10", "dotenv": "^10.0.0", - "fs": "^0.0.1-security", "next": "^10.2.3", "react": "17.0.2", "react-dom": "^17.0.2" @@ -23,5 +22,8 @@ "postcss": "^8.2.13", "tailwindcss": "^2.1.4", "typescript": "^4.2.4" + }, + "browser": { + "fs": false } } diff --git a/pages/index.tsx b/pages/index.tsx index 3d125bd..54ec829 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,3 @@ -require('dotenv').config() import Head from 'next/head'; import React, { useEffect} from 'react'; import { useRouter } from 'next/router'; diff --git a/tsconfig.json b/tsconfig.json index 9b613cf..9948595 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,5 @@ ], "exclude": [ "node_modules" - ] + ], } diff --git a/yarn.lock b/yarn.lock index 1654fa1..71940a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -972,11 +972,30 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +dotenv-defaults@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz#6b3ec2e4319aafb70940abda72d3856770ee77ac" + integrity sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg== + dependencies: + dotenv "^8.2.0" + +dotenv-webpack@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-7.0.3.tgz#f50ec3c7083a69ec6076e110566720003b7b107b" + integrity sha512-O0O9pOEwrk+n1zzR3T2uuXRlw64QxHSPeNN1GaiNBloQFNaCUL9V8jxSVz4jlXXFP/CIqK8YecWf8BAvsSgMjw== + dependencies: + dotenv-defaults "^2.0.2" + dotenv@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + electron-to-chromium@^1.3.723: version "1.3.725" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz#04fc83f9189169aff50f0a00c6b4090b910cba85" @@ -1168,11 +1187,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ= - fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" From df68fb75d6f2f5f09f55a31fc88d7f058ec7f6d5 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Fri, 25 Jun 2021 18:24:44 +0200 Subject: [PATCH 04/28] Broke out components --- components/Address.tsx | 7 +++++ components/BundleModal.tsx | 36 ++++++----------------- components/Bundles.tsx | 14 ++++++++- components/icons/externalLink.icon.tsx | 4 +++ components/icons/openBook.icon.tsx | 3 ++ components/modals/ErrorModal.tsx | 8 +++++ context/BundleData/BundleDataProvider.tsx | 6 ++++ helpers/general.tsx | 7 +++++ 8 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 components/Address.tsx create mode 100644 components/icons/externalLink.icon.tsx create mode 100644 components/icons/openBook.icon.tsx create mode 100644 components/modals/ErrorModal.tsx create mode 100644 helpers/general.tsx diff --git a/components/Address.tsx b/components/Address.tsx new file mode 100644 index 0000000..3126cba --- /dev/null +++ b/components/Address.tsx @@ -0,0 +1,7 @@ +export const Address = ({ address } : { address: string }) => { + const size = 6; + const shorten = (address: string): string => address.slice(0, size) + '...' + address.slice(-size); + return +
{ shorten(address) }
+
; +} \ No newline at end of file diff --git a/components/BundleModal.tsx b/components/BundleModal.tsx index fff28ed..09f2481 100644 --- a/components/BundleModal.tsx +++ b/components/BundleModal.tsx @@ -1,7 +1,11 @@ /* This example requires Tailwind CSS v2.0+ */ -import { Fragment, useRef, useState, useEffect } from 'react'; +import React, { Fragment, useRef, useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { Dialog, Transition } from '@headlessui/react'; +import { useTokenData } from '../context/TokenData/TokenDataProvider'; +import { Address } from './Address'; +import { timeNow } from '../helpers/general'; +import { ErrorModal } from './modals/ErrorModal'; export default function BundleModal({ open, bundle, setOpen }) { const cancelButtonRef = useRef(); @@ -62,7 +66,7 @@ export default function BundleModal({ open, bundle, setOpen }) { { bundle ? - : + : } @@ -181,7 +185,7 @@ const ExternalLinkIcon = { Object.keys(coins).map(coin =>
- + { coins[coin].logo - ? + ? : <> } { coin } @@ -276,25 +280,3 @@ function BundleTransaction(transaction, index: number) { ; } -const Error = () =>
- - Oops - -
Bundle not found, have this instead: 🍌
-
; - -function Address({ address } : { address: string }) { - const size = 6; - const shorten = (address: string): string => address.slice(0, size) + '...' + address.slice(-size); - return
-
{ shorten(address) }
-
; -} - -const now = () => { - return randomMaxMin(Date.now(), Date.now()*10000); -}; - -const randomMaxMin = (max, min) => { - return Math.floor(Math.random() * (max - min + 1)) + min; -}; diff --git a/components/Bundles.tsx b/components/Bundles.tsx index d051d83..b614e1e 100644 --- a/components/Bundles.tsx +++ b/components/Bundles.tsx @@ -71,8 +71,20 @@ export default function Bundles({ }) { - { blocks?.sort(sortBlocks).map((b, i) => ) } + { blocks?.sort(sortBlocks).slice(0, filters.limit).map((b, i) => ) } + { + blocks.length > filters.limit && ( +
+ + +
+ ) + }
diff --git a/components/icons/externalLink.icon.tsx b/components/icons/externalLink.icon.tsx new file mode 100644 index 0000000..65408ad --- /dev/null +++ b/components/icons/externalLink.icon.tsx @@ -0,0 +1,4 @@ +export const ExternalLinkIcon = + +; + diff --git a/components/icons/openBook.icon.tsx b/components/icons/openBook.icon.tsx new file mode 100644 index 0000000..c3fa0c5 --- /dev/null +++ b/components/icons/openBook.icon.tsx @@ -0,0 +1,3 @@ +export const OpenBookIcon = + +; diff --git a/components/modals/ErrorModal.tsx b/components/modals/ErrorModal.tsx new file mode 100644 index 0000000..e98a8cd --- /dev/null +++ b/components/modals/ErrorModal.tsx @@ -0,0 +1,8 @@ +import { Dialog } from "@headlessui/react"; + +export const ErrorModal = () =>
+ + Oops + +
Bundle not found, have this instead: 🍌
+
; diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 9ee32d4..05ad691 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -7,6 +7,9 @@ type BundleDataContextProps = { children: React.ReactNode | React.ReactNode[] } +// If we want to display that theres more pages, we'll need to check on ther requests +// const PAGES_AHEAD = 5 + // TODO Update export type Block = { hash: string @@ -74,6 +77,9 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // TODO: Type Safety let params: Record = {} Object.keys(filters).map(key => params[key] = filters[key]) + // This fetchs additional pages to a limit + // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` + params["limit"] = `${Number(params["limit"]) + 1}` const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` const res = await fetch(url) const { blocks } = await res.json() diff --git a/helpers/general.tsx b/helpers/general.tsx new file mode 100644 index 0000000..342ff57 --- /dev/null +++ b/helpers/general.tsx @@ -0,0 +1,7 @@ +export const timeNow = () => { + return randomMaxMin(Date.now(), Date.now()*10000); +}; + +export const randomMaxMin = (max, min) => { + return Math.floor(Math.random() * (max - min + 1)) + min; +}; From 21a989e043f43b490b935e6a10b1c68323c2ed59 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Fri, 25 Jun 2021 19:34:40 +0200 Subject: [PATCH 05/28] Manually styling --- components/BundleModal.tsx | 282 ------------------ components/Bundles.tsx | 144 --------- components/bundles/Bundle.tsx | 72 +++++ components/bundles/BundleModal.tsx | 87 ++++++ components/bundles/BundleRow.tsx | 46 +++ components/bundles/BundleTransaction.tsx | 104 +++++++ components/bundles/BundlesOverview.tsx | 119 ++++++++ components/bundles/Helpers.tsx | 1 + components/bundles/Subbundle.tsx | 28 ++ .../bundles/css/BundleOverview.module.css | 50 ++++ context/BundleData/BundleDataProvider.tsx | 18 ++ package.json | 1 + pages/Home.tsx | 6 +- styles/Home.module.css | 129 -------- yarn.lock | 24 +- 15 files changed, 534 insertions(+), 577 deletions(-) delete mode 100644 components/BundleModal.tsx delete mode 100644 components/Bundles.tsx create mode 100644 components/bundles/Bundle.tsx create mode 100644 components/bundles/BundleModal.tsx create mode 100644 components/bundles/BundleRow.tsx create mode 100644 components/bundles/BundleTransaction.tsx create mode 100644 components/bundles/BundlesOverview.tsx create mode 100644 components/bundles/Helpers.tsx create mode 100644 components/bundles/Subbundle.tsx create mode 100644 components/bundles/css/BundleOverview.module.css diff --git a/components/BundleModal.tsx b/components/BundleModal.tsx deleted file mode 100644 index 09f2481..0000000 --- a/components/BundleModal.tsx +++ /dev/null @@ -1,282 +0,0 @@ -/* This example requires Tailwind CSS v2.0+ */ -import React, { Fragment, useRef, useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { Dialog, Transition } from '@headlessui/react'; -import { useTokenData } from '../context/TokenData/TokenDataProvider'; -import { Address } from './Address'; -import { timeNow } from '../helpers/general'; -import { ErrorModal } from './modals/ErrorModal'; - -export default function BundleModal({ open, bundle, setOpen }) { - const cancelButtonRef = useRef(); - const router = useRouter(); - const close = () => { - setOpen(false); - if (bundle) { - router.back(); - } - }; - - useEffect(() => { - const { block } = router.query; - if (block === undefined) { - setOpen(false); - } - }, [router.query.block]); - - return ( - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
-
- { - bundle - ? - : - } -
-
-
- -
-
-
-
-
-
- ) -} - -const Bundle = ({ bundle }) => { - return
- - Bundles in # - - { bundle?.block_number } - - - -
-
-
- - - - - - - - - - - - - - - { - bundle.transactions.length > 1 - ? bundle.transactions.map((sb, i) => ) - : - } - - - - - - - - - - - - -
HashFromToAssetsGas usedGas priceCoinbase transferMiner reward
- { bundle.transactions.length } bundles - - { bundle.transactions.reduce((acc, b) => acc + b.length, 0) } transactions - - { bundle.transactions.reduce((acc, txs) => acc + txs.reduce((ac2, tx) => ac2 + tx.gas_used, 0), 0) - } - - { Math.round(bundle.miner_reward / bundle.gas_used / (10 ** 9)) } gwei - - Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'coinbase_transfer')), 0).toFixed(4) } - - Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'total_miner_reward')), 0).toFixed(4) } -
-
-
-
-
; -} - -function SubBundle({ subBundle, index } : { subBundle: any[], index?: number }) { - return <> - { subBundle.map(BundleTransaction) } - { - index === undefined - ? <> - : - - #{ index + 1 } - - - - { Math.round(subBundle.reduce((acc, tx) => acc + tx.gas_used, 0)) } - - - - Ξ { summarizeFp(subBundle, 'coinbase_transfer') } - - - Ξ { summarizeFp(subBundle, 'total_miner_reward') } - - - } - ; -} - -const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4); - -const ExternalLinkIcon = - -; - -function BundleTransaction(transaction, index: number) { - const [logs, setLogs] = useState([]); - const { getReceipts } = useTokenData() - const router = useRouter(); - const onClick = (e, from) => { - e.preventDefault(); - router.push(`/?from=${from}`, undefined, { shallow: true }); - }; - - useEffect( () => { - const getLogs = async () => setLogs(await getReceipts(transaction)); - getLogs(); - }, [transaction]); - - const coins = logs.reduce((acc, curr) => { - if (curr.coin.name && (curr.coin.value || acc[curr.coin.name] === undefined)) { - acc[curr.coin.name] = { - event: curr.coin.event, - address: curr.coin.address, - logo: curr.coin.logo, - value: curr.coin.value, - ethValue: curr.coin.ethValue - } - } - return acc; - }, {}); - - // block_number: 12358944 - // coinbase_transfer: "9785908415014455" - // eoa_address: "0x07A962Ea36DdddA0c6e594F8A29b89aC06EC8FB7" - // gas_price: "0" - // gas_used: 89458 - // to_address: "0xa57Bd00134B2850B2a1c55860c9e9ea100fDd6CF" - // total_miner_reward: "9785908415014455" - // transaction_hash: "0xedbaa982717813b69e215fe08525ae85c3686a095a1b908714ef8755f58e754d" - // tx_index: 0 - return - - - - { ExternalLinkIcon } - { transaction?.transaction_hash.slice(0, 10) }... - - - - - - -
- - - { - Object.keys(coins).map(coin =>
- - { - coins[coin].logo - ? - : <> - } - { coin } - - { coins[coin].value > 0 ? " " + coins[coin].value : "" } - { coins[coin].ethValue > 0 ? " ($"+coins[coin].ethValue +")" : "" } - { coins[coin].value ? "" : ` (${coins[coin].event})` } -
) - } - - -
- { Math.round(transaction?.gas_used) } -
- - -
- { Math.round(transaction?.gas_price / (10 ** 9)) } gwei -
- - -
- Ξ { (transaction?.coinbase_transfer / (10 ** 18)).toFixed(4) } -
- - -
- Ξ { (transaction?.total_miner_reward / (10 ** 18)).toFixed(4) } -
- - - ; -} - diff --git a/components/Bundles.tsx b/components/Bundles.tsx deleted file mode 100644 index b614e1e..0000000 --- a/components/Bundles.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import BundleModal from './BundleModal'; -import styles from '../styles/Home.module.css'; -import { useBundleData } from '../context/BundleData/BundleDataProvider'; - -export default function Bundles({ }) { - const router = useRouter(); - const { blocks, setFilters, filters } = useBundleData() - const [openModal, setOpenModal] = useState(false); - const [bundle, setBundle] = useState(undefined); - const [searchValue, setSearch] = useState(undefined); - - useEffect(() => { - if (router.query.block && blocks.length > 0) { - const blockNumber = router.query.block as unknown as string - const local = blocks.find(b => b.block_number == blockNumber); - if (local) { - setBundleAndOpen(local); - } else if(!filters.block_number) { - setFilters({ - ...filters, - block_number: blockNumber - }) - } - } else if (filters.block_number) { - setBundleAndOpen(undefined) - setFilters({ - ...filters, - block_number: undefined - }) - } - }, [router.query.block, blocks]); - - const setBundleAndOpen = bundle => { - if (bundle !== undefined) { - router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }); - } - setBundle(bundle); - setOpenModal(true); - }; - - const findBundleAndOpen = async (blockNumber: string) => { - - }; - - const submit = e => { - e.preventDefault(); - findBundleAndOpen(searchValue); - }; - - return
- -
- Search by block number - setSearch(e.target.value) } /> - -
-
-
-
- - - - - - - - - - - - - { blocks?.sort(sortBlocks).slice(0, filters.limit).map((b, i) => ) } - - { - blocks.length > filters.limit && ( -
- - -
- ) - } -
Block numberMiner rewardGas usedEffective gas priceBundlesInspect
-
-
-
-
; -}; - -function sortBlocks(a, b): number { - if (a.block_number < b.block_number) return 1; - if (a.block_number > b.block_number) return -1; - return 0; -} - -const ExternalLinkIcon = - -; - -const OpenBookIcon = - -; - -function Bundle({ index, bundle, setBundleAndOpen }) { - const onClick = e => { - e.preventDefault(); - setBundleAndOpen(bundle); - }; - - return - - - { ExternalLinkIcon } - { bundle?.block_number } - - - - - Ξ { (bundle?.miner_reward / (10 ** 18)).toFixed(4) } - - - -
{ bundle?.gas_used}
- - -
- { Math.round(bundle?.miner_reward / bundle?.gas_used / (10 ** 9)) } gwei -
- - -
- { bundle.transactions.length } -
- - - { OpenBookIcon } - - ; -} diff --git a/components/bundles/Bundle.tsx b/components/bundles/Bundle.tsx new file mode 100644 index 0000000..756ff44 --- /dev/null +++ b/components/bundles/Bundle.tsx @@ -0,0 +1,72 @@ +import { Dialog } from "@headlessui/react"; +import React from "react"; +import { Block } from "../../context/BundleData/BundleDataProvider"; +import { summarizeFp } from "./Helpers"; +import { SubBundle } from "./Subbundle"; + +interface IBundle { + bundle: Block +} + +export const Bundle = ({ bundle }: IBundle) => { + return
+ + Bundles in # + + { bundle?.block_number } + + + +
+
+
+ + + + + + + + + + + + + + + { + bundle.transactions.length > 1 + ? bundle.transactions.map((sb, i) => ) + : + } + + + + + + + + + + + + +
HashFromToAssetsGas usedGas priceCoinbase transferMiner reward
+ { bundle.transactions.length } bundles + + { bundle.transactions.reduce((acc, b) => acc + b.length, 0) } transactions + + { bundle.transactions.reduce((acc, txs) => acc + txs.reduce((ac2, tx) => ac2 + tx.gas_used, 0), 0) + } + + { Math.round(bundle.miner_reward / bundle.gas_used / (10 ** 9)) } gwei + + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'coinbase_transfer')), 0).toFixed(4) } + + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'total_miner_reward')), 0).toFixed(4) } +
+
+
+
+
; +} diff --git a/components/bundles/BundleModal.tsx b/components/bundles/BundleModal.tsx new file mode 100644 index 0000000..4256a66 --- /dev/null +++ b/components/bundles/BundleModal.tsx @@ -0,0 +1,87 @@ +/* This example requires Tailwind CSS v2.0+ */ +import React, { Fragment, useRef, useEffect } from 'react'; +import { useRouter } from 'next/router'; +import { Dialog, Transition } from '@headlessui/react'; +import { Bundle } from '../bundles/Bundle'; +import { ErrorModal } from '../modals/ErrorModal'; + +export default function BundleModal({ open, bundle, setOpen }) { + const cancelButtonRef = useRef(); + const router = useRouter(); + const close = () => { + setOpen(false); + if (bundle) { + router.back(); + } + }; + + useEffect(() => { + const { block } = router.query; + if (block === undefined) { + setOpen(false); + } + }, [router.query.block]); + + return ( + + +
+ + + + + {/* This element is to trick the browser into centering the modal contents. */} + + +
+
+
+ { + bundle + ? + : + } +
+
+
+ +
+
+
+
+
+
+ ) +} diff --git a/components/bundles/BundleRow.tsx b/components/bundles/BundleRow.tsx new file mode 100644 index 0000000..da31f9c --- /dev/null +++ b/components/bundles/BundleRow.tsx @@ -0,0 +1,46 @@ +import { Block } from "../../context/BundleData/BundleDataProvider"; +import { ExternalLinkIcon } from "../icons/externalLink.icon"; +import { OpenBookIcon } from "../icons/openBook.icon"; + +interface IBundleRow { + index: number + bundle: Block + setBundleAndOpen: (bundle: Block) => void +} + +export const BundleRow = ({ index, bundle, setBundleAndOpen }: IBundleRow) => { + const onClick = e => { + e.preventDefault(); + setBundleAndOpen(bundle); + }; + + return + + + { ExternalLinkIcon } + { bundle?.block_number } + + + + + Ξ { (bundle?.miner_reward / (10 ** 18)).toFixed(4) } + + + +
{ bundle?.gas_used}
+ + +
+ { Math.round(bundle?.miner_reward / bundle?.gas_used / (10 ** 9)) } gwei +
+ + +
+ { bundle.transactions.length } +
+ + + { OpenBookIcon } + + ; +} diff --git a/components/bundles/BundleTransaction.tsx b/components/bundles/BundleTransaction.tsx new file mode 100644 index 0000000..855361d --- /dev/null +++ b/components/bundles/BundleTransaction.tsx @@ -0,0 +1,104 @@ +import { useRouter } from "next/router"; +import React, { Fragment, useEffect, useState } from "react"; +import { useTokenData } from "../../context/TokenData/TokenDataProvider"; +import { timeNow } from "../../helpers/general"; +import { Address } from "../Address"; +import { ExternalLinkIcon } from "../icons/externalLink.icon"; + +export const BundleTransaction = (transaction, index: number) => { + const [logs, setLogs] = useState([]); + const { getReceipts } = useTokenData() + const router = useRouter(); + const onClick = (e, from) => { + e.preventDefault(); + router.push(`/?from=${from}`, undefined, { shallow: true }); + }; + + useEffect( () => { + const getLogs = async () => setLogs(await getReceipts(transaction)); + getLogs(); + }, [transaction]); + + const coins = logs.reduce((acc, curr) => { + if (curr.coin.name && (curr.coin.value || acc[curr.coin.name] === undefined)) { + acc[curr.coin.name] = { + event: curr.coin.event, + address: curr.coin.address, + logo: curr.coin.logo, + value: curr.coin.value, + ethValue: curr.coin.ethValue + } + } + return acc; + }, {}); + + // block_number: 12358944 + // coinbase_transfer: "9785908415014455" + // eoa_address: "0x07A962Ea36DdddA0c6e594F8A29b89aC06EC8FB7" + // gas_price: "0" + // gas_used: 89458 + // to_address: "0xa57Bd00134B2850B2a1c55860c9e9ea100fDd6CF" + // total_miner_reward: "9785908415014455" + // transaction_hash: "0xedbaa982717813b69e215fe08525ae85c3686a095a1b908714ef8755f58e754d" + // tx_index: 0 + return + + + + { ExternalLinkIcon } + { transaction?.transaction_hash.slice(0, 10) }... + + + + + + +
+ + + { + Object.keys(coins).map(coin =>
+ + { + coins[coin].logo + ? + : <> + } + { coin } + + { coins[coin].value > 0 ? " " + coins[coin].value : "" } + { coins[coin].ethValue > 0 ? " ($"+coins[coin].ethValue +")" : "" } + { coins[coin].value ? "" : ` (${coins[coin].event})` } +
) + } + + +
+ { Math.round(transaction?.gas_used) } +
+ + +
+ { Math.round(transaction?.gas_price / (10 ** 9)) } gwei +
+ + +
+ Ξ { (transaction?.coinbase_transfer / (10 ** 18)).toFixed(4) } +
+ + +
+ Ξ { (transaction?.total_miner_reward / (10 ** 18)).toFixed(4) } +
+ + + ; +} + diff --git a/components/bundles/BundlesOverview.tsx b/components/bundles/BundlesOverview.tsx new file mode 100644 index 0000000..ebf2e21 --- /dev/null +++ b/components/bundles/BundlesOverview.tsx @@ -0,0 +1,119 @@ +import React, { useState, useEffect } from 'react'; +import { useRouter } from 'next/router'; +import styles from './css/BundleOverview.module.css'; +import { BundleRow } from './BundleRow'; +import { useBundleData } from '../../context/BundleData/BundleDataProvider'; +import BundleModal from './BundleModal'; +import clsx from 'clsx'; + +export default function BundlesOverview({ }) { + const router = useRouter(); + const { blocks, setFilters, filters, page, morePages, setPage } = useBundleData() + const [openModal, setOpenModal] = useState(false); + const [bundle, setBundle] = useState(undefined); + const [searchValue, setSearch] = useState(undefined); + + useEffect(() => { + if (router.query.block && blocks.length > 0) { + const blockNumber = router.query.block as unknown as string + const local = blocks.find(b => b.block_number == blockNumber); + if (local) { + setBundleAndOpen(local); + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: blockNumber + }) + } + } else if (filters.block_number) { + setBundleAndOpen(undefined) + setFilters({ + ...filters, + block_number: undefined + }) + } + }, [router.query.block, blocks]); + + const setBundleAndOpen = bundle => { + if (bundle !== undefined) { + router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }); + } + setBundle(bundle); + setOpenModal(true); + }; + + const findBundleAndOpen = async (blockNumber: string) => { + + }; + + const submit = e => { + e.preventDefault(); + findBundleAndOpen(searchValue); + }; + + function sortBlocks(a, b): number { + if (a.block_number < b.block_number) return 1; + if (a.block_number > b.block_number) return -1; + return 0; + } + + return
+ +
+ Search by block number + setSearch(e.target.value) } /> + +
+
+
+
+ + + + + + + + + + + + + { blocks?.sort(sortBlocks).slice(0, filters.limit).map((b, i) => ) } + +
Block numberMiner rewardGas usedEffective gas priceBundlesInspect
+ { + (blocks.length > filters.limit) || page > 1 && ( +
+ + +
+ ) + } +
+
+
+
; +}; diff --git a/components/bundles/Helpers.tsx b/components/bundles/Helpers.tsx new file mode 100644 index 0000000..a5dd795 --- /dev/null +++ b/components/bundles/Helpers.tsx @@ -0,0 +1 @@ +export const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4); diff --git a/components/bundles/Subbundle.tsx b/components/bundles/Subbundle.tsx new file mode 100644 index 0000000..69dfb49 --- /dev/null +++ b/components/bundles/Subbundle.tsx @@ -0,0 +1,28 @@ +import { BundleTransaction } from "./BundleTransaction"; +import { summarizeFp } from "./Helpers"; + +export const SubBundle = ({ subBundle, index } : { subBundle: any[], index?: number }) => { + return <> + { subBundle.map(BundleTransaction) } + { + index === undefined + ? <> + : + + #{ index + 1 } + + + + { Math.round(subBundle.reduce((acc, tx) => acc + tx.gas_used, 0)) } + + + + Ξ { summarizeFp(subBundle, 'coinbase_transfer') } + + + Ξ { summarizeFp(subBundle, 'total_miner_reward') } + + + } + ; +} \ No newline at end of file diff --git a/components/bundles/css/BundleOverview.module.css b/components/bundles/css/BundleOverview.module.css new file mode 100644 index 0000000..e7fa83f --- /dev/null +++ b/components/bundles/css/BundleOverview.module.css @@ -0,0 +1,50 @@ +.search { + @apply inline-flex self-center bg-gray-200 items-center mb-7; + padding: 0 0 0 1.3rem; + border-radius: 2rem; +} + +.search span { + @apply hidden sm:inline; +} + +.search input { + margin: 0 0 0 1rem; + padding: .5rem; +} + +.search button { + text-align: center; + padding: .6rem 1.3rem .5rem .75rem; + font-family: 'Nunito Sans', sans-serif; + color: white; + border-radius: 0 2rem 2rem 0; + align-self: center; +} + +.search button:hover { + color: white; + box-shadow: 4px 4px 16px #f1f1f1, -4px -4px 16px #e6e6e6; + background: linear-gradient(-60deg, #e44e4e, #fa5549, #ffd035, #fa9049, #ff5151); + background-size: 400% 400%; + animation: Gradient 9s ease infinite; + -moz-animation: Gradient 9s ease infinite; + -webkit-animation: Gradient 9s ease infinite; + transition: 0.1s; + outline: none; +} + +.pagination{ + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.pagination > * { + cursor:pointer; + padding: 8px 16px; +} + +.pagination > *.disabled { + cursor: initial +} \ No newline at end of file diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 05ad691..90a7bd0 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -14,6 +14,10 @@ type BundleDataContextProps = { export type Block = { hash: string block_number: string + miner_reward?: number + gas_used?: number + // TODO: type this + transactions: any[] } export interface IBundleFilters { @@ -27,6 +31,7 @@ interface IBundleDataContext { blocks: Block[] page: number setPage: (page: number) => void + morePages: boolean filters: IBundleFilters setFilters: (newFilter: IBundleFilters) => void } @@ -37,6 +42,7 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { const { query } = useRouter(); const [blocks, setBlocks] = useState([]) const [page, setPage] = useState(1) + const [morePages, setMorePages] = useState(false) const [filters, _setFilters] = useState({ limit: 10 }) @@ -81,11 +87,22 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` params["limit"] = `${Number(params["limit"]) + 1}` const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` + debugger const res = await fetch(url) + debugger const { blocks } = await res.json() + debugger setBlocks(blocks.map(block => transformBundle(block))) }, []) + useEffect(() => { + if(blocks.length > filters.limit) { + setMorePages(true) + }else { + setMorePages(false) + } + }, [blocks, setMorePages]) + // Automatically update when view is changed useEffect(() => { getBlocks() @@ -101,6 +118,7 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { blocks, page, setPage, + morePages, filters, setFilters }} diff --git a/package.json b/package.json index 2fa3f69..72ce348 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "@headlessui/react": "^1.1.1", "abi-decoder": "^2.4.0", + "clsx": "^1.1.1", "csvtojson": "^2.0.10", "dotenv": "^10.0.0", "next": "^10.2.3", diff --git a/pages/Home.tsx b/pages/Home.tsx index 3d4a46a..ef3174a 100644 --- a/pages/Home.tsx +++ b/pages/Home.tsx @@ -1,11 +1,11 @@ -import { useEffect } from 'react'; -import Bundles from '../components/Bundles'; +import React, { useEffect } from 'react'; +import BundlesOverview from '../components/bundles/BundlesOverview'; import * as ga from '../lib/ga'; export default function Home({}) { useEffect(ga.pageview); // TODO: Move query logic to return ( - + ) } diff --git a/styles/Home.module.css b/styles/Home.module.css index 27694a6..78ef2ad 100644 --- a/styles/Home.module.css +++ b/styles/Home.module.css @@ -2,42 +2,6 @@ @apply text-5xl mt-14 mb-7 text-center font-semibold; } -.search { - @apply inline-flex self-center bg-gray-200 items-center mb-7; - padding: 0 0 0 1.3rem; - border-radius: 2rem; -} - -.search span { - @apply hidden sm:inline; -} - -.search input { - margin: 0 0 0 1rem; - padding: .5rem; -} - -.search button { - text-align: center; - padding: .6rem 1.3rem .5rem .75rem; - font-family: 'Nunito Sans', sans-serif; - color: white; - border-radius: 0 2rem 2rem 0; - align-self: center; -} - -.search button:hover { - color: white; - box-shadow: 4px 4px 16px #f1f1f1, -4px -4px 16px #e6e6e6; - background: linear-gradient(-60deg, #e44e4e, #fa5549, #ffd035, #fa9049, #ff5151); - background-size: 400% 400%; - animation: Gradient 9s ease infinite; - -moz-animation: Gradient 9s ease infinite; - -webkit-animation: Gradient 9s ease infinite; - transition: 0.1s; - outline: none; -} - .emoji { @apply hidden sm:inline; } @@ -92,96 +56,3 @@ .tipjar-address { @apply mx-1 px-1 border-solid border rounded border-pink-500 text-pink-500; } - -.title a { - color: #0070f3; - text-decoration: none; -} - -.title a:hover, -.title a:focus, -.title a:active { - text-decoration: underline; -} - -.title { - margin: 0; - line-height: 1.15; - font-size: 4rem; -} - -.title, -.description { - text-align: center; -} - -.description { - line-height: 1.5; - font-size: 1.5rem; -} - -.code { - background: #fafafa; - border-radius: 5px; - padding: 0.75rem; - font-size: 1.1rem; - font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, - Bitstream Vera Sans Mono, Courier New, monospace; -} - -.grid { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - max-width: 800px; - margin-top: 3rem; -} - -.card { - margin: 1rem; - padding: 1.5rem; - text-align: left; - color: inherit; - text-decoration: none; - border: 1px solid #eaeaea; - border-radius: 10px; - transition: color 0.15s ease, border-color 0.15s ease; - width: 45%; -} - -.card:hover, -.card:focus, -.card:active { - color: #0070f3; - border-color: #0070f3; -} - -.card h2 { - margin: 0 0 1rem 0; - font-size: 1.5rem; -} - -.card p { - margin: 0; - font-size: 1.25rem; - line-height: 1.5; -} - -.logo { - height: 1em; - margin-left: 0.5rem; -} - -@media (max-width: 600px) { - .grid { - width: 100%; - flex-direction: column; - } -} - -.search input[type=number]::-webkit-inner-spin-button, -.search input[type=number]::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; -} diff --git a/yarn.lock b/yarn.lock index 71940a3..0fd7102 100644 --- a/yarn.lock +++ b/yarn.lock @@ -707,6 +707,11 @@ classnames@2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -972,30 +977,11 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -dotenv-defaults@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz#6b3ec2e4319aafb70940abda72d3856770ee77ac" - integrity sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg== - dependencies: - dotenv "^8.2.0" - -dotenv-webpack@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-7.0.3.tgz#f50ec3c7083a69ec6076e110566720003b7b107b" - integrity sha512-O0O9pOEwrk+n1zzR3T2uuXRlw64QxHSPeNN1GaiNBloQFNaCUL9V8jxSVz4jlXXFP/CIqK8YecWf8BAvsSgMjw== - dependencies: - dotenv-defaults "^2.0.2" - dotenv@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - electron-to-chromium@^1.3.723: version "1.3.725" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz#04fc83f9189169aff50f0a00c6b4090b910cba85" From 408a347bfb680925e6ef280ce67592cb7f82ea31 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Fri, 25 Jun 2021 20:20:45 +0200 Subject: [PATCH 06/28] Updated readme --- README.md | 8 ++++++++ context/BundleData/BundleDataProvider.tsx | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9559ce4..a7e1b17 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,14 @@ Deployed at https://flashbots-explorer.marto.lol/ +## Installation + +Firstly, please run preferably `yarn` or alternatively `npm i` to install the dependancies + +Then make a copy of the `.env.template` file and rename it to `.env` + +For now, you dont need to make any changes to the file. + ## Development This is a create next app project so: diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 90a7bd0..9afefb2 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -87,9 +87,7 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` params["limit"] = `${Number(params["limit"]) + 1}` const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` - debugger const res = await fetch(url) - debugger const { blocks } = await res.json() debugger setBlocks(blocks.map(block => transformBundle(block))) From c76a652c6bc36ec7fed29f8689628b6ff167b7b8 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Sat, 26 Jun 2021 12:51:36 +0200 Subject: [PATCH 07/28] Unoptimised fetching complete --- components/bundles/BundlesOverview.tsx | 10 ++++--- .../bundles/css/BundleOverview.module.css | 7 +++-- context/BundleData/BundleDataProvider.tsx | 30 +++++++++++++++---- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/components/bundles/BundlesOverview.tsx b/components/bundles/BundlesOverview.tsx index ebf2e21..7fe6c18 100644 --- a/components/bundles/BundlesOverview.tsx +++ b/components/bundles/BundlesOverview.tsx @@ -79,11 +79,11 @@ export default function BundlesOverview({ }) { - { blocks?.sort(sortBlocks).slice(0, filters.limit).map((b, i) => ) } + { blocks?.sort(sortBlocks).filter((block, index) => index < ((page - 1) * filters.limit) + filters.limit && index >= (page - 1) * filters.limit).map((b, i) => ) } { - (blocks.length > filters.limit) || page > 1 && ( + ((blocks.length > filters.limit) || page > 1) && (
) diff --git a/components/bundles/css/BundleOverview.module.css b/components/bundles/css/BundleOverview.module.css index e7fa83f..b805cfd 100644 --- a/components/bundles/css/BundleOverview.module.css +++ b/components/bundles/css/BundleOverview.module.css @@ -41,10 +41,11 @@ } .pagination > * { - cursor:pointer; padding: 8px 16px; + transition-duration: 200ms; + opacity: 1; } -.pagination > *.disabled { - cursor: initial +.pagination > *:disabled { + opacity: 0; } \ No newline at end of file diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 9afefb2..936b1a4 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -16,10 +16,27 @@ export type Block = { block_number: string miner_reward?: number gas_used?: number + coinbase_transfers: number + gas_price: number + miner: string // TODO: type this transactions: any[] } + +export type Transaction = { + block_number: number + bundle_index: number + coinbase_transfer: number + eoa_address: string + gas_price: number + gas_used: number + to_address: string + total_miner_reward: number + transaction_hash: string + tx_index: number +} + export interface IBundleFilters { from?: string | string[] to?: string @@ -85,13 +102,12 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { Object.keys(filters).map(key => params[key] = filters[key]) // This fetchs additional pages to a limit // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` - params["limit"] = `${Number(params["limit"]) + 1}` + params["limit"] = `${(Number(params["limit"]) * page) + 1}` const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` const res = await fetch(url) const { blocks } = await res.json() - debugger setBlocks(blocks.map(block => transformBundle(block))) - }, []) + }, [blocks, page]) useEffect(() => { if(blocks.length > filters.limit) { @@ -103,8 +119,12 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // Automatically update when view is changed useEffect(() => { - getBlocks() - }, [filters, page]) + if ((page * filters.limit) + 1 > blocks.length) { + getBlocks() + } else if (page === 1) { + getBlocks() + } + }, [filters, page, blocks]) const setFilters = useCallback((filter: IBundleFilters) => { From 0e34f5bb86771a79c71b1649625cb811fa164661 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Sat, 26 Jun 2021 14:21:25 +0200 Subject: [PATCH 08/28] Viewing & router done --- .eslintrc.json | 82 ++ components/Address.tsx | 12 +- components/bundles/Bundle.tsx | 56 +- components/bundles/BundleModal.tsx | 67 +- components/bundles/BundleRow.tsx | 25 +- components/bundles/BundleTransaction.tsx | 82 +- components/bundles/BundlesOverview.tsx | 138 ++- components/bundles/Helpers.tsx | 2 +- components/bundles/Subbundle.tsx | 21 +- components/icons/externalLink.icon.tsx | 18 +- components/icons/openBook.icon.tsx | 19 +- components/modals/ErrorModal.tsx | 8 +- context/BundleData/BundleDataProvider.tsx | 75 +- context/TokenData/TokenDataProvider.tsx | 126 +- .../tokensList/fetchTokensApiByDex.js | 35 +- helpers/general.tsx | 8 +- lib/ga.js | 6 +- next.config.js | 13 +- package.json | 11 +- pages/Home.tsx | 11 +- pages/_app.js | 3 +- pages/_document.js | 5 +- pages/api/hello.js | 2 +- pages/index.tsx | 85 +- postcss.config.js | 4 +- tailwind.config.js | 8 +- yarn.lock | 1014 ++++++++++++++++- 27 files changed, 1585 insertions(+), 351 deletions(-) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..262edb9 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,82 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "plugins": ["@typescript-eslint", "ternary"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:ternary/recommended" + ], + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "comma-spacing": ["error", { "before": false, "after": true }], + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], + "quotes": ["error", "double"], + "semi": ["error", "never"], + "max-len": [ + "error", + { + "code": 140 + } + ], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "react/prop-types": 0, + "react/jsx-max-props-per-line": [2, { + "maximum": 1, + "when": "always" + }], + "react/jsx-fragments": "error", + "arrow-spacing": "error", + "space-infix-ops": "error", + "no-trailing-spaces": ["error", { "ignoreComments": true }], + "comma-dangle": ["error", "never"], + "object-curly-spacing": ["error", "always"], + "space-in-parens": ["error", "never"], + "ternary/no-unreachable": "off", + "ternary/nesting": "off", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/member-delimiter-style" : ["warn", { + "multiline": { + "delimiter": "none", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + }] + }, + "ignorePatterns": [ + ".github/**", + ".vscode/**", + ".yarn/**", + "**/dist/*", + "**/node_modules/*" + ], + "env": { + "browser": true, + "amd": true, + "node": true + } +} diff --git a/components/Address.tsx b/components/Address.tsx index 3126cba..489c080 100644 --- a/components/Address.tsx +++ b/components/Address.tsx @@ -1,7 +1,11 @@ +import React from "react" export const Address = ({ address } : { address: string }) => { - const size = 6; - const shorten = (address: string): string => address.slice(0, size) + '...' + address.slice(-size); - return + const size = 6 + const shorten = (address: string): string => address.slice(0, size) + "..." + address.slice(-size) + return
{ shorten(address) }
-
; + } \ No newline at end of file diff --git a/components/bundles/Bundle.tsx b/components/bundles/Bundle.tsx index 756ff44..349f175 100644 --- a/components/bundles/Bundle.tsx +++ b/components/bundles/Bundle.tsx @@ -1,8 +1,8 @@ -import { Dialog } from "@headlessui/react"; -import React from "react"; -import { Block } from "../../context/BundleData/BundleDataProvider"; -import { summarizeFp } from "./Helpers"; -import { SubBundle } from "./Subbundle"; +import { Dialog } from "@headlessui/react" +import React from "react" +import { Block } from "../../context/BundleData/BundleDataProvider" +import { summarizeFp } from "./Helpers" +import { SubBundle } from "./Subbundle" interface IBundle { bundle: Block @@ -10,9 +10,15 @@ interface IBundle { export const Bundle = ({ bundle }: IBundle) => { return
- + Bundles in # - + { bundle?.block_number } @@ -23,21 +29,31 @@ export const Bundle = ({ bundle }: IBundle) => { - - - - - - - - + + + + + + + + { bundle.transactions.length > 1 - ? bundle.transactions.map((sb, i) => ) - : + ? bundle.transactions.map((sb, i) => ) + : } @@ -57,10 +73,10 @@ export const Bundle = ({ bundle }: IBundle) => { { Math.round(bundle.miner_reward / bundle.gas_used / (10 ** 9)) } gwei @@ -68,5 +84,5 @@ export const Bundle = ({ bundle }: IBundle) => { - ; + } diff --git a/components/bundles/BundleModal.tsx b/components/bundles/BundleModal.tsx index 4256a66..84707bf 100644 --- a/components/bundles/BundleModal.tsx +++ b/components/bundles/BundleModal.tsx @@ -1,36 +1,51 @@ /* This example requires Tailwind CSS v2.0+ */ -import React, { Fragment, useRef, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { Dialog, Transition } from '@headlessui/react'; -import { Bundle } from '../bundles/Bundle'; -import { ErrorModal } from '../modals/ErrorModal'; +import React, { Fragment, useRef, useEffect, useCallback } from "react" +import { useRouter } from "next/router" +import { Dialog, Transition } from "@headlessui/react" +import { Bundle } from "../bundles/Bundle" +import { ErrorModal } from "../modals/ErrorModal" +import { Block } from "../../context/BundleData/BundleDataProvider" -export default function BundleModal({ open, bundle, setOpen }) { - const cancelButtonRef = useRef(); - const router = useRouter(); - const close = () => { - setOpen(false); - if (bundle) { - router.back(); - } - }; +interface IBundleModal { + open: boolean + bundle: Block + close: () => void +} + +export default function BundleModal({ open, bundle, close }: IBundleModal) { + const cancelButtonRef = useRef() + const router = useRouter() + // const close = () => { + // setOpen(false) + // if (bundle) { + // router.back() + // } + // } + const handleClose = useCallback(() => { + close() + // router.push insecure error + // if (bundle) { + // router.push("/", undefined, { shallow: true }) + // } + }, [close]) useEffect(() => { - const { block } = router.query; + const { block } = router.query if (block === undefined) { - setOpen(false); + handleClose() } - }, [router.query.block]); + }, [router.query, handleClose]) return ( - +
{/* This element is to trick the browser into centering the modal contents. */} -
+ return - ; + } diff --git a/components/bundles/BundleTransaction.tsx b/components/bundles/BundleTransaction.tsx index 855361d..6ad1319 100644 --- a/components/bundles/BundleTransaction.tsx +++ b/components/bundles/BundleTransaction.tsx @@ -1,23 +1,23 @@ -import { useRouter } from "next/router"; -import React, { Fragment, useEffect, useState } from "react"; -import { useTokenData } from "../../context/TokenData/TokenDataProvider"; -import { timeNow } from "../../helpers/general"; -import { Address } from "../Address"; -import { ExternalLinkIcon } from "../icons/externalLink.icon"; +import { useRouter } from "next/router" +import React, { Fragment, useEffect, useState } from "react" +import { useTokenData } from "../../context/TokenData/TokenDataProvider" +import { timeNow } from "../../helpers/general" +import { Address } from "../Address" +import { ExternalLinkIcon } from "../icons/externalLink.icon" export const BundleTransaction = (transaction, index: number) => { - const [logs, setLogs] = useState([]); + const [logs, setLogs] = useState([]) const { getReceipts } = useTokenData() - const router = useRouter(); + const router = useRouter() const onClick = (e, from) => { - e.preventDefault(); - router.push(`/?from=${from}`, undefined, { shallow: true }); - }; + e.preventDefault() + router.push(`/?from=${from}`, undefined, { shallow: true }) + } - useEffect( () => { - const getLogs = async () => setLogs(await getReceipts(transaction)); - getLogs(); - }, [transaction]); + useEffect(() => { + const getLogs = async () => setLogs(await getReceipts(transaction)) + getLogs() + }, [transaction, getReceipts]) const coins = logs.reduce((acc, curr) => { if (curr.coin.name && (curr.coin.value || acc[curr.coin.name] === undefined)) { @@ -29,8 +29,8 @@ export const BundleTransaction = (transaction, index: number) => { ethValue: curr.coin.ethValue } } - return acc; - }, {}); + return acc + }, {}) // block_number: 12358944 // coinbase_transfer: "9785908415014455" @@ -42,9 +42,13 @@ export const BundleTransaction = (transaction, index: number) => { // transaction_hash: "0xedbaa982717813b69e215fe08525ae85c3686a095a1b908714ef8755f58e754d" // tx_index: 0 return - + - ; + } diff --git a/components/bundles/BundlesOverview.tsx b/components/bundles/BundlesOverview.tsx index 7fe6c18..db59e47 100644 --- a/components/bundles/BundlesOverview.tsx +++ b/components/bundles/BundlesOverview.tsx @@ -1,67 +1,82 @@ -import React, { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import styles from './css/BundleOverview.module.css'; -import { BundleRow } from './BundleRow'; -import { useBundleData } from '../../context/BundleData/BundleDataProvider'; -import BundleModal from './BundleModal'; -import clsx from 'clsx'; +import React, { useState, useEffect, useCallback } from "react" +import { useRouter } from "next/router" +import styles from "./css/BundleOverview.module.css" +import { BundleRow } from "./BundleRow" +import { useBundleData } from "../../context/BundleData/BundleDataProvider" +import BundleModal from "./BundleModal" +import clsx from "clsx" -export default function BundlesOverview({ }) { - const router = useRouter(); +export default function BundlesOverview() { + const router = useRouter() const { blocks, setFilters, filters, page, morePages, setPage } = useBundleData() - const [openModal, setOpenModal] = useState(false); - const [bundle, setBundle] = useState(undefined); - const [searchValue, setSearch] = useState(undefined); + const [bundle, setBundle] = useState(undefined) + const [searchValue, setSearch] = useState(undefined) + const [landingMutex, setLandingMutex] = useState(false) + + + const setBundleAndOpen = useCallback(bundle => { + // router.push insecure error + // if (bundle !== undefined) { + // router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }) + // } + setBundle(bundle) + }, []) useEffect(() => { - if (router.query.block && blocks.length > 0) { + if (router.query.block && blocks.length > 0 && !landingMutex) { const blockNumber = router.query.block as unknown as string - const local = blocks.find(b => b.block_number == blockNumber); + if (blockNumber) { + const local = blocks.find(b => b.block_number == blockNumber) + if (local) { + setBundleAndOpen(local) + setLandingMutex(true) + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: blockNumber + }) + } + } + } else if (filters.block_number) { + const local = blocks.find(b => b.block_number == filters.block_number) if (local) { - setBundleAndOpen(local); - } else if(!filters.block_number) { setFilters({ ...filters, - block_number: blockNumber + block_number: undefined }) } - } else if (filters.block_number) { - setBundleAndOpen(undefined) - setFilters({ - ...filters, - block_number: undefined - }) } - }, [router.query.block, blocks]); + }, [router.query.block, blocks, filters, landingMutex, setBundleAndOpen, setFilters]) - const setBundleAndOpen = bundle => { - if (bundle !== undefined) { - router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }); - } - setBundle(bundle); - setOpenModal(true); - }; - - const findBundleAndOpen = async (blockNumber: string) => { - - }; const submit = e => { - e.preventDefault(); - findBundleAndOpen(searchValue); - }; + e.preventDefault() + const local = blocks.find(b => b.block_number == searchValue) + if (local) { + setBundleAndOpen(local) + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: searchValue + }) + } + } function sortBlocks(a, b): number { - if (a.block_number < b.block_number) return 1; - if (a.block_number > b.block_number) return -1; - return 0; + if (a.block_number < b.block_number) return 1 + if (a.block_number > b.block_number) return -1 + return 0 } return
- -
+ setBundle(undefined) } /> + Search by block number - setSearch(e.target.value) } /> + setSearch(e.target.value) } />
@@ -70,24 +85,35 @@ export default function BundlesOverview({ }) {
HashFromToAssetsGas usedGas priceCoinbase transferMiner rewardHashFromToAssetsGas usedGas priceCoinbase transferMiner reward
- Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'coinbase_transfer')), 0).toFixed(4) } + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, "coinbase_transfer")), 0).toFixed(4) } - Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'total_miner_reward')), 0).toFixed(4) } + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, "total_miner_reward")), 0).toFixed(4) }
- + { ExternalLinkIcon } { bundle?.block_number } @@ -40,7 +44,8 @@ export const BundleRow = ({ index, bundle, setBundleAndOpen }: IBundleRow) => { - { OpenBookIcon } + { OpenBookIcon }
- + { ExternalLinkIcon } { transaction?.transaction_hash.slice(0, 10) }... @@ -62,21 +66,29 @@ export const BundleTransaction = (transaction, index: number) => {
- { - Object.keys(coins).map(coin =>
- - { - coins[coin].logo - ? - : <> - } - { coin } - - { coins[coin].value > 0 ? " " + coins[coin].value : "" } - { coins[coin].ethValue > 0 ? " ($"+coins[coin].ethValue +")" : "" } - { coins[coin].value ? "" : ` (${coins[coin].event})` } -
) - } + { + Object.keys(coins).map((coin, index) =>
+ + { + coins[coin].logo + ? + : <> + } + { coin } + + { coins[coin].value > 0 ? " " + coins[coin].value : "" } + { coins[coin].ethValue > 0 ? " ($" + coins[coin].ethValue + ")" : "" } + { coins[coin].value ? "" : ` (${coins[coin].event})` } +
) + }
@@ -99,6 +111,6 @@ export const BundleTransaction = (transaction, index: number) => {
- - - - - - + + + + + + - { blocks?.sort(sortBlocks).filter((block, index) => index < ((page - 1) * filters.limit) + filters.limit && index >= (page - 1) * filters.limit).map((b, i) => ) } + { blocks?.sort(sortBlocks) + .filter((block, index) => index < ((page - 1) * filters.limit) + filters.limit && index >= (page - 1) * filters.limit) + .map((b, i) => ) }
Block numberMiner rewardGas usedEffective gas priceBundlesInspectBlock numberMiner rewardGas usedEffective gas priceBundlesInspect
{ ((blocks.length > filters.limit) || page > 1) && (
- -
- ; -}; + +} diff --git a/components/bundles/Helpers.tsx b/components/bundles/Helpers.tsx index a5dd795..f5f08bc 100644 --- a/components/bundles/Helpers.tsx +++ b/components/bundles/Helpers.tsx @@ -1 +1 @@ -export const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4); +export const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4) diff --git a/components/bundles/Subbundle.tsx b/components/bundles/Subbundle.tsx index 69dfb49..cd571eb 100644 --- a/components/bundles/Subbundle.tsx +++ b/components/bundles/Subbundle.tsx @@ -1,14 +1,17 @@ -import { BundleTransaction } from "./BundleTransaction"; -import { summarizeFp } from "./Helpers"; +import React from "react" +import { BundleTransaction } from "./BundleTransaction" +import { summarizeFp } from "./Helpers" -export const SubBundle = ({ subBundle, index } : { subBundle: any[], index?: number }) => { +export const SubBundle = ({ subBundle, index } : { subBundle: any[]; index?: number }) => { return <> { subBundle.map(BundleTransaction) } { index === undefined - ? <> - : - + ? <> + : + #{ index + 1 } @@ -17,12 +20,12 @@ export const SubBundle = ({ subBundle, index } : { subBundle: any[], index?: num - Ξ { summarizeFp(subBundle, 'coinbase_transfer') } + Ξ { summarizeFp(subBundle, "coinbase_transfer") } - Ξ { summarizeFp(subBundle, 'total_miner_reward') } + Ξ { summarizeFp(subBundle, "total_miner_reward") } } - ; + } \ No newline at end of file diff --git a/components/icons/externalLink.icon.tsx b/components/icons/externalLink.icon.tsx index 65408ad..4bea2dc 100644 --- a/components/icons/externalLink.icon.tsx +++ b/components/icons/externalLink.icon.tsx @@ -1,4 +1,16 @@ -export const ExternalLinkIcon = - -; +import React from "react" + +export const ExternalLinkIcon = + + + diff --git a/components/icons/openBook.icon.tsx b/components/icons/openBook.icon.tsx index c3fa0c5..b9e7b08 100644 --- a/components/icons/openBook.icon.tsx +++ b/components/icons/openBook.icon.tsx @@ -1,3 +1,16 @@ -export const OpenBookIcon = - -; +import React from "react" + +export const OpenBookIcon = + + + diff --git a/components/modals/ErrorModal.tsx b/components/modals/ErrorModal.tsx index e98a8cd..3e6ceb0 100644 --- a/components/modals/ErrorModal.tsx +++ b/components/modals/ErrorModal.tsx @@ -1,8 +1,10 @@ -import { Dialog } from "@headlessui/react"; +import React from "react" +import { Dialog } from "@headlessui/react" export const ErrorModal = () =>
- + Oops
Bundle not found, have this instead: 🍌
-
; + diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 936b1a4..bc9cda2 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -56,24 +56,24 @@ interface IBundleDataContext { const BundleDataContext = React.createContext(undefined) const BundleDataProvider = ({ children }: BundleDataContextProps) => { - const { query } = useRouter(); + const { query } = useRouter() const [blocks, setBlocks] = useState([]) const [page, setPage] = useState(1) const [morePages, setMorePages] = useState(false) const [filters, _setFilters] = useState({ limit: 10 }) - + const [pageMutex, setPageMutex] = useState(false) // Update filter from query useEffect(() => { - const { from } = query; + const { from } = query if (from && filters.from != from) { _setFilters({ ...filters, from: from }) } - }, [query.from]); + }, [query, filters]) useEffect(() => { // Change page back to first if filters are changed @@ -83,31 +83,42 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { function getSubBundles(bundle) { return bundle.transactions.reduce((acc, curr) => { if (acc[curr.bundle_index]) { - acc[curr.bundle_index].push(curr); + acc[curr.bundle_index].push(curr) } else { - acc[curr.bundle_index] = [curr]; + acc[curr.bundle_index] = [curr] } - return acc; - }, []); - } - - function transformBundle(bundle) { - bundle.transactions = getSubBundles(bundle); - return bundle; + return acc + }, []) } + const transformBundle = useCallback((bundle) => { + bundle.transactions = getSubBundles(bundle) + return bundle + }, []) + const getBlocks = useCallback(async () => { // TODO: Type Safety - let params: Record = {} + const params: Record = {} Object.keys(filters).map(key => params[key] = filters[key]) // This fetchs additional pages to a limit // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` params["limit"] = `${(Number(params["limit"]) * page) + 1}` const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}` const res = await fetch(url) - const { blocks } = await res.json() - setBlocks(blocks.map(block => transformBundle(block))) - }, [blocks, page]) + const resJson = await res.json() + if (resJson.blocks !== undefined) { + const existingBlocknumbers = blocks.map(block => block.block_number) + const newBlocks = resJson.blocks + .map(block => transformBundle(block)).filter(newBlock => existingBlocknumbers.indexOf(newBlock.block_number) < 0) + if (newBlocks.length > 0) { + setBlocks([ + ...blocks, + ...newBlocks + ]) + } + } + setPageMutex(false) + }, [filters, blocks, page, transformBundle]) useEffect(() => { if(blocks.length > filters.limit) { @@ -115,20 +126,34 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { }else { setMorePages(false) } - }, [blocks, setMorePages]) + }, [blocks, filters.limit, setMorePages]) // Automatically update when view is changed useEffect(() => { - if ((page * filters.limit) + 1 > blocks.length) { - getBlocks() - } else if (page === 1) { - getBlocks() + if (!pageMutex) { + if ((page * filters.limit) + 1 > blocks.length) { + setPageMutex(true) + getBlocks() + } else if (page === 1) { + setPageMutex(true) + getBlocks() + } } - }, [filters, page, blocks]) + }, [filters, page, blocks, pageMutex, getBlocks]) const setFilters = useCallback((filter: IBundleFilters) => { - - }, []) + // This intermidiary function is for removing filters gracefully later on + const newItem: IBundleFilters = { + limit: 10 + } + Object.keys(filter).map(key => { + if (filter[key]) { + newItem[key] = filter[key] + } + }) + + _setFilters(newItem) + }, [_setFilters]) return ( Promise + getReceipts: (transaction: Record) => Promise } @@ -71,59 +72,60 @@ const TokenDataProvider = ({ children }: TokenDataContextProps) => { const loadTokens = useCallback(async () => { DEXES.map(d => { - let { tokens } = require(`./tokensList/json${d}.json`) + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { tokens } = require(`./tokensList/json${d}.json`) console.log(tokens) setTokens(tokens) }) }, []) - - const addEvents = async () => { + + const addEvents = useCallback(async () => { eventsJson.map(async e => { - let { text_signature } = e; + const { text_signature } = e try { - let i = new Interface([text_signature]); - await addABI(i.fragments); + const i = new Interface([text_signature]) + await addABI(i.fragments) } catch (e) { - console.log(e); + console.log(e) } - }); - }; + }) + }, []) const getEthPrice = async () => { const res = await fetch(uniswapV2GQL, { - method: 'POST', + method: "POST", headers: { - 'Accept': 'api_version=2', - 'Content-Type': 'application/graphql' + "Accept": "api_version=2", + "Content-Type": "application/graphql" }, body: JSON.stringify({ query : ethQL }) - }); - - const { data: { bundles } } = await res.json(); - + }) + + const { data: { bundles } } = await res.json() + if (bundles.length > 0) { - return parseFloat(bundles[0].ethPrice).toFixed(6); + return parseFloat(bundles[0].ethPrice).toFixed(6) } - - return "1"; + + return "1" } - const getAllLogs = async (_logs) =>{ - const ethPrice = await getEthPrice(); + const getAllLogs = useCallback(async (_logs) => { + const ethPrice = await getEthPrice() return decodeLogs(_logs).map(log => { const { coin, logo, decimals } = tokens.find(token => token.address === log.address) - let ethValue = "0"; - let value; - + let ethValue = "0" + let value + log.events.map(e => { if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { - value = parseFloat(`${e.value / 10 ** decimals}`).toFixed(2); - if (coin === 'WETH') { - ethValue = parseFloat(`${value * parseFloat(ethPrice)}`).toFixed(2); + value = parseFloat(`${e.value / 10 ** decimals}`).toFixed(2) + if (coin === "WETH") { + ethValue = parseFloat(`${value * parseFloat(ethPrice)}`).toFixed(2) } } - }); - + }) + log.coin = { address: log.address, name: coin, @@ -132,11 +134,11 @@ const TokenDataProvider = ({ children }: TokenDataContextProps) => { decimals, value, ethValue - }; - - return log; - }); - } + } + + return log + }) + }, [tokens]) const getReceipts = useCallback(async (transaction) => { const jsonrpc = { @@ -144,8 +146,8 @@ const TokenDataProvider = ({ children }: TokenDataContextProps) => { "method": "eth_getTransactionReceipt", "params": [], "id": 1 - }; - + } + const params = { method: "POST", headers: { @@ -153,34 +155,34 @@ const TokenDataProvider = ({ children }: TokenDataContextProps) => { "Content-Type": "application/json" }, body: "" - }; - - const { transaction_hash } = transaction; - jsonrpc.params = [transaction_hash]; - params.body = JSON.stringify(jsonrpc); - + } + + const { transaction_hash } = transaction + jsonrpc.params = [transaction_hash] + params.body = JSON.stringify(jsonrpc) + try { - const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params); - const { result : { logs } } = await res.json(); + const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params) + const { result : { logs } } = await res.json() return getAllLogs(logs) } catch(e) { - console.log(e); + console.log(e) } - + return [] - }, []) + }, [getAllLogs]) // Fetch initial useEffect(() => { addEvents() loadTokens() - }, []) + }, [addEvents, loadTokens]) return ( {children} diff --git a/context/TokenData/tokensList/fetchTokensApiByDex.js b/context/TokenData/tokensList/fetchTokensApiByDex.js index c1db071..09d5e83 100644 --- a/context/TokenData/tokensList/fetchTokensApiByDex.js +++ b/context/TokenData/tokensList/fetchTokensApiByDex.js @@ -1,36 +1,37 @@ -const fs = require('fs'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const fs = require("fs") const dexUrl = { - 'COINGECKO': "https://tokens.coingecko.com/uniswap/all.json" -}; + "COINGECKO": "https://tokens.coingecko.com/uniswap/all.json" +} const tokensBySymbol = {} const readFiles = async dex => { - const tokensUrl = dexUrl[dex]; + const tokensUrl = dexUrl[dex] const config = { timeout: 3000, uri: tokensUrl, - method: 'GET', - json: true, - }; + method: "GET", + json: true + } - const tokensResponse = await fetch(config); - const { tokens } = tokensResponse; + const tokensResponse = await fetch(config) + const { tokens } = tokensResponse if (!tokens) { - console.error(`error fetching data from ${this.name}: ${error}`); - return false; + console.error(`error fetching data from ${this.name}: ${error}`) + return false } else { tokens.forEach(token => { - tokensBySymbol[token.symbol] = token; + tokensBySymbol[token.symbol] = token }) - console.log('writing files -- '); - fs.writeFile(`${__dirname}/json${dex}.json`, global.JSON.stringify(tokensResponse), console.error); - fs.writeFile(`${__dirname}/tokens${dex}.json`, global.JSON.stringify(tokensBySymbol), console.error); - return true; + console.log("writing files -- ") + fs.writeFile(`${__dirname}/json${dex}.json`, global.JSON.stringify(tokensResponse), console.error) + fs.writeFile(`${__dirname}/tokens${dex}.json`, global.JSON.stringify(tokensBySymbol), console.error) + return true } } -readFiles('COINGECKO'); +readFiles("COINGECKO") diff --git a/helpers/general.tsx b/helpers/general.tsx index 342ff57..c52bb92 100644 --- a/helpers/general.tsx +++ b/helpers/general.tsx @@ -1,7 +1,7 @@ export const timeNow = () => { - return randomMaxMin(Date.now(), Date.now()*10000); -}; + return randomMaxMin(Date.now(), Date.now() * 10000) +} export const randomMaxMin = (max, min) => { - return Math.floor(Math.random() * (max - min + 1)) + min; -}; + return Math.floor(Math.random() * (max - min + 1)) + min +} diff --git a/lib/ga.js b/lib/ga.js index 2a5bf45..096ec61 100644 --- a/lib/ga.js +++ b/lib/ga.js @@ -1,10 +1,10 @@ export const pageview = (url) => { - window.gtag('config', process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS, { + window.gtag("config", process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS, { page_path: url - }); + }) } // log specific events happening. export const event = ({ action, params }) => { - window.gtag('event', action, params); + window.gtag("event", action, params) } diff --git a/next.config.js b/next.config.js index 508524f..166ee8d 100644 --- a/next.config.js +++ b/next.config.js @@ -1,15 +1,16 @@ -require('dotenv').config() +require("dotenv").config() + module.exports = { env: { NEXT_PUBLIC_INFURA_ID: process.env.NEXT_PUBLIC_INFURA_ID, FLASHBOTS_API_URL: process.env.FLASHBOTS_API_URL }, future: { - webpack5: true, + webpack5: true }, webpack: (config) => { - config.resolve.fallback = { fs: false }; + config.resolve.fallback = { fs: false } - return config; - }, -}; \ No newline at end of file + return config + } +} diff --git a/package.json b/package.json index 72ce348..fc031cf 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,12 @@ "scripts": { "dev": "next dev", "build": "next build", - "start": "next start" + "start": "next start", + "lint": "eslint '**/**/*.{js,jsx,ts,tsx}'" }, "dependencies": { "@headlessui/react": "^1.1.1", + "abi-decoder": "^2.4.0", "clsx": "^1.1.1", "csvtojson": "^2.0.10", @@ -19,7 +21,14 @@ }, "devDependencies": { "@types/react": "^17.0.4", + "@typescript-eslint/eslint-plugin": "^4.15.2", + "@typescript-eslint/parser": "^4.15.2", "autoprefixer": "^10.2.5", + "eslint": "^6.8.0", + "eslint-plugin-cypress": "^2.11.3", + "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-ternary": "^1.0.4", "postcss": "^8.2.13", "tailwindcss": "^2.1.4", "typescript": "^4.2.4" diff --git a/pages/Home.tsx b/pages/Home.tsx index ef3174a..720ba22 100644 --- a/pages/Home.tsx +++ b/pages/Home.tsx @@ -1,9 +1,10 @@ -import React, { useEffect } from 'react'; -import BundlesOverview from '../components/bundles/BundlesOverview'; -import * as ga from '../lib/ga'; +import React, { useEffect } from "react" +import BundlesOverview from "../components/bundles/BundlesOverview" +import * as ga from "../lib/ga" -export default function Home({}) { - useEffect(ga.pageview); +export default function Home() { + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(ga.pageview) // TODO: Move query logic to return ( diff --git a/pages/_app.js b/pages/_app.js index 1040120..dbbde74 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,4 +1,5 @@ -import 'tailwindcss/tailwind.css' +import React from "react" +import "tailwindcss/tailwind.css" function MyApp({ Component, pageProps }) { return diff --git a/pages/_document.js b/pages/_document.js index 5839edd..0bf4931 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -1,4 +1,5 @@ -import Document, { Html, Head, Main, NextScript } from 'next/document'; +import React from "react" +import Document, { Html, Head, Main, NextScript } from "next/document" export default class MyDocument extends Document { render() { @@ -19,7 +20,7 @@ export default class MyDocument extends Document { gtag('config', '${process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS}', { page_path: window.location.pathname, }); - `, + ` }} /> diff --git a/pages/api/hello.js b/pages/api/hello.js index 9987aff..bffa49a 100644 --- a/pages/api/hello.js +++ b/pages/api/hello.js @@ -1,5 +1,5 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction export default (req, res) => { - res.status(200).json({ name: 'John Doe' }) + res.status(200).json({ name: "John Doe" }) } diff --git a/pages/index.tsx b/pages/index.tsx index 54ec829..27ab32c 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,48 +1,61 @@ -import Head from 'next/head'; -import React, { useEffect} from 'react'; -import { useRouter } from 'next/router'; -import * as ga from '../lib/ga'; -import styles from '../styles/Home.module.css'; -import Home from './Home'; -import { BundleDataProvider } from '../context/BundleData/BundleDataProvider'; +import Head from "next/head" +import React, { useEffect } from "react" +import { useRouter } from "next/router" +import * as ga from "../lib/ga" +import styles from "../styles/Home.module.css" +import Home from "./Home" +import { BundleDataProvider } from "../context/BundleData/BundleDataProvider" +import { TokenDataProvider } from "../context/TokenData/TokenDataProvider" export default function App() { - useEffect(ga.pageview); - const router = useRouter(); + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(ga.pageview) + const router = useRouter() useEffect(() => { const handleRouteChange = (url) => { - ga.pageview(url); - }; + ga.pageview(url) + } - router.events.on('routeChangeComplete', handleRouteChange); + router.events.on("routeChangeComplete", handleRouteChange) return () => { - router.events.off('routeChangeComplete', handleRouteChange); + router.events.off("routeChangeComplete", handleRouteChange) } - }, [router.events]); + }, [router.events]) return ( - -
- Contribute in GitHub -

- - Flashbots Bundle Explorer - 🤖 -

- - 🤖 Flashbots Bundle Explorer ⚡ - - - - - {/* */} - -
- brewed with ⚡ by marto.lol - ❤️ tip jar: 0x87122a7385fd61720d72290a6f2ed25b7eca7af7 💸 -
-
-
+ + +
+ Contribute in GitHub +

+ + Flashbots Bundle Explorer + 🤖 +

+ + 🤖 Flashbots Bundle Explorer ⚡ + + + + + {/* */} + +
+ brewed with ⚡ by marto.lol + ❤️ tip jar: + 0x87122a7385fd61720d72290a6f2ed25b7eca7af7 💸 +
+
+
+
) } \ No newline at end of file diff --git a/postcss.config.js b/postcss.config.js index 33ad091..85f717c 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { plugins: { tailwindcss: {}, - autoprefixer: {}, - }, + autoprefixer: {} + } } diff --git a/tailwind.config.js b/tailwind.config.js index b10e843..1086c1d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,11 +1,11 @@ module.exports = { - purge: ['./pages/*.{js,ts,jsx,tsx}', './components/*.{js,ts,jsx,tsx}'], + purge: ["./pages/*.{js,ts,jsx,tsx}", "./components/*.{js,ts,jsx,tsx}"], darkMode: false, // or 'media' or 'class' theme: { - extend: {}, + extend: {} }, variants: { - extend: {}, + extend: {} }, - plugins: [], + plugins: [] } diff --git a/yarn.lock b/yarn.lock index 0fd7102..1a78024 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,11 +9,23 @@ dependencies: "@babel/highlight" "^7.10.4" +"@babel/code-frame@^7.0.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + "@babel/helper-validator-identifier@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@babel/helper-validator-identifier@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" + integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== + "@babel/highlight@^7.10.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" @@ -23,6 +35,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/runtime@7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" @@ -312,6 +333,11 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001" integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw== +"@types/json-schema@^7.0.7": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" + integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== + "@types/node@*": version "15.0.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" @@ -336,6 +362,75 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== +"@typescript-eslint/eslint-plugin@^4.15.2": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz#1a66f03b264844387beb7dc85e1f1d403bd1803f" + integrity sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ== + dependencies: + "@typescript-eslint/experimental-utils" "4.28.0" + "@typescript-eslint/scope-manager" "4.28.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz#13167ed991320684bdc23588135ae62115b30ee0" + integrity sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.28.0" + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/typescript-estree" "4.28.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.15.2": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa" + integrity sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A== + dependencies: + "@typescript-eslint/scope-manager" "4.28.0" + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/typescript-estree" "4.28.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz#6a3009d2ab64a30fc8a1e257a1a320067f36a0ce" + integrity sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + +"@typescript-eslint/types@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0" + integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA== + +"@typescript-eslint/typescript-estree@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf" + integrity sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434" + integrity sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw== + dependencies: + "@typescript-eslint/types" "4.28.0" + eslint-visitor-keys "^2.0.0" + abi-decoder@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-2.4.0.tgz#99f72337c614d6ac45a28dbc83c08b44eba48ad5" @@ -344,6 +439,11 @@ abi-decoder@^2.4.0: web3-eth-abi "^1.2.1" web3-utils "^1.2.1" +acorn-jsx@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" @@ -358,22 +458,44 @@ acorn-walk@^7.0.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.0.0: +acorn@^7.0.0, acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + anser@1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760" integrity sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA== +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-regex@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -395,11 +517,44 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + array-filter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= +array-includes@^3.1.2, array-includes@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" + is-string "^1.0.5" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flatmap@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" + integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + function-bind "^1.1.1" + asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -433,6 +588,11 @@ ast-types@0.13.2: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" @@ -639,6 +799,11 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" @@ -654,7 +819,7 @@ caniuse-lite@^1.0.30001228: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz#0a80de4cdf62e1770bb46a30d884fc8d633e3958" integrity sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ== -chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -679,6 +844,11 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + chokidar@3.5.1, chokidar@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" @@ -707,6 +877,18 @@ classnames@2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + clsx@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" @@ -825,6 +1007,17 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -897,6 +1090,13 @@ debug@2: dependencies: ms "2.0.0" +debug@^4.0.1, debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -909,6 +1109,11 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -957,11 +1162,32 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dlv@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" @@ -1000,6 +1226,16 @@ elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -1034,6 +1270,28 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" +es-abstract@^1.18.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" + integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -1058,6 +1316,154 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-plugin-cypress@^2.11.3: + version "2.11.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz#54ee4067aa8192aa62810cd35080eb577e191ab7" + integrity sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q== + dependencies: + globals "^11.12.0" + +eslint-plugin-react-hooks@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" + integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== + +eslint-plugin-react@^7.22.0: + version "7.24.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz#eadedfa351a6f36b490aa17f4fa9b14e842b9eb4" + integrity sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q== + dependencies: + array-includes "^3.1.3" + array.prototype.flatmap "^1.2.4" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.0.4" + object.entries "^1.1.4" + object.fromentries "^2.0.4" + object.values "^1.1.4" + prop-types "^15.7.2" + resolve "^2.0.0-next.3" + string.prototype.matchall "^4.0.5" + +eslint-plugin-ternary@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-ternary/-/eslint-plugin-ternary-1.0.4.tgz#f5c2ad1f17cf4b2ed1b6df2c1277063a6daec179" + integrity sha512-0udBN0dxLJ02dWqWUWwEQGD7DruEbNiqqfttmPOBhXLdYJpYUYRbzPJ8YLQJPJ8SSnAxmHiv4EXE3g+ZeewWNQ== + +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -1105,7 +1511,21 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -fast-glob@^3.2.5: +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1, fast-glob@^3.2.5: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== @@ -1117,6 +1537,16 @@ fast-glob@^3.2.5: micromatch "^4.0.2" picomatch "^2.2.1" +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fastq@^1.6.0: version "1.11.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" @@ -1124,6 +1554,20 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1148,6 +1592,20 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -1183,7 +1641,12 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -1214,7 +1677,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob-parent@^5.1.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1238,6 +1701,18 @@ glob@^7.0.0, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" @@ -1246,6 +1721,30 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" +globals@^11.12.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" @@ -1330,7 +1829,7 @@ https-browserify@1.0.0, https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1349,6 +1848,29 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1372,6 +1894,34 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + is-arguments@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" @@ -1435,6 +1985,16 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" @@ -1452,7 +2012,7 @@ is-glob@^2.0.0: dependencies: is-extglob "^1.0.0" -is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -1495,11 +2055,24 @@ is-regex@^1.1.2: call-bind "^1.0.2" has-symbols "^1.0.1" +is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.2" + is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== + is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -1528,6 +2101,11 @@ isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + jest-worker@27.0.0-next.5: version "27.0.0-next.5" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28" @@ -1552,6 +2130,24 @@ js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -1568,6 +2164,22 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" + integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== + dependencies: + array-includes "^3.1.2" + object.assign "^4.1.2" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + loader-utils@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" @@ -1599,7 +2211,7 @@ lodash.topath@^4.5.2: resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= -lodash@^4.17.13, lodash@^4.17.21, lodash@^4.17.3: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1611,6 +2223,13 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -1653,6 +2272,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -1682,11 +2306,18 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + modern-normalize@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" @@ -1697,6 +2328,16 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nanoid@^3.1.22: version "3.1.22" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" @@ -1709,6 +2350,11 @@ native-url@0.3.4: dependencies: querystring "^0.2.0" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + next@^10.2.3: version "10.2.3" resolved "https://registry.yarnpkg.com/next/-/next-10.2.3.tgz#5aa058a63626338cea91c198fda8f2715c058394" @@ -1765,6 +2411,11 @@ next@^10.2.3: vm-browserify "1.1.2" watchpack "2.1.1" +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + node-emoji@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" @@ -1846,6 +2497,11 @@ object-hash@^2.1.1: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.1.1.tgz#9447d0279b4fcf80cff3259bf66a1dc73afabe09" integrity sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ== +object-inspect@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== + object-inspect@^1.9.0: version "1.10.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" @@ -1874,6 +2530,34 @@ object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" + integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + +object.fromentries@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" + integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + has "^1.0.3" + +object.values@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + once@^1.3.0, once@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1881,11 +2565,35 @@ once@^1.3.0, once@^1.3.1: dependencies: wrappy "1" +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + os-browserify@0.3.0, os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + p-limit@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -1917,6 +2625,13 @@ pako@~1.0.5: resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0, parse-asn1@^5.1.5: version "5.1.6" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" @@ -1963,11 +2678,21 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" @@ -2064,6 +2789,11 @@ postcss@^6.0.9: source-map "^0.6.1" supports-color "^5.4.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -2079,7 +2809,12 @@ process@0.11.10, process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -prop-types@15.7.2: +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prop-types@15.7.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -2253,6 +2988,29 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regexp.prototype.flags@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -2261,11 +3019,34 @@ resolve@^1.20.0: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -2274,6 +3055,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2281,6 +3067,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -2304,11 +3097,23 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -semver@^6.0.0: +semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.2: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -2327,11 +3132,37 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + shell-quote@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -2353,6 +3184,20 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + source-map@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" @@ -2370,6 +3215,11 @@ source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + stacktrace-parser@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" @@ -2436,6 +3286,38 @@ string-hash@1.1.3: resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.matchall@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" + integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" @@ -2466,13 +3348,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@6.0.0: +strip-ansi@6.0.0, strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== dependencies: ansi-regex "^5.0.0" +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -2487,6 +3376,11 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" +strip-json-comments@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + styled-jsx@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-3.3.2.tgz#2474601a26670a6049fb4d3f94bd91695b3ce018" @@ -2532,6 +3426,16 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tailwindcss@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.4.tgz#ee8a1b8ccc140db61960b6738f968a8a1c4cd1f8" @@ -2565,6 +3469,16 @@ tailwindcss@^2.1.4: reduce-css-calc "^2.1.8" resolve "^1.20.0" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -2577,6 +3491,13 @@ timers-browserify@2.0.12, timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -2611,6 +3532,18 @@ ts-pnp@^1.1.6: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -2621,17 +3554,34 @@ tty-browserify@0.0.1: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + typescript@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== -unbox-primitive@^1.0.0: +unbox-primitive@^1.0.0, unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== @@ -2656,6 +3606,13 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + url-set-query@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" @@ -2712,6 +3669,11 @@ util@^0.11.0: dependencies: inherits "2.0.3" +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + vm-browserify@1.1.2, vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -2786,11 +3748,30 @@ which-typed-array@^1.1.2: has-symbols "^1.0.1" is-typed-array "^1.1.3" +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" @@ -2826,6 +3807,11 @@ xtend@^4.0.0, xtend@^4.0.2: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From 1d2a3f3b85876914925e4c9efaaa5b6920aa1a52 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Sat, 26 Jun 2021 14:23:38 +0200 Subject: [PATCH 09/28] Inspect functional --- components/bundles/BundleModal.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/bundles/BundleModal.tsx b/components/bundles/BundleModal.tsx index 84707bf..f29729a 100644 --- a/components/bundles/BundleModal.tsx +++ b/components/bundles/BundleModal.tsx @@ -1,6 +1,5 @@ /* This example requires Tailwind CSS v2.0+ */ -import React, { Fragment, useRef, useEffect, useCallback } from "react" -import { useRouter } from "next/router" +import React, { Fragment, useRef, useCallback } from "react" import { Dialog, Transition } from "@headlessui/react" import { Bundle } from "../bundles/Bundle" import { ErrorModal } from "../modals/ErrorModal" @@ -14,7 +13,7 @@ interface IBundleModal { export default function BundleModal({ open, bundle, close }: IBundleModal) { const cancelButtonRef = useRef() - const router = useRouter() + // const router = useRouter() // const close = () => { // setOpen(false) // if (bundle) { @@ -29,12 +28,12 @@ export default function BundleModal({ open, bundle, close }: IBundleModal) { // } }, [close]) - useEffect(() => { - const { block } = router.query - if (block === undefined) { - handleClose() - } - }, [router.query, handleClose]) + // useEffect(() => { + // const { block } = router.query + // if (block === undefined) { + // handleClose() + // } + // }, [router.query, handleClose]) return ( Date: Mon, 28 Jun 2021 07:48:10 +0200 Subject: [PATCH 10/28] Update .env.template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- .env.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 415f2cf..1c79980 100644 --- a/.env.template +++ b/.env.template @@ -1,2 +1,2 @@ NEXT_PUBLIC_INFURA_ID= -FLASHBOTS_API_URL=https://blocks.flashbots.net/v1/blocks \ No newline at end of file +FLASHBOTS_API_URL=https://blocks.flashbots.net/v1/blocks From 5129655407afcc1a5bef93fbad4d869514824e2c Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:48:30 +0200 Subject: [PATCH 11/28] Update components/Address.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- components/Address.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Address.tsx b/components/Address.tsx index 489c080..7419443 100644 --- a/components/Address.tsx +++ b/components/Address.tsx @@ -8,4 +8,4 @@ export const Address = ({ address } : { address: string }) => { href={`https://etherscan.io/address/${ address }`}>
{ shorten(address) }
-} \ No newline at end of file +} From e7c54c1fc7964cdd03655b153566839597ab33ae Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:48:40 +0200 Subject: [PATCH 12/28] Update components/Address.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- components/Address.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/Address.tsx b/components/Address.tsx index 7419443..d11c924 100644 --- a/components/Address.tsx +++ b/components/Address.tsx @@ -1,4 +1,5 @@ import React from "react" + export const Address = ({ address } : { address: string }) => { const size = 6 const shorten = (address: string): string => address.slice(0, size) + "..." + address.slice(-size) From c5f44885139e460da1e618a02ab88db9d985a69b Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:48:47 +0200 Subject: [PATCH 13/28] Update components/bundles/Subbundle.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- components/bundles/Subbundle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bundles/Subbundle.tsx b/components/bundles/Subbundle.tsx index cd571eb..274662e 100644 --- a/components/bundles/Subbundle.tsx +++ b/components/bundles/Subbundle.tsx @@ -28,4 +28,4 @@ export const SubBundle = ({ subBundle, index } : { subBundle: any[]; index?: num } -} \ No newline at end of file +} From 0676a8c4def96be0e01f021505c3e91d356fa969 Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:49:44 +0200 Subject: [PATCH 14/28] Update package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index fc031cf..1073d54 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@headlessui/react": "^1.1.1", - "abi-decoder": "^2.4.0", "clsx": "^1.1.1", "csvtojson": "^2.0.10", From de336b13ee3872e380701e188e074875fa8992bd Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:51:30 +0200 Subject: [PATCH 15/28] Update pages/index.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- pages/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/index.tsx b/pages/index.tsx index 1224712..fa63c81 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -58,4 +58,4 @@ export default function App() { ) -} \ No newline at end of file +} From 0101622bc17a0d59f93d5846411270b8018c00b6 Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:51:49 +0200 Subject: [PATCH 16/28] Update components/bundles/css/BundleOverview.module.css MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- components/bundles/css/BundleOverview.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bundles/css/BundleOverview.module.css b/components/bundles/css/BundleOverview.module.css index b805cfd..806a681 100644 --- a/components/bundles/css/BundleOverview.module.css +++ b/components/bundles/css/BundleOverview.module.css @@ -48,4 +48,4 @@ .pagination > *:disabled { opacity: 0; -} \ No newline at end of file +} From 8aad74911219f2e55f8a9acc021a1a79a18edd37 Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 07:52:53 +0200 Subject: [PATCH 17/28] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- .eslintrc.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index 262edb9..21c69d5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,6 +25,7 @@ "comma-spacing": ["error", { "before": false, "after": true }], "indent": ["error", 2], "linebreak-style": ["error", "unix"], + "eol-last": ["error", "always"], "quotes": ["error", "double"], "semi": ["error", "never"], "max-len": [ @@ -49,6 +50,7 @@ "space-in-parens": ["error", "never"], "ternary/no-unreachable": "off", "ternary/nesting": "off", + "@typescript-eslint/no-var-requires": "off", "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/explicit-function-return-type": "off", From 1a965994e43577cca4631a5726cd84347711c480 Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 08:02:23 +0200 Subject: [PATCH 18/28] Update context/BundleData/BundleDataProvider.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- context/BundleData/BundleDataProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index bc9cda2..e5a4786 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -91,7 +91,7 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { }, []) } - const transformBundle = useCallback((bundle) => { + const transformBundle = useCallback(bundle => { bundle.transactions = getSubBundles(bundle) return bundle }, []) From c0f443be1c8615dc8ad7e6a6b99767419644669f Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Mon, 28 Jun 2021 08:05:55 +0200 Subject: [PATCH 19/28] Added comment --- components/bundles/BundlesOverview.tsx | 6 +++--- pages/Home.tsx | 5 +---- pages/index.tsx | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/components/bundles/BundlesOverview.tsx b/components/bundles/BundlesOverview.tsx index db59e47..9d78adb 100644 --- a/components/bundles/BundlesOverview.tsx +++ b/components/bundles/BundlesOverview.tsx @@ -11,7 +11,7 @@ export default function BundlesOverview() { const { blocks, setFilters, filters, page, morePages, setPage } = useBundleData() const [bundle, setBundle] = useState(undefined) const [searchValue, setSearch] = useState(undefined) - const [landingMutex, setLandingMutex] = useState(false) + const [landingMutex, setLandingMutex] = useState(true) const setBundleAndOpen = useCallback(bundle => { @@ -23,13 +23,13 @@ export default function BundlesOverview() { }, []) useEffect(() => { - if (router.query.block && blocks.length > 0 && !landingMutex) { + if (router.query.block && blocks.length > 0 && landingMutex) { const blockNumber = router.query.block as unknown as string if (blockNumber) { const local = blocks.find(b => b.block_number == blockNumber) if (local) { setBundleAndOpen(local) - setLandingMutex(true) + setLandingMutex(false) } else if(!filters.block_number) { setFilters({ ...filters, diff --git a/pages/Home.tsx b/pages/Home.tsx index 720ba22..1364ca0 100644 --- a/pages/Home.tsx +++ b/pages/Home.tsx @@ -1,10 +1,7 @@ -import React, { useEffect } from "react" +import React from "react" import BundlesOverview from "../components/bundles/BundlesOverview" -import * as ga from "../lib/ga" export default function Home() { - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(ga.pageview) // TODO: Move query logic to return ( diff --git a/pages/index.tsx b/pages/index.tsx index fa63c81..4a14f62 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -47,11 +47,11 @@ export default function App() { - {/* */} + {/* TODO: Implement page routing management here */} From 3fcf9f07c314190889ea9eaab8c19caaf3bcad39 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Mon, 28 Jun 2021 08:09:47 +0200 Subject: [PATCH 20/28] Convert to rem --- components/bundles/css/BundleOverview.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bundles/css/BundleOverview.module.css b/components/bundles/css/BundleOverview.module.css index 806a681..0927e73 100644 --- a/components/bundles/css/BundleOverview.module.css +++ b/components/bundles/css/BundleOverview.module.css @@ -41,7 +41,7 @@ } .pagination > * { - padding: 8px 16px; + padding: 0.5rem 1rem; transition-duration: 200ms; opacity: 1; } From 4da55fb7c857faaabf836fe603fa59e7c3c0ceef Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Mon, 28 Jun 2021 08:15:28 +0200 Subject: [PATCH 21/28] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- context/BundleData/BundleDataProvider.tsx | 13 +++---------- next.config.js | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index e5a4786..74e9480 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -121,23 +121,16 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { }, [filters, blocks, page, transformBundle]) useEffect(() => { - if(blocks.length > filters.limit) { - setMorePages(true) - }else { - setMorePages(false) - } + setMorePages(blocks.length > filters.limit) }, [blocks, filters.limit, setMorePages]) // Automatically update when view is changed useEffect(() => { if (!pageMutex) { - if ((page * filters.limit) + 1 > blocks.length) { - setPageMutex(true) - getBlocks() - } else if (page === 1) { + if ((page * filters.limit) + 1 > blocks.length || page === 1)) { setPageMutex(true) getBlocks() - } + } } }, [filters, page, blocks, pageMutex, getBlocks]) diff --git a/next.config.js b/next.config.js index 166ee8d..0faa4d3 100644 --- a/next.config.js +++ b/next.config.js @@ -10,7 +10,6 @@ module.exports = { }, webpack: (config) => { config.resolve.fallback = { fs: false } - return config } } From 338cbd031785ed9e85a89e3e6164e475109a2a25 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Mon, 28 Jun 2021 15:35:11 +0200 Subject: [PATCH 22/28] Static generation happens regardless of consumtion, home removed --- context/BundleData/BundleDataProvider.tsx | 4 ++-- pages/Home.tsx | 9 --------- pages/index.tsx | 4 ++-- 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 pages/Home.tsx diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx index 74e9480..3baa440 100644 --- a/context/BundleData/BundleDataProvider.tsx +++ b/context/BundleData/BundleDataProvider.tsx @@ -127,10 +127,10 @@ const BundleDataProvider = ({ children }: BundleDataContextProps) => { // Automatically update when view is changed useEffect(() => { if (!pageMutex) { - if ((page * filters.limit) + 1 > blocks.length || page === 1)) { + if ((page * filters.limit) + 1 > blocks.length || page === 1) { setPageMutex(true) getBlocks() - } + } } }, [filters, page, blocks, pageMutex, getBlocks]) diff --git a/pages/Home.tsx b/pages/Home.tsx deleted file mode 100644 index 1364ca0..0000000 --- a/pages/Home.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from "react" -import BundlesOverview from "../components/bundles/BundlesOverview" - -export default function Home() { - // TODO: Move query logic to - return ( - - ) -} diff --git a/pages/index.tsx b/pages/index.tsx index 4a14f62..0197bff 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -3,9 +3,9 @@ import React, { useEffect } from "react" import { useRouter } from "next/router" import * as ga from "../lib/ga" import styles from "../styles/Home.module.css" -import Home from "./Home" import { BundleDataProvider } from "../context/BundleData/BundleDataProvider" import { TokenDataProvider } from "../context/TokenData/TokenDataProvider" +import BundlesOverview from "../components/bundles/BundlesOverview" export default function App() { // eslint-disable-next-line react-hooks/exhaustive-deps @@ -48,7 +48,7 @@ export default function App() { href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css" /> {/* TODO: Implement page routing management here */} - +