Debounce useLockAssetsFeePreview to stop per-keystroke simulateTransaction calls - #182
Merged
prodbycorne merged 4 commits intoAug 19, 2026
Conversation
…alls Previously the query keyed directly on the raw, un-debounced amount string, so every keystroke that changed a still-valid amount fired a fresh simulateLockAssets call -- two real RPC round trips (getAccount + simulateTransaction) per intermediate, never-submitted value typed on the way to a final amount. Debounces inside the hook itself (350ms, matching useLeaderboard's SEARCH_DEBOUNCE_MS pattern) rather than at each call site, so future callers get the fix automatically. isFetching is overridden to also be true while amount hasn't settled into debouncedAmount yet, so UI keyed off isFetching (the "Simulating..." text and the deposit modal's canSubmit gate) reflects a pending state for the whole debounce window, not just the network request that follows it -- no changes needed in DepositModal itself.
debouncedAmount was seeded from the initial amount, so a caller that mounts the hook with a non-empty amount already (rather than typing into an initially-empty field) got its first query fired immediately, un-debounced -- the same bug this fix targets, just via mount instead of a keystroke. Starts at "" instead, matching useLeaderboard's searchQuery/searchInput split, so every value -- including the first one a caller passes -- goes through the debounce window once. Caught by the accompanying test for a non-rapid single amount entry.
- A rapid keystroke burst produces exactly one simulateLockAssets call after the debounce window, using the final typed value. - isFetching is true throughout the debounce window itself, before any RPC call has fired, so UI keyed off it doesn't look inert. - A settled single amount entry still produces a fee preview (regression, unchanged behavior). - An invalid/empty amount never calls simulateLockAssets, debounce window or not. - A slow, superseded request from an earlier amount resolving after a newer request has already resolved does not clobber the fresher result -- explicit coverage for the "superseded in-flight calls don't race" acceptance criterion, relying on React Query's per-key cache identity rather than any new code in this hook.
✅ Deploy Preview for spiffy-melomakarona-eb1e8a ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for smart-drop ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
|
Good Job done |
4 tasks
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
useLockAssetsFeePreviewkeyed its query directly on the raw, un-debounced amount string, so every keystroke that changed a still-valid amount in the Farm page's deposit modal fired a freshsimulateLockAssetscall — two real RPC round trips (getAccount+simulateTransaction) per intermediate, never-submitted value typed on the way to a final amount.amountinsideuseLockAssetsFeePreviewitself (350ms, matchinguseLeaderboard's existingSEARCH_DEBOUNCE_MSpattern) rather than at theDepositModalcall site, so any future caller of this hook gets the fix automatically.isFetchingis overridden to also betruewhile the raw amount hasn't settled into the debounced value yet, sofarm/page.tsx's "Simulating..." text and itscanSubmitgate (both already keyed offfeePreview.isFetching) correctly reflect a pending state for the whole debounce window, not just the network request that follows it — no changes needed inDepositModal/farm/page.tsx.debouncedAmountstarts at""rather than being seeded from the initialamount, matchinguseLeaderboard'ssearchQuery/searchInputsplit — otherwise a caller mounting the hook with a non-empty amount already would get an un-debounced fire on mount (caught by one of the new tests).PoolDetailClient.tsx's deposit modal doesn't use this hook at all, so this fix is correctly scoped to the Farm page only, per the issue's own note.Closes #134
Test plan
npx tsc --noEmitnpx eslint src/hooks/useSorobanQuery.ts src/hooks/useSorobanQuery.test.tsnpx vitest run— all passing except one pre-existing, unrelated failure insrc/lib/soroban-parsers.test.ts(decodeScString), confirmed to already fail identically on a clean clone of upstreammain, and not something this repo's CI gates on (only e2e/build run in CI, not vitest)simulateLockAssetscall, using the final typed valueisFetchingistruethroughout the debounce window itself, before any RPC call firessimulateLockAssetse2e/farm.spec.ts's deposit flow (amountInput.fill('10')fires a single change event, and the submit button click auto-waits on Playwright's actionability/enabled check with a 30s test timeout) — the added 350ms debounce is well within that margin and shouldn't affect the existing e2e test