Skip to content

BlockAid/Balances Scan and Fetch Rate adjustments#505

Merged
leofelix077 merged 12 commits intomainfrom
lf-bulk-scan-rate-limit
Oct 30, 2025
Merged

BlockAid/Balances Scan and Fetch Rate adjustments#505
leofelix077 merged 12 commits intomainfrom
lf-bulk-scan-rate-limit

Conversation

@leofelix077
Copy link
Copy Markdown
Collaborator

@leofelix077 leofelix077 commented Oct 27, 2025

closes #447

We were previously having rate limiting issues with Blockaid. It is known that they have already increased the rate limits on their APIs, but the improvements aim to ease it for the future as well. The 429 Errors were no longer reproducible by the time this ticket was started

Main changes are:

  • Increase balances polling from 30 to 60s and only when in focus
  • Instead of calling Bulk Scan again, extract BlockAid data from balances, which is already contained inside the returned data. No need for another set of scans
  • Increase debounce timer to 500ms instead of 200ms, to give users time to type more slowly without repeatedly calling the server. 200ms felt too quick for normal typing. The repeat requests would still trigger, unless typed very quickly

General Changes:

Screen.Recording.2025-10-28.at.09.25.41.mov

Returned data from balances:

Screenshot 2025-10-27 at 17 26 52

Example of focused polling with start/stop logic on logs - set to 10s for testing, instead of 60s:

Screen.Recording.2025-10-28.at.10.39.58.mov

PR structure

  • This PR does not mix refactoring changes with feature changes (break it down into smaller PRs if not).
  • This PR has reasonably narrow scope (break it down into smaller PRs if not).
  • This PR includes relevant before and after screenshots/videos highlighting these changes.
  • I took the time to review my own PR.

Testing

  • These changes have been tested and confirmed to work as intended on Android.
  • These changes have been tested and confirmed to work as intended on iOS.
  • These changes have been tested and confirmed to work as intended on small iOS screens.
  • These changes have been tested and confirmed to work as intended on small Android screens.
  • I have tried to break these changes while extensively testing them.
  • This PR adds tests for the new functionality or fixes.

Release

  • This is not a breaking change.
  • This PR updates existing JSDocs when applicable.
  • This PR adds JSDocs to new functionalities.
  • I've checked with the product team if we should add metrics to these changes.
  • I've shared relevant before and after screenshots/videos highlighting these changes with the design team and they've approved the changes.

@leofelix077 leofelix077 added enhancement New feature or request wip work in progress don't review yet Work in Progress / Draft PR / Code Review adjustments being worked on labels Oct 27, 2025
@leofelix077 leofelix077 changed the title [WIP] Lf bulk scan rate limit BlockAid Scan Rate adjustments Oct 28, 2025
@leofelix077 leofelix077 changed the title BlockAid Scan Rate adjustments BlockAid/Balances Scan Rate adjustments Oct 28, 2025
@leofelix077 leofelix077 changed the title BlockAid/Balances Scan Rate adjustments BlockAid/Balances Scan and Fetch Rate adjustments Oct 28, 2025
@leofelix077 leofelix077 marked this pull request as ready for review October 28, 2025 14:08
@leofelix077 leofelix077 removed wip work in progress don't review yet Work in Progress / Draft PR / Code Review adjustments being worked on labels Oct 28, 2025
Comment thread src/hooks/useFocusedPolling.ts Outdated
onPoll();
lastPollTimeRef.current = Date.now();

pollingIntervalIdRef.current = setInterval(() => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like this will overwrite the timeout ID with the polling ID, will the timeout ever get cleaned up in clearAllTimers?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added related comment here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it shouldn't be the case. the timers are cleared at the beginning of the useCallback before it gets overwritten

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but how will it clear both references if one ID overrides the other?

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [publicKey, network]);
useFocusedPolling({
onPoll: handlePoll,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lastPollTimeRef starts at 0 so this should also act as an initial fetch on mount, is the mount effect redundant?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true

Comment thread src/ducks/balances.ts Outdated
Comment on lines 330 to 335
const [pricedBalances, scanResult] = await Promise.all([
fetchPricedBalances(set, balances, statePricedBalances, params),
scanBalances(set, balances, params.network),
Promise.resolve(
extractScanResultsFromBalances(balances, params.network),
),
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const [pricedBalances, scanResult] = await Promise.all([
fetchPricedBalances(set, balances, statePricedBalances, params),
scanBalances(set, balances, params.network),
Promise.resolve(
extractScanResultsFromBalances(balances, params.network),
),
]);
const pricedBalances = await fetchPricedBalances(set, balances, statePricedBalances, params);
const scanResults = extractScanResultsFromBalances(pricedBalances, params.network);

Would it be a good call to make something like this? So we assure the scanResults are always reflecting the most up to date balances (e.g. in case the user has just added a new token).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yes. makes sense

Comment thread src/config/constants.ts Outdated
export const DEFAULT_REFRESH_DELAY = 1000;

// Balances polling interval in milliseconds
export const BALANCES_FETCH_POLLING_INTERVAL = 60000;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we are removing a redundant bulk-scan request on the frontend and only fetching on focus I think it'd be worth to keep it as 30secs so users don't need to wait too long to see a balance update

Comment on lines -55 to -56
setHasAttemptedInitialLoad(true);
setIsMounting(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember exactly why we've added this in the past, but I'd suggest testing this branch with new account creations (with no balances) and also test switching between wallet accounts while observing if there won't be any weird UI glitches with spinners flickering or stuff like that

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the behavior is close/the same to the main branch

Branch:

Screen.Recording.2025-10-29.at.12.54.33.mov

Main:

Screen.Recording.2025-10-29.at.12.57.20.mov

Comment thread src/hooks/useFocusedPolling.ts Outdated
Comment on lines +37 to +38
clearTimeout(pollingIntervalIdRef.current);
clearInterval(pollingIntervalIdRef.current);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks confusing to have the same ref be a Timeout and an Interval at the same time. Could we use separate refs here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yes

Comment thread src/hooks/useFocusedPolling.ts Outdated
remainingTimeRef.current = interval;
startPolling(true);
} else {
pollingIntervalIdRef.current = setTimeout(() => {
Copy link
Copy Markdown
Contributor

@CassioMG CassioMG Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add a comment explaining why we need to use setTimeout + setInterval here instead of calling startPolling(false)? Thanks

@leofelix077 leofelix077 self-assigned this Oct 29, 2025
Comment thread src/ducks/balances.ts
Comment on lines -356 to -363
// Set the "raw" balances right away as they don't depend on prices
set({
balances,
isFunded: isFunded ?? false,
subentryCount: subentryCount ?? 0,
});

// Get existing state priced balances to preserve price data
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we keep those comments? I think it helps clarifying things

@leofelix077 leofelix077 merged commit 8cce6eb into main Oct 30, 2025
3 checks passed
@leofelix077 leofelix077 deleted the lf-bulk-scan-rate-limit branch October 30, 2025 15:09
This was referenced Nov 7, 2025
@github-actions github-actions Bot mentioned this pull request Nov 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce Blockaid scan frequency

3 participants