Add CCIP Networks for Cross-Chain Token Tutorials (Foundry)

Guide Versions

This guide is available in multiple versions. Choose the one that matches your needs.

The smart-contract-examples repository includes default configurations for common CCIP testnet networks. This guide shows how to add support for additional networks.

The configuration file in the Foundry version of the repository stores network-specific information such as:

  • Chain selectors (unique CCIP identifiers)
  • Router addresses
  • RMN Proxy addresses
  • Token Admin Registry addresses
  • Registry Module Owner Custom addresses
  • LINK token addresses
  • Block confirmations
  • Native currency symbols

These values vary by network and must be accurate for your CCIP transactions to work correctly. If you want to use additional networks (e.g., Optimism Sepolia, BNB Chain Testnet, or mainnet networks) supported by CCIP, you'll need to update the configuration file following this guide.

Find Network Configuration Values

All CCIP-supported networks and their configuration details are available in the CCIP Directory:

The CCIP Directory provides:

  • Chain selectors (unique CCIP identifiers)
  • Router contract addresses
  • RMN Proxy addresses
  • Token Admin Registry addresses
  • Registry Module Owner Custom addresses
  • LINK token addresses

Add RPC_URL Environment Variable

To add support for additional networks, you need to configure the RPC_URL_<NEW_NETWORK_NAME> environment variable in your .env file. This variable should point to the RPC endpoint of the network you want to add.

  1. Open the .env file in the root of smart-contract-examples/ccip/cct/foundry.

  2. Add a new line for the RPC_URL_<NEW_NETWORK_NAME> variable:

    RPC_URL_=https://your-new-network-rpc-url
    

    You can obtain an RPC URL by signing up for a personal endpoint from Alchemy, Infura, or another node provider service.

  3. Save the file, then load the environment variables into the terminal session where you will run the commands:

    source .env
    

Update Configuration File

File location: smart-contract-examples/ccip/cct/foundry/script/HelperConfig.s.sol

Example structure:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {Script} from "forge-std/Script.sol";

contract HelperConfig is Script {
    // Rest of the code...

    constructor() {

        // Rest of the existing networks...

        else if (block.chainid == 43113) {
            activeNetworkConfig = getAvalancheFujiConfig();
        }

        // Rest of the existing networks...

        else {
            revert("Unsupported network");
        }
    }

    function getAvalancheFujiConfig() public pure returns (NetworkConfig memory) {
        NetworkConfig memory avalancheFujiConfig = NetworkConfig({
            chainSelector: 14767482510784806043,
            router: 0xF694E193200268f9a4868e4Aa017A0118C9a8177,
            rmnProxy: 0xAc8CFc3762a979628334a0E4C1026244498E821b,
            tokenAdminRegistry: 0xA92053a4a3922084d992fD2835bdBa4caC6877e6,
            registryModuleOwnerCustom: 0x97300785aF1edE1343DB6d90706A35CF14aA3d81,
            link: 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846,
            confirmations: 2,
            nativeCurrencySymbol: "AVAX"
        });
        return avalancheFujiConfig;
    }

    // Rest of the existing network configurations...

    function getNetworkConfig(uint256 chainId) public pure returns (NetworkConfig memory) {

        // Rest of the existing networks...

        else if (chainId == 43113) {
            return getAvalancheFujiConfig();
        }

        // Rest of the existing networks...

        else {
            revert("Unsupported chain ID");
        }
    }

}

Steps to add a new network:

  1. Navigate to your cloned repository directory:

    cd smart-contract-examples/ccip/cct/foundry
    
  2. Open script/HelperConfig.s.sol in your preferred editor

  3. Visit the CCIP Directory

  4. Locate your desired network in the directory and copy the following values:

    • Chain Selector
    • Router address
    • RMN Proxy address
    • Token Admin Registry address
    • Registry Module Owner Custom address
    • LINK token address
  5. Determine the chain ID from official network documentation, from ChainList, or by running the cast chain-id command.

  6. Add a new condition in the constructor() to detect the chain ID

  7. Create a new function (e.g., getOptimismSepoliaConfig()) following the existing pattern

  8. Set appropriate values for:

    • confirmations: Number of block confirmations to wait (typically 2-3 for testnets, 5-10 for mainnet)
    • nativeCurrencySymbol: The native currency symbol (e.g., "ETH", "AVAX", "POL")

Example: Adding Optimism Sepolia Testnet:

// Rest of the code...

constructor() {
    if (block.chainid == 11155111) {
        activeNetworkConfig = getEthereumSepoliaConfig();
    }

    // Rest of the existing networks...

    else if (block.chainid == 11155420) {
        activeNetworkConfig = getOptimismSepoliaConfig();
    } else {
        revert("Unsupported network");
    }
}

// Rest of the existing network configurations...

function getOptimismSepoliaConfig() public pure returns (NetworkConfig memory) {
    NetworkConfig memory optimismSepoliaConfig = NetworkConfig({
        chainSelector: 5224473277236331295,
        router: 0x114A20A10b43D4115e5aeef7345a1A71d2a60C57,
        rmnProxy: 0xb40A3109075965cc09E93719e33E748abf680dAe,
        tokenAdminRegistry: 0x1d702b1FA12F347f0921C722f9D9166F00DEB67A,
        registryModuleOwnerCustom: 0x49c4ba01dc6F5090f9df43Ab8F79449Db91A0CBB,
        link: 0xE4aB69C077896252FAFBD49EFD26B5D171A32410,
        confirmations: 2,
        nativeCurrencySymbol: "ETH"
    });
    return optimismSepoliaConfig;
}

function getNetworkConfig(uint256 chainId) public pure returns (NetworkConfig memory) {
    if (chainId == 11155111) {
        return getEthereumSepoliaConfig();
    }

    // Rest of the existing networks...

    else if (chainId == 11155420) {
        return getOptimismSepoliaConfig();
    } else {
        revert("Unsupported chain ID");
    }
}

Next Steps

Once you've updated your network configuration in the smart-contract-examples repository:

  1. Fund your wallet with native tokens and LINK for the new network using the Chainlink faucets (for testnets)

  2. Test the configuration by running a simple deployment:

    forge script script/DeployToken.s.sol --rpc-url $RPC_URL_<NEW_NETWORK_NAME> --private-key $PRIVATE_KEY --broadcast
    

    Contract Verification (Optional)

    Automatic Verification (Natively Supported): Most standard networks are natively supported by Foundry for contract verification. Check Foundry's StdChains.sol::StdChains::initializeStdChains() function for the complete list of supported networks.

    You just need to add the --verify flag when deploying:

    forge script script/DeployToken.s.sol --rpc-url $RPC_URL_<NEW_NETWORK_NAME> --private-key $PRIVATE_KEY --broadcast --verify
    

    Or if already deployed, you can verify using the forge verify-contract command.


    Custom Network Deployment and Verification

    Custom Network Deployment: For networks not natively supported by Foundry, replace the dynamic chain name lookup (getChain(block.chainid).chainAlias) in your deployment script with a hardcoded string, as the getChain call will revert on unsupported networks.

    So, replace this line:

    string memory chainName = getChain(block.chainid).chainAlias;
    

    with this:

    string memory chainName = "custom"; // or any other string identifier you prefer
    

    Custom Network Verification: For networks not natively supported by Foundry, include the --verifier, --verifier-url, and --verifier-api-key flags together with --verify when deploying, like:

    forge script script/DeployToken.s.sol --rpc-url $RPC_URL_<NEW_NETWORK_NAME> --private-key $PRIVATE_KEY --broadcast --verify --verifier custom --verifier-url $CUSTOM_EXPLORER_API_URL --verifier-api-key $CUSTOM_EXPLORER_API_KEY
    

    Refer to the Foundry docs for more details.

    This is particularly useful for:

    • Newer networks not yet added to Hardhat
    • Private/enterprise chains
    • Custom testnets

    Note: With Etherscan API V2, a single ETHERSCAN_API_KEY works across all Etherscan-compatible networks.

  3. Follow the tutorials using your newly configured network

Adapt for Your Own Projects

While this guide focuses on the smart-contract-examples repository structure, you can adapt these principles for your own projects.

Get the latest Chainlink content straight to your inbox.