Implement ica address fetching

pull/11/head
J M Rossy 2 years ago
parent 957b348cf0
commit 8337f29101
  1. 34
      src/features/messages/MessageDetails.tsx
  2. 51
      src/features/messages/ica.ts

@ -27,7 +27,7 @@ import { debugStatusToDesc } from '../debugger/strings';
import { MessageDebugStatus } from '../debugger/types';
import { useMessageDeliveryStatus } from '../deliveryStatus/useMessageDeliveryStatus';
import { decodeIcaBody, isIcaMessage } from './ica';
import { decodeIcaBody, isIcaMessage, useIcaAddress } from './ica';
import { PLACEHOLDER_MESSAGES } from './placeholderMessages';
import { parseMessageQueryResult } from './query';
import type { MessagesQueryResult } from './types';
@ -374,9 +374,15 @@ interface IcaDetailsCardProps {
shouldBlur: boolean;
}
function IcaDetailsCard({ message: { body }, shouldBlur }: IcaDetailsCardProps) {
function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }: IcaDetailsCardProps) {
const decodeResult = useMemo(() => decodeIcaBody(body), [body]);
const {
data: icaAddress,
isFetching,
isError,
} = useIcaAddress(originDomainId, decodeResult?.sender);
return (
<Card classes="mt-2 space-y-4" width="w-full">
<div className="flex items-center justify-between">
@ -398,13 +404,29 @@ function IcaDetailsCard({ message: { body }, shouldBlur }: IcaDetailsCardProps)
showCopy={true}
blurValue={shouldBlur}
/>
<KeyValueRow
label="ICA Address:"
labelWidth="w-28"
display={
icaAddress
? icaAddress
: isFetching
? 'Finding address...'
: isError
? 'Error finding address'
: 'Unknown address'
}
displayWidth="w-60 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
/>
{decodeResult.calls.length ? (
decodeResult.calls.map((c, i) => (
<div key={`ica-call-${i}`}>
<label className="text-sm text-gray-500">{`Function call ${i + 1} of ${
decodeResult.calls.length
}:`}</label>
<div className="mt-1.5 pl-4 border-l-2 border-gray-300 space-y-2">
<div className="mt-2 pl-4 border-l-2 border-gray-400 space-y-2.5">
<KeyValueRow
label="Destination address:"
labelWidth="w-32"
@ -464,7 +486,7 @@ function KeyValueRow({
<span>{display}</span>
{subDisplay && <span className="text-xs ml-2">{subDisplay}</span>}
</div>
{showCopy && <CopyButton copyValue={display} width={15} height={15} classes="ml-3" />}
{showCopy && <CopyButton copyValue={display} width={13} height={13} classes="ml-3" />}
</div>
);
}
@ -477,8 +499,8 @@ function HexStringBlock({ label, value }: { label: string; value: string }) {
{value}
<CopyButton
copyValue={value}
width={15}
height={15}
width={13}
height={13}
classes="absolute top-2 right-2 opacity-70"
/>
</div>

@ -1,6 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import { BigNumber, utils } from 'ethers';
import { hyperlaneCoreAddresses } from '@hyperlane-xyz/sdk';
import { InterchainAccountRouter__factory } from '@hyperlane-xyz/core';
import {
DomainIdToChainName,
chainConnectionConfigs,
hyperlaneCoreAddresses,
} from '@hyperlane-xyz/sdk';
import { Message } from '../../types';
import { areAddressesEqual, isValidAddress } from '../../utils/addresses';
@ -35,21 +41,15 @@ export function decodeIcaBody(body: string) {
sender: string;
calls: Array<[string, string]>;
};
if (typeof sender !== 'string' || !isValidAddress(sender)) {
if (typeof sender !== 'string' || !isValidAddress(sender))
throw new Error(`Invalid sender address: ${sender}`);
}
if (!Array.isArray(calls)) {
throw new Error(`Invalid call list: ${JSON.stringify(calls)}`);
}
if (!Array.isArray(calls)) throw new Error(`Invalid call list: ${JSON.stringify(calls)}`);
const formattedCalls = calls.map((c) => {
const [destinationAddress, callBytes] = c;
if (typeof destinationAddress !== 'string' || !isValidAddress(destinationAddress)) {
if (typeof destinationAddress !== 'string' || !isValidAddress(destinationAddress))
throw new Error(`Invalid call dest address: ${destinationAddress}`);
}
if (typeof callBytes !== 'string') {
throw new Error(`Invalid call bytes: ${callBytes}`);
}
if (typeof callBytes !== 'string') throw new Error(`Invalid call bytes: ${callBytes}`);
return {
destinationAddress,
callBytes,
@ -65,3 +65,32 @@ export function decodeIcaBody(body: string) {
return null;
}
}
// TODO do this on backend and use private RPC
async function fetchIcaAddress(originDomainId: number, senderAddress: string) {
try {
logger.debug('Fetching Ica address', originDomainId, senderAddress);
const chainName = DomainIdToChainName[originDomainId];
const connection = chainConnectionConfigs[chainName];
if (!connection) throw new Error(`No connection info for ${chainName}`);
const icaContract = InterchainAccountRouter__factory.connect(ICA_ADDRESS, connection.provider);
const icaAddress = await icaContract.getInterchainAccount(originDomainId, senderAddress);
if (!isValidAddress(icaAddress)) throw new Error(`Invalid Ica addr ${icaAddress}`);
logger.debug('Ica address found', icaAddress);
return icaAddress;
} catch (error) {
logger.error('Error fetching ICA address', error);
return null;
}
}
export function useIcaAddress(originDomainId: number, senderAddress?: string | null) {
return useQuery(
['messageIcaAddress', originDomainId, senderAddress],
() => {
if (!originDomainId || !senderAddress || BigNumber.from(senderAddress).isZero()) return null;
return fetchIcaAddress(originDomainId, senderAddress);
},
{ retry: false },
);
}

Loading…
Cancel
Save