Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate explorer to registry #72

Merged
merged 14 commits into from
May 16, 2024
Merged
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
Loading