@@ -9,7 +9,7 @@ import { useLatestBalance } from '.';
99import { getProviderByChainId } from '../../../../../util/notifications/methods/common' ;
1010import { BigNumber , constants } from 'ethers' ;
1111import { waitFor } from '@testing-library/react-native' ;
12- import { Hex } from '@metamask/utils' ;
12+ import { Hex , type CaipAssetId } from '@metamask/utils' ;
1313import { SolScope } from '@metamask/keyring-api' ;
1414import { cloneDeep } from 'lodash' ;
1515
@@ -366,12 +366,13 @@ describe('useLatestBalance', () => {
366366 { state : initialState } ,
367367 ) ;
368368
369- // Should not call EVM provider methods when chainId is CAIP (Solana)
370- expect ( getProviderByChainId ) . not . toHaveBeenCalled ( ) ;
371- expect ( mockProvider . getBalance ) . not . toHaveBeenCalled ( ) ;
372- expect ( result . current ) . toEqual ( {
373- displayBalance : '50.0' ,
374- atomicBalance : BigNumber . from ( '50000000000000000000' ) ,
369+ // When EVM address is used with non-EVM chainId, it tries to find it in nonEvmTokens
370+ // Since it's not found, it sets balance to 0
371+ await waitFor ( ( ) => {
372+ expect ( result . current ) . toEqual ( {
373+ displayBalance : '0' ,
374+ atomicBalance : BigNumber . from ( '0' ) ,
375+ } ) ;
375376 } ) ;
376377 } ) ;
377378
@@ -661,4 +662,233 @@ describe('useLatestBalance', () => {
661662 } ) ;
662663 } ) ;
663664 } ) ;
665+
666+ describe ( 'balance reset when token address changes' , ( ) => {
667+ it ( 'resets balance to undefined when token address changes' , async ( ) => {
668+ let tokenAddress = '0x1234567890123456789012345678901234567890' ;
669+
670+ const { result, rerender } = renderHookWithProvider (
671+ ( ) =>
672+ useLatestBalance ( {
673+ address : tokenAddress ,
674+ decimals : 6 ,
675+ chainId : '0x1' as Hex ,
676+ balance : '10.0' ,
677+ } ) ,
678+ { state : initialState } ,
679+ ) ;
680+
681+ await waitFor ( ( ) => {
682+ expect ( result . current ?. displayBalance ) . toBe ( '1.0' ) ;
683+ } ) ;
684+
685+ tokenAddress = '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ;
686+ rerender ( { state : initialState } ) ;
687+
688+ expect ( result . current ?. displayBalance ) . toBe ( '10.0' ) ;
689+ } ) ;
690+
691+ it ( 'returns cached balance immediately after token address changes' , async ( ) => {
692+ let tokenAddress = '0x1111111111111111111111111111111111111111' ;
693+ let tokenBalance = '100.5' ;
694+
695+ const { result, rerender } = renderHookWithProvider (
696+ ( ) =>
697+ useLatestBalance ( {
698+ address : tokenAddress ,
699+ decimals : 6 ,
700+ chainId : '0x1' as Hex ,
701+ balance : tokenBalance ,
702+ } ) ,
703+ { state : initialState } ,
704+ ) ;
705+
706+ expect ( result . current ?. displayBalance ) . toBe ( '100.5' ) ;
707+
708+ tokenAddress = '0x2222222222222222222222222222222222222222' ;
709+ tokenBalance = '250.75' ;
710+ rerender ( { state : initialState } ) ;
711+
712+ expect ( result . current ?. displayBalance ) . toBe ( '250.75' ) ;
713+ expect ( result . current ?. atomicBalance ) . toEqual (
714+ BigNumber . from ( '250750000' ) ,
715+ ) ;
716+ } ) ;
717+
718+ it ( 'fetches new balance after token address changes' , async ( ) => {
719+ let tokenAddress = constants . AddressZero ;
720+
721+ const { result, rerender } = renderHookWithProvider (
722+ ( ) =>
723+ useLatestBalance ( {
724+ address : tokenAddress ,
725+ decimals : 18 ,
726+ chainId : '0x1' as Hex ,
727+ } ) ,
728+ { state : initialState } ,
729+ ) ;
730+
731+ await waitFor ( ( ) => {
732+ expect ( result . current ?. displayBalance ) . toBe ( '1.0' ) ;
733+ } ) ;
734+
735+ jest . clearAllMocks ( ) ;
736+
737+ tokenAddress = '0x9999999999999999999999999999999999999999' ;
738+ rerender ( { state : initialState } ) ;
739+
740+ await waitFor ( ( ) => {
741+ expect ( getProviderByChainId ) . toHaveBeenCalled ( ) ;
742+ } ) ;
743+ } ) ;
744+
745+ it ( 'resets balance state before fetching new balance for different token' , async ( ) => {
746+ let tokenAddress = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ;
747+ let tokenBalance = '50.0' ;
748+
749+ const { result, rerender } = renderHookWithProvider (
750+ ( ) =>
751+ useLatestBalance ( {
752+ address : tokenAddress ,
753+ decimals : 6 ,
754+ chainId : '0x1' as Hex ,
755+ balance : tokenBalance ,
756+ } ) ,
757+ { state : initialState } ,
758+ ) ;
759+
760+ await waitFor ( ( ) => {
761+ expect ( result . current ?. displayBalance ) . toBe ( '1.0' ) ;
762+ } ) ;
763+
764+ const previousBalance = result . current ;
765+
766+ tokenAddress = '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ;
767+ tokenBalance = '75.0' ;
768+ rerender ( { state : initialState } ) ;
769+
770+ expect ( result . current ?. displayBalance ) . toBe ( '75.0' ) ;
771+ expect ( result . current ) . not . toBe ( previousBalance ) ;
772+ } ) ;
773+ } ) ;
774+
775+ describe ( 'non-EVM token not found in balance controller' , ( ) => {
776+ it ( 'sets balance to 0 when Solana token is not found in nonEvmTokens' , async ( ) => {
777+ const state = cloneDeep ( initialState ) ;
778+ state . engine . backgroundState . AccountsController . internalAccounts . selectedAccount =
779+ solanaAccountId ;
780+
781+ const { result } = renderHookWithProvider (
782+ ( ) =>
783+ useLatestBalance ( {
784+ chainId : SolScope . Mainnet ,
785+ address : 'TokenNotInBalanceController123' ,
786+ decimals : 9 ,
787+ } ) ,
788+ { state } ,
789+ ) ;
790+
791+ await waitFor ( ( ) => {
792+ expect ( result . current ) . toEqual ( {
793+ displayBalance : '0' ,
794+ atomicBalance : BigNumber . from ( '0' ) ,
795+ } ) ;
796+ } ) ;
797+ } ) ;
798+
799+ it ( 'sets balance to 0 when Solana token is not found in nonEvmTokens list' , async ( ) => {
800+ const state = cloneDeep ( initialState ) ;
801+ state . engine . backgroundState . AccountsController . internalAccounts . selectedAccount =
802+ solanaAccountId ;
803+
804+ const nonExistentTokenAddress =
805+ 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:NonExistentToken123' as CaipAssetId ;
806+
807+ const { result } = renderHookWithProvider (
808+ ( ) =>
809+ useLatestBalance ( {
810+ chainId : SolScope . Mainnet ,
811+ address : nonExistentTokenAddress ,
812+ decimals : 9 ,
813+ } ) ,
814+ { state } ,
815+ ) ;
816+
817+ await waitFor ( ( ) => {
818+ expect ( result . current ) . toEqual ( {
819+ displayBalance : '0' ,
820+ atomicBalance : BigNumber . from ( '0' ) ,
821+ } ) ;
822+ } ) ;
823+ } ) ;
824+
825+ it ( 'sets balance to 0 when non-EVM token has undefined balance in controller' , async ( ) => {
826+ const state = cloneDeep ( initialState ) ;
827+ state . engine . backgroundState . AccountsController . internalAccounts . selectedAccount =
828+ solanaAccountId ;
829+
830+ const { result } = renderHookWithProvider (
831+ ( ) =>
832+ useLatestBalance ( {
833+ chainId : SolScope . Mainnet ,
834+ address : 'UnknownSolanaToken456' ,
835+ decimals : 6 ,
836+ } ) ,
837+ { state } ,
838+ ) ;
839+
840+ await waitFor ( ( ) => {
841+ expect ( result . current ) . toEqual ( {
842+ displayBalance : '0' ,
843+ atomicBalance : BigNumber . from ( '0' ) ,
844+ } ) ;
845+ } ) ;
846+ } ) ;
847+
848+ it ( 'returns valid balance when Solana token is found in nonEvmTokens' , async ( ) => {
849+ const state = cloneDeep ( initialState ) ;
850+ state . engine . backgroundState . AccountsController . internalAccounts . selectedAccount =
851+ solanaAccountId ;
852+
853+ const { result } = renderHookWithProvider (
854+ ( ) =>
855+ useLatestBalance ( {
856+ chainId : SolScope . Mainnet ,
857+ address : solanaToken2Address ,
858+ decimals : 6 ,
859+ } ) ,
860+ { state } ,
861+ ) ;
862+
863+ await waitFor ( ( ) => {
864+ expect ( result . current ) . toEqual ( {
865+ displayBalance : '20000.456' ,
866+ atomicBalance : BigNumber . from ( '20000456000' ) ,
867+ } ) ;
868+ } ) ;
869+ } ) ;
870+
871+ it ( 'handles empty balance string from controller by setting to 0' , async ( ) => {
872+ const state = cloneDeep ( initialState ) ;
873+ state . engine . backgroundState . AccountsController . internalAccounts . selectedAccount =
874+ solanaAccountId ;
875+
876+ const { result } = renderHookWithProvider (
877+ ( ) =>
878+ useLatestBalance ( {
879+ chainId : SolScope . Mainnet ,
880+ address : 'TokenWithEmptyBalance789' ,
881+ decimals : 9 ,
882+ } ) ,
883+ { state } ,
884+ ) ;
885+
886+ await waitFor ( ( ) => {
887+ expect ( result . current ) . toEqual ( {
888+ displayBalance : '0' ,
889+ atomicBalance : BigNumber . from ( '0' ) ,
890+ } ) ;
891+ } ) ;
892+ } ) ;
893+ } ) ;
664894} ) ;
0 commit comments