Skip to content

Commit

Permalink
feat: check proxy contract and implementation contract
Browse files Browse the repository at this point in the history
  • Loading branch information
Xaroz committed Dec 14, 2024
1 parent 1f9e154 commit 3a04c6e
Showing 1 changed file with 55 additions and 25 deletions.
80 changes: 55 additions & 25 deletions src/features/debugger/debugMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,20 @@ import {
IMultisigIsm__factory as MultisigIsmFactory,
} from '@hyperlane-xyz/core';
import { IRegistry } from '@hyperlane-xyz/registry';
import { ChainMap, ChainMetadata, MAILBOX_VERSION, MultiProvider } from '@hyperlane-xyz/sdk';
import {
ChainMap,
ChainMetadata,
MAILBOX_VERSION,
MultiProvider,
isProxy,
proxyImplementation,
} from '@hyperlane-xyz/sdk';
import {
addressToBytes32,
errorToString,
formatMessage,
isValidAddress,
strip0x,
trimToLength,
} from '@hyperlane-xyz/utils';

Expand All @@ -29,7 +37,7 @@ import { GasPayment, IsmModuleTypes, MessageDebugResult, MessageDebugStatus } fr

type Provider = providers.Provider;

// const HANDLE_FUNCTION_SIG = 'handle(uint32,bytes32,bytes)';
const HANDLE_FUNCTION_SIG = 'handle(uint32,bytes32,bytes)';
const IGP_PAYMENT_CHECK_DELAY = 30_000; // 30 seconds

export async function debugMessage(
Expand Down Expand Up @@ -174,16 +182,6 @@ async function debugMessageDelivery(
const errorReason = extractReasonString(err);
logger.debug(errorReason);

// const bytecodeHasHandle = await tryCheckBytecodeHandle(destProvider, recipient);
// if (!bytecodeHasHandle) {
// logger.info('Bytecode does not have function matching handle sig');
// return {
// status: MessageDebugStatus.RecipientNotHandler,
// description: `Recipient contract should have handle function of signature: ${HANDLE_FUNCTION_SIG}. Check that recipient is not a proxy. Error: ${errorReason}`,
// calldataDetails,
// };
// }

if (debugIgnoredChains.includes(destName)) {
return {
status: null,
Expand All @@ -192,6 +190,26 @@ async function debugMessageDelivery(
};
}

const proxyImplementationContract = await tryGetProxyImplementationContract(
destProvider,
recipient,
);
if (proxyImplementationContract) {
const bytecodeHasHandle = await tryCheckBytecodeHandle(
destProvider,
proxyImplementationContract,
);

if (!bytecodeHasHandle) {
logger.info('Bytecode does not have function matching handle sig');
return {
status: MessageDebugStatus.RecipientNotHandler,
description: `Recipient contract should have handle function of signature: ${HANDLE_FUNCTION_SIG}. Check that recipient is not a proxy. Error: ${errorReason}`,
calldataDetails,
};
}
}

const icaCallErr = await tryDebugIcaMsg(sender, recipient, body, originDomain, destProvider);
if (icaCallErr) {
return {
Expand Down Expand Up @@ -338,19 +356,31 @@ async function fetchGasPaymentEvents(provider: Provider, messageId: string) {
return { contractToPayments, contractToTotalGas, numPayments, numIGPs };
}

// async function tryCheckBytecodeHandle(provider: Provider, recipientAddress: string) {
// try {
// // scan bytecode for handle function selector
// const bytecode = await provider.getCode(recipientAddress);
// const msgRecipientInterface = MessageRecipientFactory.createInterface();
// const handleFunction = msgRecipientInterface.functions[HANDLE_FUNCTION_SIG];
// const handleSignature = msgRecipientInterface.getSighash(handleFunction);
// return bytecode.includes(strip0x(handleSignature));
// } catch (error) {
// logger.error('Error checking bytecode for handle fn', error);
// return true;
// }
// }
async function tryGetProxyImplementationContract(provider: Provider, recipientAddress: string) {
try {
const isProxyContract = await isProxy(provider, recipientAddress);
if (!isProxyContract) return undefined;

return await proxyImplementation(provider, recipientAddress);
} catch (error) {
logger.error('Error trying to check proxy contract', error);
return undefined;
}
}

async function tryCheckBytecodeHandle(provider: Provider, recipientAddress: string) {
try {
// scan bytecode for handle function selector
const bytecode = await provider.getCode(recipientAddress);
const msgRecipientInterface = MessageRecipientFactory.createInterface();
const handleFunction = msgRecipientInterface.functions[HANDLE_FUNCTION_SIG];
const handleSignature = msgRecipientInterface.getSighash(handleFunction);
return bytecode.includes(strip0x(handleSignature));
} catch (error) {
logger.error('Error checking bytecode for handle fn', error);
return true;
}
}

async function tryDebugIcaMsg(
sender: Address,
Expand Down

0 comments on commit 3a04c6e

Please sign in to comment.