Skip to main content
This tutorial takes you from zero to a cross-chain transaction on a Multichain Virtual Environment. By the end you will have a Virtual Environment that spans more than one network, with the Bridge Module relaying messages between them, your contracts deployed on each network, funded accounts on every chain, and a working cross-chain transaction visible in the unified dashboard timeline. If you have not read the overview yet, do that first. It explains what a Multichain Virtual Environment is, how the RPC URLs are structured, and what Virtual Chain IDs mean.

Before you begin

You need:
  • A Tenderly account with multichain capabilities enabled. If you do not see the option to add multiple networks during Virtual Environment creation, contact us.
  • A wallet private key you are willing to use in a test environment. Set it as PRIVATE_KEY in your shell.
  • Foundry or Hardhat installed locally.
The rest of the tutorial assumes Ethereum mainnet, Arbitrum, Optimism, and Base, but the same flow works for any combination of supported networks.

Run the tutorial

1
Create the Multichain Virtual Environment
2
In the Tenderly Dashboard, open Virtual Environments and start a new one. Ethereum mainnet is preselected by default. Add Arbitrum, Optimism, and Base from the network picker. Production chains appear first in the list, testnets at the bottom.
3
For each network you can choose:
4
  • Fork point. Fork from the latest block (the default) or pick a specific block number, timestamp, or date.
  • Chain ID. Leave the default Virtual Chain ID unless you have a reason to override it. The Virtual Chain IDs section explains the tradeoffs.
  • 5
    Save the Virtual Environment. Take note of the slug Tenderly assigns it. The slug is part of every RPC URL you will use from here on.
    6
    Enable the Bridge Module
    7
    Open the Virtual Environment’s settings and toggle Bridging to On. Once enabled, the Bridge Module watches for cross-chain events on every network in the Virtual Environment and relays them to the destination chain automatically. See Bridges for the protocols and networks it covers.
    8
    Wire the RPCs into your project
    9
    Each network in your Virtual Environment has a unique RPC URL with a predictable shape:
    10
    https://virtual.<network>.<region>.rpc.tenderly.co/<org-slug>/<vnet-slug>
    
    11
    Copy the RPC URLs from the Virtual Environment detail page and add them to your project configuration.
    12
    Foundry
    foundry.toml
    [rpc_endpoints]
    mainnet  = "https://virtual.mainnet.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>"
    arbitrum = "https://virtual.arbitrum.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>"
    optimism = "https://virtual.optimism.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>"
    base     = "https://virtual.base.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>"
    
    To verify a deployment against the Virtual Environment explorer, set --verifier-url to the same RPC. You will get a verified contract in the dashboard the moment the deploy completes.
    Hardhat
    hardhat.config.ts
    const config: HardhatUserConfig = {
      networks: {
        tenderly_mainnet: {
          url: "https://virtual.mainnet.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>",
          accounts: [process.env.PRIVATE_KEY],
        },
        tenderly_arbitrum: {
          url: "https://virtual.arbitrum.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>",
          accounts: [process.env.PRIVATE_KEY],
        },
        tenderly_optimism: {
          url: "https://virtual.optimism.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>",
          accounts: [process.env.PRIVATE_KEY],
        },
      },
    };
    
    13
    Fund accounts on every network
    14
    Open the Unlimited Faucet for your Virtual Environment and top up the address you will deploy from. Do this on each network, since balances are kept per network. Native currency is enough for the deploy itself. If your contracts move tokens, top those up too.
    15
    Deploy and trigger a cross-chain transaction
    16
    Deploy your contracts to each network you attached to the Virtual Environment.
    17
    Foundry
    showLineNumbers
    forge create Counter \
      --private-key $PRIVATE_KEY \
      --rpc-url https://virtual.optimism.eu.rpc.tenderly.co/<org-slug>/<vnet-slug> \
      --broadcast \
      --verify \
      --verifier-url https://virtual.optimism.eu.rpc.tenderly.co/<org-slug>/<vnet-slug>
    
    Hardhat
    npx hardhat run scripts/deploy.ts --network tenderly_mainnet
    
    18
    Once the contracts are deployed on each network, send a cross-chain transaction the way you normally would (for example a LayerZero send call). With the Bridge Module on, the destination-side delivery is posted immediately. Open the Virtual Environment dashboard and you should see both the source and destination transactions on the unified timeline.
    19
    Use the Bridges Source/Destination filter to confirm the round-trip explicitly.
    You now have a working Multichain Virtual Environment with cross-chain bridging.

    What to try next

    Now that the tutorial works, here is how to apply the same setup to real workflows:

    Automate deployments in CI

    Deploy to every network on every push, in parallel, using GitHub Actions. The CI/CD guides show the matrix workflow and the secrets you need.

    Stage your frontend

    Point your dApp at the Virtual Environment RPCs and give your team and reviewers an environment that exercises the full multichain flow.

    Create Virtual Environments via API

    The multivnets endpoint creates a Multichain Virtual Environment in one call. Useful for per-PR provisioning.

    Test bridge failures

    Manual bridge controls let you stage gas starvation, duplicate deliveries, modified payloads, and other failure modes deterministically.

    See also