Repository navigation
fix(account): wait for remote config before the first balances fetch - #3064
Conversation
The Account view fired its first balances fetch on mount, before the Amplitude flags had loaded. useGetBalances reads use_balances_v2 at call time, so that first request read the hardcoded default (false) and went to the v1 endpoint even for users enrolled in v2. Later polls used v2, which skewed the v1/v2 rollout comparison. The mount effect now waits for isRemoteConfigInitialized. The reducer sets it on the failure path too, so Amplitude being down costs one round trip instead of a stuck screen. The view already renders IDLE as loading, so the wait shows the existing spinner. The test Wrapper now preloads a settled remoteConfig slice; without it every Account test would sit on the loader. Adds a regression test that asserts no balances request goes out until the flags settle. Fixes stellar#3032 Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Gate the flag read inside the balances/prices hooks, not in the Account viewMedium — the race in #3032 is still live on every entry point other than the Account route. Merge blocker as-is; the fix is small. TL;DR: The Account screen now waits for feature flags before its first balances fetch, but the flag is read at call time inside the shared balances and token-prices hooks, and those hooks are called from ~27 places. The sign-transaction popup, every fullscreen tab (history, send, swap, add asset…), and sidebar mode each open a fresh document with an uninitialized store and never pass through the Account effect, so their first request still goes to v1 for a v2 user. Moving the wait to where the flag is read fixes all entry points at once, lets the Account change and the shared test-helper change be reverted, and the e2e suite needs a default stub for the Experiment request either way. Separately, any wait on the flag fetch inherits the Experiment SDK's 10 second default timeout with errors swallowed, so a slow or blocked Amplitude host now means up to 10 seconds of spinner on every popup open; shorten that timeout to 1 to 2 seconds wherever the gate ends up living. Steps to reproduce:
Detailed explanation (for agents)Root cause: the gate is upstream of only one caller. The read sites are:
The new gate only covers the Account effect: freighter/extension/src/popup/views/Account/index.tsx Lines 96 to 106 in b97c3be
Suggested fix: add one helper to export const waitForRemoteConfig = (store: Store): Promise<void> =>
new Promise((resolve) => {
if (isRemoteConfigInitializedSelector(store.getState())) return resolve();
const unsubscribe = store.subscribe(() => {
if (isRemoteConfigInitializedSelector(store.getState())) {
unsubscribe();
resolve();
}
});
});// useGetBalances.fetchData, before getAccountBalances
await waitForRemoteConfig(store);
const useV2 = balancesV2Selector(store.getState());Same two lines at the three freighter/extension/src/popup/ducks/remoteConfig.ts Lines 177 to 181 in b97c3be With that in place the Account gate and the Two things the gate does not cover on its own, wherever it lives:
On the regression test: the negative assertion runs after one microtask tick, but the unfixed path needs several awaits (loadAccount → loadSettings → fetchBalances) before reaching freighter/extension/src/popup/views/__tests__/Account.test.tsx Lines 883 to 889 in b97c3be |
Every stubbed e2e test now waits on a real Amplitude Experiment requestMedium — likely to show up as slow or flaky e2e runs, especially on fork CI where egress is constrained. Merge blocker: this should land with the gate, since the gate is what puts the request on the critical path. TL;DR: The e2e suite stubs every external API the popup calls during login, but the Amplitude Experiment flag request is stubbed only in the maintenance-mode spec. Before this PR that did not matter because nothing waited on it. Now the Account screen blocks its first balances fetch until the flag request settles, so every other spec's login step makes a real request to Amplitude with the fake playwright deployment key and waits for it to answer or time out. The fix is a default Experiment stub in the shared stub helper so the response is immediate and local. Steps to reproduce:
Detailed explanation (for agents)Root cause: freighter/extension/e2e-tests/helpers/stubs.ts Lines 3371 to 3394 in b97c3be The only vardata route is the maintenance-mode helper, which is registered per test and only in freighter/extension/e2e-tests/helpers/stubs.ts Lines 3565 to 3586 in b97c3be Playwright sets freighter/extension/src/helpers/experimentClient.ts Lines 36 to 53 in b97c3be
freighter/extension/src/popup/views/Account/index.tsx Lines 96 to 106 in b97c3be Note the existing Suggested fix: add a default Experiment stub to export const stubExperimentDefaults = async (context: BrowserContext) => {
await context.route(AMPLITUDE_EXPERIMENT_VARDATA_ROUTE, async (route) => {
await route.fulfill({ json: {} });
});
};and call it next to This is needed wherever the gate ends up living. If the PR moves to seeding the store from the SDK's persisted variants instead of waiting, the request leaves the critical path and this becomes a hygiene fix rather than a blocker. |
Move the remote config wait from the Account view into the five places that read a flag to pick an endpoint (useGetBalances, useGetTokenPrices, AddToken), so the popup, fullscreen tabs, sidebar, and sign-transaction window all wait. Cap the Amplitude fetch at 1.5s, stub the Experiment request by default in e2e, and keep the price-history kill switch off in the test Wrapper. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Thanks for the review! Pushed 19edd8c with the changes: Gate moved into the hooks
e2e
Tests
Test helper
|
piyalbasu
left a comment
There was a problem hiding this comment.
Nice - this is looking good to me now
👷 Deploy request for freighter-docs pending review.Visit the deploys page to approve it
|
Resolve the conflict with #3064 in useGetTokenPrices. That change waits for the remote config flags before it reads use_token_prices_v2. This branch removes that flag, so the price hook does not wait for the flags. The balances hook still waits, because use_balances_v2 picks its endpoint. - Replace the new "waits for the flags" price test with a test that prices are fetched without a wait. - Remove use_token_prices_v2 from the new test fixtures. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01R8cp3zUn1aPP4zQrPvEFDQ
Fixes #3032
What
The account screen now waits for remote config flags from Amplitude to load before fetching balances in order to prevent one errant v1 call for users with v2 enabled. Updated test wrapper to default remote config to loaded since the account screen now waits on it.
Why
This bug would skew v1 vs v2 rollout comparison, since every v2 user would also be sending a v1 call. I went with the first proposed fix (waiting for the flags) instead of the seeding approach because this is similar to how mobile handles the issue, so this ensures parity between the two versions.
How I verified
I locally tested a fake slow Amplitude call with v2 enabled to ensure that the screen would wait and a v1 call would not appear. Regression testing also asserts that balances are not to be called until the flags are initialized.
Screenshots / video
N/A. Not a UI change.
Checklist