pub async fn load_settlement_layer_contracts(
    sl_client: &dyn EthInterface,
    bridgehub_address: Address,
    l2_chain_id: L2ChainId,
    multicall3: Option<Address>,
) -> anyhow::Result<Option<SettlementLayerSpecificContracts>> {
    let diamond_proxy =
        get_diamond_proxy_contract(sl_client, bridgehub_address, l2_chain_id).await?;

    if diamond_proxy.is_zero() {
        return Ok(None);
    }

    if !ProtocolSemanticVersion::try_from_packed(
        get_protocol_version(diamond_proxy, &hyperchain_contract(), sl_client).await?,
    )
    .map_err(|err| anyhow::format_err!("Failed to unpack semver: {err}"))?
    .minor
    .is_post_fflonk()
    {
        return Ok(None);
    }

    let ctm_address =
        CallFunctionArgs::new("chainTypeManager", Token::Uint(l2_chain_id.as_u64().into()))
            .for_contract(bridgehub_address, &bridgehub_contract())
            .call(sl_client)
            .await?;

    let validator_timelock_addr = CallFunctionArgs::new("validatorTimelock", ())
        .for_contract(ctm_address, &state_transition_manager_contract())
        .call(sl_client)
        .await?;

    Ok(Some(SettlementLayerSpecificContracts {
        ecosystem_contracts: EcosystemCommonContracts {
            bridgehub_proxy_addr: Some(bridgehub_address),
            state_transition_proxy_addr: Some(ctm_address),
            validator_timelock_addr: Some(validator_timelock_addr),
            multicall3,
        },
        chain_contracts_config: ChainContracts {
            diamond_proxy_addr: diamond_proxy,
        },
    }))
}
Load contacts specific for each settlement layer, using bridgehub contract
core/lib/eth_client/src/contracts_loader.rs