Created
October 7, 2020 23:59
-
-
Save karlfloersch/4278f18636cf0bd4111176e46cfcf2c0 to your computer and use it in GitHub Desktop.
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
pragma solidity ^0.5.0; | |
/* Interface Imports */ | |
import { ICrossDomainMessenger } from "./interfaces/CrossDomainMessenger.interface.sol"; | |
/** | |
* @title BaseCrossDomainMessenger | |
*/ | |
contract BaseCrossDomainMessenger is ICrossDomainMessenger { | |
event SentMessage(bytes32 msgHash); | |
/* | |
* Contract Variables | |
*/ | |
mapping (bytes32 => bool) public receivedMessages; | |
mapping (bytes32 => bool) public sentMessages; | |
address public targetMessengerAddress; | |
uint256 public messageNonce; | |
address public xDomainMessageSender; | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Sets the target messenger address. | |
* @param _targetMessengerAddress New messenger address. | |
*/ | |
function setTargetMessengerAddress( | |
address _targetMessengerAddress | |
) | |
public | |
{ | |
targetMessengerAddress = _targetMessengerAddress; | |
} | |
/** | |
* Sends a cross domain message to the target messenger. | |
* .inheritdoc IL2CrossDomainMessenger | |
*/ | |
function sendMessage( | |
address _target, | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
msg.sender, | |
_message, | |
messageNonce | |
); | |
_sendXDomainMessage(xDomainCalldata, _gasLimit); | |
messageNonce += 1; | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
sentMessages[msgHash] = true; | |
emit SentMessage(msgHash); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Generates the correct cross domain calldata for a message. | |
* @param _target Target contract address. | |
* @param _sender Message sender address. | |
* @param _message Message to send to the target. | |
* @param _messageNonce Nonce for the provided message. | |
* @return ABI encoded cross domain calldata. | |
*/ | |
function _getXDomainCalldata( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce | |
) | |
internal | |
pure | |
returns ( | |
bytes memory | |
) | |
{ | |
return abi.encodeWithSelector( | |
bytes4(keccak256(bytes("relayMessage(address,address,bytes,uint256)"))), | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit OVM gas limit for the message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) internal; | |
} |
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
pragma solidity ^0.5.0; | |
/* Interface Imports */ | |
import { ICrossDomainMessenger } from "./interfaces/CrossDomainMessenger.interface.sol"; | |
/** | |
* @title BaseCrossDomainMessenger | |
*/ | |
contract BaseCrossDomainMessenger is ICrossDomainMessenger { | |
event SentMessage(bytes32 msgHash); | |
/* | |
* Contract Variables | |
*/ | |
mapping (bytes32 => bool) public receivedMessages; | |
mapping (bytes32 => bool) public sentMessages; | |
address public targetMessengerAddress; | |
uint256 public messageNonce; | |
address public xDomainMessageSender; | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Sets the target messenger address. | |
* @param _targetMessengerAddress New messenger address. | |
*/ | |
function setTargetMessengerAddress( | |
address _targetMessengerAddress | |
) | |
public | |
{ | |
targetMessengerAddress = _targetMessengerAddress; | |
} | |
/** | |
* Sends a cross domain message to the target messenger. | |
* .inheritdoc IL2CrossDomainMessenger | |
*/ | |
function sendMessage( | |
address _target, | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
msg.sender, | |
_message, | |
messageNonce | |
); | |
_sendXDomainMessage(xDomainCalldata, _gasLimit); | |
messageNonce += 1; | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
sentMessages[msgHash] = true; | |
emit SentMessage(msgHash); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Generates the correct cross domain calldata for a message. | |
* @param _target Target contract address. | |
* @param _sender Message sender address. | |
* @param _message Message to send to the target. | |
* @param _messageNonce Nonce for the provided message. | |
* @return ABI encoded cross domain calldata. | |
*/ | |
function _getXDomainCalldata( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce | |
) | |
internal | |
pure | |
returns ( | |
bytes memory | |
) | |
{ | |
return abi.encodeWithSelector( | |
bytes4(keccak256(bytes("relayMessage(address,address,bytes,uint256)"))), | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit OVM gas limit for the message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) internal; | |
} | |
pragma solidity ^0.5.0; | |
pragma experimental ABIEncoderV2; | |
/* Library Imports */ | |
import { ContractResolver } from "../utils/resolvers/ContractResolver.sol"; | |
import { EthMerkleTrie } from "../utils/libraries/EthMerkleTrie.sol"; | |
import { BytesLib } from "../utils/libraries/BytesLib.sol"; | |
import { DataTypes } from "../utils/libraries/DataTypes.sol"; | |
/* Contract Imports */ | |
import { BaseCrossDomainMessenger } from "./BaseCrossDomainMessenger.sol"; | |
import { L1ToL2TransactionQueue } from "../queue/L1ToL2TransactionQueue.sol"; | |
import { StateCommitmentChain } from "../chain/StateCommitmentChain.sol"; | |
/** | |
* @title L1CrossDomainMessenger | |
*/ | |
contract L1CrossDomainMessenger is BaseCrossDomainMessenger, ContractResolver { | |
event RelayedL2ToL1Message(bytes32 msgHash); | |
/* | |
* Data Structures | |
*/ | |
struct L2MessageInclusionProof { | |
bytes32 stateRoot; | |
uint256 stateRootIndex; | |
DataTypes.StateElementInclusionProof stateRootProof; | |
bytes stateTrieWitness; | |
bytes storageTrieWitness; | |
} | |
/* | |
* Constructor | |
*/ | |
/** | |
* @param _addressResolver Address of the AddressResolver contract. | |
*/ | |
constructor( | |
address _addressResolver | |
) | |
public | |
ContractResolver(_addressResolver) | |
{} | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Relays a cross domain message to a contract. | |
* .inheritdoc IL1CrossDomainMessenger | |
*/ | |
function relayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce, | |
L2MessageInclusionProof memory _proof | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
require( | |
_verifyXDomainMessage( | |
xDomainCalldata, | |
_proof | |
) == true, | |
"Provided message could not be verified." | |
); | |
require( | |
receivedMessages[msgHash] == false, | |
"Provided message has already been received." | |
); | |
xDomainMessageSender = _sender; | |
_target.call(_message); | |
// Messages are considered successfully executed if they complete | |
// without running out of gas (revert or not). As a result, we can | |
// ignore the result of the call and always mark the message as | |
// successfully executed because we won't get here unless we have | |
// enough gas left over. | |
receivedMessages[msgHash] = true; | |
emit RelayedL2ToL1Message(msgHash); | |
} | |
/** | |
* Replays a cross domain message to the target messenger. | |
* .inheritdoc IL1CrossDomainMessenger | |
*/ | |
function replayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce, | |
uint32 _gasLimit | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
require( | |
sentMessages[keccak256(xDomainCalldata)] == true, | |
"Provided message has not already been sent." | |
); | |
_sendXDomainMessage(xDomainCalldata, _gasLimit); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Verifies that the given message is valid. | |
* @param _xDomainCalldata Calldata to verify. | |
* @param _proof Inclusion proof for the message. | |
* @return Whether or not the provided message is valid. | |
*/ | |
function _verifyXDomainMessage( | |
bytes memory _xDomainCalldata, | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
return ( | |
_verifyStateRootProof(_proof) && _verifyStorageProof(_xDomainCalldata, _proof) | |
); | |
} | |
/** | |
* Verifies that the state root within an inclusion proof is valid. | |
* @param _proof Message inclusion proof. | |
* @return Whether or not the provided proof is valid. | |
*/ | |
function _verifyStateRootProof( | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
// TODO: We *must* verify that the batch timestamp is sufficiently old. | |
// However, this requires that we first add timestamps to state batches | |
// and account for that change in various tests. Change of that size is | |
// out of scope for this ticket, so "TODO" for now. | |
StateCommitmentChain stateCommitmentChain = resolveStateCommitmentChain(); | |
return stateCommitmentChain.verifyElement( | |
abi.encodePacked(_proof.stateRoot), | |
_proof.stateRootIndex, | |
_proof.stateRootProof | |
); | |
} | |
/** | |
* Verifies that the storage proof within an inclusion proof is valid. | |
* @param _xDomainCalldata Encoded message calldata. | |
* @param _proof Message inclusion proof. | |
* @return Whether or not the provided proof is valid. | |
*/ | |
function _verifyStorageProof( | |
bytes memory _xDomainCalldata, | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
bytes32 storageKey = keccak256( | |
BytesLib.concat( | |
abi.encodePacked(keccak256(_xDomainCalldata)), | |
abi.encodePacked(uint256(0)) | |
) | |
); | |
return EthMerkleTrie.proveAccountStorageSlotValue( | |
0x4200000000000000000000000000000000000000, | |
storageKey, | |
bytes32(uint256(1)), | |
_proof.stateTrieWitness, | |
_proof.storageTrieWitness, | |
_proof.stateRoot | |
); | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit OVM gas limit for the message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
internal | |
{ | |
L1ToL2TransactionQueue l1ToL2TransactionQueue = resolveL1ToL2TransactionQueue(); | |
l1ToL2TransactionQueue.enqueueL1ToL2Message( | |
targetMessengerAddress, | |
_gasLimit, | |
_message | |
); | |
} | |
/* | |
* Contract Resolution | |
*/ | |
function resolveL1ToL2TransactionQueue() | |
internal | |
view | |
returns (L1ToL2TransactionQueue) | |
{ | |
return L1ToL2TransactionQueue(resolveContract("L1ToL2TransactionQueue")); | |
} | |
function resolveStateCommitmentChain() | |
internal | |
view | |
returns (StateCommitmentChain) | |
{ | |
return StateCommitmentChain(resolveContract("StateCommitmentChain")); | |
} | |
} | |
pragma solidity ^0.5.0; | |
/* Interface Imports */ | |
import { IL1MessageSender } from "../ovm/precompiles/L1MessageSender.interface.sol"; | |
import { IL2ToL1MessagePasser } from "../ovm/precompiles/L2ToL1MessagePasser.interface.sol"; | |
/* Contract Imports */ | |
import { BaseCrossDomainMessenger } from "./BaseCrossDomainMessenger.sol"; | |
/** | |
* @title L2CrossDomainMessenger | |
*/ | |
contract L2CrossDomainMessenger is BaseCrossDomainMessenger { | |
event RelayedL1ToL2Message(bytes32 msgHash); | |
/* | |
* Contract Variables | |
*/ | |
address private l1MessageSenderPrecompileAddress; | |
address private l2ToL1MessagePasserPrecompileAddress; | |
/* | |
* Constructor | |
*/ | |
/** | |
* @param _l1MessageSenderPrecompileAddress L1MessageSender address. | |
* @param _l2ToL1MessagePasserPrecompileAddress L2ToL1MessagePasser address. | |
*/ | |
constructor( | |
address _l1MessageSenderPrecompileAddress, | |
address _l2ToL1MessagePasserPrecompileAddress | |
) | |
public | |
{ | |
l1MessageSenderPrecompileAddress = _l1MessageSenderPrecompileAddress; | |
l2ToL1MessagePasserPrecompileAddress = _l2ToL1MessagePasserPrecompileAddress; | |
} | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Relays a cross domain message to a contract. | |
* .inheritdoc IL2CrossDomainMessenger | |
*/ | |
function relayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce | |
) | |
public | |
{ | |
require( | |
_verifyXDomainMessage() == true, | |
"Provided message could not be verified." | |
); | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
require( | |
receivedMessages[msgHash] == false, | |
"Provided message has already been received." | |
); | |
xDomainMessageSender = _sender; | |
_target.call(_message); | |
// Messages are considered successfully executed if they complete | |
// without running out of gas (revert or not). As a result, we can | |
// ignore the result of the call and always mark the message as | |
// successfully executed because we won't get here unless we have | |
// enough gas left over. | |
receivedMessages[msgHash] = true; | |
emit RelayedL1ToL2Message(msgHash); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Verifies that a received cross domain message is valid. | |
* @return Whether or not the message is valid. | |
*/ | |
function _verifyXDomainMessage() | |
internal | |
returns ( | |
bool | |
) | |
{ | |
IL1MessageSender l1MessageSenderPrecompile = IL1MessageSender(l1MessageSenderPrecompileAddress); | |
address l1MessageSenderAddress = l1MessageSenderPrecompile.getL1MessageSender(); | |
return l1MessageSenderAddress == targetMessengerAddress; | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit Gas limit for the provided message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
internal | |
{ | |
IL2ToL1MessagePasser l2ToL1MessagePasserPrecompile = IL2ToL1MessagePasser(l2ToL1MessagePasserPrecompileAddress); | |
l2ToL1MessagePasserPrecompile.passMessageToL1(_message); | |
} | |
} |
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
pragma solidity ^0.5.0; | |
pragma experimental ABIEncoderV2; | |
/* Library Imports */ | |
import { ContractResolver } from "../utils/resolvers/ContractResolver.sol"; | |
import { EthMerkleTrie } from "../utils/libraries/EthMerkleTrie.sol"; | |
import { BytesLib } from "../utils/libraries/BytesLib.sol"; | |
import { DataTypes } from "../utils/libraries/DataTypes.sol"; | |
/* Contract Imports */ | |
import { BaseCrossDomainMessenger } from "./BaseCrossDomainMessenger.sol"; | |
import { L1ToL2TransactionQueue } from "../queue/L1ToL2TransactionQueue.sol"; | |
import { StateCommitmentChain } from "../chain/StateCommitmentChain.sol"; | |
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.5.0; | |
pragma experimental ABIEncoderV2; | |
/** | |
* @title ICrossDomainMessenger | |
*/ | |
interface ICrossDomainMessenger { | |
/******************** | |
* View Functions * | |
********************/ | |
function receivedMessages(bytes32 messageHash) external view returns (bool); | |
function sentMessages(bytes32 messageHash) external view returns (bool); | |
function targetMessengerAddress() external view returns (address); | |
function messageNonce() external view returns (uint256); | |
function xDomainMessageSender() external view returns (address); | |
/******************** | |
* Public Functions * | |
********************/ | |
/** | |
* Sets the target messenger address. | |
* @param _targetMessengerAddress New messenger address. | |
*/ | |
function setTargetMessengerAddress( | |
address _targetMessengerAddress | |
) external; | |
/** | |
* Sends a cross domain message to the target messenger. | |
* @param _target Target contract address. | |
* @param _message Message to send to the target. | |
* @param _gasLimit Gas limit for the provided message. | |
*/ | |
function sendMessage( | |
address _target, | |
bytes calldata _message, | |
uint32 _gasLimit | |
) external; | |
} | |
/** | |
* @title L1CrossDomainMessenger | |
*/ | |
contract L1CrossDomainMessenger is BaseCrossDomainMessenger, ContractResolver { | |
event RelayedL2ToL1Message(bytes32 msgHash); | |
/* | |
* Data Structures | |
*/ | |
struct L2MessageInclusionProof { | |
bytes32 stateRoot; | |
uint256 stateRootIndex; | |
DataTypes.StateElementInclusionProof stateRootProof; | |
bytes stateTrieWitness; | |
bytes storageTrieWitness; | |
} | |
/* | |
* Constructor | |
*/ | |
/** | |
* @param _addressResolver Address of the AddressResolver contract. | |
*/ | |
constructor( | |
address _addressResolver | |
) | |
public | |
ContractResolver(_addressResolver) | |
{} | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Relays a cross domain message to a contract. | |
* .inheritdoc IL1CrossDomainMessenger | |
*/ | |
function relayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce, | |
L2MessageInclusionProof memory _proof | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
require( | |
_verifyXDomainMessage( | |
xDomainCalldata, | |
_proof | |
) == true, | |
"Provided message could not be verified." | |
); | |
require( | |
receivedMessages[msgHash] == false, | |
"Provided message has already been received." | |
); | |
xDomainMessageSender = _sender; | |
_target.call(_message); | |
// Messages are considered successfully executed if they complete | |
// without running out of gas (revert or not). As a result, we can | |
// ignore the result of the call and always mark the message as | |
// successfully executed because we won't get here unless we have | |
// enough gas left over. | |
receivedMessages[msgHash] = true; | |
emit RelayedL2ToL1Message(msgHash); | |
} | |
/** | |
* Replays a cross domain message to the target messenger. | |
* .inheritdoc IL1CrossDomainMessenger | |
*/ | |
function replayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce, | |
uint32 _gasLimit | |
) | |
public | |
{ | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
require( | |
sentMessages[keccak256(xDomainCalldata)] == true, | |
"Provided message has not already been sent." | |
); | |
_sendXDomainMessage(xDomainCalldata, _gasLimit); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Verifies that the given message is valid. | |
* @param _xDomainCalldata Calldata to verify. | |
* @param _proof Inclusion proof for the message. | |
* @return Whether or not the provided message is valid. | |
*/ | |
function _verifyXDomainMessage( | |
bytes memory _xDomainCalldata, | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
return ( | |
_verifyStateRootProof(_proof) && _verifyStorageProof(_xDomainCalldata, _proof) | |
); | |
} | |
/** | |
* Verifies that the state root within an inclusion proof is valid. | |
* @param _proof Message inclusion proof. | |
* @return Whether or not the provided proof is valid. | |
*/ | |
function _verifyStateRootProof( | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
// TODO: We *must* verify that the batch timestamp is sufficiently old. | |
// However, this requires that we first add timestamps to state batches | |
// and account for that change in various tests. Change of that size is | |
// out of scope for this ticket, so "TODO" for now. | |
StateCommitmentChain stateCommitmentChain = resolveStateCommitmentChain(); | |
return stateCommitmentChain.verifyElement( | |
abi.encodePacked(_proof.stateRoot), | |
_proof.stateRootIndex, | |
_proof.stateRootProof | |
); | |
} | |
/** | |
* Verifies that the storage proof within an inclusion proof is valid. | |
* @param _xDomainCalldata Encoded message calldata. | |
* @param _proof Message inclusion proof. | |
* @return Whether or not the provided proof is valid. | |
*/ | |
function _verifyStorageProof( | |
bytes memory _xDomainCalldata, | |
L2MessageInclusionProof memory _proof | |
) | |
internal | |
returns ( | |
bool | |
) | |
{ | |
bytes32 storageKey = keccak256( | |
BytesLib.concat( | |
abi.encodePacked(keccak256(_xDomainCalldata)), | |
abi.encodePacked(uint256(0)) | |
) | |
); | |
return EthMerkleTrie.proveAccountStorageSlotValue( | |
0x4200000000000000000000000000000000000000, | |
storageKey, | |
bytes32(uint256(1)), | |
_proof.stateTrieWitness, | |
_proof.storageTrieWitness, | |
_proof.stateRoot | |
); | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit OVM gas limit for the message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
internal | |
{ | |
L1ToL2TransactionQueue l1ToL2TransactionQueue = resolveL1ToL2TransactionQueue(); | |
l1ToL2TransactionQueue.enqueueL1ToL2Message( | |
targetMessengerAddress, | |
_gasLimit, | |
_message | |
); | |
} | |
/* | |
* Contract Resolution | |
*/ | |
function resolveL1ToL2TransactionQueue() | |
internal | |
view | |
returns (L1ToL2TransactionQueue) | |
{ | |
return L1ToL2TransactionQueue(resolveContract("L1ToL2TransactionQueue")); | |
} | |
function resolveStateCommitmentChain() | |
internal | |
view | |
returns (StateCommitmentChain) | |
{ | |
return StateCommitmentChain(resolveContract("StateCommitmentChain")); | |
} | |
} |
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
pragma solidity ^0.5.0; | |
contract IL1MessageSender { | |
/* | |
* Public Functions | |
*/ | |
function getL1MessageSender() public returns (address); | |
} |
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
pragma solidity ^0.5.0; | |
/* Interface Imports */ | |
import { IL1MessageSender } from "../ovm/precompiles/L1MessageSender.interface.sol"; | |
import { IL2ToL1MessagePasser } from "../ovm/precompiles/L2ToL1MessagePasser.interface.sol"; | |
/* Contract Imports */ | |
import { BaseCrossDomainMessenger } from "./BaseCrossDomainMessenger.sol"; | |
/** | |
* @title L2CrossDomainMessenger | |
*/ | |
contract L2CrossDomainMessenger is BaseCrossDomainMessenger { | |
event RelayedL1ToL2Message(bytes32 msgHash);pragma solidity ^0.5.0; | |
contract IL2ToL1MessagePasser { | |
/* | |
* Events | |
*/ | |
event L2ToL1Message( | |
uint _nonce, | |
address _ovmSender, | |
bytes _callData | |
); | |
/* | |
* Public Functions | |
*/ | |
function passMessageToL1(bytes memory _messageData) public; | |
} | |
/* | |
* Contract Variables | |
*/ | |
address private l1MessageSenderPrecompileAddress; | |
address private l2ToL1MessagePasserPrecompileAddress; | |
/* | |
* Constructor | |
*/ | |
/** | |
* @param _l1MessageSenderPrecompileAddress L1MessageSender address. | |
* @param _l2ToL1MessagePasserPrecompileAddress L2ToL1MessagePasser address. | |
*/ | |
constructor( | |
address _l1MessageSenderPrecompileAddress, | |
address _l2ToL1MessagePasserPrecompileAddress | |
) | |
public | |
{ | |
l1MessageSenderPrecompileAddress = _l1MessageSenderPrecompileAddress; | |
l2ToL1MessagePasserPrecompileAddress = _l2ToL1MessagePasserPrecompileAddress; | |
} | |
/* | |
* Public Functions | |
*/ | |
/** | |
* Relays a cross domain message to a contract. | |
* .inheritdoc IL2CrossDomainMessenger | |
*/ | |
function relayMessage( | |
address _target, | |
address _sender, | |
bytes memory _message, | |
uint256 _messageNonce | |
) | |
public | |
{ | |
require( | |
_verifyXDomainMessage() == true, | |
"Provided message could not be verified." | |
); | |
bytes memory xDomainCalldata = _getXDomainCalldata( | |
_target, | |
_sender, | |
_message, | |
_messageNonce | |
); | |
bytes32 msgHash = keccak256(xDomainCalldata); | |
require( | |
receivedMessages[msgHash] == false, | |
"Provided message has already been received." | |
); | |
xDomainMessageSender = _sender; | |
_target.call(_message); | |
// Messages are considered successfully executed if they complete | |
// without running out of gas (revert or not). As a result, we can | |
// ignore the result of the call and always mark the message as | |
// successfully executed because we won't get here unless we have | |
// enough gas left over. | |
receivedMessages[msgHash] = true; | |
emit RelayedL1ToL2Message(msgHash); | |
} | |
/* | |
* Internal Functions | |
*/ | |
/** | |
* Verifies that a received cross domain message is valid. | |
* @return Whether or not the message is valid. | |
*/ | |
function _verifyXDomainMessage() | |
internal | |
returns ( | |
bool | |
) | |
{ | |
IL1MessageSender l1MessageSenderPrecompile = IL1MessageSender(l1MessageSenderPrecompileAddress); | |
address l1MessageSenderAddress = l1MessageSenderPrecompile.getL1MessageSender(); | |
return l1MessageSenderAddress == targetMessengerAddress; | |
} | |
/** | |
* Sends a cross domain message. | |
* @param _message Message to send. | |
* @param _gasLimit Gas limit for the provided message. | |
*/ | |
function _sendXDomainMessage( | |
bytes memory _message, | |
uint32 _gasLimit | |
) | |
internal | |
{ | |
IL2ToL1MessagePasser l2ToL1MessagePasserPrecompile = IL2ToL1MessagePasser(l2ToL1MessagePasserPrecompileAddress); | |
l2ToL1MessagePasserPrecompile.passMessageToL1(_message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment