Update graphql queries, types, and urls for v2

Minor tweaks to card component and other styles
pull/24/head
J M Rossy 2 years ago
parent 362133a95d
commit 3bed488ee9
  1. 2
      README.md
  2. 2
      package.json
  3. 10
      src/components/layout/Card.tsx
  4. 2
      src/components/nav/Footer.tsx
  5. 2
      src/components/nav/Header.tsx
  6. 2
      src/consts/config.ts
  7. 30
      src/consts/domains.ts
  8. 13
      src/features/deliveryStatus/fetchDeliveryStatus.ts
  9. 18
      src/features/messages/MessageDetails.tsx
  10. 12
      src/features/messages/MessageSearch.tsx
  11. 18
      src/features/messages/MessageTable.tsx
  12. 27
      src/features/messages/cards/ContentDetailsCard.tsx
  13. 2
      src/features/messages/cards/IcaDetailsCard.tsx
  14. 4
      src/features/messages/cards/KeyValueRow.tsx
  15. 10
      src/features/messages/cards/TimelineCard.tsx
  16. 3
      src/features/messages/cards/TransactionCard.tsx
  17. 11
      src/features/messages/parseMessage.ts
  18. 3
      src/features/messages/placeholderMessages.ts
  19. 10
      src/features/messages/types.ts
  20. 7
      src/types.ts

@ -1,6 +1,6 @@
# Hyperlane Explorer App
A multi-chain explorer for the Hyperlane protocol and network.
An interchain explorer for the Hyperlane protocol and network.
## Setup

@ -1,6 +1,6 @@
{
"name": "@hyperlane-xyz/explorer",
"description": "A multi-chain explorer for the Hyperlane protocol and network.",
"description": "An interchain explorer for the Hyperlane protocol and network.",
"version": "0.1.0",
"author": "J M Rossy",
"dependencies": {

@ -1,17 +1,13 @@
import { PropsWithChildren } from 'react';
interface Props {
width?: string;
classes?: string;
}
export function Card(props: PropsWithChildren<Props>) {
const { width, classes } = props;
export function Card({ classes, children }: PropsWithChildren<Props>) {
return (
<div
className={`${width} p-4 bg-white shadow border border-blue-50 rounded overflow-auto ${classes}`}
>
{props.children}
<div className={`p-4 bg-white shadow border border-blue-50 rounded overflow-auto ${classes}`}>
{children}
</div>
);
}

@ -14,7 +14,7 @@ export function Footer() {
<div className="flex flex-col sm:flex-row sm:justify-between items-center gap-6 sm:gap-0">
<div className="flex items-center">
<div className="flex scale-90 sm:scale-100">
<Image src={Hyperlane} width={56} height={56} alt="" />
<Image src={Hyperlane} width={50} height={50} alt="" />
</div>
<div className="flex flex-col ml-3">
<p className="text-sm font-light leading-5">

@ -23,7 +23,7 @@ export function Header({ pathName }: { pathName: string }) {
const showSearch = !PAGES_EXCLUDING_SEARCH.includes(pathName);
return (
<header className="px-2 pt-4 pb-3 sm:pt-5 sm:pb-3 sm:px-6 lg:pr-14 w-full">
<header className="px-2 pt-4 pb-3 sm:pt-5 sm:px-6 lg:pr-14 w-full">
<div className="flex items-center justify-between">
<Link href="/" className="flex items-center">
<div className="flex items-center scale-90 sm:scale-100">

@ -14,6 +14,6 @@ export const config: Config = Object.freeze({
debug: isDevMode,
version,
url: 'https://explorer.hyperlane.xyz',
apiUrl: 'https://api.hyperlane.xyz/v1/graphql',
apiUrl: 'https://hyperlane-explorer-2.hasura.app/v1/graphql',
explorerApiKeys,
});

@ -1,30 +0,0 @@
import { invertKeysAndValues } from '../utils/objects';
// TODO move these to SDK
// Hard-coding here for better perf and reduced queries
// Should match Domain table in db
export const domainToChain = {
1000: 44787, // alfajores
6386274: 42161, // arbitrum
1634872690: 421611, // arbitrumrinkeby
421613: 421613, // arbitrumgoerli
1635069300: 1313161555, // auroratestnet
1635148152: 43114, // avalanche
6452067: 56, // bsc
1651715444: 97, // bsctestnet
1667591279: 42220, // celo
6648936: 1, // ethereum
43113: 43113, // fuji
5: 5, // goerli
3000: 42, // kovan
1836002657: 1287, // moonbasealpha
1836002669: 1284, // moonbeam
80001: 80001, // mumbai
28528: 10, // optimism
420: 420, // optimismgoerli
1869622635: 69, // optimismkovan
1886350457: 137, // polygon
280: 280, // zksync2testnet
};
export const chainToDomain = invertKeysAndValues(domainToChain);

@ -4,7 +4,6 @@ import { hyperlaneCoreAddresses } from '@hyperlane-xyz/sdk';
import { utils } from '@hyperlane-xyz/utils';
import { chainIdToName } from '../../consts/chains';
import { chainToDomain, domainToChain } from '../../consts/domains';
import { Message, MessageStatus } from '../../types';
import { validateAddress } from '../../utils/addresses';
import { getChainEnvironment } from '../../utils/chains';
@ -147,14 +146,10 @@ function validateMessage(message: Message) {
sender,
} = message;
if (!originDomainId || !domainToChain[originDomainId])
throw new Error(`Invalid origin domain ${originDomainId}`);
if (!destinationDomainId || !domainToChain[destinationDomainId])
throw new Error(`Invalid dest domain ${destinationDomainId}`);
if (!originChainId || !chainToDomain[originChainId])
throw new Error(`Invalid origin chain ${originChainId}`);
if (!destinationChainId || !chainToDomain[destinationChainId])
throw new Error(`Invalid dest chain ${destinationChainId}`);
if (!originDomainId) throw new Error(`Invalid origin domain ${originDomainId}`);
if (!destinationDomainId) throw new Error(`Invalid dest domain ${destinationDomainId}`);
if (!originChainId) throw new Error(`Invalid origin chain ${originChainId}`);
if (!destinationChainId) throw new Error(`Invalid dest chain ${destinationChainId}`);
if (!chainIdToName[originChainId]) throw new Error(`No name found for chain ${originChainId}`);
if (!chainIdToName[destinationChainId])
throw new Error(`No name found for chain ${destinationChainId}`);

@ -183,15 +183,19 @@ function StatusHeader({
}
const messageDetailsQuery = `
query MessageDetails ($messageId: bigint!){
message(where: {id: {_eq: $messageId}}, limit: 1) {
query MessageDetails ($messageId: String!){
message(where: {msg_id: {_eq: $messageId}}, limit: 1) {
destination
id
leaf_index
hash
msg_id
nonce
msg_body
origin
origin_tx_id
origin_mailbox
recipient
sender
timestamp
transaction {
id
block_id
@ -206,14 +210,10 @@ query MessageDetails ($messageId: bigint!){
timestamp
}
}
outbox_address
recipient
sender
timestamp
delivered_message {
id
tx_id
inbox_address
destination_mailbox
transaction {
block_id
gas_used

@ -10,7 +10,6 @@ import {
SearchUnknownError,
} from '../../components/search/SearchError';
import { SearchFilterBar } from '../../components/search/SearchFilterBar';
import { chainToDomain } from '../../consts/domains';
import { trimLeading0x } from '../../utils/addresses';
import useDebounce from '../../utils/debounce';
import { logger } from '../../utils/logger';
@ -128,12 +127,8 @@ function assembleQuery(
) {
const hasInput = !!searchInput;
const originChains = originFilter
? originFilter.split(',').map((c) => chainToDomain[c])
: undefined;
const destinationChains = destFilter
? destFilter.split(',').map((c) => chainToDomain[c])
: undefined;
const originChains = originFilter ? originFilter.split(',') : undefined;
const destinationChains = destFilter ? destFilter.split(',') : undefined;
const startTime = startTimeFilter ? adjustToUtcTime(startTimeFilter) : undefined;
const endTime = endTimeFilter ? adjustToUtcTime(endTimeFilter) : undefined;
const variables = {
@ -181,6 +176,7 @@ const searchWhereClause = `
const messageStubProps = `
id
msg_id
destination
origin
recipient
@ -189,7 +185,7 @@ const messageStubProps = `
delivered_message {
id
tx_id
inbox_address
destination_mailbox
transaction {
block {
timestamp

@ -45,7 +45,7 @@ export function MessageTable({
export function MessageSummaryRow({ message }: { message: MessageStub }) {
const {
id,
msgId,
status,
sender,
recipient,
@ -67,25 +67,25 @@ export function MessageSummaryRow({ message }: { message: MessageStub }) {
return (
<>
<LinkCell id={id} aClasses="flex items-center py-3.5 pl-3 sm:pl-5">
<LinkCell id={msgId} aClasses="flex items-center py-3.5 pl-3 sm:pl-5">
<ChainIcon chainId={originChainId} size={20} />
<div className={styles.chainName}>{getChainDisplayName(originChainId, true)}</div>
</LinkCell>
<LinkCell id={id} aClasses="flex items-center py-3.5 ">
<LinkCell id={msgId} aClasses="flex items-center py-3.5 ">
<ChainIcon chainId={destinationChainId} size={20} />
<div className={styles.chainName}>{getChainDisplayName(destinationChainId, true)}</div>
</LinkCell>
<LinkCell id={id} tdClasses="hidden sm:table-cell" aClasses={styles.value}>
<LinkCell id={msgId} tdClasses="hidden sm:table-cell" aClasses={styles.value}>
{shortenAddress(sender) || 'Invalid Address'}
</LinkCell>
<LinkCell id={id} tdClasses="hidden sm:table-cell" aClasses={styles.value}>
<LinkCell id={msgId} tdClasses="hidden sm:table-cell" aClasses={styles.value}>
{shortenAddress(recipient) || 'Invalid Address'}
</LinkCell>
<LinkCell id={id} aClasses={styles.valueTruncated}>
<LinkCell id={msgId} aClasses={styles.valueTruncated}>
{getHumanReadableTimeString(originTimestamp)}
</LinkCell>
<LinkCell
id={id}
id={msgId}
tdClasses="hidden lg:table-cell text-center px-4"
aClasses={styles.valueTruncated}
>
@ -93,7 +93,7 @@ export function MessageSummaryRow({ message }: { message: MessageStub }) {
? getHumanReadableDuration(destinationTimestamp - originTimestamp, 3)
: '-'}
</LinkCell>
<LinkCell id={id} aClasses="flex items-center justify-center">
<LinkCell id={msgId} aClasses="flex items-center justify-center">
<div className={`text-center w-20 md:w-[5.25rem] py-1.5 text-sm rounded ${statusColor}`}>
{statusText}
</div>
@ -107,7 +107,7 @@ function LinkCell({
tdClasses,
aClasses,
children,
}: PropsWithChildren<{ id: number; tdClasses?: string; aClasses?: string }>) {
}: PropsWithChildren<{ id: string; tdClasses?: string; aClasses?: string }>) {
return (
<td className={tdClasses}>
<Link href={`/message/${id}`} className={aClasses}>

@ -19,14 +19,15 @@ interface Props {
export function ContentDetailsCard({
message: {
msgId,
nonce,
leafIndex,
originDomainId,
originChainId,
destinationDomainId,
destinationChainId,
sender,
recipient,
leafIndex,
hash,
body,
decodedBody,
},
@ -54,7 +55,7 @@ export function ContentDetailsCard({
);
return (
<Card classes="space-y-4" width="w-full">
<Card classes="w-full space-y-4">
<div className="flex items-center justify-between">
<div className="relative -top-px -left-0.5">
<ChainToChain originChainId={originChainId} destinationChainId={destinationChainId} />
@ -67,6 +68,14 @@ export function ContentDetailsCard({
/>
</div>
</div>
<KeyValueRow
label="Message Id:"
labelWidth="w-20"
display={msgId}
displayWidth="w-60 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
/>
<KeyValueRow
label="Sender:"
labelWidth="w-20"
@ -83,13 +92,20 @@ export function ContentDetailsCard({
showCopy={true}
blurValue={shouldBlur}
/>
<div className="flex space-x-20">
<KeyValueRow
label="Leaf index:"
label="Nonce:"
labelWidth="w-20"
display={nonce.toString()}
blurValue={shouldBlur}
/>
<KeyValueRow
label="Leaf Index:"
labelWidth="w-20"
display={leafIndex.toString()}
displayWidth="w-60 sm:w-80"
blurValue={shouldBlur}
/>
</div>
<div>
<div className="flex items-center">
<label className="text-sm text-gray-500">Message Content:</label>
@ -103,7 +119,6 @@ export function ContentDetailsCard({
<CodeBlock value={bodyDisplay} />
</div>
<LabelAndCodeBlock label="Raw bytes:" value={rawBytes} />
<LabelAndCodeBlock label="Message hash:" value={hash} />
</Card>
);
}

@ -23,7 +23,7 @@ export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }
} = useIcaAddress(originDomainId, decodeResult?.sender);
return (
<Card classes="space-y-4" width="w-full">
<Card classes="w-full space-y-4">
<div className="flex items-center justify-between">
<div className="relative -top-px -left-0.5">
<InterchainAccount />

@ -4,7 +4,7 @@ interface Props {
label: string;
labelWidth: string;
display: string;
displayWidth: string;
displayWidth?: string;
subDisplay?: string;
showCopy?: boolean;
blurValue?: boolean;
@ -22,7 +22,7 @@ export function KeyValueRow({
return (
<div className="flex items-center pl-px">
<label className={`text-sm text-gray-500 ${labelWidth}`}>{label}</label>
<div className={`text-sm ml-2 truncate ${displayWidth} ${blurValue && 'blur-xs'}`}>
<div className={`text-sm ml-2 truncate ${displayWidth || ''} ${blurValue && 'blur-xs'}`}>
<span>{display}</span>
{subDisplay && <span className="text-xs ml-2">{subDisplay}</span>}
</div>

@ -36,19 +36,19 @@ interface Props {
export function TimelineCard({ message, resolvedStatus: status, resolvedDestinationTx }: Props) {
const {
leafIndex,
originChainId,
destinationChainId,
originTimestamp,
destinationTimestamp,
leafIndex,
originTransaction,
} = message;
const { stage, timings } = useMessageStage(
status,
leafIndex,
originChainId,
destinationChainId,
leafIndex,
originTransaction.blockNumber,
originTimestamp,
destinationTimestamp || resolvedDestinationTx?.timestamp,
@ -57,7 +57,7 @@ export function TimelineCard({ message, resolvedStatus: status, resolvedDestinat
const timeSent = new Date(originTimestamp);
return (
<Card width="w-full">
<Card classes="w-full">
{/* <div className="flex items-center justify-end">
<h3 className="text-gray-500 font-medium text-md mr-2">Delivery Timeline</h3>
<HelpIcon size={16} text="A breakdown of the stages for delivering a message" />
@ -203,9 +203,9 @@ function getStageClass(targetStage: Stage, currentStage: Stage, messageStatus: M
function useMessageStage(
status: MessageStatus,
leafIndex: number,
originChainId: number,
destChainId: number,
leafIndex: number,
originBlockNumber: number,
originTimestamp: number,
destinationTimestamp?: number,
@ -214,11 +214,11 @@ function useMessageStage(
[
'messageStage',
status,
leafIndex,
originChainId,
destChainId,
originTimestamp,
destinationTimestamp,
leafIndex,
originBlockNumber,
],
async () => {

@ -2,7 +2,6 @@ import { Spinner } from '../../../components/animation/Spinner';
import { ChainIcon } from '../../../components/icons/ChainIcon';
import { HelpIcon } from '../../../components/icons/HelpIcon';
import { Card } from '../../../components/layout/Card';
import { chainToDomain } from '../../../consts/domains';
import { MessageStatus, PartialTransactionReceipt } from '../../../types';
import { getChainDisplayName } from '../../../utils/chains';
import { getTxExplorerUrl } from '../../../utils/explorers';
@ -55,7 +54,7 @@ export function TransactionCard({
<KeyValueRow
label="Chain:"
labelWidth="w-16"
display={`${getChainDisplayName(chainId)} (${chainId} / ${chainToDomain[chainId]})`}
display={`${getChainDisplayName(chainId)} (${chainId})`}
displayWidth="w-60 sm:w-64"
blurValue={shouldBlur}
/>

@ -1,5 +1,4 @@
import { TEST_RECIPIENT_ADDRESS } from '../../consts/addresses';
import { domainToChain } from '../../consts/domains';
import { Message, MessageStatus, MessageStub, PartialTransactionReceipt } from '../../types';
import { areAddressesEqual, ensureLeading0x, trimLeading0x } from '../../utils/addresses';
import { logger } from '../../utils/logger';
@ -30,13 +29,14 @@ function parseMessageStub(m: MessageStubEntry): MessageStub | null {
: undefined;
return {
id: m.id,
msgId: m.msg_id,
status,
sender: parsePaddedAddress(m.sender),
recipient: parsePaddedAddress(m.recipient),
originDomainId: m.origin,
destinationDomainId: m.destination,
originChainId: domainToChain[m.origin],
destinationChainId: domainToChain[m.destination],
originChainId: m.origin,
destinationChainId: m.destination,
originTimestamp: parseTimestampString(m.timestamp),
destinationTimestamp,
};
@ -58,13 +58,14 @@ function parseMessage(m: MessageEntry): Message | null {
const body = decodePostgresBinaryHex(m.msg_body ?? '');
const isTestRecipient = areAddressesEqual(stub.recipient, TEST_RECIPIENT_ADDRESS);
const decodedBody = isTestRecipient ? tryUtf8DecodeBytes(body) : undefined;
const leafIndex = 1; //TODO
return {
...stub,
nonce: m.nonce,
leafIndex,
body,
decodedBody,
leafIndex: m.leaf_index,
hash: ensureLeading0x(m.hash),
originTransaction: parseTransaction(m.transaction),
destinationTransaction,
};

@ -17,12 +17,13 @@ const BODY_ZERO =
export const PLACEHOLDER_MESSAGE: Message = {
id: 1,
msgId: TX_HASH_ZERO.substring(2),
leafIndex: 1,
nonce: 1,
status: MessageStatus.Pending,
sender: constants.AddressZero,
recipient: constants.AddressZero,
body: BODY_ZERO,
hash: TX_HASH_ZERO,
originDomainId: 0,
destinationDomainId: 0,
originChainId: 0,

@ -24,8 +24,8 @@ export interface TransactionEntry {
export interface DeliveredMessageStubEntry {
id: number;
inbox_address: string; // binary e.g. \\x123
tx_id: number;
destination_mailbox: string;
transaction: {
block: {
timestamp: string; // e.g. "2022-08-28T17:30:15"
@ -48,22 +48,22 @@ export interface MessageStateEntry {
export interface MessageStubEntry {
id: number;
msg_id: string;
destination: number;
origin: number;
recipient: string; // binary e.g. \\x123
sender: string; // binary e.g. \\x123
timestamp: string; // e.g. "2022-08-28T17:30:15"
transaction: TransactionEntry; // origin transaction
delivered_message: DeliveredMessageStubEntry | null | undefined;
message_states: MessageStateEntry[];
}
export interface MessageEntry extends MessageStubEntry {
outbox_address: string; // binary e.g. \\x123
nonce: number;
msg_body: string | null | undefined; // binary e.g. \\x123
hash: string; // message hash, not related to tx
leaf_index: number;
origin_mailbox: string;
origin_tx_id: number;
transaction: TransactionEntry; // origin transaction
delivered_message: DeliveredMessageEntry | null | undefined;
}

@ -15,7 +15,8 @@ export enum MessageStatus {
}
export interface MessageStub {
id: number;
id: number; // Database id
msgId: string; // Message hash
status: MessageStatus;
sender: Address;
recipient: Address;
@ -28,10 +29,10 @@ export interface MessageStub {
}
export interface Message extends MessageStub {
nonce: number;
leafIndex: number;
body: string;
decodedBody?: string;
leafIndex: number;
hash: string; // message hash, not related to txs
originTransaction: PartialTransactionReceipt;
destinationTransaction?: PartialTransactionReceipt;
}

Loading…
Cancel
Save