A demonstration of Optimism's L2-to-L2 cross-chain messaging using two OP chains in a SuperSim environment. This project implements a cross-chain ad auction system where users can bid with ETH to control ad content displayed across multiple L2 chains.
This project is based on the SuperSim Cross-chain Contract Calls tutorial, but has been adapted to demonstrate a practical use case of cross-chain ad auctions.
This project demonstrates:
- L2-to-L2 direct messaging between Optimism chains
- Cross-chain ad content and bid synchronization
- ETH-based auction system for ad space
- Using SuperSim to run a local OP Stack devnet
- Deterministic deployments using CREATE2
- Cross-chain communication via the L2ToL2CrossDomainMessenger
- Start SuperSim with auto-relay enabled:
supersim --interop.autorelay
This will launch two OP chains with the following configuration:
- OPChainA: Chain ID 901, port 9545
- OPChainB: Chain ID 902, port 9546
- Available accounts, with the first account (used for deployment) having private key
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
- Deploy the contracts to both chains:
./deploy.sh
The deploy script will:
- Create identical contracts on both chain 901 and chain 902 at the same address (using CREATE2)
- Initialize chain 901 with empty ad information and a bid amount of 0
Successful deployment will look like:
Deploying to OPChainA (Chain ID 901)...
[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.
== Logs ==
Deployed at: 0x986b4BDD089EfDAfAab6B28cFE075bCF45574517
## Setting up 1 EVM.
==========================
Chain 901
... (deployment details)
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Deploying to OPChainB (Chain ID 902)...
[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.
== Logs ==
Deployed at: 0x986b4BDD089EfDAfAab6B28cFE075bCF45574517
## Setting up 1 EVM.
==========================
Chain 902
... (deployment details)
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Note: Deployment can only happen once per SuperSim session as the CREATE2 addresses will already exist on subsequent attempts. If you need to redeploy, restart SuperSim.
To check the current ad information and bid amounts on both chains:
./check.sh
Initial state should show empty ad information with a bid amount of 0 on OPChainA (901) and nothing on OPChainB (902).
To place a bid from Chain A to Chain B:
./bid.sh 901 "1000000000000000000" "My New Ad" "https://example.com"
Parameters:
901
: The chain ID you're bidding from"1000000000000000000"
: The bid amount in wei (1 ETH = 10^18 wei)"My New Ad"
: The title for your ad"https://example.com"
: The URL for your ad
The script will:
- Check if your bid is higher than the current bid
- If higher, place your bid by sending ETH and updating the ad content
- Pay the previous owner their bid amount (if any)
- Send a cross-chain message to synchronize the content to the other chain
You can also bid from Chain B to Chain A:
./bid.sh 902 "2000000000000000000" "Updated Ad" "https://updated-example.com"
This would outbid the previous ad with 2 ETH from Chain B.
You should see transaction details and in the SuperSim logs, you'll see messages like:
INFO [timestamp] L2ToL2CrossChainMessenger#SentMessage sourceChainID=901 destinationChainID=902 ...
INFO [timestamp] L2ToL2CrossChainMessenger#RelayedMessage sourceChainID=901 destinationChainID=902 ...
After placing a bid, check the ad status on both chains:
./check.sh
You should see that both chains now have the same ad information and bid amount, demonstrating successful cross-chain synchronization, though actual ETH transfers only happen on the chain where the bid was placed.
-
Bidding Mechanism:
- Anyone can bid on the ad slot with ETH
- New bids must be higher than the current bid amount
- When outbidding, the previous owner receives their bid amount back
- The highest bidder gets to control the ad content across all chains
-
Cross-Chain Synchronization:
- When a user bids on Chain A:
- Chain A updates the ad content, owner, and bid amount locally
- Chain A pays the previous owner their bid amount
- Chain A sends a cross-chain message to Chain B
- Chain B receives the update and synchronizes the ad info
- No ETH transfers happen on Chain B (ETH stays on the source chain)
- When a user bids on Chain A:
-
Ad Content Information:
- The ad information includes:
timestamp
: When the ad was last updatedlastUpdaterChainId
: The chain ID where the ad was last updatedowner
: The address of the current ad ownerbidAmount
: The current highest bid amounttitle
: The title of the adurl
: The URL of the ad
- The ad information includes:
Both contracts are deployed to the same address on different chains through CREATE2, using the same salt value:
CrossChainAd adSystem = new CrossChainAd{salt: "crosschainad"}(901);
The contract includes safeguards to ensure messages come from valid sources:
modifier onlyCrossDomainCallback() {
if (msg.sender != address(messenger)) revert CallerNotL2ToL2CrossDomainMessenger();
if (messenger.crossDomainMessageSender() != address(this)) revert InvalidCrossDomainSender();
_;
}
The bidding logic ensures that bids are always increasing:
// Verify bid is high enough
if (msg.value <= adInfo.bidAmount) revert BidTooLow();
// Pay the previous owner if necessary
if (previousOwner != address(0) && previousBid > 0) {
(bool success, ) = previousOwner.call{value: previousBid}("");
if (!success) revert PaymentFailed();
}
- Deployment Fails: If you see revert errors during deployment, it's likely because the contracts have already been deployed. Restart SuperSim to reset the chains.
- Bid Not Accepted: Ensure your bid amount is higher than the current bid amount.
- Ad Not Updating: Ensure SuperSim's auto-relay is enabled with the
--interop.autorelay
flag. - Script Permissions: If scripts don't run, ensure they have executable permissions:
chmod +x *.sh