Five steps, one contract live on the EEZ-X mainnet rollup. Everything you need is on this page — the walkthroughs explain why it works, and none of them are prerequisites.
The demos and this page are pinned to Foundry v1.7.1; download the archive for your OS and architecture from the official v1.7.1 release. Verify its published checksums or attestations before extracting the tools into a directory on your PATH. Step 2 also needs a browser wallet.
$ forge --version $ cast --version # Both should report version 1.7.1 after installation.
Send the key a small amount of ETH on Ethereum mainnet, only what you are willing to spend. Import the key into a browser wallet, then move some ETH to the EEZ-X rollup with the Bridge & Calls tab of the mainnet dashboard, a demo app on the testnet (it shows the rollup balance as ETH). Then import it into an encrypted local keystore. Enter the private key and a strong keystore password only at the hidden prompts; never put either secret in a command or environment variable:
$ cast wallet import eez-mainnet --interactive $ export ADDR=$(cast wallet address --account eez-mainnet)
⚠ This is mainnet: transactions cost real ETH. Use a fresh key that holds only what you plan to spend here.
Send transactions to the chain’s front URL. It forwards ordinary transactions, like this deploy, unchanged and composes cross-chain ones; a cross-chain call sent to the direct RPC would bypass the composer. The front also answers the reads used below; the direct RPC is for reads and protocol tooling. The L2 manager is a genesis predeploy, read from the deployment’s genesis profile (eez-rollupX @ 2c19e36 puts it at 0x4B27…402C); the L1 manager is the EEZ contract on Ethereum mainnet. Every URL, manager address and explorer in the table comes from the dashboard’s own config; the chain ids are what eth_chainId returns on each RPC.
| CHAIN | RPC URLS | CHAIN ID | EEZ MANAGER | EXPLORER |
|---|---|---|---|---|
| EEZ-X Mainnet (L2) | fronthttps://mainnet.eez.dev/composer/l2 readshttps://mainnet.eez.dev/rpc/l2 |
696990 | 0x4B2760F84B83d6b3829E30A7573B0172B6d6402C | mainnet.eez.dev/explorer |
| Ethereum (L1) | fronthttps://mainnet.eez.dev/composer/l1 readshttps://mainnet.eez.dev/rpc/l1 |
1 | 0x4b2760f84b83d6b3829e30a7573b0172b6d6402c | etherscan.io |
$ export EEZ_RPC=https://mainnet.eez.dev/composer/l2
One command. src/MyContract.sol is whatever you're shipping. Without --broadcast, Foundry 1.7.1 only prints the unsigned transaction.
$ forge create src/MyContract.sol:MyContract --rpc-url "$EEZ_RPC" --account eez-mainnet --broadcast
Deployer: 0x… Deployed to: 0x… ← this line means you're done Transaction hash: 0x…
Verify it landed — non-empty bytes means deployed:
$ cast code <address> --rpc-url $EEZ_RPC
The key isn't funded on the EEZ-X rollup — move ETH over with the dashboard's Bridge & Calls tab on mainnet.eez.dev, then cast balance $ADDR --rpc-url $EEZ_RPC to confirm before retrying.
$EEZ_RPC doesn't match the table in step 3 — re-copy it. cast chain-id --rpc-url $EEZ_RPC should print the chain id from the table.
An earlier transaction from this key is stuck or already mined — cast nonce $ADDR --rpc-url $EEZ_RPC to inspect, then resend.
In this order.
One call across two rollups, run locally, then patterns you can copy.
Your contract's stand-in on every other rollup — readable before anything is deployed.
An ordinary encode, sent to the proxy — the answer comes back in the same transaction.
Cross-chain, msg.sender is the proxy — not your contract. Fix the check before it ships.