@@ -955,7 +955,8 @@ func AddLane(
955955
956956 if fromFamily == chainsel .FamilyAptos || toFamily == chainsel .FamilyAptos {
957957 // lanes.ConnectChains configures both legs of the lane, including the non-Aptos
958- // peer, so no additional per-family src/dest changesets are needed.
958+ // peer. Some mixed-family adapter combinations can omit the EVM router half,
959+ // so reconcile it after ConnectChains has had the first chance to configure.
959960 changesets = append (changesets , AddLaneAptosChangesets (t , from , to , isTestRouter , gasPrices , tokenPrices )... )
960961 } else {
961962 switch fromFamily {
@@ -981,9 +982,126 @@ func AddLane(
981982 if err != nil {
982983 return err
983984 }
985+
986+ if fromFamily == chainsel .FamilyAptos || toFamily == chainsel .FamilyAptos {
987+ if err := ensureEVMRouterLaneConfig (t , e , state , from , to , fromFamily , toFamily , isTestRouter , gasPrices , tokenPrices , fqCfg ); err != nil {
988+ return err
989+ }
990+ }
991+
984992 return nil
985993}
986994
995+ func ensureEVMRouterLaneConfig (
996+ t * testing.T ,
997+ e * DeployedEnv ,
998+ state stateview.CCIPOnChainState ,
999+ from , to uint64 ,
1000+ fromFamily , toFamily string ,
1001+ isTestRouter bool ,
1002+ gasPrices map [uint64 ]* big.Int ,
1003+ tokenPrices map [string ]* big.Int ,
1004+ fqCfg fee_quoter.FeeQuoterDestChainConfig ,
1005+ ) error {
1006+ changesets := make ([]commoncs.ConfiguredChangeSet , 0 , 6 )
1007+
1008+ if fromFamily == chainsel .FamilyEVM && toFamily == chainsel .FamilyAptos {
1009+ wired , err := evmSourceRouterWired (e , state , from , to , isTestRouter )
1010+ if err != nil {
1011+ return err
1012+ }
1013+ if ! wired {
1014+ evmTokenPrices := make (map [common.Address ]* big.Int , len (tokenPrices ))
1015+ for address , price := range tokenPrices {
1016+ evmTokenPrices [common .HexToAddress (address )] = price
1017+ }
1018+ changesets = append (changesets , AddEVMSrcChangesets (from , to , isTestRouter , gasPrices , evmTokenPrices , fqCfg )... )
1019+ }
1020+ }
1021+
1022+ if fromFamily == chainsel .FamilyAptos && toFamily == chainsel .FamilyEVM {
1023+ wired , err := evmDestRouterWired (e , state , to , from , isTestRouter )
1024+ if err != nil {
1025+ return err
1026+ }
1027+ if ! wired {
1028+ changesets = append (changesets , AddEVMDestChangesets (e , to , from , isTestRouter )... )
1029+ }
1030+ }
1031+
1032+ if len (changesets ) > 0 {
1033+ var err error
1034+ e .Env , _ , err = commoncs .ApplyChangesets (t , e .Env , changesets )
1035+ if err != nil {
1036+ return err
1037+ }
1038+ }
1039+
1040+ if fromFamily == chainsel .FamilyEVM && toFamily == chainsel .FamilyAptos {
1041+ wired , err := evmSourceRouterWired (e , state , from , to , isTestRouter )
1042+ if err != nil {
1043+ return err
1044+ }
1045+ if ! wired {
1046+ return fmt .Errorf ("EVM source router on chain %d missing on-ramp for destination %d" , from , to )
1047+ }
1048+ }
1049+
1050+ if fromFamily == chainsel .FamilyAptos && toFamily == chainsel .FamilyEVM {
1051+ wired , err := evmDestRouterWired (e , state , to , from , isTestRouter )
1052+ if err != nil {
1053+ return err
1054+ }
1055+ if ! wired {
1056+ return fmt .Errorf ("EVM destination router on chain %d missing off-ramp for source %d" , to , from )
1057+ }
1058+ }
1059+
1060+ return nil
1061+ }
1062+
1063+ func evmSourceRouterWired (e * DeployedEnv , state stateview.CCIPOnChainState , evmSource , remoteDest uint64 , isTestRouter bool ) (bool , error ) {
1064+ chainState := state .MustGetEVMChainState (evmSource )
1065+ routerContract := chainState .Router
1066+ if isTestRouter {
1067+ routerContract = chainState .TestRouter
1068+ }
1069+ if routerContract == nil {
1070+ return false , fmt .Errorf ("router not found for EVM source chain %d" , evmSource )
1071+ }
1072+ if chainState .OnRamp == nil {
1073+ return false , fmt .Errorf ("on-ramp not found for EVM source chain %d" , evmSource )
1074+ }
1075+
1076+ onRamp , err := routerContract .GetOnRamp (& bind.CallOpts {Context : e .Env .GetContext ()}, remoteDest )
1077+ if err != nil {
1078+ return false , fmt .Errorf ("get on-ramp for EVM source chain %d and destination %d: %w" , evmSource , remoteDest , err )
1079+ }
1080+
1081+ return onRamp == chainState .OnRamp .Address (), nil
1082+ }
1083+
1084+ func evmDestRouterWired (e * DeployedEnv , state stateview.CCIPOnChainState , evmDest , remoteSource uint64 , isTestRouter bool ) (bool , error ) {
1085+ chainState := state .MustGetEVMChainState (evmDest )
1086+ routerContract := chainState .Router
1087+ if isTestRouter {
1088+ routerContract = chainState .TestRouter
1089+ }
1090+ if routerContract == nil {
1091+ return false , fmt .Errorf ("router not found for EVM destination chain %d" , evmDest )
1092+ }
1093+ if chainState .OffRamp == nil {
1094+ return false , fmt .Errorf ("off-ramp not found for EVM destination chain %d" , evmDest )
1095+ }
1096+
1097+ isOffRamp , err := routerContract .IsOffRamp (& bind.CallOpts {Context : e .Env .GetContext ()}, remoteSource , chainState .OffRamp .Address ())
1098+ if err != nil {
1099+ return false , fmt .Errorf ("check off-ramp for EVM destination chain %d and source %d: %w" , evmDest , remoteSource , err )
1100+ }
1101+
1102+ return isOffRamp , nil
1103+ }
1104+
9871105func AddLaneSolanaChangesetsV0_1_0 (e * DeployedEnv , solChainSelector , remoteChainSelector uint64 , remoteFamily string ) []commoncs.ConfiguredChangeSet {
9881106 var chainFamilySelector [4 ]uint8
9891107 switch remoteFamily {
@@ -1181,7 +1299,7 @@ func AddLaneAptosChangesets(t *testing.T, srcChainSelector, destChainSelector ui
11811299 Selector : selector ,
11821300 GasPrice : gasPrices [selector ],
11831301 }
1184- if family == chainsel . FamilyAptos {
1302+ if selector == srcChainSelector {
11851303 definition .TokenPrices = tokenPrices
11861304 }
11871305 return definition
0 commit comments