From e6afd9173e093200164fcd096023ade7b8e7ad21 Mon Sep 17 00:00:00 2001 From: karooolis Date: Thu, 3 Oct 2024 11:31:08 +0300 Subject: [PATCH] handle incoming txs from observer, retry receipt fetch --- .../observe/TransactionsTableContainer.tsx | 96 ++++++++++--------- .../observe/TransactionsTableView.tsx | 2 +- packages/explorer/src/observer/store.ts | 2 + 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableContainer.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableContainer.tsx index 44c5d8bad4..9592756567 100644 --- a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableContainer.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableContainer.tsx @@ -28,7 +28,7 @@ export type WatchedTransaction = { transaction?: Transaction; functionData?: DecodeFunctionDataReturnType; receipt?: TransactionReceipt; - status: "pending" | "success" | "reverted"; + status: "pending" | "success" | "reverted" | "unknown"; write?: Write; logs?: Log[]; error?: BaseError; @@ -80,16 +80,6 @@ export function TransactionsTableContainer() { const transaction = await getTransaction(wagmiConfig, { hash }); if (transaction.to !== worldAddress) return; - setTransactions((prevTransactions) => [ - { - hash, - timestamp, - transaction, - status: "pending", - }, - ...prevTransactions, - ]); - let functionName: string | undefined; let args: readonly unknown[] | undefined; let transactionError: BaseError | undefined; @@ -103,22 +93,42 @@ export function TransactionsTableContainer() { functionName = transaction.input.length > 10 ? transaction.input.slice(0, 10) : "unknown"; } - setTransactions((prevTransactions) => - prevTransactions.map((transaction) => - transaction.hash === hash - ? { - ...transaction, - functionData: { - functionName, - args, - }, - } - : transaction, - ), - ); + setTransactions((prevTransactions) => [ + { + hash, + timestamp, + transaction, + status: "pending", + functionData: { + functionName, + args, + }, + }, + ...prevTransactions, + ]); + + // Receipt + const maxRetries = 10; + const retryInterval = 2000; + let receipt: TransactionReceipt | undefined; + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + receipt = await getTransactionReceipt(wagmiConfig, { hash }); + if (receipt) break; + } catch (error) { + console.error(`Failed to fetch receipt, attempt ${attempt + 1}:`, error); + } + + if (attempt < maxRetries - 1) { + await new Promise((resolve) => setTimeout(resolve, retryInterval)); + } + } + + if (!receipt) { + console.error(`Failed to fetch transaction receipt after ${maxRetries} attempts`); + } - const receipt = await getTransactionReceipt(wagmiConfig, { hash }); - if (receipt.status === "reverted" && functionName) { + if (receipt && receipt.status === "reverted" && functionName) { try { // Simulate the failed transaction to retrieve the revert reason // Note, it only works for functions that are declared in the ABI @@ -137,9 +147,10 @@ export function TransactionsTableContainer() { } } + const status = receipt ? receipt.status : "unknown"; const logs = parseEventLogs({ abi, - logs: receipt.logs, + logs: receipt?.logs || [], }); setTransactions((prevTransactions) => @@ -149,7 +160,7 @@ export function TransactionsTableContainer() { ...transaction, receipt, logs, - status: receipt.status, + status, error: transactionError, } : transaction, @@ -159,6 +170,18 @@ export function TransactionsTableContainer() { [abi, wagmiConfig, worldAddress], ); + useEffect(() => { + for (const write of observerWrites) { + const hash = write.hash; + if (write.type === "waitForTransactionReceipt" && hash) { + const transaction = transactions.find((transaction) => transaction.hash === hash); + if (!transaction) { + handleTransaction(hash, BigInt(write.time) / 1000n); + } + } + } + }, [handleTransaction, observerWrites, transactions]); + useWatchBlocks({ onBlock(block) { for (const hash of block.transactions) { @@ -170,22 +193,5 @@ export function TransactionsTableContainer() { pollingInterval: 500, }); - useEffect(() => { - const handleVisibilityChange = () => { - if (!document.hidden) { - for (const write of observerWrites) { - if (write.hash && !transactions.find((t) => t.hash === write.hash)) { - handleTransaction(write.hash, BigInt(write.time) / 1000n); - } - } - } - }; - - document.addEventListener("visibilitychange", handleVisibilityChange); - return () => { - document.removeEventListener("visibilitychange", handleVisibilityChange); - }; - }, [handleTransaction, observerWrites, transactions]); - return ; } diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableView.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableView.tsx index 62975e804d..d93a3b9d3a 100644 --- a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableView.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/TransactionsTableView.tsx @@ -13,7 +13,7 @@ import { WatchedTransaction } from "./TransactionsTableContainer"; const columnHelper = createColumnHelper(); export const columns = [ - columnHelper.accessor("transaction.blockNumber", { + columnHelper.accessor("receipt.blockNumber", { header: "Block", cell: (row) => { const blockNumber = row.getValue(); diff --git a/packages/explorer/src/observer/store.ts b/packages/explorer/src/observer/store.ts index 0eae89719d..5c4e78b414 100644 --- a/packages/explorer/src/observer/store.ts +++ b/packages/explorer/src/observer/store.ts @@ -8,6 +8,7 @@ import { Message, MessageType } from "./messages"; export type Write = { writeId: string; + type: MessageType; hash?: Hex; address: Address; functionSignature: string; @@ -37,6 +38,7 @@ channel.addEventListener("message", ({ data }: MessageEvent) => { ...state.writes, [data.writeId]: { ...write, + type: data.type, hash: data.type === "waitForTransactionReceipt" ? data.hash : write.hash, events: [...write.events, data], },