|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
import { constants } from 'ethers'; |
|
|
|
|
|
|
|
|
|
import { IMailbox__factory } from '@hyperlane-xyz/core'; |
|
|
|
|
import { ChainMap, MultiProvider } from '@hyperlane-xyz/sdk'; |
|
|
|
|
|
|
|
|
|
import { Message, MessageStatus } from '../../types'; |
|
|
|
@ -9,7 +10,6 @@ import type { ChainConfig } from '../chains/chainConfig'; |
|
|
|
|
import { getContractAddress } from '../chains/utils'; |
|
|
|
|
import { debugExplorerMessage } from '../debugger/debugMessage'; |
|
|
|
|
import { MessageDebugStatus } from '../debugger/types'; |
|
|
|
|
import { TX_HASH_ZERO } from '../messages/placeholderMessages'; |
|
|
|
|
|
|
|
|
|
import { |
|
|
|
|
MessageDeliveryFailingResult, |
|
|
|
@ -17,12 +17,6 @@ import { |
|
|
|
|
MessageDeliverySuccessResult, |
|
|
|
|
} from './types'; |
|
|
|
|
|
|
|
|
|
// The keccak-256 hash of the ProcessId event: ProcessId(bytes32)
|
|
|
|
|
// https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/1.0.0-beta0/solidity/contracts/Mailbox.sol#L84
|
|
|
|
|
// https://emn178.github.io/online-tools/keccak_256.html
|
|
|
|
|
// Alternatively could get this by creating the Mailbox contract object via SDK
|
|
|
|
|
const PROCESS_TOPIC_0 = '0x1cae38cdd3d3919489272725a5ae62a4f48b2989b0dae843d3c279fee18073a9'; |
|
|
|
|
|
|
|
|
|
export async function fetchDeliveryStatus( |
|
|
|
|
multiProvider: MultiProvider, |
|
|
|
|
customChainConfigs: ChainMap<ChainConfig>, |
|
|
|
@ -31,35 +25,37 @@ export async function fetchDeliveryStatus( |
|
|
|
|
const destName = multiProvider.getChainName(message.destinationChainId); |
|
|
|
|
const destMailboxAddr = getContractAddress(customChainConfigs, destName, 'mailbox'); |
|
|
|
|
|
|
|
|
|
const logs = await fetchMessageLogs(multiProvider, message, destMailboxAddr); |
|
|
|
|
const { isDelivered, blockNumber, transactionHash } = await checkIsMessageDelivered( |
|
|
|
|
multiProvider, |
|
|
|
|
message, |
|
|
|
|
destMailboxAddr, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (logs?.length) { |
|
|
|
|
logger.debug(`Found delivery log for tx ${message.origin.hash}`); |
|
|
|
|
const log = logs[0]; // Should only be 1 log per message delivery
|
|
|
|
|
if (isDelivered) { |
|
|
|
|
const txDetails = await fetchTransactionDetails( |
|
|
|
|
multiProvider, |
|
|
|
|
message.destinationChainId, |
|
|
|
|
log.transactionHash, |
|
|
|
|
transactionHash, |
|
|
|
|
); |
|
|
|
|
// If a delivery (aka process) tx is found, mark as success
|
|
|
|
|
const result: MessageDeliverySuccessResult = { |
|
|
|
|
status: MessageStatus.Delivered, |
|
|
|
|
deliveryTransaction: { |
|
|
|
|
timestamp: toDecimalNumber(txDetails.timestamp || 0) * 1000, |
|
|
|
|
hash: log.transactionHash, |
|
|
|
|
from: txDetails.from || constants.AddressZero, |
|
|
|
|
to: txDetails.to || constants.AddressZero, |
|
|
|
|
blockHash: txDetails.blockHash || TX_HASH_ZERO, |
|
|
|
|
blockNumber: toDecimalNumber(log.blockNumber), |
|
|
|
|
timestamp: toDecimalNumber(txDetails?.timestamp || 0) * 1000, |
|
|
|
|
hash: transactionHash || constants.HashZero, |
|
|
|
|
from: txDetails?.from || constants.AddressZero, |
|
|
|
|
to: txDetails?.to || constants.AddressZero, |
|
|
|
|
blockHash: txDetails?.blockHash || constants.HashZero, |
|
|
|
|
blockNumber: toDecimalNumber(blockNumber || 0), |
|
|
|
|
mailbox: constants.AddressZero, |
|
|
|
|
nonce: txDetails.nonce || 0, |
|
|
|
|
gasLimit: toDecimalNumber(txDetails.gasLimit || 0), |
|
|
|
|
gasPrice: toDecimalNumber(txDetails.gasPrice || 0), |
|
|
|
|
effectiveGasPrice: toDecimalNumber(txDetails.gasPrice || 0), |
|
|
|
|
gasUsed: toDecimalNumber(txDetails.gasLimit || 0), |
|
|
|
|
cumulativeGasUsed: toDecimalNumber(txDetails.gasLimit || 0), |
|
|
|
|
maxFeePerGas: toDecimalNumber(txDetails.maxFeePerGas || 0), |
|
|
|
|
maxPriorityPerGas: toDecimalNumber(txDetails.maxPriorityFeePerGas || 0), |
|
|
|
|
nonce: txDetails?.nonce || 0, |
|
|
|
|
gasLimit: toDecimalNumber(txDetails?.gasLimit || 0), |
|
|
|
|
gasPrice: toDecimalNumber(txDetails?.gasPrice || 0), |
|
|
|
|
effectiveGasPrice: toDecimalNumber(txDetails?.gasPrice || 0), |
|
|
|
|
gasUsed: toDecimalNumber(txDetails?.gasLimit || 0), |
|
|
|
|
cumulativeGasUsed: toDecimalNumber(txDetails?.gasLimit || 0), |
|
|
|
|
maxFeePerGas: toDecimalNumber(txDetails?.maxFeePerGas || 0), |
|
|
|
|
maxPriorityPerGas: toDecimalNumber(txDetails?.maxPriorityFeePerGas || 0), |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
return result; |
|
|
|
@ -81,17 +77,41 @@ export async function fetchDeliveryStatus( |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchMessageLogs(multiProvider: MultiProvider, message: Message, mailboxAddr: Address) { |
|
|
|
|
const { msgId, origin, destinationChainId } = message; |
|
|
|
|
logger.debug(`Searching for delivery logs for tx ${origin.hash}`); |
|
|
|
|
async function checkIsMessageDelivered( |
|
|
|
|
multiProvider: MultiProvider, |
|
|
|
|
message: Message, |
|
|
|
|
mailboxAddr: Address, |
|
|
|
|
) { |
|
|
|
|
const { msgId, destinationChainId } = message; |
|
|
|
|
const provider = multiProvider.getProvider(destinationChainId); |
|
|
|
|
return provider.getLogs({ |
|
|
|
|
topics: [PROCESS_TOPIC_0, msgId], |
|
|
|
|
address: mailboxAddr, |
|
|
|
|
}); |
|
|
|
|
const mailbox = IMailbox__factory.connect(mailboxAddr, provider); |
|
|
|
|
|
|
|
|
|
// Try finding logs first as they have more info
|
|
|
|
|
try { |
|
|
|
|
logger.debug(`Searching for process logs for msgId ${msgId}`); |
|
|
|
|
const logs = await mailbox.queryFilter(mailbox.filters.ProcessId(msgId)); |
|
|
|
|
if (logs?.length) { |
|
|
|
|
logger.debug(`Found process log for ${msgId}}`); |
|
|
|
|
const log = logs[0]; // Should only be 1 log per message delivery
|
|
|
|
|
return { |
|
|
|
|
isDelivered: true, |
|
|
|
|
transactionHash: log.transactionHash, |
|
|
|
|
blockNumber: log.blockNumber, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} catch (error) { |
|
|
|
|
logger.warn(`Error querying for process logs for msgId ${msgId}`, error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Logs are unreliable so check the mailbox itself as a fallback
|
|
|
|
|
logger.debug(`Querying mailbox about msgId ${msgId}`); |
|
|
|
|
const isDelivered = await mailbox.delivered(msgId); |
|
|
|
|
logger.debug(`Mailbox delivery status for ${msgId}: ${isDelivered}}`); |
|
|
|
|
return { isDelivered }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchTransactionDetails(multiProvider: MultiProvider, chainId: ChainId, txHash: string) { |
|
|
|
|
function fetchTransactionDetails(multiProvider: MultiProvider, chainId: ChainId, txHash?: string) { |
|
|
|
|
if (!txHash) return null; |
|
|
|
|
logger.debug(`Searching for transaction details for ${txHash}`); |
|
|
|
|
const provider = multiProvider.getProvider(chainId); |
|
|
|
|
return provider.getTransaction(txHash); |
|
|
|
|