-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: wormhole l1 to l2 to l1 messaging experiments
- Loading branch information
Showing
11 changed files
with
548 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
/// @title WormholeL1Receiver - Smart contract for the L1 message receiving via wormhole | ||
/// @author Aleksandr Kuperman - <[email protected]> | ||
/// @author Andrey Lebedev - <[email protected]> | ||
/// @author Mariapia Moscatiello - <[email protected]> | ||
contract WormholeL1Receiver { | ||
event MessageReceived(bytes32 indexed sourceMessageSender, bytes data, bytes32 deliveryHash, uint256 sourceChain); | ||
|
||
/// @dev Processes a message received from L1 Wormhole Relayer contract. | ||
/// @notice The sender must be the source contract address. | ||
/// @param data Bytes message sent from L1 Wormhole Relayer contract. | ||
/// @param sourceAddress The (wormhole format) address on the sending chain which requested this delivery. | ||
/// @param sourceChain The wormhole chain Id where this delivery was requested. | ||
/// @param deliveryHash The VAA hash of the deliveryVAA. | ||
function receiveWormholeMessages( | ||
bytes memory data, | ||
bytes[] memory, | ||
bytes32 sourceAddress, | ||
uint16 sourceChain, | ||
bytes32 deliveryHash | ||
) external payable { | ||
// Emit received message | ||
emit MessageReceived(sourceAddress, data, deliveryHash, sourceChain); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
import {IBridgeErrors} from "../../interfaces/IBridgeErrors.sol"; | ||
|
||
interface IWormhole { | ||
function sendPayloadToEvm( | ||
// Chain ID in Wormhole format | ||
uint16 targetChain, | ||
// Contract Address on target chain we're sending a message to | ||
address targetAddress, | ||
// The payload, encoded as bytes | ||
bytes memory payload, | ||
// How much value to attach to the delivery transaction | ||
uint256 receiverValue, | ||
// The gas limit to set on the delivery transaction | ||
uint256 gasLimit | ||
) external payable returns ( | ||
// Unique, incrementing ID, used to identify a message | ||
uint64 sequence | ||
); | ||
} | ||
|
||
/// @title WormholeL1Sender - Smart contract for sending a message from L2 to L1 via wormhole | ||
/// @author Aleksandr Kuperman - <[email protected]> | ||
/// @author Andrey Lebedev - <[email protected]> | ||
/// @author Mariapia Moscatiello - <[email protected]> | ||
contract WormholeL1Sender is IBridgeErrors { | ||
event MessageReceived(bytes32 indexed sourceMessageSender, bytes data, bytes32 deliveryHash, uint256 sourceChain); | ||
|
||
uint256 public constant GAS_LIMIT = 50_000; | ||
// L2 Wormhole Relayer address that receives the message across the bridge from the source L1 network | ||
address public immutable wormholeRelayer; | ||
// Source chain Id | ||
uint16 public immutable sourceChainId; | ||
// Source contract to communicate with on L1 | ||
address public sourceSender; | ||
|
||
/// @dev WormholeMessenger constructor. | ||
/// @param _wormholeRelayer L2 Wormhole Relayer address. | ||
/// @param _sourceChainId Source wormhole format chain Id. | ||
constructor(address _wormholeRelayer, uint16 _sourceChainId, address _sourceSender) { | ||
// Check for zero addresses | ||
if (_wormholeRelayer == address(0) || _sourceSender == address(0)) { | ||
revert ZeroAddress(); | ||
} | ||
|
||
// Check source chain Id | ||
if (_sourceChainId == 0) { | ||
revert ZeroValue(); | ||
} | ||
|
||
wormholeRelayer = _wormholeRelayer; | ||
sourceChainId = _sourceChainId; | ||
sourceSender = _sourceSender; | ||
} | ||
|
||
function sendMessage() external payable { | ||
bytes32 message = keccak256(abi.encode("Hello")); | ||
|
||
// Send the message | ||
IWormhole(wormholeRelayer).sendPayloadToEvm{value: msg.value}( | ||
sourceChainId, | ||
sourceSender, | ||
abi.encode(message), | ||
0, | ||
GAS_LIMIT | ||
); | ||
} | ||
|
||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.23; | ||
|
||
import {IBridgeErrors} from "../../interfaces/IBridgeErrors.sol"; | ||
|
||
interface IWormhole { | ||
function quoteEVMDeliveryPrice( | ||
uint16 targetChain, | ||
uint256 receiverValue, | ||
uint256 gasLimit | ||
) external returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused); | ||
|
||
function sendPayloadToEvm( | ||
// Chain ID in Wormhole format | ||
uint16 targetChain, | ||
// Contract Address on target chain we're sending a message to | ||
address targetAddress, | ||
// The payload, encoded as bytes | ||
bytes memory payload, | ||
// How much value to attach to the delivery transaction | ||
uint256 receiverValue, | ||
// The gas limit to set on the delivery transaction | ||
uint256 gasLimit | ||
) external payable returns ( | ||
// Unique, incrementing ID, used to identify a message | ||
uint64 sequence | ||
); | ||
} | ||
|
||
/// @title WormholeL2ReceiverL1Sender - Smart contract for the L1-L2-L1 message relaying via wormhole | ||
/// @author Aleksandr Kuperman - <[email protected]> | ||
/// @author Andrey Lebedev - <[email protected]> | ||
/// @author Mariapia Moscatiello - <[email protected]> | ||
contract WormholeL2ReceiverL1Sender is IBridgeErrors { | ||
event MessageReceived(bytes32 indexed sourceMessageSender, bytes data, bytes32 deliveryHash, uint256 sourceChain); | ||
|
||
uint256 public constant GAS_LIMIT = 50_000; | ||
// L2 Wormhole Relayer address that receives the message across the bridge from the source L1 network | ||
address public immutable wormholeRelayer; | ||
// Source chain Id | ||
uint16 public immutable sourceChainId; | ||
// Source contract to communicate with on L1 | ||
address public sourceSender; | ||
// Delivery hashes | ||
mapping(bytes32 => bool) public mapDeliveryHashes; | ||
|
||
/// @dev WormholeMessenger constructor. | ||
/// @param _wormholeRelayer L2 Wormhole Relayer address. | ||
/// @param _sourceChainId Source wormhole format chain Id. | ||
constructor(address _wormholeRelayer, uint16 _sourceChainId) { | ||
// Check for zero addresses | ||
if (_wormholeRelayer == address(0)) { | ||
revert ZeroAddress(); | ||
} | ||
|
||
// Check source chain Id | ||
if (_sourceChainId == 0) { | ||
revert ZeroValue(); | ||
} | ||
|
||
wormholeRelayer = _wormholeRelayer; | ||
sourceChainId = _sourceChainId; | ||
} | ||
|
||
|
||
/// @dev Processes a message received from L2 Wormhole Relayer contract. | ||
/// @notice The sender must be the source contract address. | ||
/// @param data Bytes message sent from L2 Wormhole Relayer contract. | ||
/// @param sourceAddress The (wormhole format) address on the sending chain which requested this delivery. | ||
/// @param sourceChain The wormhole chain Id where this delivery was requested. | ||
/// @param deliveryHash The VAA hash of the deliveryVAA. | ||
function receiveWormholeMessages( | ||
bytes memory data, | ||
bytes[] memory, | ||
bytes32 sourceAddress, | ||
uint16 sourceChain, | ||
bytes32 deliveryHash | ||
) external payable { | ||
// Check L2 Wormhole Relayer address | ||
if (msg.sender != wormholeRelayer) { | ||
revert TargetRelayerOnly(msg.sender, wormholeRelayer); | ||
} | ||
|
||
// Check the source chain Id | ||
if (sourceChain != sourceChainId) { | ||
revert WrongSourceChainId(sourceChain, sourceChainId); | ||
} | ||
|
||
// Check the delivery hash uniqueness | ||
if (mapDeliveryHashes[deliveryHash]) { | ||
revert AlreadyDelivered(deliveryHash); | ||
} | ||
mapDeliveryHashes[deliveryHash] = true; | ||
|
||
sourceSender = abi.decode(data, (address)); | ||
|
||
// Get a quote for the cost of gas for delivery | ||
uint256 cost; | ||
(cost, ) = IWormhole(wormholeRelayer).quoteEVMDeliveryPrice(sourceChain, 0, GAS_LIMIT); | ||
|
||
// Send the message | ||
IWormhole(wormholeRelayer).sendPayloadToEvm{value: cost}( | ||
sourceChain, | ||
sourceSender, | ||
abi.encode(keccak256("Hello")), | ||
0, | ||
GAS_LIMIT | ||
); | ||
|
||
// Emit received message | ||
emit MessageReceived(sourceAddress, data, deliveryHash, sourceChain); | ||
} | ||
|
||
receive() external payable {} | ||
} |
58 changes: 58 additions & 0 deletions
58
scripts/deployment/bridges/wormhole/test/l1_l2_l1/deploy_03_womholel2receiverl1sender.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/*global process*/ | ||
|
||
const { ethers } = require("hardhat"); | ||
const { LedgerSigner } = require("@anders-t/ethers-ledger"); | ||
|
||
async function main() { | ||
const fs = require("fs"); | ||
const globalsFile = "globals.json"; | ||
const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); | ||
let parsedData = JSON.parse(dataFromJSON); | ||
const useLedger = parsedData.useLedger; | ||
const derivationPath = parsedData.derivationPath; | ||
const providerName = parsedData.providerName; | ||
const gasPriceInGwei = parsedData.gasPriceInGwei; | ||
let EOA; | ||
|
||
const provider = new ethers.providers.JsonRpcProvider(parsedData.networkURL); | ||
const signers = await ethers.getSigners(); | ||
|
||
if (useLedger) { | ||
EOA = new LedgerSigner(provider, derivationPath); | ||
} else { | ||
EOA = signers[0]; | ||
} | ||
// EOA address | ||
const deployer = await EOA.getAddress(); | ||
console.log("EOA is:", deployer); | ||
|
||
// Transaction signing and execution | ||
console.log("1. EOA to deploy WormholeL2ReceiverL1Sender contract"); | ||
const WormholeL2ReceiverL1Sender = await ethers.getContractFactory("WormholeL2ReceiverL1Sender"); | ||
console.log("You are signing the following transaction: WormholeL2ReceiverL1Sender.connect(EOA).deploy()"); | ||
const wormholeL2ReceiverL1Sender = await WormholeL2ReceiverL1Sender.connect(EOA).deploy(parsedData.L2WormholeRelayerAddress, | ||
parsedData.sourceChainId, parsedData.wormholeL1ReceiverAddress); | ||
const result = await wormholeL2ReceiverL1Sender.deployed(); | ||
|
||
// Transaction details | ||
console.log("Contract deployment: WormholeL2ReceiverL1Sender"); | ||
console.log("Contract address:", wormholeL2ReceiverL1Sender.address); | ||
console.log("Transaction:", result.deployTransaction.hash); | ||
|
||
// Writing updated parameters back to the JSON file | ||
parsedData.wormholeL2ReceiverL1SenderAddress = wormholeL2ReceiverL1Sender.address; | ||
fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); | ||
|
||
// Contract verification | ||
if (parsedData.contractVerification) { | ||
const execSync = require("child_process").execSync; | ||
execSync("npx hardhat verify --constructor-args scripts/deployment/bridges/wormhole/test/l1_l2_l1/verify_03_womholel2receiverl1sender.js --network " + providerName + " " + wormholeL2ReceiverL1Sender.address, { encoding: "utf-8" }); | ||
} | ||
} | ||
|
||
main() | ||
.then(() => process.exit(0)) | ||
.catch((error) => { | ||
console.error(error); | ||
process.exit(1); | ||
}); |
57 changes: 57 additions & 0 deletions
57
scripts/deployment/bridges/wormhole/test/l1_l2_l1/deploy_04_womholel1receiver.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/*global process*/ | ||
|
||
const { ethers } = require("hardhat"); | ||
const { LedgerSigner } = require("@anders-t/ethers-ledger"); | ||
|
||
async function main() { | ||
const fs = require("fs"); | ||
const globalsFile = "globals.json"; | ||
const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); | ||
let parsedData = JSON.parse(dataFromJSON); | ||
const useLedger = parsedData.useLedger; | ||
const derivationPath = parsedData.derivationPath; | ||
const providerName = "sepolia"; | ||
const gasPriceInGwei = parsedData.gasPriceInGwei; | ||
let EOA; | ||
|
||
const provider = await ethers.providers.getDefaultProvider(providerName); | ||
const signers = await ethers.getSigners(); | ||
|
||
if (useLedger) { | ||
EOA = new LedgerSigner(provider, derivationPath); | ||
} else { | ||
EOA = signers[0]; | ||
} | ||
// EOA address | ||
const deployer = await EOA.getAddress(); | ||
console.log("EOA is:", deployer); | ||
|
||
// Transaction signing and execution | ||
console.log("1. EOA to deploy WormholeL1Receiver contract"); | ||
const WormholeL1Receiver = await ethers.getContractFactory("WormholeL1Receiver"); | ||
console.log("You are signing the following transaction: WormholeL1Receiver.connect(EOA).deploy()"); | ||
const wormholeL1Receiver = await WormholeL1Receiver.connect(EOA).deploy(); | ||
const result = await wormholeL1Receiver.deployed(); | ||
|
||
// Transaction details | ||
console.log("Contract deployment: WormholeL1Receiver"); | ||
console.log("Contract address:", wormholeL1Receiver.address); | ||
console.log("Transaction:", result.deployTransaction.hash); | ||
|
||
// Writing updated parameters back to the JSON file | ||
parsedData.wormholeL1ReceiverAddress = wormholeL1Receiver.address; | ||
fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); | ||
|
||
// Contract verification | ||
if (parsedData.contractVerification) { | ||
const execSync = require("child_process").execSync; | ||
execSync("npx hardhat verify --network " + providerName + " " + wormholeL1Receiver.address, { encoding: "utf-8" }); | ||
} | ||
} | ||
|
||
main() | ||
.then(() => process.exit(0)) | ||
.catch((error) => { | ||
console.error(error); | ||
process.exit(1); | ||
}); |
58 changes: 58 additions & 0 deletions
58
scripts/deployment/bridges/wormhole/test/l1_l2_l1/deploy_05_womholel1sender.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/*global process*/ | ||
|
||
const { ethers } = require("hardhat"); | ||
const { LedgerSigner } = require("@anders-t/ethers-ledger"); | ||
|
||
async function main() { | ||
const fs = require("fs"); | ||
const globalsFile = "globals.json"; | ||
const dataFromJSON = fs.readFileSync(globalsFile, "utf8"); | ||
let parsedData = JSON.parse(dataFromJSON); | ||
const useLedger = parsedData.useLedger; | ||
const derivationPath = parsedData.derivationPath; | ||
const providerName = parsedData.providerName; | ||
const gasPriceInGwei = parsedData.gasPriceInGwei; | ||
let EOA; | ||
|
||
const provider = new ethers.providers.JsonRpcProvider(parsedData.networkURL); | ||
const signers = await ethers.getSigners(); | ||
|
||
if (useLedger) { | ||
EOA = new LedgerSigner(provider, derivationPath); | ||
} else { | ||
EOA = signers[0]; | ||
} | ||
// EOA address | ||
const deployer = await EOA.getAddress(); | ||
console.log("EOA is:", deployer); | ||
|
||
// Transaction signing and execution | ||
console.log("1. EOA to deploy WormholeL1Sender contract"); | ||
const WormholeL1Sender = await ethers.getContractFactory("WormholeL1Sender"); | ||
console.log("You are signing the following transaction: WormholeL1Sender.connect(EOA).deploy()"); | ||
const wormholeL1Sender = await WormholeL1Sender.connect(EOA).deploy(parsedData.L2WormholeRelayerAddress, | ||
parsedData.sourceChainId, parsedData.wormholeL1ReceiverAddress); | ||
const result = await wormholeL1Sender.deployed(); | ||
|
||
// Transaction details | ||
console.log("Contract deployment: WormholeL1Sender"); | ||
console.log("Contract address:", wormholeL1Sender.address); | ||
console.log("Transaction:", result.deployTransaction.hash); | ||
|
||
// Writing updated parameters back to the JSON file | ||
parsedData.wormholeL1SenderAddress = wormholeL1Sender.address; | ||
fs.writeFileSync(globalsFile, JSON.stringify(parsedData)); | ||
|
||
// Contract verification | ||
if (parsedData.contractVerification) { | ||
const execSync = require("child_process").execSync; | ||
execSync("npx hardhat verify --constructor-args scripts/deployment/bridges/wormhole/test/l1_l2_l1/verify_05_womholel1sender.js --network " + providerName + " " + wormholeL1Sender.address, { encoding: "utf-8" }); | ||
} | ||
} | ||
|
||
main() | ||
.then(() => process.exit(0)) | ||
.catch((error) => { | ||
console.error(error); | ||
process.exit(1); | ||
}); |
1 change: 1 addition & 0 deletions
1
scripts/deployment/bridges/wormhole/test/l1_l2_l1/globals_optimistic_sepolia.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"contractVerification":true,"useLedger":false,"derivationPath":"m/44'/60'/2'/0/0","providerName":"optimisticSepolia","gasPriceInGwei":"2","networkURL":"https://sepolia.optimism.io","sourceChainId":"10002","L1WormholeRelayerAddress":"0x7B1bD7a6b4E61c2a123AC6BC2cbfC614437D0470","L2WormholeRelayerAddress":"0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE","wormholeL2ReceiverL1SenderAddress":"0x1d333b46dB6e8FFd271b6C2D2B254868BD9A2dbd","wormholeL1ReceiverAddress":"0xF66E23209074FA7946E41f45f43d765281af2207","wormholeL1SenderAddress":"0x04A0afD079F14D539B17253Ea93563934A024165"} |
Oops, something went wrong.