编译器
0.8.18+commit.87f61d96
文件 1 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 7:GasUsage.sol
pragma solidity ^0.8.18;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IGasOracle} from "./interfaces/IGasOracle.sol";
abstract contract GasUsage is Ownable {
IGasOracle internal gasOracle;
mapping(uint chainId => uint amount) public gasUsage;
constructor(IGasOracle gasOracle_) {
gasOracle = gasOracle_;
}
function setGasUsage(uint chainId, uint gasAmount) external onlyOwner {
gasUsage[chainId] = gasAmount;
}
function setGasOracle(IGasOracle gasOracle_) external onlyOwner {
gasOracle = gasOracle_;
}
function getTransactionCost(uint chainId) external view returns (uint) {
unchecked {
return gasOracle.getTransactionGasCostInNativeToken(chainId, gasUsage[chainId]);
}
}
}
文件 3 的 7:HashUtils.sol
pragma solidity ^0.8.18;
library HashUtils {
function replaceChainBytes(
bytes32 data,
uint8 sourceChainId,
uint8 destinationChainId
) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, data)
mstore8(0x00, sourceChainId)
mstore8(0x01, destinationChainId)
result := mload(0x0)
}
}
function hashWithSender(bytes32 message, bytes32 sender) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, message)
mstore(0x20, sender)
result := or(
and(
message,
0xffff000000000000000000000000000000000000000000000000000000000000
),
and(
keccak256(0x00, 0x40),
0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
)
)
}
}
function hashWithSenderAddress(bytes32 message, address sender) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, message)
mstore(0x20, sender)
result := or(
and(
message,
0xffff000000000000000000000000000000000000000000000000000000000000
),
and(
keccak256(0x00, 0x40),
0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
)
)
}
}
function hashed(bytes32 message) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, message)
result := keccak256(0x00, 0x20)
}
}
}
文件 4 的 7:IGasOracle.sol
pragma solidity ^0.8.18;
interface IGasOracle {
function chainData(uint chainId) external view returns (uint128 price, uint128 gasPrice);
function chainId() external view returns (uint);
function crossRate(uint otherChainId) external view returns (uint);
function getTransactionGasCostInNativeToken(uint otherChainId, uint256 gasAmount) external view returns (uint);
function getTransactionGasCostInUSD(uint otherChainId, uint256 gasAmount) external view returns (uint);
function price(uint chainId) external view returns (uint);
function setChainData(uint chainId, uint128 price, uint128 gasPrice) external;
function setGasPrice(uint chainId, uint128 gasPrice) external;
function setPrice(uint chainId, uint128 price) external;
}
文件 5 的 7:IMessenger.sol
pragma solidity ^0.8.18;
interface IMessenger {
function sentMessagesBlock(bytes32 message) external view returns (uint);
function receivedMessages(bytes32 message) external view returns (uint);
function sendMessage(bytes32 message) external payable;
function receiveMessage(bytes32 message, uint v1v2, bytes32 r1, bytes32 s1, bytes32 r2, bytes32 s2) external;
}
文件 6 的 7:Messenger.sol
pragma solidity ^0.8.18;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IGasOracle} from "./interfaces/IGasOracle.sol";
import {IMessenger} from "./interfaces/IMessenger.sol";
import {GasUsage} from "./GasUsage.sol";
import {HashUtils} from "./libraries/HashUtils.sol";
contract Messenger is Ownable, GasUsage, IMessenger {
using HashUtils for bytes32;
uint public immutable chainId;
bytes32 public otherChainIds;
address private primaryValidator;
mapping(address => bool) private secondaryValidators;
mapping(bytes32 messageHash => uint blockNumber) public override sentMessagesBlock;
mapping(bytes32 messageHash => uint isReceived) public override receivedMessages;
event MessageSent(bytes32 indexed message);
event MessageReceived(bytes32 indexed message);
event Received(address, uint);
event SecondaryValidatorsSet(address[] oldValidators, address[] newValidators);
constructor(
uint chainId_,
bytes32 otherChainIds_,
IGasOracle gasOracle_,
address primaryValidator_,
address[] memory validators
) GasUsage(gasOracle_) {
chainId = chainId_;
otherChainIds = otherChainIds_;
primaryValidator = primaryValidator_;
uint length = validators.length;
for (uint index; index < length; ) {
secondaryValidators[validators[index]] = true;
unchecked {
index++;
}
}
}
function sendMessage(bytes32 message) external payable override {
require(uint8(message[0]) == chainId, "Messenger: wrong chainId");
require(otherChainIds[uint8(message[1])] != 0, "Messenger: wrong destination");
bytes32 messageWithSender = message.hashWithSenderAddress(msg.sender);
require(sentMessagesBlock[messageWithSender] == 0, "Messenger: has message");
sentMessagesBlock[messageWithSender] = block.number;
require(msg.value >= this.getTransactionCost(uint8(message[1])), "Messenger: not enough fee");
emit MessageSent(messageWithSender);
}
function receiveMessage(
bytes32 message,
uint v1v2,
bytes32 r1,
bytes32 s1,
bytes32 r2,
bytes32 s2
) external override {
bytes32 hashedMessage = message.hashed();
require(ecrecover(hashedMessage, uint8(v1v2 >> 8), r1, s1) == primaryValidator, "Messenger: invalid primary");
require(secondaryValidators[ecrecover(hashedMessage, uint8(v1v2), r2, s2)], "Messenger: invalid secondary");
require(uint8(message[1]) == chainId, "Messenger: wrong chainId");
receivedMessages[message] = 1;
emit MessageReceived(message);
}
function withdrawGasTokens(uint amount) external onlyOwner {
payable(msg.sender).transfer(amount);
}
function setPrimaryValidator(address value) external onlyOwner {
primaryValidator = value;
}
function setSecondaryValidators(address[] memory oldValidators, address[] memory newValidators) external onlyOwner {
uint length = oldValidators.length;
uint index;
for (; index < length; ) {
secondaryValidators[oldValidators[index]] = false;
unchecked {
index++;
}
}
length = newValidators.length;
index = 0;
for (; index < length; ) {
secondaryValidators[newValidators[index]] = true;
unchecked {
index++;
}
}
emit SecondaryValidatorsSet(oldValidators, newValidators);
}
function setOtherChainIds(bytes32 value) external onlyOwner {
otherChainIds = value;
}
fallback() external payable {
revert("Unsupported");
}
receive() external payable {
emit Received(msg.sender, msg.value);
}
}
文件 7 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/Messenger.sol": "Messenger"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"},{"internalType":"bytes32","name":"otherChainIds_","type":"bytes32"},{"internalType":"contract IGasOracle","name":"gasOracle_","type":"address"},{"internalType":"address","name":"primaryValidator_","type":"address"},{"internalType":"address[]","name":"validators","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"oldValidators","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"newValidators","type":"address[]"}],"name":"SecondaryValidatorsSet","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"gasUsage","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getTransactionCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherChainIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"message","type":"bytes32"},{"internalType":"uint256","name":"v1v2","type":"uint256"},{"internalType":"bytes32","name":"r1","type":"bytes32"},{"internalType":"bytes32","name":"s1","type":"bytes32"},{"internalType":"bytes32","name":"r2","type":"bytes32"},{"internalType":"bytes32","name":"s2","type":"bytes32"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"receivedMessages","outputs":[{"internalType":"uint256","name":"isReceived","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"sentMessagesBlock","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IGasOracle","name":"gasOracle_","type":"address"}],"name":"setGasOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"gasAmount","type":"uint256"}],"name":"setGasUsage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"setOtherChainIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setPrimaryValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"oldValidators","type":"address[]"},{"internalType":"address[]","name":"newValidators","type":"address[]"}],"name":"setSecondaryValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawGasTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]