> ## Documentation Index
> Fetch the complete documentation index at: https://docs.optimism.io/llms.txt
> Use this file to discover all available pages before exploring further.

# OP Mainnet Contract Addresses

> A comprehensive list of L1 and L2 contract addresses for OP Mainnet and OP Sepolia.

export const L2ContractTable = ({chain, legacy}) => {
  const PREDEPLOYS = {
    'L2ToL1MessagePasser': '0x4200000000000000000000000000000000000016',
    'L2CrossDomainMessenger': '0x4200000000000000000000000000000000000007',
    'L2StandardBridge': '0x4200000000000000000000000000000000000010',
    'L2ERC721Bridge': '0x4200000000000000000000000000000000000014',
    'SequencerFeeVault': '0x4200000000000000000000000000000000000011',
    'OptimismMintableERC20Factory': '0x4200000000000000000000000000000000000012',
    'OptimismMintableERC721Factory': '0x4200000000000000000000000000000000000017',
    'L1Block': '0x4200000000000000000000000000000000000015',
    'GasPriceOracle': '0x420000000000000000000000000000000000000F',
    'ProxyAdmin': '0x4200000000000000000000000000000000000018',
    'BaseFeeVault': '0x4200000000000000000000000000000000000019',
    'L1FeeVault': '0x420000000000000000000000000000000000001A',
    'GovernanceToken': '0x4200000000000000000000000000000000000042',
    'SchemaRegistry': '0x4200000000000000000000000000000000000020',
    'EAS': '0x4200000000000000000000000000000000000021',
    'L1MessageSender': '0x4200000000000000000000000000000000000001',
    'DeployerWhitelist': '0x4200000000000000000000000000000000000002',
    'LegacyERC20ETH': '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
    'L1BlockNumber': '0x4200000000000000000000000000000000000013',
    'LegacyMessagePasser': '0x4200000000000000000000000000000000000000'
  };
  const LEGACY_CONTRACT_NAMES = ['AddressManager', 'DeployerWhitelist', 'L1MessageSender', 'LegacyERC20ETH', 'LegacyMessagePasser', 'L1BlockNumber'];
  const CHAIN_CONSTANTS = {
    1: {
      explorer: 'https://etherscan.io'
    },
    10: {
      explorer: 'https://explorer.optimism.io'
    },
    11155111: {
      explorer: 'https://sepolia.etherscan.io'
    },
    11155420: {
      explorer: 'https://sepolia-optimism.etherscan.io'
    }
  };
  const filtered = Object.keys(PREDEPLOYS || ({})).filter(key => LEGACY_CONTRACT_NAMES.includes(key) === legacy).reduce((acc, key) => {
    acc[key] = PREDEPLOYS[key];
    return acc;
  }, {});
  const explorerUrl = CHAIN_CONSTANTS[parseInt(chain)]?.explorer || 'https://explorer.optimism.io';
  return <table>
      <thead>
        <tr>
          <th>Contract Name</th>
          <th>Contract Address</th>
        </tr>
      </thead>
      <tbody>
        {Object.entries(filtered).filter(([name, address]) => address && address !== '').map(([contract, address]) => <tr key={`${chain}.${contract}.${address}`}>
              <td>
                <code>{contract}</code>
              </td>
              <td>
                <a href={`${explorerUrl}/address/${address}`} target="_blank" rel="noreferrer">
                  <code>{address}</code>
                </a>
              </td>
            </tr>)}
      </tbody>
    </table>;
};

export const L1ContractTable = ({chain, explorer, legacy}) => {
  const [addresses, setAddresses] = useState({});
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  useEffect(() => {
    async function fetchAddresses() {
      try {
        const response = await fetch('https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses/addresses.json');
        if (!response.ok) {
          throw new Error('Failed to fetch addresses');
        }
        const data = await response.json();
        const chainData = data[chain] || ({});
        setAddresses(chainData);
      } catch (err) {
        setError(err.message);
        console.error('Error fetching addresses:', err);
      } finally {
        setLoading(false);
      }
    }
    fetchAddresses();
  }, [chain, legacy]);
  const LEGACY_CONTRACT_NAMES = ['AddressManager', 'DeployerWhitelist', 'L1MessageSender', 'LegacyERC20ETH', 'LegacyMessagePasser', 'L1BlockNumber'];
  const CHAIN_CONSTANTS = {
    1: {
      explorer: 'https://etherscan.io'
    },
    10: {
      explorer: 'https://explorer.optimism.io'
    },
    11155111: {
      explorer: 'https://sepolia.etherscan.io'
    },
    11155420: {
      explorer: 'https://sepolia-optimism.etherscan.io'
    }
  };
  if (loading) {
    return <div>Loading...</div>;
  }
  if (error) {
    return <div>Error: {error}</div>;
  }
  const filtered = Object.keys(addresses || ({})).filter(key => LEGACY_CONTRACT_NAMES.includes(key) === legacy).reduce((acc, key) => {
    acc[key] = addresses[key];
    return acc;
  }, {});
  const explorerUrl = CHAIN_CONSTANTS[parseInt(explorer)]?.explorer || 'https://etherscan.io';
  return <table>
      <thead>
        <tr>
          <th>Contract Name</th>
          <th>Contract Address</th>
        </tr>
      </thead>
      <tbody>
        {Object.entries(filtered).filter(([name, address]) => address && address !== '').map(([contract, address]) => <tr key={`${chain}.${contract}.${address}`}>
              <td>
                <code>{contract}</code>
              </td>
              <td>
                <a href={`${explorerUrl}/address/${address}`} target="_blank" rel="noreferrer">
                  <code>{address}</code>
                </a>
              </td>
            </tr>)}
      </tbody>
    </table>;
};

export const SuperchainContractTable = ({chain, explorer}) => {
  const [config, setConfig] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const getConfigUrl = chain => {
    const isTestnet = chain === '11155111';
    const network = isTestnet ? 'sepolia' : 'mainnet';
    return `https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/configs/${network}/superchain.toml`;
  };
  const parseSimpleToml = tomlText => {
    const result = {};
    const lines = tomlText.split('\n');
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {
        const [key, value] = trimmed.split('=', 2);
        const cleanKey = key.trim();
        const cleanValue = value.trim().replace(/['"]/g, '');
        if ((/^0x[a-fA-F0-9]{40}$/).test(cleanValue)) {
          result[cleanKey] = cleanValue;
        }
      }
    }
    return result;
  };
  const extractAddresses = obj => {
    const addresses = {};
    for (const [key, value] of Object.entries(obj)) {
      if (typeof value === 'string' && (/^0x[a-fA-F0-9]{40}$/).test(value)) {
        let newKey = key;
        if (key === 'superchain_config_addr') newKey = 'SuperchainConfig';
        if (key === 'op_contracts_manager_proxy_addr') newKey = 'OPContractsManagerProxy';
        addresses[newKey] = value;
      }
    }
    return addresses;
  };
  useEffect(() => {
    async function fetchAddresses() {
      try {
        const configUrl = getConfigUrl(chain);
        const response = await fetch(configUrl);
        if (!response.ok) {
          throw new Error(`Failed to fetch config from ${configUrl}`);
        }
        const text = await response.text();
        const data = parseSimpleToml(text);
        setConfig(data);
      } catch (err) {
        setError(err.message);
        console.error('Error fetching or parsing config:', err);
      } finally {
        setLoading(false);
      }
    }
    fetchAddresses();
  }, [chain]);
  if (loading) {
    return <div>Loading...</div>;
  }
  if (error) {
    return <div>Error: {error}</div>;
  }
  const addresses = extractAddresses(config || ({}));
  const CHAIN_CONSTANTS = {
    1: {
      explorer: 'https://etherscan.io'
    },
    10: {
      explorer: 'https://explorer.optimism.io'
    },
    11155111: {
      explorer: 'https://sepolia.etherscan.io'
    },
    11155420: {
      explorer: 'https://sepolia-optimism.etherscan.io'
    }
  };
  const explorerUrl = CHAIN_CONSTANTS[parseInt(explorer)]?.explorer || 'https://etherscan.io';
  return <table>
      <thead>
        <tr>
          <th>Contract Name</th>
          <th>Contract Address</th>
        </tr>
      </thead>
      <tbody>
        {Object.entries(addresses || ({})).filter(([name, address]) => address && address !== '').map(([contract, address]) => <tr key={`${chain}.${contract}.${address}`}>
              <td>
                <code>{contract}</code>
              </td>
              <td>
                <a href={`${explorerUrl}/address/${address}`} target="_blank" rel="noreferrer">
                  <code>{address}</code>
                </a>
              </td>
            </tr>)}
      </tbody>
    </table>;
};

This page lists all contract addresses for OP Mainnet and OP Sepolia. For high-level details and source code, see the [Smart Contracts Overview](/op-stack/protocol/smart-contracts).

<Info>
  Contract addresses are automatically synced from the [superchain-registry](https://github.com/ethereum-optimism/superchain-registry/tree/main).
</Info>

## L2 Contract Addresses

### OP Mainnet

<L2ContractTable chain="10" legacy={false} />

### OP Sepolia

<L2ContractTable chain="11155420" legacy={false} />

## L1 Contract Addresses

### Ethereum Mainnet

<L1ContractTable chain="10" explorer="1" legacy={false} />

### Ethereum Testnet (Sepolia)

<L1ContractTable chain="11155420" explorer="11155111" legacy={false} />

## Shared Contracts

### Ethereum Mainnet

<SuperchainContractTable chain="1" explorer="1" />

### Ethereum Testnet (Sepolia)

<SuperchainContractTable chain="11155111" explorer="11155111" />

## Legacy Contracts

<Info>
  Legacy contracts are from previous versions of the OP Stack and are maintained for backwards compatibility.
</Info>

### OP Mainnet Legacy (L2)

<L2ContractTable chain="10" legacy={true} />

### Ethereum Mainnet Legacy (L1)

<L1ContractTable chain="10" explorer="1" legacy={true} />
