Skip to content

feat: move pending transaction polling to background#2231

Closed
janek26 wants to merge 1 commit intomasterfrom
feat/pending-tx-background-polling
Closed

feat: move pending transaction polling to background#2231
janek26 wants to merge 1 commit intomasterfrom
feat/pending-tx-background-polling

Conversation

@janek26
Copy link
Contributor

@janek26 janek26 commented Mar 13, 2026

Move pending transaction polling to background

Pending transactions were only polled while the popup was open. If the user closed the popup after sending a tx (e.g. after approving an EIP-5792 batch from a dApp), we never checked the receipt. The tx stayed pending, batch status never updated, and dApps couldn’t see completion via wallet_getCallsStatus.
Receipt polling now runs in the background service worker instead of the popup, so pending txs are updated to confirmed/failed even when the popup is closed, batch status is updated when mined, and dApps can reliably detect completion.

Design choices & review focus

  • Background updates, popup removes – The background only updates status in-place (pending → confirmed/failed). The popup removes txs from the pending store after they appear in the consolidated cache (or immediately for custom chains) to avoid indexer lag.
  • Chain-specific intervals – Polling uses block-time tiers (e.g. ~12s mainnet, ~1s L2s) instead of a single interval.
  • Timeout handling – Timed-out txs are skipped on later polls but rechecked on worker start so they’re not left stuck.
  • Two cleanup paths – Both PendingTransactionWatcher (receipt-based) and useTransactionListForPendingTxs (nonce-based) can remove txs; removePendingTransactionsForAddress is idempotent.

PR-Codex overview

This PR introduces functionality to monitor pending transactions in the background service worker, enhancing the transaction polling mechanism and updating the UI accordingly. It adds new handlers and modifies existing components to improve the transaction handling process.

Detailed summary

  • Deleted useWatchPendingTransactions hook.
  • Added handleWatchPendingTransactions in src/entries/background/handlers/handleWatchPendingTransactions.ts.
  • Integrated handleWatchPendingTransactions into src/entries/background/index.ts.
  • Implemented polling logic for pending transactions.
  • Updated PendingTransactionWatcher in src/entries/popup/hooks/usePendingTransactionWatcher.ts to utilize the new polling mechanism.
  • Enhanced transaction state management and error handling in the polling process.
  • Defined transaction polling schedules in src/core/state/networks/timing.ts.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

@janek26
Copy link
Contributor Author

janek26 commented Mar 13, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@janek26 janek26 marked this pull request as ready for review March 13, 2026 12:20
@janek26 janek26 requested a review from DanielSinclair March 13, 2026 12:22
@janek26 janek26 force-pushed the feat/pending-tx-background-polling branch from 6522f01 to 1ee6d5f Compare March 13, 2026 13:04
@janek26 janek26 force-pushed the 03-05-feat_implement_wallet_showcallsstatus_to_open_transaction_detail branch from bfdec1e to a56fc01 Compare March 13, 2026 13:04
@DanielSinclair
Copy link
Collaborator

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79dc11f216

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +14 to +20
const { pendingTransactions } = usePendingTransactionsStore.getState();
const intervalMs = getMinPollingIntervalForPendingTxs(pendingTransactions);

nextPollTimeout = setTimeout(() => {
nextPollTimeout = null;
runPollCycle();
}, intervalMs);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recompute timer when pending transactions change

This schedules the next poll from a single snapshot of pendingTransactions and does not reschedule when new pending txs are added before the timeout fires. In practice, if a long-delay timer (e.g. 30s from an older mainnet tx) is already set and a fresh tx is submitted right after, that new tx will not be checked until the old timer expires, which delays mined-status propagation and dapp status updates.

Useful? React with 👍 / 👎.

Comment on lines +100 to +104
.filter((tx) => {
if (!skipTimedOutTxs) return true;
const pendingDurationMs = tx.lastSubmittedTimestamp
? now - tx.lastSubmittedTimestamp
: 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate each tx poll by its own tier interval

The poll loop only excludes timed-out txs; it does not skip txs whose per-chain tier interval has not elapsed yet. That means when one fast-chain tx drives the global timer to 1–2s, all other pending txs (including slow chains configured for 15–30s) are still fetched every cycle, creating avoidable background/network load and defeating the intended tiered polling behavior.

Useful? React with 👍 / 👎.

() =>
pendingTransactions.filter(
(tx): tx is MinedTransaction => tx.status !== 'pending',
),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usePendingTransactionWatcher.ts:56-62 — minedTransactions is a new array reference on every
render (.filter() always returns a new array). It's in the useEffect dep array at line 168.
When the effect calls removePendingTransactionsForAddress, the store updates,
pendingTransactions changes, minedTransactions gets a new reference, and the effect
re-fires.

The old code avoided this because watchPendingTransactions was a useCallback invoked by
usePoll, not an effect triggered by store state.

Suggestion: Stabilize minedTransactions with a deep comparison (e.g., serialize the
hash+chainId list) or use a ref to track which txs have already been processed:

const minedTxKey = useMemo(                                                
     () => minedTransactions.map((tx) => `${tx.hash}:${tx.chainId}`).join(','),                
     [minedTransactions],
   );                                                                                          
   // use minedTxKey in the dep array instead of minedTransactions 

}

const { pendingTransactions } = usePendingTransactionsStore.getState();
const intervalMs = getMinPollingIntervalForPendingTxs(pendingTransactions);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns 5s even when pendingTransactions is empty, so we start a polling loop with nothing to poll

});
};

userAssetsFetchQuery({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we warming the cache with this?

Copy link
Collaborator

@DanielSinclair DanielSinclair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted a few issues. These might be addressed in the upstream versions of this implementation

@DanielSinclair
Copy link
Collaborator

@janek26 Was this a requirement or a parallel fix that is no longer needed?

@janek26 janek26 closed this Mar 21, 2026
@janek26
Copy link
Contributor Author

janek26 commented Mar 21, 2026

I split this into tinier PRs which are now merged. Closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants