Back to How-To Guides
HOW-TO9 min read2025-06-23

How to Deploy a Smart Contract to Multiple Blockchains — Multi-Chain Strategy

Deploying the same smart contract to multiple EVM-compatible chains is straightforward but requires careful chain-specific configuration. Learn the multi-chain deployment architecture.

ClickMasters Team
Step-by-step implementation
Expert Assistance

Ready to Deploy Multi-Chain?

Get expert guidance on deploying your smart contract across multiple EVM chains.

Complete Guide

Quick Answer

Multi-chain deployment uses the same bytecode on all EVM-compatible chains (Ethereum, Arbitrum, Base, Polygon) — but requires chain-specific addresses for oracles, routers, and tokens. Use Foundry with chain-specific RPC endpoints and a registry library for addresses. Recommended: phase the rollout — deploy to Arbitrum first, run for 30-90 days, then expand to Base, Optimism, and Polygon.

The Multi-Chain Deployment Architecture

Same bytecode, different addresses: EVM-compatible chains share the same instruction set. The same compiled Solidity bytecode deploys to Ethereum, Arbitrum, Base, and Polygon — at different addresses on each chain.

What varies per chain:

Gas price and limits (check `forge gas-price`)

Block time (important for timelock calculations)

Chain ID (for EIP-712 signatures)

External contract addresses (oracles, routers, tokens)

Foundry Multi-Chain Configuration

Example
[rpc_endpoints]
[rpc_endpoints]
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
arbitrum = "https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
optimism = "https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
base = "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
polygon = "https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"

[etherscan]
mainnet = { key = "${ETHERSCAN_KEY}" }
arbitrum = { key = "${ARBISCAN_KEY}", url = "https://api.arbiscan.io/api" }
base = { key = "${BASESCAN_KEY}", url = "https://api.basescan.org/api" }
polygon = { key = "${POLYGONSCAN_KEY}", url = "https://api.polygonscan.com/api" }

Chain-Specific Address Registry

Example
// addresses/Addresses.sol
library ChainAddresses {
    
    struct ChainConfig {
        address usdc;
        address weth;
        address uniswapV3Router;
        address chainlinkEthUsd;
    }
    
    function get(uint256 chainId) internal pure returns (ChainConfig memory) {
        if (chainId == 1) { // Ethereum mainnet
            return ChainConfig({
                usdc: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,
                weth: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,
                uniswapV3Router: 0xE592427A0AEce92De3Edee1F18E0157C05861564,
                chainlinkEthUsd: 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
            });
        } else if (chainId == 42161) { // Arbitrum One
            return ChainConfig({
                usdc: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831,
                weth: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1,
                uniswapV3Router: 0xE592427A0AEce92De3Edee1F18E0157C05861564,
                chainlinkEthUsd: 0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612
            });
        }
        // Add more chains...
        revert("Unsupported chain");
    }
}

Deployment Script

Example
// script/Deploy.s.sol
contract DeployScript is Script {
    function run() external {
        ChainAddresses.ChainConfig memory config = ChainAddresses.get(block.chainid);
        
        vm.startBroadcast(vm.envUint("DEPLOYER_KEY"));
        
        MyProtocol protocol = new MyProtocol(
            config.usdc,
            config.weth,
            config.uniswapV3Router,
            config.chainlinkEthUsd
        );
        
        vm.stopBroadcast();
        
        // Write deployment to JSON
        _writeDeployment(block.chainid, address(protocol));
    }
}
Example
# Deploy to all chains
for CHAIN in mainnet arbitrum optimism base polygon; do
  forge script script/Deploy.s.sol     --rpc-url $CHAIN     --broadcast     --verify     -vvvv
done

Frequently Asked Questions

Common questions before following this guide

Clear answers to the most common practical, technical, and implementation questions.

1

Answers

Should we deploy to all chains simultaneously or phase the rollout?

Phase the rollout. Deploy to Arbitrum first (largest DeFi ecosystem), run for 30–90 days, confirm the protocol works as expected. Then deploy to Base, then Optimism. Each deployment requires its own liquidity bootstrapping and user acquisition — spreading across 5 chains at launch dilutes your liquidity and user attention.

Expert Assistance

Ready to Deploy Multi-Chain?

Get expert guidance on deploying your smart contract across multiple EVM chains.