diff --git a/next.config.js b/next.config.js index 310e00b..5fd8bbc 100644 --- a/next.config.js +++ b/next.config.js @@ -10,6 +10,10 @@ const nextConfig = { }, ]; }, + images: { + domains: ['defillama.com'], + formats: ['image/avif', 'image/webp'], + }, pageExtensions: ['page.tsx'], }; diff --git a/package.json b/package.json index 7782ce8..70a22b4 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@storybook/client-api": "^6.5.10", "@storybook/manager-webpack5": "^6.4.19", "bignumber.js": "^9.0.2", + "colorthief": "^2.3.2", "esm": "^3.2.25", "lodash": "^4.17.21", "next": "12.1.0", diff --git a/pages/chain-list/chain-list.test.tsx b/pages/chain-list/chain-list.test.tsx new file mode 100644 index 0000000..ffc3d92 --- /dev/null +++ b/pages/chain-list/chain-list.test.tsx @@ -0,0 +1,172 @@ +import { render } from '@testing-library/react'; +import { expect } from 'earljs'; + +import { changeTargetValue } from '../../test/helpers/changeTargetValue'; +import ChainList from './index.page'; + +// test pagination +// test searching for chain + +const mockChain = { + name: 'Mock chain', + chain: 'ETH', + icon: 'ethereum', + rpc: [ + 'https://mainnet.infura.io/v3/${INFURA_API_KEY}', + 'wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}', + 'https://api.mycryptoapi.com/eth', + 'https://cloudflare-eth.com', + ], + faucets: [], + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + }, + infoURL: 'https://ethereum.org', + shortName: 'eth', + chainId: 1, + networkId: 1, + slip44: 60, + ens: { + registry: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', + }, + explorers: [ + { + name: 'etherscan', + url: 'https://etherscan.io', + standard: 'EIP3091', + }, + ], + chainSlug: 'ethereum', + tvl: 55101671827.85486, +}; + +const fetchedChains = [ + ...Array.from({ length: 16 }).map((_, index) => ({ + ...mockChain, + chainId: index + 3, + })), + { + name: 'Binance Smart Chain Mainnet', + chain: 'BSC', + rpc: [ + 'https://bsc-dataseed1.binance.org', + 'https://bsc-dataseed2.binance.org', + 'https://bsc-dataseed3.binance.org', + 'https://bsc-dataseed4.binance.org', + 'https://bsc-dataseed1.defibit.io', + 'https://bsc-dataseed2.defibit.io', + 'https://bsc-dataseed3.defibit.io', + 'https://bsc-dataseed4.defibit.io', + 'https://bsc-dataseed1.ninicoin.io', + 'https://bsc-dataseed2.ninicoin.io', + 'https://bsc-dataseed3.ninicoin.io', + 'https://bsc-dataseed4.ninicoin.io', + 'wss://bsc-ws-node.nariox.org', + ], + faucets: ['https://free-online-app.com/faucet-for-eth-evm-chains/'], + nativeCurrency: { + name: 'Binance Chain Native Token', + symbol: 'BNB', + decimals: 18, + }, + infoURL: 'https://www.binance.org', + shortName: 'bnb', + chainId: 56, + networkId: 56, + slip44: 714, + explorers: [ + { + name: 'bscscan', + url: 'https://bscscan.com', + standard: 'EIP3091', + }, + ], + chainSlug: 'binance', + tvl: 6664169203.011698, + }, + { + name: 'Polygon Mainnet', + chain: 'Polygon', + rpc: [ + 'https://polygon-rpc.com/', + 'https://rpc-mainnet.matic.network', + 'https://matic-mainnet.chainstacklabs.com', + 'https://rpc-mainnet.maticvigil.com', + 'https://rpc-mainnet.matic.quiknode.pro', + 'https://matic-mainnet-full-rpc.bwarelabs.com', + ], + faucets: [], + nativeCurrency: { + name: 'MATIC', + symbol: 'MATIC', + decimals: 18, + }, + infoURL: 'https://polygon.technology/', + shortName: 'matic', + chainId: 137, + networkId: 137, + slip44: 966, + explorers: [ + { + name: 'polygonscan', + url: 'https://polygonscan.com', + standard: 'EIP3091', + }, + ], + chainSlug: 'polygon', + tvl: 2313673290.8639984, + }, +]; + +describe(ChainList.name, () => { + it('changes pages', () => { + const root = render( + } fetchedChains={fetchedChains} />, + ); + { + const chainList = root.getByLabelText('chain list'); + + expect(chainList.children.length).toEqual(10); + } + const previousPageButton = root.getByText( + 'Previous page', + ) as HTMLButtonElement; + + expect(previousPageButton.disabled).toEqual(true); + + const nextPageButton = root.getByText('Next Page') as HTMLButtonElement; + + nextPageButton.click(); + + const chainList = root.getByLabelText('chain list'); + + expect(chainList.children.length).toEqual(8); + expect(nextPageButton.disabled).toEqual(true); + expect(previousPageButton.disabled).toEqual(false); + }); + + it('filters chains', () => { + const root = render( + } fetchedChains={fetchedChains} />, + ); + const filterInput = root.getByPlaceholderText('Ethereum Mainnet'); + + changeTargetValue(filterInput, 'Bina'); + + const filterQueryResults = root.getByLabelText( + 'chain filter query results', + ); + + expect(filterQueryResults.children.length).toEqual(1); + expect(filterQueryResults.children[0].textContent).toEqual( + 'Binance Smart Chain Mainnet', + ); + + changeTargetValue(filterInput, ''); + + // Empty filter query always results in hidden results + expect(() => root.getByLabelText('chain filter query results')).toThrow(); + }); +}); diff --git a/pages/chain-list/index.page.tsx b/pages/chain-list/index.page.tsx new file mode 100644 index 0000000..a950585 --- /dev/null +++ b/pages/chain-list/index.page.tsx @@ -0,0 +1,298 @@ +import { Combobox, Dialog } from '@headlessui/react'; +import { uniqBy } from 'lodash'; +import { GetStaticProps, NextPage } from 'next'; +import React, { ReactElement, useEffect, useState } from 'react'; + +import { ChainEntity } from '../../src/components/Chain'; +import { StackIcon } from '../../src/components/icons/StackIcon'; +import { Button } from '../../src/components/lib/Button'; +import { Entity } from '../../src/components/lib/Entity'; +import { Header } from '../../src/components/lib/Header'; +import { ToolContainer } from '../../src/components/ToolContainer'; +import chainIds from '../../src/misc/liamaChainSlugs'; +import { safeFetch } from '../../src/misc/safeFetch'; +import { Chain, ChainTVL } from '../../src/types/liamaChainAPI'; + +interface ChainFilterProps { + filtered: T[]; + queryState: [string, (query: string) => void]; + selectedItemState: [T | undefined, (chain: T | undefined) => void]; + setIsOpen: (isOpen: boolean) => void; +} + +export const getStaticProps: GetStaticProps = async (): Promise<{ + props: PageProps; +}> => { + let fetchedChains = await safeFetch( + 'https://chainid.network/chains.json', + ).then((response) => uniqBy(response, 'chain')); + + const chainTvls = await safeFetch('https://api.llama.fi/chains'); + + fetchedChains = fetchedChains + .map((chain) => { + const found = chainTvls.find( + (chainTvl) => chainTvl.chainId === chain.chainId, + ); + const chainSlug = chainIds[chain.chainId]; + return found && chainSlug + ? { + ...chain, + chainSlug, + tvl: found.tvl, + } + : chain; + }) + .sort((a, b) => (b.tvl ?? 0) - (a.tvl ?? 0)); + + return { + props: { + fetchedChains, + }, + }; +}; + +const ChainList: NextPage = ({ fetchedChains, mockIcon }) => { + const [filtered, setFiltered] = useState([]); + const [page, setPage] = useState({ currentPage: 1, chainsPerPage: 10 }); + + const [selectedChain, setSelectedChain] = useState(); + const [isOpen, setIsOpen] = useState(false); + const [query, setQuery] = useState(''); + + useEffect(() => { + if (query === '' && !selectedChain) setFiltered([]); + }, [query, selectedChain]); + + useEffect(() => { + const filtered = + query.length > 0 && + fetchedChains + .filter(({ name }) => { + return name.toLowerCase().includes(query.toLowerCase()); + }) + .slice(0, 20); + if (filtered) setFiltered(filtered); + }, [query, fetchedChains]); + + function handleNextPage(): void { + setFiltered([]); + if (page.currentPage * page.chainsPerPage < fetchedChains.length) + setPage((page) => { + return { + ...page, + currentPage: page.currentPage + 1, + }; + }); + } + + function handlePreviousPage(): void { + setFiltered([]); + if (page.currentPage > 1) + setPage((page) => { + return { + ...page, + currentPage: page.currentPage - 1, + }; + }); + } + + const indexOfLastPost = page.currentPage * page.chainsPerPage; + const indexOfFirstPost = indexOfLastPost - page.chainsPerPage; + const currentChains = fetchedChains.slice(indexOfFirstPost, indexOfLastPost); + + const isPreviousButtonDisabled = page.currentPage <= 1; + const isNextButtonDisabled = + page.currentPage * page.chainsPerPage >= fetchedChains.length; + + return ( + +
} + text={['Lists', 'Chain List']} + /> + +
+ + + + + + + + + +
+ 0 ? filtered : currentChains} + /> + + ); +}; + +function PaginatedChains({ + chains, + mockIcon, +}: PaginatedChainsProps): ReactElement { + return ( +
+ {chains.map((chain) => { + return ( + + ); + })} +
+ ); +} + +interface PaginatedChainsProps { + chains: Chain[]; + mockIcon?: JSX.Element; +} + +// @internal +interface PageProps { + fetchedChains: Array; + mockIcon?: JSX.Element; +} + +// @internal +function ChainDialog({ + isOpenState, + selectedChain, +}: ChainDialogProps): ReactElement { + const [isOpen, setIsOpen] = isOpenState; + + return ( + setIsOpen(false)} + className="relative z-50" + > + + ); +} + +interface ChainDialogProps { + selectedChain: Chain; + isOpenState: [boolean, (isOpen: boolean) => void]; +} + +// @internal +function ChainFilter({ + queryState, + filtered, + selectedItemState, + setIsOpen, +}: ChainFilterProps): ReactElement { + const [selectedItem, setSelectedItem] = selectedItemState; + const [showResults, setShowResults] = useState(true); + const [, setQuery] = queryState; + + function handleChangeInput(newValue: string): void { + if (newValue === '') setShowResults(false); + else setShowResults(true); + setQuery(newValue); + } + + return ( + { + const found = filtered.find( + (chain) => chain.name === (item as unknown as string), + ); + setSelectedItem(found); + setIsOpen(true); + }} + > +
+ handleChangeInput(target.value)} + onClick={() => setSelectedItem(undefined)} + /> + {showResults && ( + +
+ +
+ {filtered.length > 0 ? ( + filtered.map((chain) => ( + + {({ active }) => ( +

+ {chain.name} +

+ )} +
+ )) + ) : ( +
+ Looks like there are no results for this query :( +
+ )} +
+ + )} +
+ + ); +} + +export default ChainList; diff --git a/src/components/Chain/Chain.tsx b/src/components/Chain/Chain.tsx new file mode 100644 index 0000000..b307290 --- /dev/null +++ b/src/components/Chain/Chain.tsx @@ -0,0 +1,312 @@ +// @ts-ignore +import colorthief from 'colorthief'; +import Image from 'next/image'; +import Link from 'next/link'; +import React, { + ComponentPropsWithoutRef, + ReactElement, + useEffect, + useMemo, + useState, +} from 'react'; +import { Chain } from 'src/types/liamaChainAPI'; + +import { CoinStackIcon } from '../icons/CoinStackIcon'; +import { EthereumIcon } from '../icons/EthereumIcon'; +import { ExploreIcon } from '../icons/ExploreIcon'; +import { Table } from '../Table'; +import { ChainDetailPanelElement, ChainDetails } from './ChainDetails'; + +const rgbToHex = (r: number, g: number, b: number): string => + '#' + + [r, g, b] + .map((x) => { + const hex = x.toString(16); + return hex.length === 1 ? '0' + hex : hex; + }) + .join(''); + +type ChainEntityColorCacheKey = `chain-icon-${number}`; + +const chainEntityColorCache: Record = {}; + +export function ChainEntity({ + chain, + className, + mockIcon, + ...props +}: ChainEntityProps): ReactElement { + const [isLoading, setIsLoading] = useState(true); + const [selected, setSelected] = useState< + ChainDetailPanelElement | undefined + >(); + + const icon = useMemo(() => { + try { + return ( + chain.chainSlug && + `https://defillama.com/chain-icons/rsz_${chain.chainSlug}.jpg` + ); + } catch (error) {} + }, [chain]); + + useEffect(() => { + if (!icon) setIsLoading(false); + }, [icon]); + + function handleLoadImage(): void { + const currentKey: ChainEntityColorCacheKey = `chain-icon-${chain.chainId}`; + if (currentKey in chainEntityColorCache) { + setIsLoading(false); + return setDominantColors(chainEntityColorCache[currentKey]); + } + + const img = document.getElementById(`chain-icon-${chain.chainId}`); + + const colorThief = new colorthief(); + try { + const result = colorThief.getPalette(img, 3) as number[][]; + const hexArray = result.map((rgb) => rgbToHex(rgb[0], rgb[1], rgb[2])); + + const cacheChainId: ChainEntityColorCacheKey = `chain-icon-${chain.chainId}`; + chainEntityColorCache[cacheChainId] = hexArray; + + setDominantColors(hexArray); + } catch (error) { + setIsLoading(false); + } finally { + setIsLoading(false); + } + } + + const [dominantColors, setDominantColors] = useState(); + + return ( + <> +
+ {isLoading && ( +
+ )} + {dominantColors ? ( + <> +
+
+ + ) : ( + <> +
+
+ + )} +
+
+
+ {icon ? ( +
+ {mockIcon ? ( + mockIcon + ) : ( + handleLoadImage()} + className="absolute rounded blur" + src={icon} + layout="fill" + objectFit="contain" + /> + )} +
+ ) : ( +
+ +
+ )} + +
+
+

chain id:

+ {chain.chainId} +
+ +

+ {chain.name} +

+

+ TVL: {chain.tvl?.toString().split('.')[0]}$ +

+
+
+ +
+ + {chain.nativeCurrency?.symbol} + {chain.nativeCurrency?.decimals} + +

+ {chain.nativeCurrency?.name} +

+
+
+ + +
+ + 0 || false} + name="RPC" + selectedState={[selected, setSelected]} + > + RPC + + + + {chain.infoURL} + + + 0) || false + } + name="Explorers" + type="button" + selectedState={[selected, setSelected]} + > + + + + 0) || false} + name="Faucets" + type="button" + selectedState={[selected, setSelected]} + > + + + +
+ {chain.ens ? ( +

ENS ✔

+ ) : ( +

+ ENS +

+ )} +
+
+ + + {chain.explorers && + chain.explorers.length > 0 && + selected === 'Explorers' && ( + + + name + standard + url + + {chain.explorers.map((explorer) => { + return ( + + {explorer.name} + {explorer.standard} + + +

+ {explorer.url} +

+ +
+
+ ); + })} +
+ )} + + {selected === 'RPC' && chain.rpc.length > 0 && ( + <> + + + id + url + + {chain.rpc.map((url, id) => { + return ( + + {id + 1} + {url} + + ); + })} +
+ + )} + + {chain.faucets && + chain.faucets.length > 0 && + selected === 'Faucets' && ( + <> + + + id + url + + {chain.faucets.map((faucet, index) => { + return ( + + {index} + {faucet} + + ); + })} +
+ + )} +
+
+
+
+ + ); +} + +interface ChainEntityProps extends ComponentPropsWithoutRef<'div'> { + mockIcon?: JSX.Element; + chain: Chain; +} diff --git a/src/components/Chain/ChainDetails.tsx b/src/components/Chain/ChainDetails.tsx new file mode 100644 index 0000000..5825e9b --- /dev/null +++ b/src/components/Chain/ChainDetails.tsx @@ -0,0 +1,114 @@ +import React, { + ComponentPropsWithoutRef, + Dispatch, + ReactElement, + ReactNode, + SetStateAction, +} from 'react'; +import { ReactChildren } from 'src/types/util'; + +import { LinkIcon } from '../icons/LinkIcon'; + +const colors = require('../../../tailwind.config').theme.colors; + +export type ChainDetailPanelElement = typeof ChainDetailPanelElements[number]; + +const ChainDetailPanelElements = [ + 'RPC', + 'Explorers', + 'Faucets', + 'URL', +] as const; + +function ChainDetailsRoot({ + children, + ...props +}: ChainDetailsRootProps): ReactElement { + return ( +
+
{children}
+
+ ); +} + +interface ChainDetailsRootProps extends ComponentPropsWithoutRef<'div'> { + children: ReactNode; +} + +// this type guard is really narrowed, as ReactNode +// could be also a boolean, null etc., +// but for this use case it does its job +function isChildReactElement( + children: ReactElement | ReactNode, +): children is ReactElement { + return ( + (children && typeof children === 'object' && 'type' in children) || false + ); +} + +function Element({ + children, + type = 'button', + selectedState, + show = true, + name, +}: ElementProps): ReactElement | null { + const [selected, setSelected] = selectedState; + + return show ? ( + type === 'button' ? ( + + ) : ( + + + + ) + ) : null; +} + +interface ElementProps { + type?: 'button' | 'link'; + show?: boolean; + name: ChainDetailPanelElement; + children: ReactElement | string; + selectedState: [ + ChainDetailPanelElement | undefined, + Dispatch>, + ]; +} + +function Panel({ children }: ReactChildren): ReactElement { + return
{children}
; +} + +function Data({ children }: ReactChildren): ReactElement { + return <>{children}; +} + +export const ChainDetails = Object.assign(ChainDetailsRoot, { + Panel, + Data, + Element, +}); diff --git a/src/components/Chain/index.tsx b/src/components/Chain/index.tsx new file mode 100644 index 0000000..b7930ab --- /dev/null +++ b/src/components/Chain/index.tsx @@ -0,0 +1 @@ +export * from './Chain'; diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx new file mode 100644 index 0000000..89aa0bd --- /dev/null +++ b/src/components/Table/Table.tsx @@ -0,0 +1,78 @@ +import { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react'; + +function TableRoot({ + children, + className, + ...props +}: TableProps): ReactElement { + return ( +
+ + {children} +
+
+ ); +} + +function Head({ children }: HeadProps): ReactElement { + return ( + + + {children} + + + ); +} + +interface HeadProps { + children: ReactNode; +} + +function HeadRow({ children }: HeadRowProps): ReactElement { + return ( + + {children} + + ); +} + +interface HeadRowProps { + children: ReactNode; +} + +function Rows({ children }: RowsProps): ReactElement { + return ( + + + {children} + + + ); +} + +interface RowsProps { + children: ReactNode; +} + +function Row({ children }: RowProps): ReactElement { + return {children}; +} + +interface RowProps { + children: ReactNode; +} + +export const Table = Object.assign(TableRoot, { Rows, Row, Head, HeadRow }); + +interface TableProps extends ComponentPropsWithoutRef<'div'> { + children: ReactNode; +} diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx new file mode 100644 index 0000000..75193ad --- /dev/null +++ b/src/components/Table/index.tsx @@ -0,0 +1 @@ +export * from './Table'; diff --git a/src/components/ToolTree.tsx b/src/components/ToolTree.tsx index e046858..4cf811a 100644 --- a/src/components/ToolTree.tsx +++ b/src/components/ToolTree.tsx @@ -8,6 +8,7 @@ import { EncodersIcon } from './icons/EncodersIcon'; import { GeneratorIcon } from './icons/GeneratorIcon'; import { MinusIcon } from './icons/MinusIcon'; import { PlusIcon } from './icons/PlusIcon'; +import { StackIcon } from './icons/StackIcon'; import { NavigationSocial } from './NavigationSocial'; interface ToolTreeProps extends React.ComponentPropsWithoutRef<'section'> { @@ -129,6 +130,15 @@ const tree: Tree = { }, ], }, + lists: { + icon: , + tools: [ + { + title: 'Chain list', + pageHref: 'chain-list', + }, + ], + }, }; // @internal diff --git a/src/components/icons/CoinStackIcon.tsx b/src/components/icons/CoinStackIcon.tsx new file mode 100644 index 0000000..7f83469 --- /dev/null +++ b/src/components/icons/CoinStackIcon.tsx @@ -0,0 +1,19 @@ +import React, { ReactElement, SVGProps } from 'react'; + +export function CoinStackIcon(props: SVGProps): ReactElement { + return ( + + + + ); +} diff --git a/src/components/icons/EthereumIcon.tsx b/src/components/icons/EthereumIcon.tsx new file mode 100644 index 0000000..10963c2 --- /dev/null +++ b/src/components/icons/EthereumIcon.tsx @@ -0,0 +1,18 @@ +import React, { ReactElement, SVGProps } from 'react'; + +export function EthereumIcon(props: SVGProps): ReactElement { + return ( + + + + ); +} diff --git a/src/components/icons/ExploreIcon.tsx b/src/components/icons/ExploreIcon.tsx new file mode 100644 index 0000000..1cdb344 --- /dev/null +++ b/src/components/icons/ExploreIcon.tsx @@ -0,0 +1,19 @@ +import React, { ReactElement, SVGProps } from 'react'; + +export function ExploreIcon(props: SVGProps): ReactElement { + return ( + + + + ); +} diff --git a/src/components/icons/LinkIcon.tsx b/src/components/icons/LinkIcon.tsx new file mode 100644 index 0000000..ffd4d6c --- /dev/null +++ b/src/components/icons/LinkIcon.tsx @@ -0,0 +1,19 @@ +import React, { ReactElement, SVGProps } from 'react'; + +export function LinkIcon(props: SVGProps): ReactElement { + return ( + + + + ); +} diff --git a/src/components/icons/StackIcon.tsx b/src/components/icons/StackIcon.tsx new file mode 100644 index 0000000..805ad24 --- /dev/null +++ b/src/components/icons/StackIcon.tsx @@ -0,0 +1,19 @@ +import React, { ReactElement, SVGProps } from 'react'; + +export function StackIcon(props: SVGProps): ReactElement { + return ( + + + + ); +} diff --git a/src/components/lib/Button/Button.tsx b/src/components/lib/Button/Button.tsx index e0fea5b..5b21bd1 100644 --- a/src/components/lib/Button/Button.tsx +++ b/src/components/lib/Button/Button.tsx @@ -21,8 +21,8 @@ export const Button = forwardRef( /** @internal */ export const variants = { primary: - 'bg-gradient-to-r from-pink to-purple hover:outline-gray-50 ' + - 'hover:shadow-lg hover:shadow-pink/25', + 'bg-gradient-to-tr from-pink to-purple hover:outline-gray-50 ' + + 'hover:shadow-md hover:shadow-pink/25', secondary: 'bg-gray-600 text-gray-300 hover:shadow-lg hover:shadow-white/10', tertiary: 'border border-gray-600 bg-gray-900 text-gray-400', text: '', diff --git a/src/components/lib/Entity/Entity.tsx b/src/components/lib/Entity/Entity.tsx index 9e6f2d8..84c52ac 100644 --- a/src/components/lib/Entity/Entity.tsx +++ b/src/components/lib/Entity/Entity.tsx @@ -9,7 +9,7 @@ export function Entity({ }: EntityProps): ReactElement { return (
diff --git a/src/globals.css b/src/globals.css index 734d7bd..4f1fb0b 100644 --- a/src/globals.css +++ b/src/globals.css @@ -19,6 +19,10 @@ html { height: 100vh; } +* { + @apply focus-visible:outline-none; +} + @layer base { a { @apply no-underline; @@ -29,3 +33,29 @@ input[type='number']::-webkit-inner-spin-button, input[type='number']::-webkit-outer-spin-button { opacity: 1; } + +.blur { + content: ''; + -webkit-filter: blur(0.4px); + filter: blur(0.4px); +} + +.blur-xl { + filter: blur(36px); +} + +.animate-gradient { + animation: gradient 15s ease infinite; +} + +@keyframes gradient { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} diff --git a/src/lib/decodeBySigHash.ts b/src/lib/decodeBySigHash.ts index 5576adc..01dc837 100644 --- a/src/lib/decodeBySigHash.ts +++ b/src/lib/decodeBySigHash.ts @@ -1,6 +1,6 @@ import { Interface } from '@ethersproject/abi'; -import fetch from 'node-fetch'; +import { safeFetch } from '../../src/misc/safeFetch'; import { hexSchema } from '../misc/validation/schemas/hexSchema'; import { decodeCalldata, DecodeResult } from './decodeCalldata'; import { DecodedEventResult, decodeEvent, EventProps } from './decodeEvent'; @@ -78,16 +78,6 @@ async function fetch4Bytes( return result; } -async function safeFetch(...args: Parameters): Promise { - return fetch(...args).then(async (response) => { - if (response.status === 200) { - return response.json() as unknown as T; - } else { - throw new Error(`${response.status} ${response.statusText}`); - } - }); -} - // @internal interface FourBytesReponseEntry { id: number; diff --git a/src/misc/liamaChainSlugs.ts b/src/misc/liamaChainSlugs.ts new file mode 100644 index 0000000..754aef7 --- /dev/null +++ b/src/misc/liamaChainSlugs.ts @@ -0,0 +1,79 @@ +const chainIds: Record = { + 0: 'kardia', + 1: 'ethereum', + 2: 'expanse', + 8: 'ubiq', + 10: 'optimism', + 19: 'songbird', + 20: 'elastos', + 25: 'cronos', + 30: 'rsk', + 40: 'telos', + 50: 'xdc', + 52: 'csc', + 55: 'zyx', + 56: 'binance', + 57: 'syscoin', + 60: 'gochain', + 61: 'ethereumclassic', + 66: 'okexchain', + 70: 'hoo', + 82: 'meter', + 87: 'nova network', + 88: 'tomochain', + 100: 'xdai', + 106: 'velas', + 108: 'thundercore', + 122: 'fuse', + 128: 'heco', + 137: 'polygon', + 200: 'xdaiarb', + 246: 'energyweb', + 250: 'fantom', + 269: 'hpb', + 288: 'boba', + 321: 'kucoin', + 336: 'shiden', + 361: 'theta', + 416: 'sx', + 534: 'candle', + 592: 'astar', + 820: 'callisto', + 888: 'wanchain', + 970: 'ccn', + 971: 'ccnbeta', + 1088: 'metis', + 1246: 'omchain', + 1284: 'moonbeam', + 1285: 'moonriver', + 2000: 'dogechain', + 2020: 'ronin', + 2222: 'kava', + 2612: 'ezchain', + 4181: 'phi', + 4689: 'iotex', + 5050: 'xlc', + 5551: 'nahmii', + 7777: 'nmactest', + 8217: 'klaytn', + 9001: 'evmos', + 10000: 'smartbch', + 900000: 'posichain', + 103090: 'crystaleum', + 32659: 'fusion', + 42161: 'arbitrum', + 42170: 'arb-nova', + 42220: 'celo', + 42262: 'oasis', + 43114: 'avalanche', + 71402: 'godwoken', + 100100: 'chiado', + 200625: 'akroma', + 333999: 'polis', + 1313161554: 'aurora', + 1666600000: 'harmony', + 11297108109: 'palm', + 836542336838601: 'curio', +}; + +export default chainIds; diff --git a/src/misc/safeFetch.ts b/src/misc/safeFetch.ts new file mode 100644 index 0000000..6b0d0e5 --- /dev/null +++ b/src/misc/safeFetch.ts @@ -0,0 +1,11 @@ +export async function safeFetch( + ...args: Parameters +): Promise { + return fetch(...args).then(async (response) => { + if (response.status === 200) { + return response.json() as unknown as T; + } else { + throw new Error(`${response.status} ${response.statusText}`); + } + }); +} diff --git a/src/types/liamaChainAPI.d.ts b/src/types/liamaChainAPI.d.ts new file mode 100644 index 0000000..c14ecca --- /dev/null +++ b/src/types/liamaChainAPI.d.ts @@ -0,0 +1,41 @@ +export interface ChainTVL { + chainId: number; + cmcId: string; + gecko_id: string; + name: string; + tokenSymbol: string; + tvl: number; +} + +export interface Explorer { + name: string; + standard: string; + url: string; +} + +export interface NativeCurrency { + name: string; + symbol: string; + decimals: number; +} + +export interface Chain { + name: string; + shortName: string; + chain: string; + chainId: number; + networkId: number; + infoURL: string; + nativeCurrency?: NativeCurrency; + rpc: string[]; + slip44?: number; + ens?: { + // hex str + registry: string; + }; + chainSlug?: string; + explorers?: Explorer[]; + faucets?: string[]; + icon?: string; + tvl?: number; +} diff --git a/src/types/util.d.ts b/src/types/util.d.ts index 2f3700c..f9078f2 100644 --- a/src/types/util.d.ts +++ b/src/types/util.d.ts @@ -5,3 +5,7 @@ export type RequireAtLeastOne = Pick< { [K in Keys]-?: Required> & Partial>>; }[Keys]; + +export type ReactChildren = { children: ReactNode }; + +export type WithReactChildren = T & { children: ReactNode }; diff --git a/tailwind.config.js b/tailwind.config.js index c3d8b9d..4bccf4c 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -38,9 +38,42 @@ module.exports = { transform: 'translateX(100%)', }, }, + 'gradient-y': { + '0%, 100%': { + 'background-size': '400% 400%', + 'background-position': 'center top', + }, + '50%': { + 'background-size': '200% 200%', + 'background-position': 'center center', + }, + }, + 'gradient-x': { + '0%, 100%': { + 'background-size': '200% 200%', + 'background-position': 'left center', + }, + '50%': { + 'background-size': '200% 200%', + 'background-position': 'right center', + }, + }, + 'gradient-xy': { + '0%, 100%': { + 'background-size': '400% 400%', + 'background-position': 'left center', + }, + '50%': { + 'background-size': '200% 200%', + 'background-position': 'right center', + }, + }, }, animation: { shimmer: 'shimmer 2s ease-in-out infinite', + 'gradient-x': 'gradient-x 6s ease infinite', + 'gradient-y': 'gradient-y 6s ease infinite', + 'gradient-xy': 'gradient-xy 6s ease infinite', }, typography: (theme) => ({ DEFAULT: { diff --git a/yarn.lock b/yarn.lock index 1dfbb89..1ae832a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1768,9 +1768,9 @@ "@hapi/hoek" "^9.0.0" "@headlessui/react@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.5.0.tgz#483b44ba2c8b8d4391e1d2c863898d7dd0cc0296" - integrity sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ== + version "1.6.6" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.6.6.tgz#3073c066b85535c9d28783da0a4d9288b5354d0c" + integrity sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q== "@humanwhocodes/config-array@^0.9.2": version "0.9.5" @@ -4375,7 +4375,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -6464,6 +6464,14 @@ colors@1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +colorthief@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/colorthief/-/colorthief-2.3.2.tgz#00b984f421abe5a2af71c4d464c9d80d407fd53d" + integrity sha512-1r4nPW553JviRcFRvN3fS2V9nUSQGjRIws8UfEeFLIxk8j1tvtaX+AAYTkH3A4B5Muiys8SA1WJxf+00xVTXyg== + dependencies: + get-pixels "^3.3.2" + quantize "github:lokesh/quantize" + combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -6898,6 +6906,13 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== +cwise-compiler@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5" + integrity sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ== + dependencies: + uniq "^1.0.0" + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -6972,6 +6987,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-0.0.3.tgz#18ae979a6a0ca994b0625853916d2662bbae0b1a" + integrity sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw== + data-urls@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.1.tgz#597fc2ae30f8bc4dbcf731fcd1b1954353afc6f8" @@ -8574,6 +8594,23 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-pixels@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/get-pixels/-/get-pixels-3.3.3.tgz#71e2dfd4befb810b5478a61c6354800976ce01c7" + integrity sha512-5kyGBn90i9tSMUVHTqkgCHsoWoR+/lGbl4yC83Gefyr0HLIhgSWEx/2F/3YgsZ7UpYNuM6pDhDK7zebrUJ5nXg== + dependencies: + data-uri-to-buffer "0.0.3" + jpeg-js "^0.4.1" + mime-types "^2.0.1" + ndarray "^1.0.13" + ndarray-pack "^1.1.1" + node-bitmap "0.0.1" + omggif "^1.0.5" + parse-data-uri "^0.2.0" + pngjs "^3.3.3" + request "^2.44.0" + through "^2.3.4" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -8775,6 +8812,19 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -9106,6 +9156,15 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + http-signature@~1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" @@ -9256,6 +9315,11 @@ invariant@^2.2.2, invariant@^2.2.4: dependencies: loose-envify "^1.0.0" +iota-array@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/iota-array/-/iota-array-1.0.0.tgz#81ef57fe5d05814cd58c2483632a99c30a0e8087" + integrity sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA== + ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -9340,7 +9404,7 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: +is-buffer@^1.0.2, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -9901,6 +9965,11 @@ joi@^17.6.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" +jpeg-js@^0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -10071,6 +10140,16 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + jsprim@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" @@ -10631,6 +10710,13 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +mime-types@^2.0.1, mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime-types@^2.1.12: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" @@ -10638,13 +10724,6 @@ mime-types@^2.1.12: dependencies: mime-db "1.51.0" -mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -10893,6 +10972,22 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +ndarray-pack@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ndarray-pack/-/ndarray-pack-1.2.1.tgz#8caebeaaa24d5ecf70ff86020637977da8ee585a" + integrity sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g== + dependencies: + cwise-compiler "^1.1.2" + ndarray "^1.0.13" + +ndarray@^1.0.13: + version "1.0.19" + resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e" + integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ== + dependencies: + iota-array "^1.0.0" + is-buffer "^1.0.2" + negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -10965,6 +11060,11 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== +node-bitmap@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091" + integrity sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA== + node-dir@^0.1.10: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -11091,6 +11191,11 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -11193,6 +11298,11 @@ objectorarray@^1.0.5: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== +omggif@^1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" + integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -11432,6 +11542,13 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-data-uri@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/parse-data-uri/-/parse-data-uri-0.2.0.tgz#bf04d851dd5c87b0ab238e5d01ace494b604b4c9" + integrity sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w== + dependencies: + data-uri-to-buffer "0.0.3" + parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -11628,6 +11745,11 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" +pngjs@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" + integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== + pnp-webpack-plugin@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" @@ -12038,6 +12160,10 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +"quantize@github:lokesh/quantize": + version "1.2.0" + resolved "https://codeload.github.com/lokesh/quantize/tar.gz/f572abd2646b5944852535c8a26fdb958a5d7c4b" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -12581,6 +12707,32 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" +request@^2.44.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -13158,7 +13310,7 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.14.1: +sshpk@^1.14.1, sshpk@^1.7.0: version "1.17.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== @@ -13671,7 +13823,7 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.8: +through@^2.3.4, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -14036,6 +14188,11 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" +uniq@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA== + unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"