Skip to content

fix: guard wallet RPC calls against undefined result and retry transients#899

Merged
eskp merged 4 commits intostagingfrom
fix/wallet-balance-rpc-retry
Apr 21, 2026
Merged

fix: guard wallet RPC calls against undefined result and retry transients#899
eskp merged 4 commits intostagingfrom
fix/wallet-balance-rpc-retry

Conversation

@joelorzet
Copy link
Copy Markdown

Summary

  • Consolidate the three near-duplicate balance fetchers (fetchNativeBalance, fetchTokenBalance, fetchSupportedTokenBalance) onto a single rpcCall helper with retry/backoff.
  • rpcCall retries on HTTP 429, HTTP 5xx, network errors, and malformed responses (missing result field). Skips retry on RPC-reported errors and non-429 4xx.
  • Extract encodeBalanceOfCallData and hexWeiToBigInt helpers. hexWeiToBigInt treats "0x" as zero so BigInt() never receives an invalid string.
  • Name all retry knobs in a single RPC_RETRY_CONFIG block with two schedules: standard (500ms, 1s, 2s, cap 3s) and rate-limit (1s, 2s, 4s, cap 5s).

Background

The analytics page was showing TypeError: Cannot convert undefined to a BigInt on the Base chain card. Root cause: fetchNativeBalance called BigInt(result.result) without guarding against malformed gateway responses where result.result was undefined (no error field, no result field). The same class of transient failure on the sibling ERC20 fetchers was silently caught and displayed to users as well.

Instead of patching just the one call site, this refactor unifies all three fetchers so the fix, the retry behaviour, and the error semantics are consistent across native and ERC20 paths.

…ents

Consolidate native and ERC20 balance fetchers onto a shared rpcCall helper
with exponential backoff for HTTP 429, 5xx, network errors, and malformed
gateway responses with missing result fields. The missing-result case was
surfacing as BigInt(undefined) on the analytics page.
…ress validation

Split rpcCall and helpers out of fetch-balances.ts into lib/wallet/rpc.ts so
the retry logic is unit-testable in isolation. Add randomized jitter (up to
30%) to the backoff to avoid lockstep retries, and clamp the absolute maximum
delay to 5s regardless of schedule. Validate EVM addresses before encoding
balanceOf call data so an oversized input cannot silently produce wrong call
data via padStart. Emit a Sentry breadcrumb on every retry attempt so the
retry history is attached to any captured exception.

Add lib/wallet/rpc.test.ts covering encodeBalanceOfCallData validation,
hexWeiToBigInt edge cases, getRpcBackoffMs jitter and cap behavior, and all
rpcCall retry/throw branches.
@github-actions
Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

…fails

Wire the chain-level default_fallback_rpc through ChainData so the wallet
balance fetchers can fail over when the primary RPC is throttled or down.
Add rpcCallWithFailover that walks the URL list in order with a reduced
per-URL retry budget so the handoff is fast. Emit rpc.failover breadcrumbs
for every hop. The user now sees an error only when every configured RPC
is exhausted, not when the primary alone gets a 429.
@github-actions
Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@github-actions
Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@eskp eskp merged commit a0f1c19 into staging Apr 21, 2026
32 checks passed
@eskp eskp deleted the fix/wallet-balance-rpc-retry branch April 21, 2026 06:35
@github-actions
Copy link
Copy Markdown

🧹 PR Environment Cleaned Up

The PR environment has been successfully deleted.

Deleted Resources:

  • Namespace: pr-899
  • All Helm releases (Keeperhub, Scheduler, Event services)
  • PostgreSQL Database (including data)
  • LocalStack, Redis
  • All associated secrets and configs

All resources have been cleaned up and will no longer incur costs.

@eskp eskp mentioned this pull request Apr 21, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants