fix(useTransactions): include limit in txKeys.list's query key - #70
Merged
abayomicornelius merged 8 commits intoAug 21, 2026
Conversation
txKeys.list's query key never included limit, so every useRecentTransactions call for the same wallet — regardless of what limit was passed — collided on one shared React Query cache entry (StellarSend#51). Dashboard.tsx alone has three callers with different limits (5, 50, 50); History.tsx has two (100, 50). Whichever queryFn happened to run for the shared key determined the data every subscriber received, silently under- or over-reporting activity. Adds txKeys.list's limit param and two direct unit tests of the key factory's shape.
…ding on one cache entry Mirrors Dashboard.tsx's exact scenario: RecentTransactions calls useRecentTransactions(5) while QuickStats/ActivityChart call useRecentTransactions(50) for the same connected wallet at the same time. Asserts fetchTransactionsFromHorizon is invoked once per distinct limit and each hook instance receives a dataset sized for its own limit. Verified this fails against the pre-fix txKeys.list (fetcher called only once, with whichever limit happened to run first for the shared key) and passes against the fix.
Confirms the fix doesn't overcorrect into never sharing a cache entry: RecentTransactions(5), QuickStats(50), and ActivityChart(50) mounted together produce exactly two fetches, not three — the two limit=50 callers correctly dedupe to one shared query and the same data reference, while limit=5 gets its own independent fetch.
Independent collision from Dashboard's — HistoryChart(100) and HistorySummary(50) on a separate page, same class of bug. Confirms both fetch independently and each receives its own limit-sized dataset.
General correctness check that the fix didn't overcorrect into always fetching separately: two useRecentTransactions(50) instances for the same wallet still dedupe to a single fetch and the same data reference.
…ery distinct-limit query Now that txKeys.list()'s key includes limit, this confirms the broader txKeys.all-prefix invalidation useInvalidateTransactions relies on still reaches every limit variant under a wallet, not just one — both a limit=5 and a limit=50 query refetch after a single invalidate() call.
…eal type
The regression tests' mock transactions only set {id}, which happened to
work for vitest (no type-checking at runtime) but failed tsc/npm run build
— Transaction requires hash, createdAt, type, status, direction,
counterparty, and more. Adds a makeTransaction/makeTransactions fixture
builder satisfying the full type and uses it everywhere the tests fabricate
transaction data.
Contributor
Author
|
All checks passed. please review |
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.
Summary
useRecentTransactions(limit)'s React Query cache key never includedlimit, so every call for the same wallet — regardless of whatlimitwas passed — resolved to the identical query key. React Query treats those as one shared query and deduplicates/shares results between them.Dashboard.tsxalone has three simultaneous callers with different limits (RecentTransactions(5),QuickStats(50),ActivityChart(50));History.tsxhas two more (HistoryChart(100),HistorySummary(50)). WhicheverqueryFnhappened to run for the shared key determined the data every subscriber received —QuickStats's totals andActivityChart's 7-day chart could silently under-report real activity with no error and no visible sign anything was wrong.Fix:
txKeys.listnow takeslimitas an explicit parameter and includes it in the returned key tuple, exactly as the issue's suggested fix describes.fix: includelimitintxKeys.list's query key, plus direct unit tests of the key factory's shapetest: regression test mirroring the issue's exact reproduction — two different limits for the same wallet now fetch and receive independent, correctly-sized datasets (verified this fails against the pre-fix key: only 1 fetch call instead of 2)test: fixed the regression test's mockTransactionfixtures to satisfy the real type (vitest doesn't type-check, buttsc/npm run builddo)test: Dashboard's exact 3-caller scenario (5, 50, 50) — confirms the fix doesn't overcorrect: the twolimit=50callers still correctly dedupe to one shared fetch/data reference, whilelimit=5gets its owntest: History's exact 2-caller scenario (100, 50)test: identical limits across two hook instances still share one fetch (general caching-efficiency sanity check)test:useInvalidateTransactions(which invalidates via the broadertxKeys.allprefix) still correctly invalidates every distinct-limit query after the key shape changedocs: note the fix in CHANGELOG, matching this repo's existing conventionTest plan
npx vitest run— 113/113 passing across 27 test filesnpx tsc --noEmit— cleannpm run lint— 0 warnings (--max-warnings 0)npm run build— succeedstxKeys.list(fetcher called once instead of twice) and passes against the fixCloses #51