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

# Plasma Mainnet

> LayerZero V2 deployment addresses and configuration for Plasma. Find Endpoint, DVN, and Executor contract addresses for integration. Endpoint, DVN, Executor,...

export const ChainDetails = ({chainKey, chainDisplayName, nativeChainId, eid, stage}) => {
  const {useState, useEffect, useMemo} = React;
  const SOLANA_CHAINS = ["solana", "solana-testnet"];
  const APTOS_CHAINS = ["aptos", "aptos-testnet"];
  const [deployment, setDeployment] = useState(null);
  const [dvnData, setDvnData] = useState([]);
  const [chainlistRPCs, setChainlistRPCs] = useState([]);
  const [ofts, setOfts] = useState([]);
  const [loadingOfts, setLoadingOfts] = useState(true);
  const [showAllOfts, setShowAllOfts] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [copied, setCopied] = useState(null);
  const [iconErrors, setIconErrors] = useState({});
  const handleCopy = (text, id) => {
    if (typeof window !== "undefined" && window.navigator && window.navigator.clipboard) {
      window.navigator.clipboard.writeText(text);
      setCopied(id);
      setTimeout(() => setCopied(null), 1000);
    }
  };
  const handleIconError = id => {
    setIconErrors(prev => {
      const next = {};
      Object.keys(prev).forEach(k => {
        next[k] = prev[k];
      });
      next[id] = true;
      return next;
    });
  };
  const getExplorerUrl = address => "https://layerzeroscan.com/api/explorer/" + chainKey + "/address/" + address;
  const getProtocolIcon = name => "https://icons-ckg.pages.dev/lz-scan/protocols/" + name.toLowerCase().replace(/ /g, "-") + ".svg";
  const getNetworkIcon = key => iconErrors["network-" + key] ? "https://icons-ckg.pages.dev/lz-scan/networks/default.svg" : "https://icons-ckg.pages.dev/lz-scan/networks/" + key + ".svg";
  const getDvnIcon = key => iconErrors["dvn-" + key] ? "https://icons-ckg.pages.dev/lz-scan/dvns/default.svg" : "https://icons-ckg.pages.dev/lz-scan/dvns/" + key + ".svg";
  const lowerChainKey = chainKey ? chainKey.toLowerCase() : "";
  const isSolana = SOLANA_CHAINS.indexOf(lowerChainKey) >= 0;
  const isAptos = APTOS_CHAINS.indexOf(lowerChainKey) >= 0;
  const isEVM = !isSolana && !isAptos;
  const fetchLocalFile = async path => {
    try {
      const r = await fetch("/public" + path);
      if (r.ok) {
        const t = await r.text();
        if (!t.trim().startsWith("<")) return JSON.parse(t);
      }
    } catch (e) {}
    const r = await fetch(path);
    if (!r.ok) throw new Error("Not available");
    const t = await r.text();
    if (t.trim().startsWith("<")) throw new Error("HTML response");
    return JSON.parse(t);
  };
  useEffect(() => {
    if (typeof window === "undefined") return;
    const loadData = async () => {
      try {
        let deploymentsData, dvnDataResult, rpcsData;
        try {
          [deploymentsData, dvnDataResult, rpcsData] = await Promise.all([fetchLocalFile("/data/deploymentsV2.json"), fetchLocalFile("/data/dvnDeployments.json"), fetchLocalFile("/data/chainlistRPCs.json")]);
        } catch (localErr) {
          console.log("Local files not available, fetching from API...");
          const [depsRes, rpcsRes] = await Promise.all([fetch("https://metadata.layerzero-api.com/v1/metadata/deployments"), fetch("https://chainid.network/chains.json")]);
          const depsData = await depsRes.json();
          rpcsData = await rpcsRes.json();
          const chainData = depsData[lowerChainKey + "-mainnet"] || depsData[lowerChainKey + "-testnet"] || depsData[lowerChainKey];
          if (chainData && chainData.deployments) {
            const v2Dep = chainData.deployments.find(d => d.version === 2 || d.eid === eid || d.eid && parseInt(d.eid) >= 30000);
            if (v2Dep) {
              deploymentsData = [{
                ...v2Dep,
                chainKey: lowerChainKey
              }];
            }
          }
          if (chainData && chainData.dvns) {
            dvnDataResult = Object.entries(chainData.dvns).map(([address, info]) => ({
              dvnAddress: address,
              dvnDisplayName: info.canonicalName || info.id || "Unknown DVN",
              id: info.id || address.slice(0, 8),
              lzReadCompatible: info.lzReadCompatible || false,
              chainKey: lowerChainKey
            }));
          } else {
            dvnDataResult = [];
          }
        }
        if (deploymentsData) {
          const chainDeployment = deploymentsData.find(d => d.chainKey && d.chainKey.toLowerCase() === lowerChainKey);
          if (chainDeployment) {
            setDeployment(chainDeployment);
          }
        }
        if (dvnDataResult) {
          const chainDvns = dvnDataResult.filter(dvn => dvn.chainKey && dvn.chainKey.toLowerCase() === lowerChainKey);
          setDvnData(chainDvns);
        }
        if (rpcsData) {
          setChainlistRPCs(rpcsData);
        }
      } catch (err) {
        console.error("Error loading data:", err);
      } finally {
        setIsLoading(false);
      }
    };
    loadData();
  }, [lowerChainKey, eid]);
  useEffect(() => {
    if (typeof window === "undefined") return;
    const fetchOfts = async () => {
      try {
        const res = await fetch("https://metadata.layerzero-api.com/v1/metadata/experiment/ofts/list?chainNames=" + chainKey);
        const data = await res.json();
        const chainOfts = [];
        Object.entries(data).forEach(([symbol, oftList]) => {
          oftList.forEach(oft => {
            if (oft.endpointVersion === "v2" && oft.deployments && oft.deployments[chainKey]) {
              chainOfts.push({
                symbol,
                name: oft.name,
                deployment: oft.deployments[chainKey],
                sharedDecimals: oft.sharedDecimals
              });
            }
          });
        });
        setOfts(chainOfts);
      } catch (err) {
        console.error("Error fetching OFTs:", err);
      } finally {
        setLoadingOfts(false);
      }
    };
    fetchOfts();
  }, [chainKey]);
  const pushDvns = useMemo(() => dvnData.filter(d => !d.lzReadCompatible).sort((a, b) => a.dvnDisplayName.localeCompare(b.dvnDisplayName)), [dvnData]);
  const readDvns = useMemo(() => dvnData.filter(d => d.lzReadCompatible).sort((a, b) => a.dvnDisplayName.localeCompare(b.dvnDisplayName)), [dvnData]);
  const contractEntries = useMemo(() => {
    if (!deployment) return [];
    const result = [];
    if (lowerChainKey === "ton") {
      if (deployment.controller?.address) result.push({
        label: "Controller",
        address: deployment.controller.address
      });
      if (deployment.sendUln302?.address) result.push({
        label: "SendUln302",
        address: deployment.sendUln302.address
      });
      if (deployment.receiveUln302?.address) result.push({
        label: "ReceiveUln302",
        address: deployment.receiveUln302.address
      });
      if (deployment.readLib1002?.address) result.push({
        label: "ReadLib1002",
        address: deployment.readLib1002.address
      });
      if (deployment.executor?.address) result.push({
        label: "Executor",
        address: deployment.executor.address
      });
      return result;
    }
    if (isSolana) {
      if (deployment.sendUln302?.address) result.push({
        label: "ULN302 Program",
        address: deployment.sendUln302.address
      });
      if (deployment.blocked_messagelib?.address) result.push({
        label: "BlockedLib Program",
        address: deployment.blocked_messagelib.address
      });
      if (deployment.executor?.address) result.push({
        label: "Executor Program",
        address: deployment.executor.address
      });
      if (deployment.executor?.pda) result.push({
        label: "Executor PDA",
        address: deployment.executor.pda
      });
      return result;
    }
    if (deployment.endpointV2?.address) result.push({
      label: "Endpoint V2",
      address: deployment.endpointV2.address
    });
    if (deployment.sendUln302?.address) result.push({
      label: "SendUln302",
      address: deployment.sendUln302.address
    });
    if (deployment.receiveUln302?.address) result.push({
      label: "ReceiveUln302",
      address: deployment.receiveUln302.address
    });
    if (deployment.readLib1002?.address) result.push({
      label: "ReadLib1002",
      address: deployment.readLib1002.address
    });
    if (deployment.executor?.address) result.push({
      label: "Executor",
      address: deployment.executor.address
    });
    if (deployment.blockedMessageLib?.address) result.push({
      label: "Blocked Message Library",
      address: deployment.blockedMessageLib.address
    });
    if (deployment.deadDVN?.address) result.push({
      label: "Dead DVN",
      address: deployment.deadDVN.address
    });
    return result;
  }, [deployment, lowerChainKey, isSolana]);
  const addToMetaMask = async () => {
    if (typeof window === "undefined" || !window.ethereum) return;
    const targetChainId = parseInt(nativeChainId, 10);
    const chainEntry = chainlistRPCs.find(c => c.chainId === targetChainId);
    if (!chainEntry) return;
    const rpcUrls = Array.isArray(chainEntry.rpc) ? chainEntry.rpc.filter(Boolean) : chainEntry.rpc ? [chainEntry.rpc] : [];
    if (rpcUrls.length === 0) return;
    const explorerUrls = chainEntry.explorers ? chainEntry.explorers.map(e => e.url) : [];
    const params = {
      chainId: "0x" + targetChainId.toString(16),
      chainName: chainEntry.name,
      rpcUrls,
      nativeCurrency: chainEntry.nativeCurrency || ({
        name: "Ether",
        symbol: "ETH",
        decimals: 18
      }),
      blockExplorerUrls: explorerUrls
    };
    try {
      await window.ethereum.request({
        method: "eth_requestAccounts"
      });
      await window.ethereum.request({
        method: "wallet_addEthereumChain",
        params: [params]
      });
    } catch (err) {
      console.error("Error adding network:", err);
    }
  };
  if (isLoading) return <div className="p-8 text-center text-zinc-500">Loading...</div>;
  const CopyIcon = () => <svg width="14" height="14" viewBox="0 0 20 20" fill="none">
      <path fillRule="evenodd" clipRule="evenodd" d="M4 3H14V5H15V3V2H14H4H3V3V15V16H4H6V15H4V3Z" fill="currentColor" />
      <rect x="6.5" y="5.5" width="11" height="13" stroke="currentColor" />
    </svg>;
  const CheckIcon = () => <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
      <path d="M1.5 6L4.5 9L10.5 3" stroke="#9EFC7E" strokeWidth="1.5" />
    </svg>;
  const ExternalLinkIcon = () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
      <polyline points="15 3 21 3 21 9" />
      <line x1="10" y1="14" x2="21" y2="3" />
    </svg>;
  const visibleOfts = showAllOfts ? ofts : ofts.slice(0, 4);
  return <div className="max-w-5xl mx-auto p-4">
      <div className="flex items-center p-4 gap-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg mb-4">
        <div className="w-14 h-14 flex-shrink-0 flex items-center justify-center">
          <img src={getNetworkIcon(chainKey)} alt="" style={{
    width: 56,
    height: 56
  }} className="dark:invert dark:brightness-110 dark:contrast-100 no-zoom" onError={() => handleIconError("network-" + chainKey)} />
        </div>
        <div className="flex-1 flex flex-col gap-2">
          <h1 className="text-xl font-semibold text-zinc-900 dark:text-white m-0">{chainDisplayName}</h1>
          <div className="flex items-center gap-3 text-sm text-zinc-600 dark:text-zinc-400 flex-wrap">
            <span>
              Chain ID: <b className="text-zinc-900 dark:text-white">{nativeChainId}</b>
            </span>
            <span className="text-zinc-400">-</span>
            <span>
              Endpoint ID: <b className="text-zinc-900 dark:text-white">{eid}</b>
            </span>
            <span className="text-zinc-400">-</span>
            <span className="bg-purple-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold uppercase">
              {stage}
            </span>
            {isEVM && <button onClick={addToMetaMask} className="inline-flex items-center justify-center w-8 h-8 rounded-lg hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Add to MetaMask">
                <img src="https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg" alt="MetaMask" className="w-5 h-5 no-zoom" />
              </button>}
            {isSolana && <a href="https://solana.com/docs/core/clusters" target="_blank" rel="noopener noreferrer" className="inline-flex items-center justify-center w-8 h-8 rounded-lg hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Open Solana page">
                <ExternalLinkIcon />
              </a>}
            {isAptos && <a href="https://aptos.dev/en/network/nodes/networks" target="_blank" rel="noopener noreferrer" className="inline-flex items-center justify-center w-8 h-8 rounded-lg hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Open Aptos page">
                <ExternalLinkIcon />
              </a>}
          </div>
        </div>
      </div>

      <div className="flex items-center gap-2 mb-4 text-sm text-zinc-500">
        <a href="/v2/deployments/deployed-contracts" className="text-zinc-600 dark:text-zinc-400 hover:text-purple-500 dark:hover:text-purple-400 no-underline hover:underline">
          View all chains
        </a>
        <span className="text-zinc-400">-</span>
        <a href="/v2/deployments/dvn-addresses" className="text-zinc-600 dark:text-zinc-400 hover:text-purple-500 dark:hover:text-purple-400 no-underline hover:underline">
          View all DVNs
        </a>
      </div>

      {deployment && deployment.note && <div className="mb-4 p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-700/50 rounded-lg text-sm text-yellow-800 dark:text-yellow-200 leading-relaxed">
          {deployment.note}
        </div>}

      <div className="mb-4">
        <div className="inline-flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-white mb-4">
          <span>Protocol Contracts</span>
          <span className="bg-purple-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold">
            {contractEntries.length}
          </span>
        </div>
        <div className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg p-4">
          {contractEntries.length > 0 ? <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
              {contractEntries.map((contract, idx) => <div key={idx} className="group flex flex-col gap-2 p-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md hover:border-purple-500 transition-colors">
                  <div className="text-xs font-semibold text-zinc-500 uppercase tracking-wide">{contract.label}</div>
                  <div className="flex items-center gap-2 text-sm font-mono text-zinc-900 dark:text-white">
                    <a href={getExplorerUrl(contract.address)} target="_blank" rel="noreferrer" className="flex-1 truncate text-zinc-900 dark:text-white no-underline hover:text-purple-500">
                      {contract.address}
                    </a>
                    <button onClick={() => handleCopy(contract.address, "contract-" + idx)} className="p-1 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Copy to clipboard">
                      {copied === "contract-" + idx ? <CheckIcon /> : <CopyIcon />}
                    </button>
                  </div>
                </div>)}
            </div> : <div className="p-4 text-center text-zinc-500">No protocol contracts found for this chain.</div>}
        </div>
      </div>

      <div className="mt-6 mb-4">
        <div className="flex justify-between items-center mb-4">
          <div className="inline-flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-white">
            <span>Omnichain Fungible Tokens (OFTs)</span>
            <span className="bg-purple-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold">
              {ofts.length}
            </span>
          </div>
          <a href="https://layerzero.foundation/request-oft" target="_blank" rel="noopener noreferrer" className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg text-sm font-medium no-underline transition-colors">
            + Add my token
          </a>
        </div>
        {loadingOfts ? <div className="p-8 text-center text-zinc-500 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg">
            Loading OFTs...
          </div> : ofts.length > 0 ? <div>
            <div className="grid gap-3" style={{
    gridTemplateColumns: "repeat(auto-fill, minmax(340px, 1fr))"
  }}>
              {visibleOfts.map((oft, idx) => <div key={idx} className="group flex flex-col gap-3 p-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg hover:border-purple-500 transition-colors">
                  <div className="flex items-center gap-2" style={{
    minHeight: "20px",
    alignItems: "center"
  }}>
                    <div style={{
    width: 20,
    height: 20,
    flexShrink: 0,
    borderRadius: "50%",
    overflow: "hidden",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
                      <img src={getProtocolIcon(oft.name)} alt="" className="no-zoom" style={{
    width: 20,
    height: 20,
    display: "block"
  }} onError={e => {
    e.target.src = "https://icons-ckg.pages.dev/lz-scan/networks/unknown.svg";
  }} />
                    </div>
                    <span className="font-semibold text-zinc-900 dark:text-white" style={{
    fontSize: "14px",
    lineHeight: "20px"
  }}>
                      {oft.symbol}
                    </span>
                    <span className="ml-auto bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 rounded font-semibold uppercase" style={{
    fontSize: "10px",
    padding: "2px 8px",
    letterSpacing: "0.5px",
    lineHeight: "1"
  }}>
                      {oft.deployment.type}
                    </span>
                  </div>
                  <div className="text-zinc-600 dark:text-zinc-400" style={{
    fontSize: "13px"
  }}>
                    {oft.name}
                  </div>
                  <div className="flex items-center gap-2 font-mono text-zinc-900 dark:text-white" style={{
    fontSize: "12px"
  }}>
                    <a href={getExplorerUrl(oft.deployment.address)} target="_blank" rel="noreferrer" className="flex-1 truncate text-zinc-900 dark:text-white no-underline hover:text-purple-500">
                      {oft.deployment.address}
                    </a>
                    <button onClick={() => handleCopy(oft.deployment.address, "oft-" + idx)} className="p-1 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Copy to clipboard">
                      {copied === "oft-" + idx ? <CheckIcon /> : <CopyIcon />}
                    </button>
                  </div>
                  <div className="text-zinc-500 flex gap-3" style={{
    fontSize: "11px"
  }}>
                    <span>Decimals: {oft.deployment.localDecimals}</span>
                  </div>
                </div>)}
            </div>
            {ofts.length > 4 && <button onClick={() => setShowAllOfts(!showAllOfts)} className="mt-3 mx-auto block px-4 py-2 border border-zinc-200 dark:border-zinc-700 rounded-lg text-sm font-medium text-zinc-900 dark:text-white hover:border-purple-500 hover:text-purple-500 transition-colors bg-transparent">
                {showAllOfts ? "Show less" : "See more"}
              </button>}
            <div className="mt-4 text-center text-sm text-zinc-500">
              <p className="m-0">
                To programmatically retrieve and interact with these tokens, see the{" "}
                <a href="/v2/tools/api/oft-reference" className="text-zinc-600 dark:text-zinc-400 hover:text-purple-500">
                  OFT API
                </a>
                . To build advanced crosschain workflows, see the{" "}
                <a href="/v2/concepts/applications/composer-standard" className="text-zinc-600 dark:text-zinc-400 hover:text-purple-500">
                  Composers section
                </a>
                .
              </p>
            </div>
          </div> : <div className="p-8 text-center text-zinc-500 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg">
            No OFT API deployment records found.
          </div>}
      </div>

      <hr className="border-t border-zinc-200 dark:border-zinc-700 my-8 opacity-50" />

      <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
        <div>
          <div className="inline-flex items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-white mb-4">
            <span>Push-based DVNs</span>
            <span className="bg-purple-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold">
              {pushDvns.length}
            </span>
          </div>
          {pushDvns.length > 0 ? <div className="flex flex-col gap-3">
              {pushDvns.map((dvn, idx) => <div key={idx} className="group flex flex-col gap-3 p-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg hover:border-purple-500 transition-colors">
                  <div className="flex items-center gap-2" style={{
    minHeight: "20px",
    alignItems: "center"
  }}>
                    <div style={{
    width: 20,
    height: 20,
    flexShrink: 0,
    borderRadius: "50%",
    overflow: "hidden",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
                      <img src={getDvnIcon(dvn.id)} alt="" className="no-zoom" style={{
    width: 20,
    height: 20,
    display: "block"
  }} onError={() => handleIconError("dvn-" + dvn.id)} />
                    </div>
                    <span className="text-zinc-600 dark:text-zinc-400" style={{
    fontSize: "13px",
    lineHeight: "20px"
  }}>
                      {dvn.dvnDisplayName}
                    </span>
                  </div>
                  <div className="flex items-center gap-2 text-sm font-mono text-zinc-900 dark:text-white" style={{
    fontSize: "12px"
  }}>
                    <a href={getExplorerUrl(dvn.dvnAddress)} target="_blank" rel="noreferrer" className="flex-1 truncate text-zinc-900 dark:text-white no-underline hover:text-purple-500">
                      {dvn.dvnAddress}
                    </a>
                    <button onClick={() => handleCopy(dvn.dvnAddress, "push-dvn-" + idx)} className="p-1 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Copy to clipboard">
                      {copied === "push-dvn-" + idx ? <CheckIcon /> : <CopyIcon />}
                    </button>
                  </div>
                </div>)}
            </div> : <div className="p-8 text-center text-zinc-500 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg">
              No push-based DVNs available for this chain
            </div>}
        </div>
        <div>
          <div className="inline-flex items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-white mb-4">
            <span>Pull-based DVNs</span>
            <span className="bg-purple-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold">
              {readDvns.length}
            </span>
          </div>
          {readDvns.length > 0 ? <div className="flex flex-col gap-3">
              {readDvns.map((dvn, idx) => <div key={idx} className="group flex flex-col gap-3 p-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg hover:border-purple-500 transition-colors">
                  <div className="flex items-center gap-2" style={{
    minHeight: "20px",
    alignItems: "center"
  }}>
                    <div style={{
    width: 20,
    height: 20,
    flexShrink: 0,
    borderRadius: "50%",
    overflow: "hidden",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
                      <img src={getDvnIcon(dvn.id)} alt="" className="no-zoom" style={{
    width: 20,
    height: 20,
    display: "block"
  }} onError={() => handleIconError("dvn-" + dvn.id)} />
                    </div>
                    <span className="text-zinc-600 dark:text-zinc-400" style={{
    fontSize: "13px",
    lineHeight: "20px"
  }}>
                      {dvn.dvnDisplayName}
                    </span>
                  </div>
                  <div className="flex items-center gap-2 text-sm font-mono text-zinc-900 dark:text-white" style={{
    fontSize: "12px"
  }}>
                    <a href={getExplorerUrl(dvn.dvnAddress)} target="_blank" rel="noreferrer" className="flex-1 truncate text-zinc-900 dark:text-white no-underline hover:text-purple-500">
                      {dvn.dvnAddress}
                    </a>
                    <button onClick={() => handleCopy(dvn.dvnAddress, "pull-dvn-" + idx)} className="p-1 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" title="Copy to clipboard">
                      {copied === "pull-dvn-" + idx ? <CheckIcon /> : <CopyIcon />}
                    </button>
                  </div>
                </div>)}
            </div> : <div className="p-8 text-center text-zinc-500 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg">
              No pull-based DVNs available for this chain
            </div>}
        </div>
      </div>
    </div>;
};

<ChainDetails chainKey="plasma" chainDisplayName="Plasma Mainnet" nativeChainId="9745" eid="30383" stage="mainnet" />
