Fix /vaults discovery: vetted RPC transports, one indexer query, device-known fallback - #31
Merged
Merged
Conversation
Capture the conventions the strict-payouts block surfaced: testnet branch fast-forward after prod merges, NEXT_PUBLIC_* redeploy requirement, the eth_simulateV1 wallet-less verification pattern with its shared-block-gas pitfall, and the on-chain-probed Sablier tranche facts (500 cap, exact-sum requirement).
…ce-known fallback A BNB Chain user reported slow vault loads, a wall of CORS errors, and vaults that looked merged. Three separate causes: - wagmi used viem's default RPC per chain. Ethereum's (eth.merkle.io) now rejects CORS preflight, and RainbowKit runs mainnet ENS lookups on every page when chain 1 is configured — hence the console storm, and no working read transport on Ethereum at all. Each chain now carries a CORS-verified rpcUrls list; wagmi builds fallback(http…) transports from it, and NEXT_PUBLIC_RPC_URLS can prepend a keyed provider per chain. - The indexer-down fallback scanned Transfer logs in chunks larger than every public RPC's eth_getLogs cap (BSC: 1,000 blocks vs 10k), so it failed on 6 of 7 chains, and on BNB would need ~74k calls even at the cap. The scan is gone. Discovery is one indexer query for all deployment chains (the indexer allows 250 req/min per IP; the per-chain fan-out is gone too) with typed retries on 429/5xx, falling back to stream IDs the device already knows (/create's label keys + a cache of the last indexer result), read via multicall and filtered by ownerOf. - Lock-until and Panic Lock streams are created with total = cliff + 1s, so the "One Drop" label was unreachable and they read "Wait, then reloads". The aggregate header repeated each card's "Total locked" eyebrow and summed fully-claimed test locks, which is how two vaults read as one merged 4,045. It now shows "Still locked" across N vaults. Verified: tsc, eslint, 151 vitest tests, Vercel-style build, and a live run against the indexer + BSC RPC for the reporting wallet (indexer and on-chain fallback return identical records; the fallback transport resolves ENS past the dead merkle endpoint). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A BNB Chain user reported slow vault loads, a console full of CORS errors, and vaults that "looked merged" with balances "a bit off". Probing prod on 2026-09-05 turned up three independent causes; this PR fixes all three.
Root causes
eth.merkle.io) now returns 405 to the CORS preflight and 429 to POSTs. RainbowKit runs a mainnet ENS lookup on every page whenever chain 1 is configured (it has been since the 7-chain expansion), so every page load retried a dead endpoint. Noise for BNB users, but it also meant Ethereum mainnet had no working read transport at all.Transferlogs in 10k-block chunks (50k on Base). Every default public RPC except Arbitrum capseth_getLogsbelow that (BSC: 1,000 blocks), so the fallback failed instantly on 6 of 7 chains. On BNB it would need ~74k sequential calls even at the cap. The cross-chain "where are my vaults" probe also fanned out 6 more indexer requests per empty result.total = cliff + 1s(Sablier requires cliff < total), so the "One Drop" branch was unreachable and they read "Wait, then reloads" on any device without the stored preset label. The aggregate header reused each card's "Total locked" eyebrow and summed fully-claimed test locks: this user's 3,030 + 1,010 + a claimed 5 rendered as one "4,045 Total locked".What changed
config/chains.ts: each chain carries an orderedrpcUrlslist (every URL checked for a permissive preflight from ripguard.xyz).NEXT_PUBLIC_RPC_URLS(JSON keyed by chainId) prepends a keyed provider per chain, public list stays as fallback.streamStartBlock/logChunkSizeremoved. NewDEPLOYMENT_CHAINS.config/wagmi.ts: explicitfallback(http…)transports from the registry.lib/vaults.ts(new, tested): one indexer query for all deployment chains via GraphQL variables, parsed at the boundary into bigint/seconds, typedIndexerErrorwith retries only on 429/5xx/network. Fallback reads stream IDs the device already knows (/create'sripguard:lock:*keys plus a cache of the last indexer result) via multicall, filtered byownerOf.getScheduleTypetreats the 1-second tail as One Drop.lib/retry.ts:shouldRetryoption (user rejections still never retried).config/abis.ts:ownerOf./vaults: rewired onto the module; header now reads "Across N vaults on " with Still locked (deposits − claimed − claimable) instead of repeating "Total locked"; honest copy for the indexer-down and device-known states.AGENTS.md, README,.env.example: sharp-edge note and the new env var.Verification
tsc --noEmit,eslint,vitest run(151 tests, 42 new), and the Vercel-style build (CI=1 pnpm install && next buildinsidepackages/app) all pass.[1644, 1645, 1646, 99999, 1643]returns exactly the same three records (foreign + nonexistent IDs filtered);fallback([merkle, publicnode])resolvesvitalik.ethpast the dead endpoint.next startsmoke:/,/create,/vaults200; noeth.merkle.iorequests.Preview click-test
Connect the BNB wallet on
/vaults: expect three cards (two "Lock until Sep 24, 2026" / "One Drop", one claimed 5 USDC), header "Across 3 vaults on BNB Chain · 0 Claimable now · 4,040 Still locked · 5 Claimed", and a clean console apart from the Vercel Analytics 404.Notes / follow-ups
git push origin origin/main:testnet.ripguardproject (/_vercel/insights/script.js404s), socontract_errorevents are dropped. Tracked as tixripguard-75b8f7.NEXT_PUBLIC_RPC_URLSand redeploy.🤖 Generated with Claude Code