Skip to content

Commit

Permalink
Migrate explorer to registry (#72)
Browse files Browse the repository at this point in the history
- Migrate explorer from SDK consts to registry
- Update to latest hyperlane libs
- Fix problems with delivery checking
- Remove status badge from message table
- Update react-query lib
- Remove unused, outdated wagmi + rainbowkit libs
- Fix error when filtering to all mainnets
- Avoid misleading status check for non-evm chains
- Hide v2 link banner
  • Loading branch information
jmrossy authored May 16, 2024
2 parents 2ed4977 + b4f3834 commit 72b5f58
Show file tree
Hide file tree
Showing 35 changed files with 2,953 additions and 2,239 deletions.
2 changes: 1 addition & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const securityHeaders = [
key: 'Content-Security-Policy',
value: `default-src 'self'; script-src 'self'${
isDev ? " 'unsafe-eval'" : ''
}; connect-src *; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self' data:; base-uri 'self'; form-action 'self'`,
}; connect-src *; img-src 'self' data: https://raw.githubusercontent.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; base-uri 'self'; form-action 'self'`,
},
]

Expand Down
13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"name": "@hyperlane-xyz/explorer",
"description": "An interchain explorer for the Hyperlane protocol and network.",
"version": "3.8.0",
"version": "3.11.0",
"author": "J M Rossy",
"dependencies": {
"@headlessui/react": "^1.7.17",
"@hyperlane-xyz/sdk": "3.8.0",
"@hyperlane-xyz/utils": "3.8.0",
"@hyperlane-xyz/widgets": "3.8.0",
"@hyperlane-xyz/registry": "^1.1.2",
"@hyperlane-xyz/sdk": "3.11.1",
"@hyperlane-xyz/utils": "3.11.1",
"@hyperlane-xyz/widgets": "3.11.0",
"@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6",
"@rainbow-me/rainbowkit": "0.12.16",
"@tanstack/react-query": "^4.24.10",
"@tanstack/react-query": "^5.35.5",
"bignumber.js": "^9.1.2",
"buffer": "^6.0.3",
"ethers": "^5.7.2",
Expand All @@ -23,7 +23,6 @@
"react-toastify": "^9.1.1",
"react-tooltip": "^5.26.3",
"urql": "^3.0.3",
"wagmi": "0.12.18",
"zod": "^3.21.2",
"zustand": "4.3.8"
},
Expand Down
25 changes: 17 additions & 8 deletions src/components/icons/ChainLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { ComponentProps } from 'react';

import { ChainLogo as ChainLogoInner } from '@hyperlane-xyz/widgets';

import { getChainName } from '../../features/chains/utils';
import { useMultiProvider } from '../../features/providers/multiProvider';
import { useMultiProvider, useRegistry } from '../../store';

export function ChainLogo(props: ComponentProps<typeof ChainLogoInner>) {
const { chainName, chainId, ...rest } = props;
export function ChainLogo({
chainId,
chainName,
background,
size,
}: {
chainId: ChainId;
chainName?: string;
background?: boolean;
size?: number;
}) {
const multiProvider = useMultiProvider();
const name = chainName || getChainName(multiProvider, props.chainId);
return <ChainLogoInner {...rest} chainName={name} chainId={chainId} />;
const registry = useRegistry();
const name = chainName || multiProvider.tryGetChainName(chainId) || '';
return (
<ChainLogoInner chainName={name} registry={registry} size={size} background={background} />
);
}
39 changes: 0 additions & 39 deletions src/components/icons/ChainToChain.tsx

This file was deleted.

3 changes: 1 addition & 2 deletions src/components/layout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { toTitleCase } from '@hyperlane-xyz/utils';

import { Footer } from '../nav/Footer';
import { Header } from '../nav/Header';
import { InfoBanner } from '../nav/InfoBanner';

interface Props {
pathName: string;
Expand All @@ -23,7 +22,7 @@ export function AppLayout({ pathName, children }: PropsWithChildren<Props>) {
style={styles.container}
className="relative w-full min-w-screen h-full min-h-screen flex flex-col justify-between bg-blue-500"
>
<InfoBanner />
{/* <InfoBanner /> */}
<Header pathName={pathName} />
<div className="max-w-5xl mx-auto grow">
<main style={styles.main} className="relative min-h-full pt-3 z-20">
Expand Down
12 changes: 6 additions & 6 deletions src/components/nav/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,12 @@ export function Header({ pathName }: { pathName: string }) {
<Link href="/" className={navLinkClass('/')}>
Home
</Link>
<Link href="/settings" className={navLinkClass('/settings')}>
Settings
</Link>
<Link href="/api-docs" className={navLinkClass('/api-docs')}>
API
</Link>
<a className={navLinkClass()} target="_blank" href={links.home} rel="noopener noreferrer">
About
</a>
<Link href="/api-docs" className={navLinkClass('/api-docs')}>
API
</Link>
<a
className={navLinkClass()}
target="_blank"
Expand All @@ -76,6 +73,9 @@ export function Header({ pathName }: { pathName: string }) {
>
Docs
</a>
<Link href="/settings" className={navLinkClass('/settings')}>
Settings
</Link>
{showSearch && <MiniSearchBar />}
</nav>
{/* Dropdown menu, used on mobile */}
Expand Down
42 changes: 24 additions & 18 deletions src/components/search/SearchFilterBar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Image from 'next/image';
import Link from 'next/link';
import { useState } from 'react';
import { useMemo, useState } from 'react';

import { ChainMetadata, mainnetChainsMetadata, testnetChainsMetadata } from '@hyperlane-xyz/sdk';
import { arrayToObject } from '@hyperlane-xyz/utils';
import { ChainMetadata } from '@hyperlane-xyz/sdk';
import { ProtocolType, arrayToObject } from '@hyperlane-xyz/utils';

import { getChainDisplayName } from '../../features/chains/utils';
import { useMultiProvider } from '../../features/providers/multiProvider';
import GearIcon from '../../images/icons/gear.svg';
import { useMultiProvider } from '../../store';
import { Color } from '../../styles/Color';
import { SolidButton } from '../buttons/SolidButton';
import { TextButton } from '../buttons/TextButton';
Expand All @@ -17,8 +17,6 @@ import { CheckBox } from '../input/Checkbox';
import { DatetimeField } from '../input/DatetimeField';
import { DropdownModal } from '../layout/Dropdown';

const mainnetAndTestChains = [...mainnetChainsMetadata, ...testnetChainsMetadata];

interface Props {
originChain: string | null;
onChangeOrigin: (value: string | null) => void;
Expand Down Expand Up @@ -85,12 +83,20 @@ function ChainMultiSelector({
position?: string;
}) {
const multiProvider = useMultiProvider();
const { chains, mainnets, testnets } = useMemo(() => {
const chains = Object.values(multiProvider.metadata);
// Filtering to EVM is necessary to prevent errors until cosmos support is added
// https://github.com/hyperlane-xyz/hyperlane-explorer/issues/61
const mainnets = chains.filter((c) => !c.isTestnet && c.protocol === ProtocolType.Ethereum);
const testnets = chains.filter((c) => !!c.isTestnet && c.protocol === ProtocolType.Ethereum);
return { chains, mainnets, testnets };
}, [multiProvider]);

// Need local state as buffer before user hits apply
const [checkedChains, setCheckedChains] = useState(
value
? arrayToObject(value.split(','))
: arrayToObject(mainnetAndTestChains.map((c) => c.chainId.toString())),
: arrayToObject(chains.map((c) => c.chainId.toString())),
);

const hasAnyUncheckedChain = (chains: ChainMetadata[]) => {
Expand All @@ -102,7 +108,7 @@ function ChainMultiSelector({

const onToggle = (chainId: string | number) => {
return (checked: boolean) => {
if (!hasAnyUncheckedChain(mainnetAndTestChains)) {
if (!hasAnyUncheckedChain(chains)) {
// If none are unchecked, uncheck all except this one
setCheckedChains({ [chainId]: true });
} else {
Expand All @@ -125,7 +131,7 @@ function ChainMultiSelector({
};

const onToggleAll = () => {
setCheckedChains(arrayToObject(mainnetAndTestChains.map((c) => c.chainId.toString())));
setCheckedChains(arrayToObject(chains.map((c) => c.chainId.toString())));
};

const onToggleNone = () => {
Expand All @@ -134,7 +140,7 @@ function ChainMultiSelector({

const onClickApply = (closeDropdown?: () => void) => {
const checkedList = Object.keys(checkedChains).filter((c) => !!checkedChains[c]);
if (checkedList.length === 0 || checkedList.length === mainnetAndTestChains.length) {
if (checkedList.length === 0 || checkedList.length === chains.length) {
// Use null value, indicating to filter needed
onChangeValue(null);
} else {
Expand Down Expand Up @@ -175,14 +181,14 @@ function ChainMultiSelector({
<div className="flex flex-col">
<div className="pb-1.5">
<CheckBox
checked={!hasAnyUncheckedChain(mainnetChainsMetadata)}
onToggle={onToggleSection(mainnetChainsMetadata)}
checked={!hasAnyUncheckedChain(mainnets)}
onToggle={onToggleSection(mainnets)}
name="mainnet-chains"
>
<h4 className="ml-2 text-gray-800">Mainnet Chains</h4>
</CheckBox>
</div>
{mainnetChainsMetadata.map((c) => (
{mainnets.map((c) => (
<CheckBox
key={c.name}
checked={!!checkedChains[c.chainId]}
Expand All @@ -193,7 +199,7 @@ function ChainMultiSelector({
<span className="mr-2 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</span>
<ChainLogo chainId={c.chainId} size={12} color={false} background={false} />
<ChainLogo chainId={c.chainId} size={12} background={false} />
</div>
</CheckBox>
))}
Expand All @@ -202,14 +208,14 @@ function ChainMultiSelector({
<div className="flex flex-col">
<div className="pb-1.5">
<CheckBox
checked={!hasAnyUncheckedChain(testnetChainsMetadata)}
onToggle={onToggleSection(testnetChainsMetadata)}
checked={!hasAnyUncheckedChain(testnets)}
onToggle={onToggleSection(testnets)}
name="testnet-chains"
>
<h4 className="ml-2 text-gray-800">Testnet Chains</h4>
</CheckBox>
</div>
{testnetChainsMetadata.map((c) => (
{testnets.map((c) => (
<CheckBox
key={c.name}
checked={!!checkedChains[c.chainId]}
Expand All @@ -220,7 +226,7 @@ function ChainMultiSelector({
<span className="mr-2 font-light">
{getChainDisplayName(multiProvider, c.chainId, true)}
</span>
<ChainLogo chainId={c.chainId} size={12} color={false} background={false} />
<ChainLogo chainId={c.chainId} size={12} background={false} />
</div>
</CheckBox>
))}
Expand Down
2 changes: 1 addition & 1 deletion src/components/search/SearchStates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export function SearchUnknownError({ show }: { show: boolean }) {
<SearchError
show={show}
imgSrc={ErrorIcon}
text="Sorry, an error has occurred. Please try a query or try again later."
text="Sorry, an error has occurred. Please try again later."
imgWidth={70}
/>
);
Expand Down
3 changes: 0 additions & 3 deletions src/consts/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ export const ENVIRONMENT_BUCKET_SEGMENT: Record<Environment, string> = {
[Environment.Mainnet]: 'mainnet3',
[Environment.Testnet]: 'testnet4',
};

// TODO replace with SDK version
export const MAILBOX_VERSION = 3;
1 change: 1 addition & 0 deletions src/consts/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export const docLinks = {
pi: 'https://v3.hyperlane.xyz/docs/deploy-hyperlane',
ism: 'https://v3.hyperlane.xyz/docs/reference/ISM/specify-your-ISM',
gas: 'https://v3.hyperlane.xyz/docs/protocol/interchain-gas-payment',
registry: 'https://docs.hyperlane.xyz/docs/reference/registries',
};
7 changes: 3 additions & 4 deletions src/features/api/getMessages.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Client } from '@urql/core';
import type { NextApiRequest } from 'next';

import { MultiProvider } from '@hyperlane-xyz/sdk';

import { API_GRAPHQL_QUERY_LIMIT } from '../../consts/api';
import { logger } from '../../utils/logger';
import { sanitizeString } from '../../utils/string';
Expand All @@ -11,7 +9,7 @@ import { MessagesQueryResult } from '../messages/queries/fragments';
import { parseMessageQueryResult } from '../messages/queries/parse';

import { ApiHandlerResult, ApiMessage, toApiMessage } from './types';
import { failureResult, successResult } from './utils';
import { failureResult, getMultiProvider, successResult } from './utils';

export async function handler(
req: NextApiRequest,
Expand All @@ -27,7 +25,8 @@ export async function handler(
API_GRAPHQL_QUERY_LIMIT,
);
const result = await client.query<MessagesQueryResult>(query, variables).toPromise();
const multiProvider = new MultiProvider();

const multiProvider = await getMultiProvider();
const messages = parseMessageQueryResult(multiProvider, result.data);
return successResult(messages.map(toApiMessage));
}
Expand Down
6 changes: 2 additions & 4 deletions src/features/api/getStatus.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Client } from '@urql/core';
import type { NextApiRequest } from 'next';

import { MultiProvider } from '@hyperlane-xyz/sdk';

import { API_GRAPHQL_QUERY_LIMIT } from '../../consts/api';
import { MessageStatus } from '../../types';
import { logger } from '../../utils/logger';
Expand All @@ -12,7 +10,7 @@ import { parseMessageStubResult } from '../messages/queries/parse';

import { parseQueryParams } from './getMessages';
import { ApiHandlerResult } from './types';
import { failureResult, successResult } from './utils';
import { failureResult, getMultiProvider, successResult } from './utils';

interface MessageStatusResult {
id: string;
Expand All @@ -35,7 +33,7 @@ export async function handler(
);
const result = await client.query<MessagesStubQueryResult>(query, variables).toPromise();

const multiProvider = new MultiProvider();
const multiProvider = await getMultiProvider();
const messages = parseMessageStubResult(multiProvider, result.data);

return successResult(messages.map((m) => ({ id: m.msgId, status: m.status })));
Expand Down
6 changes: 2 additions & 4 deletions src/features/api/searchMessages.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Client } from '@urql/core';
import type { NextApiRequest } from 'next';

import { MultiProvider } from '@hyperlane-xyz/sdk';

import { API_GRAPHQL_QUERY_LIMIT } from '../../consts/api';
import { logger } from '../../utils/logger';
import { sanitizeString } from '../../utils/string';
Expand All @@ -11,7 +9,7 @@ import { MessagesQueryResult } from '../messages/queries/fragments';
import { parseMessageQueryResult } from '../messages/queries/parse';

import { ApiHandlerResult, ApiMessage, toApiMessage } from './types';
import { failureResult, successResult } from './utils';
import { failureResult, getMultiProvider, successResult } from './utils';

const SEARCH_QUERY_PARAM_NAME = 'query';

Expand All @@ -34,7 +32,7 @@ export async function handler(
);
const result = await client.query<MessagesQueryResult>(query, variables).toPromise();

const multiProvider = new MultiProvider();
const multiProvider = await getMultiProvider();
const messages = parseMessageQueryResult(multiProvider, result.data);

return successResult(messages.map(toApiMessage));
Expand Down
Loading

0 comments on commit 72b5f58

Please sign in to comment.