Skip to content

Commit

Permalink
feat: use chain name or domain as identifier instead of chainId (#136)
Browse files Browse the repository at this point in the history
relates to:
- hyperlane-xyz/hyperlane-warp-ui-template#313
- hyperlane-xyz/hyperlane-monorepo#4798

testing:
- [x] update SDK to latest once monorepo PR is merged + rolled out
- [x] add duplicate chain metadata with different domain id to custom
yaml

---------

Signed-off-by: pbio <[email protected]>
  • Loading branch information
paulbalaji authored Nov 7, 2024
1 parent ec0db73 commit b8e0d31
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 181 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"dependencies": {
"@headlessui/react": "^2.1.8",
"@hyperlane-xyz/registry": "5.1.0",
"@hyperlane-xyz/sdk": "5.7.0",
"@hyperlane-xyz/utils": "5.7.0",
"@hyperlane-xyz/widgets": "5.7.0",
"@hyperlane-xyz/sdk": "6.0.0",
"@hyperlane-xyz/utils": "6.0.0",
"@hyperlane-xyz/widgets": "6.0.0",
"@tanstack/react-query": "^5.35.5",
"bignumber.js": "^9.1.2",
"buffer": "^6.0.3",
Expand Down
7 changes: 2 additions & 5 deletions src/components/icons/ChainLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import { ChainLogo as ChainLogoInner } from '@hyperlane-xyz/widgets';

import { useMultiProvider, useRegistry } from '../../store';
import { useRegistry } from '../../store';

export function ChainLogo({
chainId,
chainName,
background,
size,
}: {
chainId: ChainId;
chainName?: string;
background?: boolean;
size?: number;
}) {
const multiProvider = useMultiProvider();
const registry = useRegistry();
const name = chainName || multiProvider.tryGetChainName(chainId) || '';
const name = chainName || '';
return (
<ChainLogoInner chainName={name} registry={registry} size={size} background={background} />
);
Expand Down
10 changes: 6 additions & 4 deletions src/components/search/SearchFilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,16 @@ function ChainSelector({
onChangeValue,
}: {
text: string;
value: ChainId | null;
value: string | null;
onChangeValue: (value: string | null) => void;
}) {
const { isOpen, open, close } = useModal();

const multiProvider = useMultiProvider();
const chainName = value
? trimToLength(getChainDisplayName(multiProvider, value, true), 12)

const chainName = value ? multiProvider.getChainName(value) : undefined;
const chainDisplayName = chainName
? trimToLength(getChainDisplayName(multiProvider, chainName, true), 12)
: undefined;

const onClickChain = (c: ChainMetadata) => {
Expand All @@ -93,7 +95,7 @@ function ChainSelector({
)}
onClick={open}
>
<span>{chainName || text} </span>
<span>{chainDisplayName || text} </span>
{!value && (
<ChevronIcon
direction="s"
Expand Down
15 changes: 2 additions & 13 deletions src/features/chains/MissingChainConfigToast.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
export function MissingChainConfigToast({
domainId,
chainId,
}: {
domainId: number;
chainId: number | string | null | undefined;
}) {
const errorDesc = chainId
? `chain ID: ${chainId}`
: domainId
? `domain ID: ${domainId}`
: 'unknown message chain';
export function MissingChainConfigToast({ domainId }: { domainId: number }) {
return (
<div>
<span>{`No chain config found for ${errorDesc}. You can add a config in the origin/destination chain selector.`}</span>
<span>{`No chain config found for domain ${domainId}. You can add a config in the origin/destination chain selector.`}</span>
</div>
);
}
8 changes: 4 additions & 4 deletions src/features/chains/queries/useScrapedChains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export function useScrapedChains(multiProvider: MultiProvider) {
const scrapedChains = objFilter(
chainMetadata,
(_, chainMetadata): chainMetadata is ChainMetadata =>
!isPiChain(multiProvider, scrapedDomains, chainMetadata.chainId) &&
!isUnscrapedDbChain(multiProvider, chainMetadata.chainId),
!isPiChain(multiProvider, scrapedDomains, chainMetadata.domainId) &&
!isUnscrapedDbChain(multiProvider, chainMetadata.domainId),
);
return { chains: scrapedChains };
}, [multiProvider, chainMetadata, scrapedDomains]);
Expand All @@ -52,7 +52,7 @@ export function useScrapedChains(multiProvider: MultiProvider) {
}

// TODO: Remove once all chains in the DB are scraped
export function isUnscrapedDbChain(multiProvider: MultiProvider, chainIdOrName: number | string) {
const chainName = multiProvider.tryGetChainName(chainIdOrName);
export function isUnscrapedDbChain(multiProvider: MultiProvider, domainId: DomainId) {
const chainName = multiProvider.tryGetChainName(domainId);
return chainName && unscrapedChainsInDb.includes(chainName);
}
18 changes: 9 additions & 9 deletions src/features/chains/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,33 @@ export async function getMailboxAddress(

export function getChainDisplayName(
multiProvider: MultiProvider,
chainOrDomainId?: ChainId | DomainId,
chainName?: string,
shortName = false,
fallbackToId = true,
): string {
const metadata = multiProvider.tryGetChainMetadata(chainOrDomainId || 0);
if (!metadata) return fallbackToId && chainOrDomainId ? chainOrDomainId.toString() : 'Unknown';
const metadata = multiProvider.tryGetChainMetadata(chainName || 0);
if (!metadata) return fallbackToId && chainName ? chainName : 'Unknown';
const displayName = shortName ? metadata.displayNameShort : metadata.displayName;
return toTitleCase(displayName || metadata.displayName || metadata.name);
}

export function getChainEnvironment(multiProvider: MultiProvider, chainIdOrName: number | string) {
const isTestnet = multiProvider.tryGetChainMetadata(chainIdOrName)?.isTestnet;
export function getChainEnvironment(multiProvider: MultiProvider, domainId: DomainId) {
const isTestnet = multiProvider.tryGetChainMetadata(domainId)?.isTestnet;
return isTestnet ? Environment.Testnet : Environment.Mainnet;
}

// Is a 'Permisionless Interop' chain (i.e. one not deployed and scraped by Abacus Works)
export function isPiChain(
multiProvider: MultiProvider,
scrapedChains: DomainsEntry[],
chainIdOrName: number | string,
domainId: DomainId,
) {
const chainName = multiProvider.tryGetChainName(chainIdOrName);
const chainName = multiProvider.tryGetChainName(domainId);
// Note: .trim() because one chain name in the DB has a trailing \n char for some reason
return !chainName || !scrapedChains.find((chain) => chain.name.trim() === chainName);
}

export function isEvmChain(multiProvider: MultiProvider, chainIdOrName: number | string) {
const protocol = multiProvider.tryGetProtocol(chainIdOrName);
export function isEvmChain(multiProvider: MultiProvider, domainId: DomainId) {
const protocol = multiProvider.tryGetProtocol(domainId);
return protocol === ProtocolType.Ethereum;
}
16 changes: 10 additions & 6 deletions src/features/deliveryStatus/fetchDeliveryStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function fetchDeliveryStatus(
overrideChainMetadata: ChainMap<Partial<ChainMetadata>>,
message: Message,
): Promise<MessageDeliveryStatusResponse> {
const destName = multiProvider.getChainName(message.destinationChainId);
const destName = multiProvider.getChainName(message.destinationDomainId);
const destMailboxAddr = await getMailboxAddress(destName, overrideChainMetadata, registry);
if (!destMailboxAddr)
throw new Error(
Expand All @@ -41,7 +41,7 @@ export async function fetchDeliveryStatus(
if (isDelivered) {
const txDetails = await fetchTransactionDetails(
multiProvider,
message.destinationChainId,
message.destinationDomainId,
transactionHash,
);
// If a delivery (aka process) tx is found, mark as success
Expand Down Expand Up @@ -85,8 +85,8 @@ async function checkIsMessageDelivered(
message: Message,
mailboxAddr: Address,
) {
const { msgId, destinationChainId } = message;
const provider = multiProvider.getProvider(destinationChainId);
const { msgId, destinationDomainId } = message;
const provider = multiProvider.getProvider(destinationDomainId);
const mailbox = IMailbox__factory.connect(mailboxAddr, provider);

// Try finding logs first as they have more info
Expand Down Expand Up @@ -114,9 +114,13 @@ async function checkIsMessageDelivered(
return { isDelivered };
}

function fetchTransactionDetails(multiProvider: MultiProvider, chainId: ChainId, txHash?: string) {
function fetchTransactionDetails(
multiProvider: MultiProvider,
domainId: DomainId,
txHash?: string,
) {
if (!txHash) return null;
logger.debug(`Searching for transaction details for ${txHash}`);
const provider = multiProvider.getProvider(chainId);
const provider = multiProvider.getProvider(domainId);
return provider.getTransaction(txHash);
}
17 changes: 8 additions & 9 deletions src/features/deliveryStatus/useMessageDeliveryStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ export function useMessageDeliveryStatus({
return { message };
}

const { id, originChainId, originDomainId, destinationChainId, destinationDomainId } =
message;
const { id, originDomainId, destinationDomainId } = message;

if (
!checkChain(multiProvider, originChainId, originDomainId) ||
!checkChain(multiProvider, destinationChainId, destinationDomainId)
!checkChain(multiProvider, originDomainId) ||
!checkChain(multiProvider, destinationDomainId)
) {
return { message };
}
Expand Down Expand Up @@ -93,13 +92,13 @@ export function useMessageDeliveryStatus({
};
}

function checkChain(multiProvider: MultiProvider, chainId: ChainId, domainId: number) {
if (!multiProvider.hasChain(chainId)) {
toast.error(<MissingChainConfigToast chainId={chainId} domainId={domainId} />);
function checkChain(multiProvider: MultiProvider, domainId: number) {
if (!multiProvider.hasChain(domainId)) {
toast.error(<MissingChainConfigToast domainId={domainId} />);
return false;
}
if (!isEvmChain(multiProvider, chainId)) {
logger.debug('Skipping delivery status check for non-EVM chain:', chainId);
if (!isEvmChain(multiProvider, domainId)) {
logger.debug('Skipping delivery status check for non-EVM chain:', domainId);
return false;
}
return true;
Expand Down
26 changes: 10 additions & 16 deletions src/features/messages/MessageDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,38 +73,32 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
enabled: isMessageFound,
});

const {
msgId,
status,
originChainId,
destinationChainId,
originDomainId,
destinationDomainId,
origin,
destination,
isPiMsg,
} = message;
const { msgId, status, originDomainId, destinationDomainId, origin, destination, isPiMsg } =
message;

const duration = destination?.timestamp
? getHumanReadableDuration(destination.timestamp - origin.timestamp, 3)
: undefined;

const showTimeline =
!isPiMsg &&
isEvmChain(multiProvider, originChainId) &&
isEvmChain(multiProvider, destinationChainId);
isEvmChain(multiProvider, originDomainId) &&
isEvmChain(multiProvider, destinationDomainId);

// Banner color setter
useDynamicBannerColor(isFetching, status, isMessageFound, isError || isPiError);

const originChainName = multiProvider.getChainName(originDomainId);
const destinationChainName = multiProvider.getChainName(destinationDomainId);

return (
<>
<Card className="flex items-center justify-between rounded-full px-1">
<h2 className="font-medium text-blue-500">{`${
isIcaMsg ? 'ICA ' : ''
} Message ${trimToLength(msgId, 6)} to ${getChainDisplayName(
multiProvider,
destinationChainId,
destinationChainName,
)}`}</h2>
<StatusHeader
messageStatus={status}
Expand All @@ -115,13 +109,13 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
</Card>
<div className="mt-3 flex flex-wrap items-stretch justify-between gap-3 md:mt-4 md:gap-4">
<OriginTransactionCard
chainId={originChainId}
chainName={originChainName}
domainId={originDomainId}
transaction={origin}
blur={blur}
/>
<DestinationTransactionCard
chainId={destinationChainId}
chainName={destinationChainName}
domainId={destinationDomainId}
status={status}
transaction={destination}
Expand Down
15 changes: 10 additions & 5 deletions src/features/messages/MessageTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function MessageTable({
}

export function MessageSummaryRow({ message, mp }: { message: MessageStub; mp: MultiProvider }) {
const { msgId, status, sender, recipient, originChainId, destinationChainId, origin } = message;
const { msgId, status, sender, recipient, originDomainId, destinationDomainId, origin } = message;

let statusIcon = undefined;
let statusTitle = '';
Expand All @@ -67,15 +67,20 @@ export function MessageSummaryRow({ message, mp }: { message: MessageStub; mp: M

const base64 = message.isPiMsg ? serializeMessage(message) : undefined;

const originChainName = mp.getChainName(originDomainId);
const destinationChainName = mp.getChainName(destinationDomainId);

return (
<>
<LinkCell id={msgId} base64={base64} aClasses="flex items-center py-3.5 pl-3 sm:pl-5">
<ChainLogo chainId={originChainId} size={20} />
<div className={styles.chainName}>{getChainDisplayName(mp, originChainId, true)}</div>
<ChainLogo chainName={originChainName} size={20} />
<div className={styles.chainName}>{getChainDisplayName(mp, originChainName, true)}</div>
</LinkCell>
<LinkCell id={msgId} base64={base64} aClasses="flex items-center py-3.5 ">
<ChainLogo chainId={destinationChainId} size={20} />
<div className={styles.chainName}>{getChainDisplayName(mp, destinationChainId, true)}</div>
<ChainLogo chainName={destinationChainName} size={20} />
<div className={styles.chainName}>
{getChainDisplayName(mp, destinationChainName, true)}
</div>
</LinkCell>
<LinkCell id={msgId} base64={base64} tdClasses="hidden sm:table-cell" aClasses={styles.value}>
{shortenAddress(sender) || 'Invalid Address'}
Expand Down
2 changes: 1 addition & 1 deletion src/features/messages/cards/GasDetailsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface Props {
export function GasDetailsCard({ message, blur, igpPayments = {} }: Props) {
const multiProvider = useMultiProvider();
const unitOptions = useMemo(() => {
const originMetadata = multiProvider.tryGetChainMetadata(message.originChainId);
const originMetadata = multiProvider.tryGetChainMetadata(message.originDomainId);
const nativeCurrencyName = originMetadata?.nativeToken?.symbol || 'Eth';
return [
{ value: 18, display: toTitleCase(nativeCurrencyName) },
Expand Down
Loading

0 comments on commit b8e0d31

Please sign in to comment.