@@ -17,6 +17,7 @@ import reducer, {
1717 selectIsBridgeEnabledDest ,
1818 selectIsSwapsLive ,
1919 selectDestChainRanking ,
20+ selectSourceChainRanking ,
2021} from '.' ;
2122import {
2223 BridgeToken ,
@@ -531,25 +532,28 @@ describe('bridge slice', () => {
531532 } ) ;
532533
533534 it ( 'returns false when bridge is not enabled as source for the chain' , ( ) => {
534- const mockState = cloneDeep ( mockRootState ) as unknown as RootState ;
535- // @ts -expect-error - Mock state has correct structure at runtime
536- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
537- mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . chains [
538- 'eip155:1'
539- ] . isActiveSrc = false ;
535+ const mockState = cloneDeep ( mockRootState ) ;
536+ // Remove chain from chainRanking to disable it (chainRanking presence = enabled)
537+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
538+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking . filter (
539+ ( chain ) => chain . chainId !== 'eip155:1' ,
540+ ) ;
540541
541- const result = selectIsBridgeEnabledSource ( mockState , '0x1' ) ;
542+ const result = selectIsBridgeEnabledSource (
543+ mockState as unknown as RootState ,
544+ '0x1' ,
545+ ) ;
542546
543547 expect ( result ) . toBe ( false ) ;
544548 } ) ;
545549
546- it ( 'returns undefined when chain is not in bridge config' , ( ) => {
550+ it ( 'returns false when chain is not in bridge config' , ( ) => {
547551 const result = selectIsBridgeEnabledSource (
548552 mockRootState as unknown as RootState ,
549553 '0x999' as Hex ,
550554 ) ;
551555
552- expect ( result ) . toBeUndefined ( ) ;
556+ expect ( result ) . toBe ( false ) ;
553557 } ) ;
554558 } ) ;
555559
@@ -597,6 +601,77 @@ describe('bridge slice', () => {
597601 } ) ;
598602 } ) ;
599603
604+ describe ( 'selectSourceChainRanking' , ( ) => {
605+ it ( 'returns only supported and user-configured chains' , ( ) => {
606+ const result = selectSourceChainRanking (
607+ mockRootState as unknown as RootState ,
608+ ) ;
609+
610+ // Should return chains that are both in ALLOWED_BRIDGE_CHAIN_IDS
611+ // and in the user's configured networks
612+ expect ( Array . isArray ( result ) ) . toBe ( true ) ;
613+ expect ( result . length ) . toBeGreaterThan ( 0 ) ;
614+
615+ // Ethereum (0x1) is allowed and configured in the mock state
616+ expect ( result . some ( ( chain ) => chain . chainId === 'eip155:1' ) ) . toBe ( true ) ;
617+ } ) ;
618+
619+ it ( 'filters out unsupported EVM chains from chainRanking' , ( ) => {
620+ const mockState = cloneDeep ( mockRootState ) ;
621+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
622+ [
623+ ...mockState . engine . backgroundState . RemoteFeatureFlagController
624+ . remoteFeatureFlags . bridgeConfigV2 . chainRanking ,
625+ { chainId : 'eip155:99999' , name : 'Unsupported EVM Chain' } ,
626+ ] ;
627+
628+ const result = selectSourceChainRanking (
629+ mockState as unknown as RootState ,
630+ ) ;
631+
632+ expect ( result . some ( ( chain ) => chain . chainId === 'eip155:99999' ) ) . toBe (
633+ false ,
634+ ) ;
635+ } ) ;
636+
637+ it ( 'filters out unsupported non-EVM chains from chainRanking' , ( ) => {
638+ const mockState = cloneDeep ( mockRootState ) ;
639+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
640+ [
641+ ...mockState . engine . backgroundState . RemoteFeatureFlagController
642+ . remoteFeatureFlags . bridgeConfigV2 . chainRanking ,
643+ { chainId : 'cosmos:cosmoshub-4' , name : 'Unsupported Cosmos Chain' } ,
644+ ] ;
645+
646+ const result = selectSourceChainRanking (
647+ mockState as unknown as RootState ,
648+ ) ;
649+
650+ expect (
651+ result . some ( ( chain ) => chain . chainId === 'cosmos:cosmoshub-4' ) ,
652+ ) . toBe ( false ) ;
653+ } ) ;
654+
655+ it ( 'filters out chains not in user-configured networks' , ( ) => {
656+ const result = selectSourceChainRanking (
657+ mockRootState as unknown as RootState ,
658+ ) ;
659+
660+ // Optimism (0xa) is in chainRanking and ALLOWED_BRIDGE_CHAIN_IDS
661+ // AND in the mock user's configured networks
662+ const hasOptimism = result . some ( ( chain ) => chain . chainId === 'eip155:10' ) ;
663+ expect ( hasOptimism ) . toBe ( true ) ;
664+
665+ // Verify no chains appear that aren't in the user's configured networks
666+ // The user only has Ethereum (0x1) and Optimism (0xa) configured as EVM networks
667+ result . forEach ( ( chain ) => {
668+ if ( chain . chainId . startsWith ( 'eip155:' ) ) {
669+ expect ( [ 'eip155:1' , 'eip155:10' ] ) . toContain ( chain . chainId ) ;
670+ }
671+ } ) ;
672+ } ) ;
673+ } ) ;
674+
600675 describe ( 'selectDestChainRanking' , ( ) => {
601676 it ( 'returns chainRanking from feature flags' , ( ) => {
602677 const result = selectDestChainRanking (
@@ -622,16 +697,75 @@ describe('bridge slice', () => {
622697 expect ( hasEthereum ) . toBe ( true ) ;
623698 } ) ;
624699
625- it ( 'returns all chains without filtering (unlike selectSourceChainRanking) ' , ( ) => {
700+ it ( 'returns all supported chains without filtering by user-configured networks ' , ( ) => {
626701 const result = selectDestChainRanking (
627702 mockRootState as unknown as RootState ,
628703 ) ;
629704
630- // selectDestChainRanking should return all chains from feature flags
705+ // selectDestChainRanking should return all supported chains from feature flags
631706 // This is the key difference from selectSourceChainRanking which filters
632707 // by user-configured networks
633708 expect ( result . length ) . toBeGreaterThan ( 0 ) ;
634709 } ) ;
710+
711+ it ( 'filters out unsupported EVM chains not in ALLOWED_BRIDGE_CHAIN_IDS' , ( ) => {
712+ const mockState = cloneDeep ( mockRootState ) ;
713+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
714+ [
715+ ...mockState . engine . backgroundState . RemoteFeatureFlagController
716+ . remoteFeatureFlags . bridgeConfigV2 . chainRanking ,
717+ { chainId : 'eip155:99999' , name : 'Unsupported Future Chain' } ,
718+ ] ;
719+
720+ const result = selectDestChainRanking ( mockState as unknown as RootState ) ;
721+
722+ expect ( result . some ( ( chain ) => chain . chainId === 'eip155:99999' ) ) . toBe (
723+ false ,
724+ ) ;
725+ expect ( result . some ( ( chain ) => chain . chainId === 'eip155:1' ) ) . toBe ( true ) ;
726+ } ) ;
727+
728+ it ( 'filters out unsupported non-EVM chains not in ALLOWED_BRIDGE_CHAIN_IDS' , ( ) => {
729+ const mockState = cloneDeep ( mockRootState ) ;
730+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
731+ [
732+ ...mockState . engine . backgroundState . RemoteFeatureFlagController
733+ . remoteFeatureFlags . bridgeConfigV2 . chainRanking ,
734+ { chainId : 'cosmos:cosmoshub-4' , name : 'Unsupported Cosmos Chain' } ,
735+ ] ;
736+
737+ const result = selectDestChainRanking ( mockState as unknown as RootState ) ;
738+
739+ expect (
740+ result . some ( ( chain ) => chain . chainId === 'cosmos:cosmoshub-4' ) ,
741+ ) . toBe ( false ) ;
742+ expect (
743+ result . some (
744+ ( chain ) =>
745+ chain . chainId === 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp' ,
746+ ) ,
747+ ) . toBe ( true ) ;
748+ } ) ;
749+ } ) ;
750+
751+ describe ( 'selectIsBridgeEnabledSource - ALLOWED_BRIDGE_CHAIN_IDS filtering' , ( ) => {
752+ it ( 'returns false for a chain in chainRanking but not in ALLOWED_BRIDGE_CHAIN_IDS' , ( ) => {
753+ const mockState = cloneDeep ( mockRootState ) ;
754+ // Add an unsupported chain to chainRanking
755+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
756+ [
757+ ...mockState . engine . backgroundState . RemoteFeatureFlagController
758+ . remoteFeatureFlags . bridgeConfigV2 . chainRanking ,
759+ { chainId : 'eip155:99999' , name : 'Unsupported Future Chain' } ,
760+ ] ;
761+
762+ const result = selectIsBridgeEnabledSource (
763+ mockState as unknown as RootState ,
764+ '0x1869F' as Hex , // hex for 99999
765+ ) ;
766+
767+ expect ( result ) . toBe ( false ) ;
768+ } ) ;
635769 } ) ;
636770
637771 describe ( 'selectIsSwapsLive' , ( ) => {
@@ -671,19 +805,24 @@ describe('bridge slice', () => {
671805 } ) ;
672806
673807 it ( 'returns false when bridge is disabled for both source and destination' , ( ) => {
674- const mockState = cloneDeep ( mockRootState ) as unknown as RootState ;
675- // @ts -expect-error - Mock state has correct structure at runtime
676- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
677- mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . chains [
678- 'eip155:1'
679- ] . isActiveSrc = false ;
680- // @ts -expect-error - Mock state has correct structure at runtime
808+ const mockState = cloneDeep ( mockRootState ) ;
809+ // Remove chain from chainRanking to disable source (chainRanking presence = enabled)
810+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
811+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking . filter (
812+ ( chain ) => chain . chainId !== 'eip155:1' ,
813+ ) ;
814+ // Disable destination via chains config
681815 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
682- mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . chains [
816+ (
817+ mockState as any
818+ ) . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . chains [
683819 'eip155:1'
684820 ] . isActiveDest = false ;
685821
686- const result = selectIsSwapsLive ( mockState , '0x1' ) ;
822+ const result = selectIsSwapsLive (
823+ mockState as unknown as RootState ,
824+ '0x1' ,
825+ ) ;
687826
688827 expect ( result ) . toBe ( false ) ;
689828 } ) ;
@@ -697,13 +836,24 @@ describe('bridge slice', () => {
697836 expect ( result ) . toBeUndefined ( ) ;
698837 } ) ;
699838
700- it ( 'returns false when support flag is disabled' , ( ) => {
701- const mockState = cloneDeep ( mockRootState ) as unknown as RootState ;
702- // @ts -expect-error - Mock state has correct structure at runtime
839+ it ( 'returns false when support flag is disabled and source is not in chainRanking' , ( ) => {
840+ const mockState = cloneDeep ( mockRootState ) ;
841+ // Remove chain from chainRanking to disable source
842+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking =
843+ mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 . chainRanking . filter (
844+ ( chain ) => chain . chainId !== 'eip155:1' ,
845+ ) ;
846+ // Disable destination via support flag
703847 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
704- mockState . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . support = false ;
848+ (
849+ mockState as any
850+ ) . engine . backgroundState . RemoteFeatureFlagController . remoteFeatureFlags . bridgeConfigV2 ! . support =
851+ false ;
705852
706- const result = selectIsSwapsLive ( mockState , '0x1' ) ;
853+ const result = selectIsSwapsLive (
854+ mockState as unknown as RootState ,
855+ '0x1' ,
856+ ) ;
707857
708858 expect ( result ) . toBe ( false ) ;
709859 } ) ;
0 commit comments