Skip to content

Commit a007d2e

Browse files
chore(runway): cherry-pick fix: cp-7.58.0 update swap asset balance on switch (#21631)
- fix: cp-7.58.0 update swap asset balance on switch (#21625) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix an issue where asset balances were not recalculated after users switch assets on swaps and added appropriate unit tests <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: null ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Ensure cached balance updates when token address changes and add unit tests covering memoization and balance parsing edge cases. > > - **Bridge > useLatestBalance**: > - Include `token.address` in `useMemo` deps for `cachedBalance` to refresh cache on token switch (with explanatory comments). > - **Tests** (`useLatestBalance.test.tsx`): > - Add suite for cached balance memoization and parsing: > - Validates memoization when deps unchanged and refresh on address change. > - Handles missing `decimals`, zero balance, very large/small balances. > - Confirms behavior when `balance` present but `decimals` missing and general parsing robustness. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d770d6c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [9e43877](9e43877) Co-authored-by: George Gkasdrogkas <[email protected]>
1 parent 2b39326 commit a007d2e

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed

app/components/UI/Bridge/hooks/useLatestBalance/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ export const useLatestBalance = (token: {
176176
}
177177

178178
return { displayBalance, atomicBalance };
179-
}, [token.balance, token.decimals]);
179+
// Include token.address in the dependency array to ensure
180+
// that the cached balance is updated when the token address changes.
181+
// eslint-disable-next-line react-hooks/exhaustive-deps
182+
}, [token.balance, token.decimals, token.address]);
180183

181184
if (!token.address || !token.decimals) {
182185
return undefined;

app/components/UI/Bridge/hooks/useLatestBalance/useLatestBalance.test.tsx

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,4 +526,139 @@ describe('useLatestBalance', () => {
526526
});
527527
});
528528
});
529+
530+
describe('cachedBalance memoization', () => {
531+
it('returns undefined when decimals is missing during balance parsing', () => {
532+
const { result } = renderHookWithProvider(
533+
() =>
534+
useLatestBalance({
535+
address: '0x1234567890123456789012345678901234567890',
536+
decimals: undefined,
537+
chainId: '0x1' as Hex,
538+
balance: '10.0',
539+
}),
540+
{ state: initialState },
541+
);
542+
543+
expect(result.current).toBeUndefined();
544+
});
545+
546+
it('memoizes cached balance when dependencies do not change', () => {
547+
const { result, rerender } = renderHookWithProvider(
548+
() =>
549+
useLatestBalance({
550+
address: '0x1234567890123456789012345678901234567890',
551+
decimals: 18,
552+
chainId: '0x1' as Hex,
553+
balance: '5.5',
554+
}),
555+
{ state: initialState },
556+
);
557+
558+
const firstResult = result.current;
559+
rerender({ state: initialState });
560+
561+
expect(result.current).toBe(firstResult);
562+
});
563+
564+
it('returns cached balance when token address changes', () => {
565+
const firstToken = {
566+
address: '0x1234567890123456789012345678901234567890',
567+
decimals: 18,
568+
chainId: '0x1' as Hex,
569+
balance: '5.5',
570+
};
571+
572+
const { result: firstResult } = renderHookWithProvider(
573+
() => useLatestBalance(firstToken),
574+
{ state: initialState },
575+
);
576+
577+
expect(firstResult.current?.displayBalance).toBe('5.5');
578+
579+
const secondToken = {
580+
address: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
581+
decimals: 18,
582+
chainId: '0x1' as Hex,
583+
balance: '10.0',
584+
};
585+
586+
const { result: secondResult } = renderHookWithProvider(
587+
() => useLatestBalance(secondToken),
588+
{ state: initialState },
589+
);
590+
591+
expect(secondResult.current?.displayBalance).toBe('10.0');
592+
expect(secondResult.current).not.toBe(firstResult.current);
593+
});
594+
595+
it('returns undefined when balance is provided but decimals is missing', () => {
596+
const { result } = renderHookWithProvider(
597+
() =>
598+
useLatestBalance({
599+
address: '0x1234567890123456789012345678901234567890',
600+
decimals: undefined,
601+
chainId: '0x1' as Hex,
602+
balance: '100.0',
603+
}),
604+
{ state: initialState },
605+
);
606+
607+
expect(result.current).toBeUndefined();
608+
});
609+
610+
it('handles zero balance correctly', () => {
611+
const { result } = renderHookWithProvider(
612+
() =>
613+
useLatestBalance({
614+
address: '0x1234567890123456789012345678901234567890',
615+
decimals: 18,
616+
chainId: '0x1' as Hex,
617+
balance: '0',
618+
}),
619+
{ state: initialState },
620+
);
621+
622+
expect(result.current).toEqual({
623+
displayBalance: '0',
624+
atomicBalance: BigNumber.from('0'),
625+
});
626+
});
627+
628+
it('handles very large balance values', () => {
629+
const { result } = renderHookWithProvider(
630+
() =>
631+
useLatestBalance({
632+
address: '0x1234567890123456789012345678901234567890',
633+
decimals: 18,
634+
chainId: '0x1' as Hex,
635+
balance: '999999999999999999999999.123456789012345678',
636+
}),
637+
{ state: initialState },
638+
);
639+
640+
expect(result.current?.displayBalance).toBe(
641+
'999999999999999999999999.123456789012345678',
642+
);
643+
expect(result.current?.atomicBalance).toBeDefined();
644+
});
645+
646+
it('handles very small decimal balance values', () => {
647+
const { result } = renderHookWithProvider(
648+
() =>
649+
useLatestBalance({
650+
address: '0x1234567890123456789012345678901234567890',
651+
decimals: 18,
652+
chainId: '0x1' as Hex,
653+
balance: '0.000000000000000001',
654+
}),
655+
{ state: initialState },
656+
);
657+
658+
expect(result.current).toEqual({
659+
displayBalance: '0.000000000000000001',
660+
atomicBalance: BigNumber.from('1'),
661+
});
662+
});
663+
});
529664
});

0 commit comments

Comments
 (0)