// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Contract Imports */
import { Ownable } from "./Lib_Ownable.sol";
/**
* @title Lib_AddressManager
*/
contract Lib_AddressManager is Ownable {
/**********
* Events *
**********/
event AddressSet(
string _name,
address _newAddress
);
/*******************************************
* Contract Variables: Internal Accounting *
*******************************************/
mapping (bytes32 => address) private addresses;
/********************
* Public Functions *
********************/
function setAddress(
string memory _name,
address _address
)
public
onlyOwner
{
emit AddressSet(_name, _address);
addresses[_getNameHash(_name)] = _address;
}
function getAddress(
string memory _name
)
public
view
returns (address)
{
return addresses[_getNameHash(_name)];
}
/**********************
* Internal Functions *
**********************/
function _getNameHash(
string memory _name
)
internal
pure
returns (
bytes32 _hash
)
{
return keccak256(abi.encodePacked(_name));
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Library Imports */
import { Lib_AddressManager } from "./Lib_AddressManager.sol";
/**
* @title Lib_AddressResolver
*/
abstract contract Lib_AddressResolver {
/*******************************************
* Contract Variables: Contract References *
*******************************************/
Lib_AddressManager public libAddressManager;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Lib_AddressManager.
*/
constructor(
address _libAddressManager
) {
libAddressManager = Lib_AddressManager(_libAddressManager);
}
/********************
* Public Functions *
********************/
function resolve(
string memory _name
)
public
view
returns (
address _contract
)
{
return libAddressManager.getAddress(_name);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title Lib_Byte32Utils
*/
library Lib_Bytes32Utils {
/**********************
* Internal Functions *
**********************/
/**
* Converts a bytes32 value to a boolean. Anything non-zero will be converted to "true."
* @param _in Input bytes32 value.
* @return Bytes32 as a boolean.
*/
function toBool(
bytes32 _in
)
internal
pure
returns (
bool
)
{
return _in != 0;
}
/**
* Converts a boolean to a bytes32 value.
* @param _in Input boolean value.
* @return Boolean as a bytes32.
*/
function fromBool(
bool _in
)
internal
pure
returns (
bytes32
)
{
return bytes32(uint256(_in ? 1 : 0));
}
/**
* Converts a bytes32 value to an address. Takes the *last* 20 bytes.
* @param _in Input bytes32 value.
* @return Bytes32 as an address.
*/
function toAddress(
bytes32 _in
)
internal
pure
returns (
address
)
{
return address(uint160(uint256(_in)));
}
/**
* Converts an address to a bytes32.
* @param _in Input address value.
* @return Address as a bytes32.
*/
function fromAddress(
address _in
)
internal
pure
returns (
bytes32
)
{
return bytes32(uint256(_in));
}
/**
* Removes the leading zeros from a bytes32 value and returns a new (smaller) bytes value.
* @param _in Input bytes32 value.
* @return Bytes32 without any leading zeros.
*/
function removeLeadingZeros(
bytes32 _in
)
internal
pure
returns (
bytes memory
)
{
bytes memory out;
assembly {
// Figure out how many leading zero bytes to remove.
let shift := 0
for { let i := 0 } and(lt(i, 32), eq(byte(i, _in), 0)) { i := add(i, 1) } {
shift := add(shift, 1)
}
// Reserve some space for our output and fix the free memory pointer.
out := mload(0x40)
mstore(0x40, add(out, 0x40))
// Shift the value and store it into the output bytes.
mstore(add(out, 0x20), shl(mul(shift, 8), _in))
// Store the new size (with leading zero bytes removed) in the output byte size.
mstore(out, sub(32, shift))
}
return out;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title Lib_BytesUtils
*/
library Lib_BytesUtils {
/**********************
* Internal Functions *
**********************/
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
)
internal
pure
returns (bytes memory)
{
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function slice(
bytes memory _bytes,
uint256 _start
)
internal
pure
returns (bytes memory)
{
if (_bytes.length - _start == 0) {
return bytes('');
}
return slice(_bytes, _start, _bytes.length - _start);
}
function toBytes32PadLeft(
bytes memory _bytes
)
internal
pure
returns (bytes32)
{
bytes32 ret;
uint256 len = _bytes.length <= 32 ? _bytes.length : 32;
assembly {
ret := shr(mul(sub(32, len), 8), mload(add(_bytes, 32)))
}
return ret;
}
function toBytes32(
bytes memory _bytes
)
internal
pure
returns (bytes32)
{
if (_bytes.length < 32) {
bytes32 ret;
assembly {
ret := mload(add(_bytes, 32))
}
return ret;
}
return abi.decode(_bytes,(bytes32)); // will truncate if input length > 32 bytes
}
function toUint256(
bytes memory _bytes
)
internal
pure
returns (uint256)
{
return uint256(toBytes32(_bytes));
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, "toUint24_overflow");
require(_bytes.length >= _start + 3 , "toUint24_outOfBounds");
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_start + 1 >= _start, "toUint8_overflow");
require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, "toAddress_overflow");
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toNibbles(
bytes memory _bytes
)
internal
pure
returns (bytes memory)
{
bytes memory nibbles = new bytes(_bytes.length * 2);
for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
}
return nibbles;
}
function fromNibbles(
bytes memory _bytes
)
internal
pure
returns (bytes memory)
{
bytes memory ret = new bytes(_bytes.length / 2);
for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
}
return ret;
}
function equal(
bytes memory _bytes,
bytes memory _other
)
internal
pure
returns (bool)
{
return keccak256(_bytes) == keccak256(_other);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/**
* @title Lib_ErrorUtils
*/
library Lib_ErrorUtils {
/**********************
* Internal Functions *
**********************/
/**
* Encodes an error string into raw solidity-style revert data.
* (i.e. ascii bytes, prefixed with bytes4(keccak("Error(string))"))
* Ref: https://docs.soliditylang.org/en/v0.8.2/control-structures.html?highlight=Error(string)#panic-via-assert-and-error-via-require
* @param _reason Reason for the reversion.
* @return Standard solidity revert data for the given reason.
*/
function encodeRevertString(
string memory _reason
)
internal
pure
returns (
bytes memory
)
{
return abi.encodeWithSignature(
"Error(string)",
_reason
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title Lib_MerkleTree
* @author River Keefer
*/
library Lib_MerkleTree {
/**********************
* Internal Functions *
**********************/
/**
* Calculates a merkle root for a list of 32-byte leaf hashes. WARNING: If the number
* of leaves passed in is not a power of two, it pads out the tree with zero hashes.
* If you do not know the original length of elements for the tree you are verifying,
* then this may allow empty leaves past _elements.length to pass a verification check down the line.
* Note that the _elements argument is modified, therefore it must not be used again afterwards
* @param _elements Array of hashes from which to generate a merkle root.
* @return Merkle root of the leaves, with zero hashes for non-powers-of-two (see above).
*/
function getMerkleRoot(
bytes32[] memory _elements
)
internal
pure
returns (
bytes32
)
{
require(
_elements.length > 0,
"Lib_MerkleTree: Must provide at least one leaf hash."
);
if (_elements.length == 1) {
return _elements[0];
}
uint256[16] memory defaults = [
0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563,
0x633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d,
0x890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d,
0x3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8,
0xecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da,
0xdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5,
0x617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7,
0x292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead,
0xe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e10,
0x7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f82,
0xe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e83636516,
0x3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c,
0xad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e,
0xa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab,
0x4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c862,
0x2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf10
];
// Reserve memory space for our hashes.
bytes memory buf = new bytes(64);
// We'll need to keep track of left and right siblings.
bytes32 leftSibling;
bytes32 rightSibling;
// Number of non-empty nodes at the current depth.
uint256 rowSize = _elements.length;
// Current depth, counting from 0 at the leaves
uint256 depth = 0;
// Common sub-expressions
uint256 halfRowSize; // rowSize / 2
bool rowSizeIsOdd; // rowSize % 2 == 1
while (rowSize > 1) {
halfRowSize = rowSize / 2;
rowSizeIsOdd = rowSize % 2 == 1;
for (uint256 i = 0; i < halfRowSize; i++) {
leftSibling = _elements[(2 * i) ];
rightSibling = _elements[(2 * i) + 1];
assembly {
mstore(add(buf, 32), leftSibling )
mstore(add(buf, 64), rightSibling)
}
_elements[i] = keccak256(buf);
}
if (rowSizeIsOdd) {
leftSibling = _elements[rowSize - 1];
rightSibling = bytes32(defaults[depth]);
assembly {
mstore(add(buf, 32), leftSibling)
mstore(add(buf, 64), rightSibling)
}
_elements[halfRowSize] = keccak256(buf);
}
rowSize = halfRowSize + (rowSizeIsOdd ? 1 : 0);
depth++;
}
return _elements[0];
}
/**
* Verifies a merkle branch for the given leaf hash. Assumes the original length
* of leaves generated is a known, correct input, and does not return true for indices
* extending past that index (even if _siblings would be otherwise valid.)
* @param _root The Merkle root to verify against.
* @param _leaf The leaf hash to verify inclusion of.
* @param _index The index in the tree of this leaf.
* @param _siblings Array of sibline nodes in the inclusion proof, starting from depth 0 (bottom of the tree).
* @param _totalLeaves The total number of leaves originally passed into.
* @return Whether or not the merkle branch and leaf passes verification.
*/
function verify(
bytes32 _root,
bytes32 _leaf,
uint256 _index,
bytes32[] memory _siblings,
uint256 _totalLeaves
)
internal
pure
returns (
bool
)
{
require(
_totalLeaves > 0,
"Lib_MerkleTree: Total leaves must be greater than zero."
);
require(
_index < _totalLeaves,
"Lib_MerkleTree: Index out of bounds."
);
require(
_siblings.length == _ceilLog2(_totalLeaves),
"Lib_MerkleTree: Total siblings does not correctly correspond to total leaves."
);
bytes32 computedRoot = _leaf;
for (uint256 i = 0; i < _siblings.length; i++) {
if ((_index & 1) == 1) {
computedRoot = keccak256(
abi.encodePacked(
_siblings[i],
computedRoot
)
);
} else {
computedRoot = keccak256(
abi.encodePacked(
computedRoot,
_siblings[i]
)
);
}
_index >>= 1;
}
return _root == computedRoot;
}
/*********************
* Private Functions *
*********************/
/**
* Calculates the integer ceiling of the log base 2 of an input.
* @param _in Unsigned input to calculate the log.
* @return ceil(log_base_2(_in))
*/
function _ceilLog2(
uint256 _in
)
private
pure
returns (
uint256
)
{
require(
_in > 0,
"Lib_MerkleTree: Cannot compute ceil(log_2) of 0."
);
if (_in == 1) {
return 0;
}
// Find the highest set bit (will be floor(log_2)).
// Borrowed with <3 from https://github.com/ethereum/solidity-examples
uint256 val = _in;
uint256 highest = 0;
for (uint256 i = 128; i >= 1; i >>= 1) {
if (val & (uint(1) << i) - 1 << i != 0) {
highest += i;
val >>= i;
}
}
// Increment by one if this is not a perfect logarithm.
if ((uint(1) << highest) != _in) {
highest += 1;
}
return highest;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol";
/**
* @title Lib_OVMCodec
*/
library Lib_OVMCodec {
/*********
* Enums *
*********/
enum EOASignatureType {
EIP155_TRANSACTION,
ETH_SIGNED_MESSAGE
}
enum QueueOrigin {
SEQUENCER_QUEUE,
L1TOL2_QUEUE
}
/***********
* Structs *
***********/
struct Account {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
address ethAddress;
bool isFresh;
}
struct EVMAccount {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
}
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
uint256 prevTotalElements;
bytes extraData;
}
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}
struct Transaction {
uint256 timestamp;
uint256 blockNumber;
QueueOrigin l1QueueOrigin;
address l1TxOrigin;
address entrypoint;
uint256 gasLimit;
bytes data;
}
struct TransactionChainElement {
bool isSequenced;
uint256 queueIndex; // QUEUED TX ONLY
uint256 timestamp; // SEQUENCER TX ONLY
uint256 blockNumber; // SEQUENCER TX ONLY
bytes txData; // SEQUENCER TX ONLY
}
struct QueueElement {
bytes32 transactionHash;
uint40 timestamp;
uint40 blockNumber;
}
struct EIP155Transaction {
uint256 nonce;
uint256 gasPrice;
uint256 gasLimit;
address to;
uint256 value;
bytes data;
uint256 chainId;
}
/**********************
* Internal Functions *
**********************/
/**
* Decodes an EOA transaction (i.e., native Ethereum RLP encoding).
* @param _transaction Encoded EOA transaction.
* @return Transaction decoded into a struct.
*/
function decodeEIP155Transaction(
bytes memory _transaction,
bool _isEthSignedMessage
)
internal
pure
returns (
EIP155Transaction memory
)
{
if (_isEthSignedMessage) {
(
uint256 _nonce,
uint256 _gasLimit,
uint256 _gasPrice,
uint256 _chainId,
address _to,
bytes memory _data
) = abi.decode(
_transaction,
(uint256, uint256, uint256, uint256, address ,bytes)
);
return EIP155Transaction({
nonce: _nonce,
gasPrice: _gasPrice,
gasLimit: _gasLimit,
to: _to,
value: 0,
data: _data,
chainId: _chainId
});
} else {
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_transaction);
return EIP155Transaction({
nonce: Lib_RLPReader.readUint256(decoded[0]),
gasPrice: Lib_RLPReader.readUint256(decoded[1]),
gasLimit: Lib_RLPReader.readUint256(decoded[2]),
to: Lib_RLPReader.readAddress(decoded[3]),
value: Lib_RLPReader.readUint256(decoded[4]),
data: Lib_RLPReader.readBytes(decoded[5]),
chainId: Lib_RLPReader.readUint256(decoded[6])
});
}
}
/**
* Decompresses a compressed EIP155 transaction.
* @param _transaction Compressed EIP155 transaction bytes.
* @return Transaction parsed into a struct.
*/
function decompressEIP155Transaction(
bytes memory _transaction
)
internal
returns (
EIP155Transaction memory
)
{
return EIP155Transaction({
gasLimit: Lib_BytesUtils.toUint24(_transaction, 0),
gasPrice: uint256(Lib_BytesUtils.toUint24(_transaction, 3)) * 1000000,
nonce: Lib_BytesUtils.toUint24(_transaction, 6),
to: Lib_BytesUtils.toAddress(_transaction, 9),
data: Lib_BytesUtils.slice(_transaction, 29),
chainId: Lib_SafeExecutionManagerWrapper.safeCHAINID(),
value: 0
});
}
/**
* Encodes an EOA transaction back into the original transaction.
* @param _transaction EIP155transaction to encode.
* @param _isEthSignedMessage Whether or not this was an eth signed message.
* @return Encoded transaction.
*/
function encodeEIP155Transaction(
EIP155Transaction memory _transaction,
bool _isEthSignedMessage
)
internal
pure
returns (
bytes memory
)
{
if (_isEthSignedMessage) {
return abi.encode(
_transaction.nonce,
_transaction.gasLimit,
_transaction.gasPrice,
_transaction.chainId,
_transaction.to,
_transaction.data
);
} else {
bytes[] memory raw = new bytes[](9);
raw[0] = Lib_RLPWriter.writeUint(_transaction.nonce);
raw[1] = Lib_RLPWriter.writeUint(_transaction.gasPrice);
raw[2] = Lib_RLPWriter.writeUint(_transaction.gasLimit);
if (_transaction.to == address(0)) {
raw[3] = Lib_RLPWriter.writeBytes('');
} else {
raw[3] = Lib_RLPWriter.writeAddress(_transaction.to);
}
raw[4] = Lib_RLPWriter.writeUint(0);
raw[5] = Lib_RLPWriter.writeBytes(_transaction.data);
raw[6] = Lib_RLPWriter.writeUint(_transaction.chainId);
raw[7] = Lib_RLPWriter.writeBytes(bytes(''));
raw[8] = Lib_RLPWriter.writeBytes(bytes(''));
return Lib_RLPWriter.writeList(raw);
}
}
/**
* Encodes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return Encoded transaction bytes.
*/
function encodeTransaction(
Transaction memory _transaction
)
internal
pure
returns (
bytes memory
)
{
return abi.encodePacked(
_transaction.timestamp,
_transaction.blockNumber,
_transaction.l1QueueOrigin,
_transaction.l1TxOrigin,
_transaction.entrypoint,
_transaction.gasLimit,
_transaction.data
);
}
/**
* Hashes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return Hashed transaction
*/
function hashTransaction(
Transaction memory _transaction
)
internal
pure
returns (
bytes32
)
{
return keccak256(encodeTransaction(_transaction));
}
/**
* Converts an OVM account to an EVM account.
* @param _in OVM account to convert.
* @return Converted EVM account.
*/
function toEVMAccount(
Account memory _in
)
internal
pure
returns (
EVMAccount memory
)
{
return EVMAccount({
nonce: _in.nonce,
balance: _in.balance,
storageRoot: _in.storageRoot,
codeHash: _in.codeHash
});
}
/**
* @notice RLP-encodes an account state struct.
* @param _account Account state struct.
* @return RLP-encoded account state.
*/
function encodeEVMAccount(
EVMAccount memory _account
)
internal
pure
returns (
bytes memory
)
{
bytes[] memory raw = new bytes[](4);
// Unfortunately we can't create this array outright because
// Lib_RLPWriter.writeList will reject fixed-size arrays. Assigning
// index-by-index circumvents this issue.
raw[0] = Lib_RLPWriter.writeBytes(
Lib_Bytes32Utils.removeLeadingZeros(
bytes32(_account.nonce)
)
);
raw[1] = Lib_RLPWriter.writeBytes(
Lib_Bytes32Utils.removeLeadingZeros(
bytes32(_account.balance)
)
);
raw[2] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.storageRoot));
raw[3] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.codeHash));
return Lib_RLPWriter.writeList(raw);
}
/**
* @notice Decodes an RLP-encoded account state into a useful struct.
* @param _encoded RLP-encoded account state.
* @return Account state struct.
*/
function decodeEVMAccount(
bytes memory _encoded
)
internal
pure
returns (
EVMAccount memory
)
{
Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
return EVMAccount({
nonce: Lib_RLPReader.readUint256(accountState[0]),
balance: Lib_RLPReader.readUint256(accountState[1]),
storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
codeHash: Lib_RLPReader.readBytes32(accountState[3])
});
}
/**
* Calculates a hash for a given batch header.
* @param _batchHeader Header to hash.
* @return Hash of the header.
*/
function hashBatchHeader(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
internal
pure
returns (
bytes32
)
{
return keccak256(
abi.encode(
_batchHeader.batchRoot,
_batchHeader.batchSize,
_batchHeader.prevTotalElements,
_batchHeader.extraData
)
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title Ownable
* @dev Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
*/
abstract contract Ownable {
/*************
* Variables *
*************/
address public owner;
/**********
* Events *
**********/
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/***************
* Constructor *
***************/
constructor() {
owner = msg.sender;
emit OwnershipTransferred(address(0), owner);
}
/**********************
* Function Modifiers *
**********************/
modifier onlyOwner() {
require(
owner == msg.sender,
"Ownable: caller is not the owner"
);
_;
}
/********************
* Public Functions *
********************/
function renounceOwnership()
public
virtual
onlyOwner
{
emit OwnershipTransferred(owner, address(0));
owner = address(0);
}
function transferOwnership(address _newOwner)
public
virtual
onlyOwner
{
require(
_newOwner != address(0),
"Ownable: new owner cannot be the zero address"
);
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title Lib_RLPReader
* @dev Adapted from "RLPReader" by Hamdi Allam (hamdi.allam97@gmail.com).
*/
library Lib_RLPReader {
/*************
* Constants *
*************/
uint256 constant internal MAX_LIST_LENGTH = 32;
/*********
* Enums *
*********/
enum RLPItemType {
DATA_ITEM,
LIST_ITEM
}
/***********
* Structs *
***********/
struct RLPItem {
uint256 length;
uint256 ptr;
}
/**********************
* Internal Functions *
**********************/
/**
* Converts bytes to a reference to memory position and length.
* @param _in Input bytes to convert.
* @return Output memory reference.
*/
function toRLPItem(
bytes memory _in
)
internal
pure
returns (
RLPItem memory
)
{
uint256 ptr;
assembly {
ptr := add(_in, 32)
}
return RLPItem({
length: _in.length,
ptr: ptr
});
}
/**
* Reads an RLP list value into a list of RLP items.
* @param _in RLP list value.
* @return Decoded RLP list items.
*/
function readList(
RLPItem memory _in
)
internal
pure
returns (
RLPItem[] memory
)
{
(
uint256 listOffset,
,
RLPItemType itemType
) = _decodeLength(_in);
require(
itemType == RLPItemType.LIST_ITEM,
"Invalid RLP list value."
);
// Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by
// writing to the length. Since we can't know the number of RLP items without looping over
// the entire input, we'd have to loop twice to accurately size this array. It's easier to
// simply set a reasonable maximum list length and decrease the size before we finish.
RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
uint256 itemCount = 0;
uint256 offset = listOffset;
while (offset < _in.length) {
require(
itemCount < MAX_LIST_LENGTH,
"Provided RLP list exceeds max list length."
);
(
uint256 itemOffset,
uint256 itemLength,
) = _decodeLength(RLPItem({
length: _in.length - offset,
ptr: _in.ptr + offset
}));
out[itemCount] = RLPItem({
length: itemLength + itemOffset,
ptr: _in.ptr + offset
});
itemCount += 1;
offset += itemOffset + itemLength;
}
// Decrease the array size to match the actual item count.
assembly {
mstore(out, itemCount)
}
return out;
}
/**
* Reads an RLP list value into a list of RLP items.
* @param _in RLP list value.
* @return Decoded RLP list items.
*/
function readList(
bytes memory _in
)
internal
pure
returns (
RLPItem[] memory
)
{
return readList(
toRLPItem(_in)
);
}
/**
* Reads an RLP bytes value into bytes.
* @param _in RLP bytes value.
* @return Decoded bytes.
*/
function readBytes(
RLPItem memory _in
)
internal
pure
returns (
bytes memory
)
{
(
uint256 itemOffset,
uint256 itemLength,
RLPItemType itemType
) = _decodeLength(_in);
require(
itemType == RLPItemType.DATA_ITEM,
"Invalid RLP bytes value."
);
return _copy(_in.ptr, itemOffset, itemLength);
}
/**
* Reads an RLP bytes value into bytes.
* @param _in RLP bytes value.
* @return Decoded bytes.
*/
function readBytes(
bytes memory _in
)
internal
pure
returns (
bytes memory
)
{
return readBytes(
toRLPItem(_in)
);
}
/**
* Reads an RLP string value into a string.
* @param _in RLP string value.
* @return Decoded string.
*/
function readString(
RLPItem memory _in
)
internal
pure
returns (
string memory
)
{
return string(readBytes(_in));
}
/**
* Reads an RLP string value into a string.
* @param _in RLP string value.
* @return Decoded string.
*/
function readString(
bytes memory _in
)
internal
pure
returns (
string memory
)
{
return readString(
toRLPItem(_in)
);
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @param _in RLP bytes32 value.
* @return Decoded bytes32.
*/
function readBytes32(
RLPItem memory _in
)
internal
pure
returns (
bytes32
)
{
require(
_in.length <= 33,
"Invalid RLP bytes32 value."
);
(
uint256 itemOffset,
uint256 itemLength,
RLPItemType itemType
) = _decodeLength(_in);
require(
itemType == RLPItemType.DATA_ITEM,
"Invalid RLP bytes32 value."
);
uint256 ptr = _in.ptr + itemOffset;
bytes32 out;
assembly {
out := mload(ptr)
// Shift the bytes over to match the item size.
if lt(itemLength, 32) {
out := div(out, exp(256, sub(32, itemLength)))
}
}
return out;
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @param _in RLP bytes32 value.
* @return Decoded bytes32.
*/
function readBytes32(
bytes memory _in
)
internal
pure
returns (
bytes32
)
{
return readBytes32(
toRLPItem(_in)
);
}
/**
* Reads an RLP uint256 value into a uint256.
* @param _in RLP uint256 value.
* @return Decoded uint256.
*/
function readUint256(
RLPItem memory _in
)
internal
pure
returns (
uint256
)
{
return uint256(readBytes32(_in));
}
/**
* Reads an RLP uint256 value into a uint256.
* @param _in RLP uint256 value.
* @return Decoded uint256.
*/
function readUint256(
bytes memory _in
)
internal
pure
returns (
uint256
)
{
return readUint256(
toRLPItem(_in)
);
}
/**
* Reads an RLP bool value into a bool.
* @param _in RLP bool value.
* @return Decoded bool.
*/
function readBool(
RLPItem memory _in
)
internal
pure
returns (
bool
)
{
require(
_in.length == 1,
"Invalid RLP boolean value."
);
uint256 ptr = _in.ptr;
uint256 out;
assembly {
out := byte(0, mload(ptr))
}
require(
out == 0 || out == 1,
"Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1"
);
return out != 0;
}
/**
* Reads an RLP bool value into a bool.
* @param _in RLP bool value.
* @return Decoded bool.
*/
function readBool(
bytes memory _in
)
internal
pure
returns (
bool
)
{
return readBool(
toRLPItem(_in)
);
}
/**
* Reads an RLP address value into a address.
* @param _in RLP address value.
* @return Decoded address.
*/
function readAddress(
RLPItem memory _in
)
internal
pure
returns (
address
)
{
if (_in.length == 1) {
return address(0);
}
require(
_in.length == 21,
"Invalid RLP address value."
);
return address(readUint256(_in));
}
/**
* Reads an RLP address value into a address.
* @param _in RLP address value.
* @return Decoded address.
*/
function readAddress(
bytes memory _in
)
internal
pure
returns (
address
)
{
return readAddress(
toRLPItem(_in)
);
}
/**
* Reads the raw bytes of an RLP item.
* @param _in RLP item to read.
* @return Raw RLP bytes.
*/
function readRawBytes(
RLPItem memory _in
)
internal
pure
returns (
bytes memory
)
{
return _copy(_in);
}
/*********************
* Private Functions *
*********************/
/**
* Decodes the length of an RLP item.
* @param _in RLP item to decode.
* @return Offset of the encoded data.
* @return Length of the encoded data.
* @return RLP item type (LIST_ITEM or DATA_ITEM).
*/
function _decodeLength(
RLPItem memory _in
)
private
pure
returns (
uint256,
uint256,
RLPItemType
)
{
require(
_in.length > 0,
"RLP item cannot be null."
);
uint256 ptr = _in.ptr;
uint256 prefix;
assembly {
prefix := byte(0, mload(ptr))
}
if (prefix <= 0x7f) {
// Single byte.
return (0, 1, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xb7) {
// Short string.
uint256 strLen = prefix - 0x80;
require(
_in.length > strLen,
"Invalid RLP short string."
);
return (1, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xbf) {
// Long string.
uint256 lenOfStrLen = prefix - 0xb7;
require(
_in.length > lenOfStrLen,
"Invalid RLP long string length."
);
uint256 strLen;
assembly {
// Pick out the string length.
strLen := div(
mload(add(ptr, 1)),
exp(256, sub(32, lenOfStrLen))
)
}
require(
_in.length > lenOfStrLen + strLen,
"Invalid RLP long string."
);
return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xf7) {
// Short list.
uint256 listLen = prefix - 0xc0;
require(
_in.length > listLen,
"Invalid RLP short list."
);
return (1, listLen, RLPItemType.LIST_ITEM);
} else {
// Long list.
uint256 lenOfListLen = prefix - 0xf7;
require(
_in.length > lenOfListLen,
"Invalid RLP long list length."
);
uint256 listLen;
assembly {
// Pick out the list length.
listLen := div(
mload(add(ptr, 1)),
exp(256, sub(32, lenOfListLen))
)
}
require(
_in.length > lenOfListLen + listLen,
"Invalid RLP long list."
);
return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
}
}
/**
* Copies the bytes from a memory location.
* @param _src Pointer to the location to read from.
* @param _offset Offset to start reading from.
* @param _length Number of bytes to read.
* @return Copied bytes.
*/
function _copy(
uint256 _src,
uint256 _offset,
uint256 _length
)
private
pure
returns (
bytes memory
)
{
bytes memory out = new bytes(_length);
if (out.length == 0) {
return out;
}
uint256 src = _src + _offset;
uint256 dest;
assembly {
dest := add(out, 32)
}
// Copy over as many complete words as we can.
for (uint256 i = 0; i < _length / 32; i++) {
assembly {
mstore(dest, mload(src))
}
src += 32;
dest += 32;
}
// Pick out the remaining bytes.
uint256 mask = 256 ** (32 - (_length % 32)) - 1;
assembly {
mstore(
dest,
or(
and(mload(src), not(mask)),
and(mload(dest), mask)
)
)
}
return out;
}
/**
* Copies an RLP item into bytes.
* @param _in RLP item to copy.
* @return Copied bytes.
*/
function _copy(
RLPItem memory _in
)
private
pure
returns (
bytes memory
)
{
return _copy(_in.ptr, 0, _in.length);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
/**
* @title Lib_RLPWriter
* @author Bakaoh (with modifications)
*/
library Lib_RLPWriter {
/**********************
* Internal Functions *
**********************/
/**
* RLP encodes a byte string.
* @param _in The byte string to encode.
* @return _out The RLP encoded string in bytes.
*/
function writeBytes(
bytes memory _in
)
internal
pure
returns (
bytes memory _out
)
{
bytes memory encoded;
if (_in.length == 1 && uint8(_in[0]) < 128) {
encoded = _in;
} else {
encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
}
return encoded;
}
/**
* RLP encodes a list of RLP encoded byte byte strings.
* @param _in The list of RLP encoded byte strings.
* @return _out The RLP encoded list of items in bytes.
*/
function writeList(
bytes[] memory _in
)
internal
pure
returns (
bytes memory _out
)
{
bytes memory list = _flatten(_in);
return abi.encodePacked(_writeLength(list.length, 192), list);
}
/**
* RLP encodes a string.
* @param _in The string to encode.
* @return _out The RLP encoded string in bytes.
*/
function writeString(
string memory _in
)
internal
pure
returns (
bytes memory _out
)
{
return writeBytes(bytes(_in));
}
/**
* RLP encodes an address.
* @param _in The address to encode.
* @return _out The RLP encoded address in bytes.
*/
function writeAddress(
address _in
)
internal
pure
returns (
bytes memory _out
)
{
return writeBytes(abi.encodePacked(_in));
}
/**
* RLP encodes a uint.
* @param _in The uint256 to encode.
* @return _out The RLP encoded uint256 in bytes.
*/
function writeUint(
uint256 _in
)
internal
pure
returns (
bytes memory _out
)
{
return writeBytes(_toBinary(_in));
}
/**
* RLP encodes a bool.
* @param _in The bool to encode.
* @return _out The RLP encoded bool in bytes.
*/
function writeBool(
bool _in
)
internal
pure
returns (
bytes memory _out
)
{
bytes memory encoded = new bytes(1);
encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
return encoded;
}
/*********************
* Private Functions *
*********************/
/**
* Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
* @param _len The length of the string or the payload.
* @param _offset 128 if item is string, 192 if item is list.
* @return _encoded RLP encoded bytes.
*/
function _writeLength(
uint256 _len,
uint256 _offset
)
private
pure
returns (
bytes memory _encoded
)
{
bytes memory encoded;
if (_len < 56) {
encoded = new bytes(1);
encoded[0] = byte(uint8(_len) + uint8(_offset));
} else {
uint256 lenLen;
uint256 i = 1;
while (_len / i != 0) {
lenLen++;
i *= 256;
}
encoded = new bytes(lenLen + 1);
encoded[0] = byte(uint8(lenLen) + uint8(_offset) + 55);
for(i = 1; i <= lenLen; i++) {
encoded[i] = byte(uint8((_len / (256**(lenLen-i))) % 256));
}
}
return encoded;
}
/**
* Encode integer in big endian binary form with no leading zeroes.
* @notice TODO: This should be optimized with assembly to save gas costs.
* @param _x The integer to encode.
* @return _binary RLP encoded bytes.
*/
function _toBinary(
uint256 _x
)
private
pure
returns (
bytes memory _binary
)
{
bytes memory b = abi.encodePacked(_x);
uint256 i = 0;
for (; i < 32; i++) {
if (b[i] != 0) {
break;
}
}
bytes memory res = new bytes(32 - i);
for (uint256 j = 0; j < res.length; j++) {
res[j] = b[i++];
}
return res;
}
/**
* Copies a piece of memory to another location.
* @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
* @param _dest Destination location.
* @param _src Source location.
* @param _len Length of memory to copy.
*/
function _memcpy(
uint256 _dest,
uint256 _src,
uint256 _len
)
private
pure
{
uint256 dest = _dest;
uint256 src = _src;
uint256 len = _len;
for(; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
uint256 mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
/**
* Flattens a list of byte strings into one byte string.
* @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
* @param _list List of byte strings to flatten.
* @return _flattened The flattened byte string.
*/
function _flatten(
bytes[] memory _list
)
private
pure
returns (
bytes memory _flattened
)
{
if (_list.length == 0) {
return new bytes(0);
}
uint256 len;
uint256 i = 0;
for (; i < _list.length; i++) {
len += _list[i].length;
}
bytes memory flattened = new bytes(len);
uint256 flattenedPtr;
assembly { flattenedPtr := add(flattened, 0x20) }
for(i = 0; i < _list.length; i++) {
bytes memory item = _list[i];
uint256 listPtr;
assembly { listPtr := add(item, 0x20)}
_memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length;
}
return flattened;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Library Imports */
import { Lib_ErrorUtils } from "../utils/Lib_ErrorUtils.sol";
/**
* @title Lib_SafeExecutionManagerWrapper
* @dev The Safe Execution Manager Wrapper provides functions which facilitate writing OVM safe
* code using the standard solidity compiler, by routing all its operations through the Execution
* Manager.
*
* Compiler used: solc
* Runtime target: OVM
*/
library Lib_SafeExecutionManagerWrapper {
/**********************
* Internal Functions *
**********************/
/**
* Performs a safe ovmCALL.
* @param _gasLimit Gas limit for the call.
* @param _target Address to call.
* @param _calldata Data to send to the call.
* @return _success Whether or not the call reverted.
* @return _returndata Data returned by the call.
*/
function safeCALL(
uint256 _gasLimit,
address _target,
bytes memory _calldata
)
internal
returns (
bool _success,
bytes memory _returndata
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCALL(uint256,address,bytes)",
_gasLimit,
_target,
_calldata
)
);
return abi.decode(returndata, (bool, bytes));
}
/**
* Performs a safe ovmDELEGATECALL.
* @param _gasLimit Gas limit for the call.
* @param _target Address to call.
* @param _calldata Data to send to the call.
* @return _success Whether or not the call reverted.
* @return _returndata Data returned by the call.
*/
function safeDELEGATECALL(
uint256 _gasLimit,
address _target,
bytes memory _calldata
)
internal
returns (
bool _success,
bytes memory _returndata
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmDELEGATECALL(uint256,address,bytes)",
_gasLimit,
_target,
_calldata
)
);
return abi.decode(returndata, (bool, bytes));
}
/**
* Performs a safe ovmCREATE call.
* @param _gasLimit Gas limit for the creation.
* @param _bytecode Code for the new contract.
* @return _contract Address of the created contract.
*/
function safeCREATE(
uint256 _gasLimit,
bytes memory _bytecode
)
internal
returns (
address,
bytes memory
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_gasLimit,
abi.encodeWithSignature(
"ovmCREATE(bytes)",
_bytecode
)
);
return abi.decode(returndata, (address, bytes));
}
/**
* Performs a safe ovmEXTCODESIZE call.
* @param _contract Address of the contract to query the size of.
* @return _EXTCODESIZE Size of the requested contract in bytes.
*/
function safeEXTCODESIZE(
address _contract
)
internal
returns (
uint256 _EXTCODESIZE
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmEXTCODESIZE(address)",
_contract
)
);
return abi.decode(returndata, (uint256));
}
/**
* Performs a safe ovmCHAINID call.
* @return _CHAINID Result of calling ovmCHAINID.
*/
function safeCHAINID()
internal
returns (
uint256 _CHAINID
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCHAINID()"
)
);
return abi.decode(returndata, (uint256));
}
/**
* Performs a safe ovmCALLER call.
* @return _CALLER Result of calling ovmCALLER.
*/
function safeCALLER()
internal
returns (
address _CALLER
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCALLER()"
)
);
return abi.decode(returndata, (address));
}
/**
* Performs a safe ovmADDRESS call.
* @return _ADDRESS Result of calling ovmADDRESS.
*/
function safeADDRESS()
internal
returns (
address _ADDRESS
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmADDRESS()"
)
);
return abi.decode(returndata, (address));
}
/**
* Performs a safe ovmGETNONCE call.
* @return _nonce Result of calling ovmGETNONCE.
*/
function safeGETNONCE()
internal
returns (
uint256 _nonce
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmGETNONCE()"
)
);
return abi.decode(returndata, (uint256));
}
/**
* Performs a safe ovmINCREMENTNONCE call.
*/
function safeINCREMENTNONCE()
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmINCREMENTNONCE()"
)
);
}
/**
* Performs a safe ovmCREATEEOA call.
* @param _messageHash Message hash which was signed by EOA
* @param _v v value of signature (0 or 1)
* @param _r r value of signature
* @param _s s value of signature
*/
function safeCREATEEOA(
bytes32 _messageHash,
uint8 _v,
bytes32 _r,
bytes32 _s
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCREATEEOA(bytes32,uint8,bytes32,bytes32)",
_messageHash,
_v,
_r,
_s
)
);
}
/**
* Performs a safe REVERT.
* @param _reason String revert reason to pass along with the REVERT.
*/
function safeREVERT(
string memory _reason
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmREVERT(bytes)",
Lib_ErrorUtils.encodeRevertString(
_reason
)
)
);
}
/**
* Performs a safe "require".
* @param _condition Boolean condition that must be true or will revert.
* @param _reason String revert reason to pass along with the REVERT.
*/
function safeREQUIRE(
bool _condition,
string memory _reason
)
internal
{
if (!_condition) {
safeREVERT(
_reason
);
}
}
/**
* Performs a safe ovmSLOAD call.
*/
function safeSLOAD(
bytes32 _key
)
internal
returns (
bytes32
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmSLOAD(bytes32)",
_key
)
);
return abi.decode(returndata, (bytes32));
}
/**
* Performs a safe ovmSSTORE call.
*/
function safeSSTORE(
bytes32 _key,
bytes32 _value
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmSSTORE(bytes32,bytes32)",
_key,
_value
)
);
}
/*********************
* Private Functions *
*********************/
/**
* Performs an ovm interaction and the necessary safety checks.
* @param _gasLimit Gas limit for the interaction.
* @param _calldata Data to send to the OVM_ExecutionManager (encoded with sighash).
* @return _returndata Data sent back by the OVM_ExecutionManager.
*/
function _safeExecutionManagerInteraction(
uint256 _gasLimit,
bytes memory _calldata
)
private
returns (
bytes memory _returndata
)
{
address ovmExecutionManager = msg.sender;
(
bool success,
bytes memory returndata
) = ovmExecutionManager.call{gas: _gasLimit}(_calldata);
if (success == false) {
assembly {
revert(add(returndata, 0x20), mload(returndata))
}
} else if (returndata.length == 1) {
assembly {
return(0, 1)
}
} else {
return returndata;
}
}
function _safeExecutionManagerInteraction(
bytes memory _calldata
)
private
returns (
bytes memory _returndata
)
{
return _safeExecutionManagerInteraction(
gasleft(),
_calldata
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_MerkleTree } from "../../libraries/utils/Lib_MerkleTree.sol";
/* Interface Imports */
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol";
/* External Imports */
import '@openzeppelin/contracts/math/SafeMath.sol';
/**
* @title OVM_StateCommitmentChain
* @dev The State Commitment Chain (SCC) contract contains a list of proposed state roots which
* Proposers assert to be a result of each transaction in the Canonical Transaction Chain (CTC).
* Elements here have a 1:1 correspondence with transactions in the CTC, and should be the unique
* state root calculated off-chain by applying the canonical transactions one by one.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResolver {
/*************
* Constants *
*************/
uint256 public FRAUD_PROOF_WINDOW;
uint256 public SEQUENCER_PUBLISH_WINDOW;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _libAddressManager,
uint256 _fraudProofWindow,
uint256 _sequencerPublishWindow
)
Lib_AddressResolver(_libAddressManager)
{
FRAUD_PROOF_WINDOW = _fraudProofWindow;
SEQUENCER_PUBLISH_WINDOW = _sequencerPublishWindow;
}
/********************
* Public Functions *
********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches()
public
view
returns (
iOVM_ChainStorageContainer
)
{
return iOVM_ChainStorageContainer(
resolve("OVM_ChainStorageContainer:SCC:batches")
);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getTotalElements()
override
public
view
returns (
uint256 _totalElements
)
{
(uint40 totalElements, ) = _getBatchExtraData();
return uint256(totalElements);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getTotalBatches()
override
public
view
returns (
uint256 _totalBatches
)
{
return batches().length();
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getLastSequencerTimestamp()
override
public
view
returns (
uint256 _lastSequencerTimestamp
)
{
(, uint40 lastSequencerTimestamp) = _getBatchExtraData();
return uint256(lastSequencerTimestamp);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function appendStateBatch(
bytes32[] memory _batch,
uint256 _shouldStartAtElement
)
override
public
{
// Fail fast in to make sure our batch roots aren't accidentally made fraudulent by the
// publication of batches by some other user.
require(
_shouldStartAtElement == getTotalElements(),
"Actual batch start index does not match expected start index."
);
// Proposers must have previously staked at the BondManager
require(
iOVM_BondManager(resolve("OVM_BondManager")).isCollateralized(msg.sender),
"Proposer does not have enough collateral posted"
);
require(
_batch.length > 0,
"Cannot submit an empty state batch."
);
require(
getTotalElements() + _batch.length <= iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")).getTotalElements(),
"Number of state roots cannot exceed the number of canonical transactions."
);
// Pass the block's timestamp and the publisher of the data
// to be used in the fraud proofs
_appendBatch(
_batch,
abi.encode(block.timestamp, msg.sender)
);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function deleteStateBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
override
public
{
require(
msg.sender == resolve("OVM_FraudVerifier"),
"State batches can only be deleted by the OVM_FraudVerifier."
);
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
require(
insideFraudProofWindow(_batchHeader),
"State batches can only be deleted within the fraud proof window."
);
_deleteBatch(_batchHeader);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function verifyStateCommitment(
bytes32 _element,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _proof
)
override
public
view
returns (
bool
)
{
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
require(
Lib_MerkleTree.verify(
_batchHeader.batchRoot,
_element,
_proof.index,
_proof.siblings,
_batchHeader.batchSize
),
"Invalid inclusion proof."
);
return true;
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function insideFraudProofWindow(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
override
public
view
returns (
bool _inside
)
{
(uint256 timestamp,) = abi.decode(
_batchHeader.extraData,
(uint256, address)
);
require(
timestamp != 0,
"Batch header timestamp cannot be zero"
);
return SafeMath.add(timestamp, FRAUD_PROOF_WINDOW) > block.timestamp;
}
/**********************
* Internal Functions *
**********************/
/**
* Parses the batch context from the extra data.
* @return Total number of elements submitted.
* @return Timestamp of the last batch submitted by the sequencer.
*/
function _getBatchExtraData()
internal
view
returns (
uint40,
uint40
)
{
bytes27 extraData = batches().getGlobalMetadata();
uint40 totalElements;
uint40 lastSequencerTimestamp;
assembly {
extraData := shr(40, extraData)
totalElements := and(extraData, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
lastSequencerTimestamp := shr(40, and(extraData, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000))
}
return (
totalElements,
lastSequencerTimestamp
);
}
/**
* Encodes the batch context for the extra data.
* @param _totalElements Total number of elements submitted.
* @param _lastSequencerTimestamp Timestamp of the last batch submitted by the sequencer.
* @return Encoded batch context.
*/
function _makeBatchExtraData(
uint40 _totalElements,
uint40 _lastSequencerTimestamp
)
internal
pure
returns (
bytes27
)
{
bytes27 extraData;
assembly {
extraData := _totalElements
extraData := or(extraData, shl(40, _lastSequencerTimestamp))
extraData := shl(40, extraData)
}
return extraData;
}
/**
* Appends a batch to the chain.
* @param _batch Elements within the batch.
* @param _extraData Any extra data to append to the batch.
*/
function _appendBatch(
bytes32[] memory _batch,
bytes memory _extraData
)
internal
{
address sequencer = resolve("OVM_Proposer");
(uint40 totalElements, uint40 lastSequencerTimestamp) = _getBatchExtraData();
if (msg.sender == sequencer) {
lastSequencerTimestamp = uint40(block.timestamp);
} else {
// We keep track of the last batch submitted by the sequencer so there's a window in
// which only the sequencer can publish state roots. A window like this just reduces
// the chance of "system breaking" state roots being published while we're still in
// testing mode. This window should be removed or significantly reduced in the future.
require(
lastSequencerTimestamp + SEQUENCER_PUBLISH_WINDOW < block.timestamp,
"Cannot publish state roots within the sequencer publication window."
);
}
// For efficiency reasons getMerkleRoot modifies the `_batch` argument in place
// while calculating the root hash therefore any arguments passed to it must not
// be used again afterwards
Lib_OVMCodec.ChainBatchHeader memory batchHeader = Lib_OVMCodec.ChainBatchHeader({
batchIndex: getTotalBatches(),
batchRoot: Lib_MerkleTree.getMerkleRoot(_batch),
batchSize: _batch.length,
prevTotalElements: totalElements,
extraData: _extraData
});
emit StateBatchAppended(
batchHeader.batchIndex,
batchHeader.batchRoot,
batchHeader.batchSize,
batchHeader.prevTotalElements,
batchHeader.extraData
);
batches().push(
Lib_OVMCodec.hashBatchHeader(batchHeader),
_makeBatchExtraData(
uint40(batchHeader.prevTotalElements + batchHeader.batchSize),
lastSequencerTimestamp
)
);
}
/**
* Removes a batch and all subsequent batches from the chain.
* @param _batchHeader Header of the batch to remove.
*/
function _deleteBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
internal
{
require(
_batchHeader.batchIndex < batches().length(),
"Invalid batch index."
);
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
batches().deleteElementsAfterInclusive(
_batchHeader.batchIndex,
_makeBatchExtraData(
uint40(_batchHeader.prevTotalElements),
0
)
);
emit StateBatchDeleted(
_batchHeader.batchIndex,
_batchHeader.batchRoot
);
}
/**
* Checks that a batch header matches the stored hash for the given index.
* @param _batchHeader Batch header to validate.
* @return Whether or not the header matches the stored one.
*/
function _isValidBatchHeader(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
internal
view
returns (
bool
)
{
return Lib_OVMCodec.hashBatchHeader(_batchHeader) == batches().get(_batchHeader.batchIndex);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
interface ERC20 {
function transfer(address, uint256) external returns (bool);
function transferFrom(address, address, uint256) external returns (bool);
}
/// All the errors which may be encountered on the bond manager
library Errors {
string constant ERC20_ERR = "BondManager: Could not post bond";
string constant ALREADY_FINALIZED = "BondManager: Fraud proof for this pre-state root has already been finalized";
string constant SLASHED = "BondManager: Cannot finalize withdrawal, you probably got slashed";
string constant WRONG_STATE = "BondManager: Wrong bond state for proposer";
string constant CANNOT_CLAIM = "BondManager: Cannot claim yet. Dispute must be finalized first";
string constant WITHDRAWAL_PENDING = "BondManager: Withdrawal already pending";
string constant TOO_EARLY = "BondManager: Too early to finalize your withdrawal";
string constant ONLY_TRANSITIONER = "BondManager: Only the transitioner for this pre-state root may call this function";
string constant ONLY_FRAUD_VERIFIER = "BondManager: Only the fraud verifier may call this function";
string constant ONLY_STATE_COMMITMENT_CHAIN = "BondManager: Only the state commitment chain may call this function";
string constant WAIT_FOR_DISPUTES = "BondManager: Wait for other potential disputes";
}
/**
* @title iOVM_BondManager
*/
interface iOVM_BondManager {
/*******************
* Data Structures *
*******************/
/// The lifecycle of a proposer's bond
enum State {
// Before depositing or after getting slashed, a user is uncollateralized
NOT_COLLATERALIZED,
// After depositing, a user is collateralized
COLLATERALIZED,
// After a user has initiated a withdrawal
WITHDRAWING
}
/// A bond posted by a proposer
struct Bond {
// The user's state
State state;
// The timestamp at which a proposer issued their withdrawal request
uint32 withdrawalTimestamp;
// The time when the first disputed was initiated for this bond
uint256 firstDisputeAt;
// The earliest observed state root for this bond which has had fraud
bytes32 earliestDisputedStateRoot;
// The state root's timestamp
uint256 earliestTimestamp;
}
// Per pre-state root, store the number of state provisions that were made
// and how many of these calls were made by each user. Payouts will then be
// claimed by users proportionally for that dispute.
struct Rewards {
// Flag to check if rewards for a fraud proof are claimable
bool canClaim;
// Total number of `recordGasSpent` calls made
uint256 total;
// The gas spent by each user to provide witness data. The sum of all
// values inside this map MUST be equal to the value of `total`
mapping(address => uint256) gasSpent;
}
/********************
* Public Functions *
********************/
function recordGasSpent(
bytes32 _preStateRoot,
bytes32 _txHash,
address _who,
uint256 _gasSpent
) external;
function finalize(
bytes32 _preStateRoot,
address _publisher,
uint256 _timestamp
) external;
function deposit() external;
function startWithdrawal() external;
function finalizeWithdrawal() external;
function claim(
address _who
) external;
function isCollateralized(
address _who
) external view returns (bool);
function getGasSpent(
bytes32 _preStateRoot,
address _who
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { iOVM_ChainStorageContainer } from "./iOVM_ChainStorageContainer.sol";
/**
* @title iOVM_CanonicalTransactionChain
*/
interface iOVM_CanonicalTransactionChain {
/**********
* Events *
**********/
event TransactionEnqueued(
address _l1TxOrigin,
address _target,
uint256 _gasLimit,
bytes _data,
uint256 _queueIndex,
uint256 _timestamp
);
event QueueBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event SequencerBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event TransactionBatchAppended(
uint256 indexed _batchIndex,
bytes32 _batchRoot,
uint256 _batchSize,
uint256 _prevTotalElements,
bytes _extraData
);
/***********
* Structs *
***********/
struct BatchContext {
uint256 numSequencedTransactions;
uint256 numSubsequentQueueTransactions;
uint256 timestamp;
uint256 blockNumber;
}
/********************
* Public Functions *
********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches()
external
view
returns (
iOVM_ChainStorageContainer
);
/**
* Accesses the queue storage container.
* @return Reference to the queue storage container.
*/
function queue()
external
view
returns (
iOVM_ChainStorageContainer
);
/**
* Retrieves the total number of elements submitted.
* @return _totalElements Total submitted elements.
*/
function getTotalElements()
external
view
returns (
uint256 _totalElements
);
/**
* Retrieves the total number of batches submitted.
* @return _totalBatches Total submitted batches.
*/
function getTotalBatches()
external
view
returns (
uint256 _totalBatches
);
/**
* Returns the index of the next element to be enqueued.
* @return Index for the next queue element.
*/
function getNextQueueIndex()
external
view
returns (
uint40
);
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function getQueueElement(
uint256 _index
)
external
view
returns (
Lib_OVMCodec.QueueElement memory _element
);
/**
* Returns the timestamp of the last transaction.
* @return Timestamp for the last transaction.
*/
function getLastTimestamp()
external
view
returns (
uint40
);
/**
* Returns the blocknumber of the last transaction.
* @return Blocknumber for the last transaction.
*/
function getLastBlockNumber()
external
view
returns (
uint40
);
/**
* Get the number of queue elements which have not yet been included.
* @return Number of pending queue elements.
*/
function getNumPendingQueueElements()
external
view
returns (
uint40
);
/**
* Retrieves the length of the queue, including
* both pending and canonical transactions.
* @return Length of the queue.
*/
function getQueueLength()
external
view
returns (
uint40
);
/**
* Adds a transaction to the queue.
* @param _target Target contract to send the transaction to.
* @param _gasLimit Gas limit for the given transaction.
* @param _data Transaction data.
*/
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
)
external;
/**
* Appends a given number of queued transactions as a single batch.
* @param _numQueuedTransactions Number of transactions to append.
*/
function appendQueueBatch(
uint256 _numQueuedTransactions
)
external;
/**
* Allows the sequencer to append a batch of transactions.
* @dev This function uses a custom encoding scheme for efficiency reasons.
* .param _shouldStartAtElement Specific batch we expect to start appending to.
* .param _totalElementsToAppend Total number of batch elements we expect to append.
* .param _contexts Array of batch contexts.
* .param _transactionDataFields Array of raw transaction data.
*/
function appendSequencerBatch(
// uint40 _shouldStartAtElement,
// uint24 _totalElementsToAppend,
// BatchContext[] _contexts,
// bytes[] _transactionDataFields
)
external;
/**
* Verifies whether a transaction is included in the chain.
* @param _transaction Transaction to verify.
* @param _txChainElement Transaction chain element corresponding to the transaction.
* @param _batchHeader Header of the batch the transaction was included in.
* @param _inclusionProof Inclusion proof for the provided transaction chain element.
* @return True if the transaction exists in the CTC, false if not.
*/
function verifyTransaction(
Lib_OVMCodec.Transaction memory _transaction,
Lib_OVMCodec.TransactionChainElement memory _txChainElement,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _inclusionProof
)
external
view
returns (
bool
);
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/**
* @title iOVM_ChainStorageContainer
*/
interface iOVM_ChainStorageContainer {
/********************
* Public Functions *
********************/
/**
* Sets the container's global metadata field. We're using `bytes27` here because we use five
* bytes to maintain the length of the underlying data structure, meaning we have an extra
* 27 bytes to store arbitrary data.
* @param _globalMetadata New global metadata to set.
*/
function setGlobalMetadata(
bytes27 _globalMetadata
)
external;
/**
* Retrieves the container's global metadata field.
* @return Container global metadata field.
*/
function getGlobalMetadata()
external
view
returns (
bytes27
);
/**
* Retrieves the number of objects stored in the container.
* @return Number of objects in the container.
*/
function length()
external
view
returns (
uint256
);
/**
* Pushes an object into the container.
* @param _object A 32 byte value to insert into the container.
*/
function push(
bytes32 _object
)
external;
/**
* Pushes an object into the container. Function allows setting the global metadata since
* we'll need to touch the "length" storage slot anyway, which also contains the global
* metadata (it's an optimization).
* @param _object A 32 byte value to insert into the container.
* @param _globalMetadata New global metadata for the container.
*/
function push(
bytes32 _object,
bytes27 _globalMetadata
)
external;
/**
* Retrieves an object from the container.
* @param _index Index of the particular object to access.
* @return 32 byte object value.
*/
function get(
uint256 _index
)
external
view
returns (
bytes32
);
/**
* Removes all objects after and including a given index.
* @param _index Object index to delete from.
*/
function deleteElementsAfterInclusive(
uint256 _index
)
external;
/**
* Removes all objects after and including a given index. Also allows setting the global
* metadata field.
* @param _index Object index to delete from.
* @param _globalMetadata New global metadata for the container.
*/
function deleteElementsAfterInclusive(
uint256 _index,
bytes27 _globalMetadata
)
external;
/**
* Marks an index as overwritable, meaing the underlying buffer can start to write values over
* any objects before and including the given index.
*/
function setNextOverwritableIndex(
uint256 _index
)
external;
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { iOVM_StateTransitioner } from "./iOVM_StateTransitioner.sol";
/**
* @title iOVM_FraudVerifier
*/
interface iOVM_FraudVerifier {
/**********
* Events *
**********/
event FraudProofInitialized(
bytes32 _preStateRoot,
uint256 _preStateRootIndex,
bytes32 _transactionHash,
address _who
);
event FraudProofFinalized(
bytes32 _preStateRoot,
uint256 _preStateRootIndex,
bytes32 _transactionHash,
address _who
);
/***************************************
* Public Functions: Transition Status *
***************************************/
function getStateTransitioner(bytes32 _preStateRoot, bytes32 _txHash) external view returns (iOVM_StateTransitioner _transitioner);
/****************************************
* Public Functions: Fraud Verification *
****************************************/
function initializeFraudVerification(
bytes32 _preStateRoot,
Lib_OVMCodec.ChainBatchHeader calldata _preStateRootBatchHeader,
Lib_OVMCodec.ChainInclusionProof calldata _preStateRootProof,
Lib_OVMCodec.Transaction calldata _transaction,
Lib_OVMCodec.TransactionChainElement calldata _txChainElement,
Lib_OVMCodec.ChainBatchHeader calldata _transactionBatchHeader,
Lib_OVMCodec.ChainInclusionProof calldata _transactionProof
) external;
function finalizeFraudVerification(
bytes32 _preStateRoot,
Lib_OVMCodec.ChainBatchHeader calldata _preStateRootBatchHeader,
Lib_OVMCodec.ChainInclusionProof calldata _preStateRootProof,
bytes32 _txHash,
bytes32 _postStateRoot,
Lib_OVMCodec.ChainBatchHeader calldata _postStateRootBatchHeader,
Lib_OVMCodec.ChainInclusionProof calldata _postStateRootProof
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_StateCommitmentChain
*/
interface iOVM_StateCommitmentChain {
/**********
* Events *
**********/
event StateBatchAppended(
uint256 indexed _batchIndex,
bytes32 _batchRoot,
uint256 _batchSize,
uint256 _prevTotalElements,
bytes _extraData
);
event StateBatchDeleted(
uint256 indexed _batchIndex,
bytes32 _batchRoot
);
/********************
* Public Functions *
********************/
/**
* Retrieves the total number of elements submitted.
* @return _totalElements Total submitted elements.
*/
function getTotalElements()
external
view
returns (
uint256 _totalElements
);
/**
* Retrieves the total number of batches submitted.
* @return _totalBatches Total submitted batches.
*/
function getTotalBatches()
external
view
returns (
uint256 _totalBatches
);
/**
* Retrieves the timestamp of the last batch submitted by the sequencer.
* @return _lastSequencerTimestamp Last sequencer batch timestamp.
*/
function getLastSequencerTimestamp()
external
view
returns (
uint256 _lastSequencerTimestamp
);
/**
* Appends a batch of state roots to the chain.
* @param _batch Batch of state roots.
* @param _shouldStartAtElement Index of the element at which this batch should start.
*/
function appendStateBatch(
bytes32[] calldata _batch,
uint256 _shouldStartAtElement
)
external;
/**
* Deletes all state roots after (and including) a given batch.
* @param _batchHeader Header of the batch to start deleting from.
*/
function deleteStateBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
external;
/**
* Verifies a batch inclusion proof.
* @param _element Hash of the element to verify a proof for.
* @param _batchHeader Header of the batch in which the element was included.
* @param _proof Merkle inclusion proof for the element.
*/
function verifyStateCommitment(
bytes32 _element,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _proof
)
external
view
returns (
bool _verified
);
/**
* Checks whether a given batch is still inside its fraud proof window.
* @param _batchHeader Header of the batch to check.
* @return _inside Whether or not the batch is inside the fraud proof window.
*/
function insideFraudProofWindow(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
external
view
returns (
bool _inside
);
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_StateTransitioner
*/
interface iOVM_StateTransitioner {
/**********
* Events *
**********/
event AccountCommitted(
address _address
);
event ContractStorageCommitted(
address _address,
bytes32 _key
);
/**********************************
* Public Functions: State Access *
**********************************/
function getPreStateRoot() external view returns (bytes32 _preStateRoot);
function getPostStateRoot() external view returns (bytes32 _postStateRoot);
function isComplete() external view returns (bool _complete);
/***********************************
* Public Functions: Pre-Execution *
***********************************/
function proveContractState(
address _ovmContractAddress,
address _ethContractAddress,
bytes calldata _stateTrieWitness
) external;
function proveStorageSlot(
address _ovmContractAddress,
bytes32 _key,
bytes calldata _storageTrieWitness
) external;
/*******************************
* Public Functions: Execution *
*******************************/
function applyTransaction(
Lib_OVMCodec.Transaction calldata _transaction
) external;
/************************************
* Public Functions: Post-Execution *
************************************/
function commitContractState(
address _ovmContractAddress,
bytes calldata _stateTrieWitness
) external;
function commitStorageSlot(
address _ovmContractAddress,
bytes32 _key,
bytes calldata _storageTrieWitness
) external;
/**********************************
* Public Functions: Finalization *
**********************************/
function completeTransition() external;
}
{
"compilationTarget": {
"contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol": "OVM_StateCommitmentChain"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_libAddressManager","type":"address"},{"internalType":"uint256","name":"_fraudProofWindow","type":"uint256"},{"internalType":"uint256","name":"_sequencerPublishWindow","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_batchIndex","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_batchRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_batchSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_prevTotalElements","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"StateBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_batchIndex","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_batchRoot","type":"bytes32"}],"name":"StateBatchDeleted","type":"event"},{"inputs":[],"name":"FRAUD_PROOF_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEQUENCER_PUBLISH_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_batch","type":"bytes32[]"},{"internalType":"uint256","name":"_shouldStartAtElement","type":"uint256"}],"name":"appendStateBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batches","outputs":[{"internalType":"contract iOVM_ChainStorageContainer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"internalType":"uint256","name":"batchSize","type":"uint256"},{"internalType":"uint256","name":"prevTotalElements","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct Lib_OVMCodec.ChainBatchHeader","name":"_batchHeader","type":"tuple"}],"name":"deleteStateBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getLastSequencerTimestamp","outputs":[{"internalType":"uint256","name":"_lastSequencerTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalBatches","outputs":[{"internalType":"uint256","name":"_totalBatches","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalElements","outputs":[{"internalType":"uint256","name":"_totalElements","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"internalType":"uint256","name":"batchSize","type":"uint256"},{"internalType":"uint256","name":"prevTotalElements","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct Lib_OVMCodec.ChainBatchHeader","name":"_batchHeader","type":"tuple"}],"name":"insideFraudProofWindow","outputs":[{"internalType":"bool","name":"_inside","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"libAddressManager","outputs":[{"internalType":"contract Lib_AddressManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"resolve","outputs":[{"internalType":"address","name":"_contract","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_element","type":"bytes32"},{"components":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"internalType":"uint256","name":"batchSize","type":"uint256"},{"internalType":"uint256","name":"prevTotalElements","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct Lib_OVMCodec.ChainBatchHeader","name":"_batchHeader","type":"tuple"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"}],"internalType":"struct Lib_OVMCodec.ChainInclusionProof","name":"_proof","type":"tuple"}],"name":"verifyStateCommitment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]