Replace Chainstack with public RPC provider pools#40
Conversation
Move external-chain balance and RPC-proxy endpoints off the Chainstack vendor onto static, ordered pools of public endpoints with per-provider failover: - BTC balances via Esplora (mempool.space, Blockstream), integer sats - ETH/BNB/SOL via public JSON-RPC pools (PublicNode + independents) - Optional env overrides: ETH_RPC_URLS / BNB_RPC_URLS / SOL_RPC_URLS / BTC_ESPLORA_URLS Scope reductions: - Drop the /private-api/broadcast/:chain endpoint: transactions are signed and broadcast client-side via MetaMask, so it had no consumers - Drop TRON/TON/APT handlers, which are not exposed in the UI Hardening: - Per-chain address validation (also blocks path traversal via the balance route), returning 400 on bad input instead of walking the provider pool - 10s per-provider timeout, short-lived balance cache with in-flight dedup - Replace hand-rolled hex bignum with native BigInt Removes CHAINSTACK_API_KEY and the defunct Chainz BTC fallback.
|
Warning Review limit reached
Next review available in: 11 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR replaces Chainstack-specific balance/broadcast/RPC logic with a chain-provider pool architecture. New ChangesProvider pool based chain balance/RPC refactor
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant balance
participant fetchChainBalance
participant tryProviders
participant RpcProvider
Client->>balance: GET balance(chain, address)
balance->>fetchChainBalance: fetchChainBalance(chain, address)
fetchChainBalance->>tryProviders: fetchBalance via provider pool
tryProviders->>RpcProvider: jsonRpcPost / fetchEsploraBalance
RpcProvider-->>tryProviders: result or error
tryProviders-->>fetchChainBalance: balance or TerminalProviderError
fetchChainBalance-->>balance: cached/fresh result
balance-->>Client: response with x-provider header
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 602bd18e3e
ℹ️ 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".
| headers: JSON_RPC_HEADERS, | ||
| timeout: PROVIDER_TIMEOUT_MS, | ||
| }); | ||
| return { providerId: provider.id, data: response.data }; |
There was a problem hiding this comment.
Throw on JSON-RPC errors before accepting a provider
When the first public RPC endpoint responds with HTTP 200 but a JSON-RPC error object (for example, a provider-side rate limit or an allowed method disabled on that endpoint), this callback returns it as a successful tryProviders result, so the remaining healthy providers are never attempted and the proxy surfaces the first provider's failure. The balance path already treats data.error as a provider failure; this proxy path should do the same for provider-side JSON-RPC errors or otherwise classify client parameter errors explicitly.
Useful? React with 👍 / 👎.
- RPC proxy: fail over to the next provider when one returns a JSON-RPC error body over HTTP 200 (e.g. a rate-limited node), while still passing the error envelope through if every provider returns one. - Solana balance: read the u64 lamport value from the raw response text so balances above 2^53 aren't truncated by JSON double parsing. - Helius: pass the API key as an Authorization bearer header instead of a URL query param, keeping it out of access logs and error traces.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
README.md (1)
57-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocker env docs missing RPC override vars.
The dev "Environment variables" section documents
ETH_RPC_URLS,BNB_RPC_URLS,SOL_RPC_URLS, andBTC_ESPLORA_URLS, but the Docker section only addsHELIUS_API_KEY.docker-compose.ymlpasses through all four RPC override vars to the container, so Docker users won't know these overrides are supported.📝 Proposed fix
* `BLOCKSTREAM_CLIENT_ID` * `BLOCKSTREAM_CLIENT_SECRET` * `HELIUS_API_KEY` + * `ETH_RPC_URLS` + * `BNB_RPC_URLS` + * `SOL_RPC_URLS` + * `BTC_ESPLORA_URLS`🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 57 - 59, Update the Docker environment variables docs in README.md to include the RPC override vars that docker-compose.yml already passes through: ETH_RPC_URLS, BNB_RPC_URLS, SOL_RPC_URLS, and BTC_ESPLORA_URLS. Keep the existing env list structure near BLOCKSTREAM_CLIENT_ID, BLOCKSTREAM_CLIENT_SECRET, and HELIUS_API_KEY, and make sure the Docker section matches the main “Environment variables” documentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@README.md`:
- Around line 57-59: Update the Docker environment variables docs in README.md
to include the RPC override vars that docker-compose.yml already passes through:
ETH_RPC_URLS, BNB_RPC_URLS, SOL_RPC_URLS, and BTC_ESPLORA_URLS. Keep the
existing env list structure near BLOCKSTREAM_CLIENT_ID,
BLOCKSTREAM_CLIENT_SECRET, and HELIUS_API_KEY, and make sure the Docker section
matches the main “Environment variables” documentation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 13980ad8-e51b-4426-80f9-69ef0859e0d6
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (9)
README.mddocker-compose.ymlpackage.jsonsrc/server/chain-providers.tssrc/server/handlers/constants.tssrc/server/handlers/private-api.tssrc/server/handlers/wallet-api.tssrc/server/helper.tssrc/server/index.tsx
💤 Files with no reviewable changes (3)
- src/server/index.tsx
- package.json
- src/server/handlers/wallet-api.ts
Moves the external-chain balance and RPC-proxy endpoints off the Chainstack vendor onto static, ordered pools of public endpoints, each with per-provider failover. No client changes are required:
/private-api/balance/:chain/:addresskeeps the same response shape (echoedchain, integer base-unitbalancestring,unit), and/private-api/rpc/:chainstays a transparent JSON-RPC proxy.Providers (all keyless by default; optional free keys only)
mempool.space, then Blockstream), integer satoshi. This also fixes the old default path returning a decimal BTC string.ETH_RPC_URLS,BNB_RPC_URLS,SOL_RPC_URLS,BTC_ESPLORA_URLS(comma-separated), so endpoints can be swapped without a code change.Scope reductions
POST /private-api/broadcast/:chain. Transactions are signed and broadcast client-side through MetaMask; the endpoint had no consumers.Hardening
400on malformed input instead of walking the whole provider pool.BigIntin place of the hand-rolled hex bignum for EVM balances.Config / env
CHAINSTACK_API_KEYand the defunct Chainz BTC fallback (CHAINZ_API_KEY).BLOCKSTREAM_CLIENT_ID/SECRETremain optional (Blockstream enterprise BTC fallback); adds optionalHELIUS_API_KEYas an extra Solana fallback.Balance and RPC paths were exercised live against the new pools (correct integer balances per chain, failover on a dead primary, validation → 400, RPC proxy
getLatestBlockhash).Summary by CodeRabbit
New Features
Bug Fixes
Chores