More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 23,404 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Append Sequencer... | 13596383 | 921 days ago | IN | 0 ETH | 0.12307133 | ||||
Append Sequencer... | 13596336 | 921 days ago | IN | 0 ETH | 0.13139387 | ||||
Append Sequencer... | 13596294 | 921 days ago | IN | 0 ETH | 0.12528423 | ||||
Append Sequencer... | 13596214 | 921 days ago | IN | 0 ETH | 0.09519711 | ||||
Append Sequencer... | 13596128 | 921 days ago | IN | 0 ETH | 0.10094345 | ||||
Append Sequencer... | 13596050 | 921 days ago | IN | 0 ETH | 0.09867502 | ||||
Append Sequencer... | 13596011 | 921 days ago | IN | 0 ETH | 0.12904662 | ||||
Append Sequencer... | 13595988 | 921 days ago | IN | 0 ETH | 0.11998187 | ||||
Append Sequencer... | 13595946 | 921 days ago | IN | 0 ETH | 0.10908284 | ||||
Append Sequencer... | 13595909 | 921 days ago | IN | 0 ETH | 0.1080654 | ||||
Append Sequencer... | 13595865 | 921 days ago | IN | 0 ETH | 0.11166103 | ||||
Append Sequencer... | 13595809 | 921 days ago | IN | 0 ETH | 0.10054835 | ||||
Append Sequencer... | 13595765 | 921 days ago | IN | 0 ETH | 0.09615864 | ||||
Append Sequencer... | 13595742 | 921 days ago | IN | 0 ETH | 0.11249475 | ||||
Append Sequencer... | 13595718 | 921 days ago | IN | 0 ETH | 0.10919725 | ||||
Append Sequencer... | 13595699 | 921 days ago | IN | 0 ETH | 0.13655006 | ||||
Append Sequencer... | 13595693 | 921 days ago | IN | 0 ETH | 0.10244325 | ||||
Append Sequencer... | 13595648 | 921 days ago | IN | 0 ETH | 0.08712182 | ||||
Append Sequencer... | 13595607 | 921 days ago | IN | 0 ETH | 0.1149967 | ||||
Append Sequencer... | 13595599 | 921 days ago | IN | 0 ETH | 0.11860622 | ||||
Append Sequencer... | 13595554 | 921 days ago | IN | 0 ETH | 0.08584625 | ||||
Append Sequencer... | 13595523 | 921 days ago | IN | 0 ETH | 0.11326008 | ||||
Append Sequencer... | 13595508 | 921 days ago | IN | 0 ETH | 0.0745963 | ||||
Append Sequencer... | 13595496 | 921 days ago | IN | 0 ETH | 0.07054381 | ||||
Append Sequencer... | 13595469 | 921 days ago | IN | 0 ETH | 0.08940974 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
OVM_CanonicalTransactionChain
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // @unsupported: ovm 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_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol"; import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol"; /* Contract Imports */ import { OVM_ExecutionManager } from "../execution/OVM_ExecutionManager.sol"; /* External Imports */ import { Math } from "@openzeppelin/contracts/math/Math.sol"; /** * @title OVM_CanonicalTransactionChain * @dev The Canonical Transaction Chain (CTC) contract is an append-only log of transactions * which must be applied to the rollup state. It defines the ordering of rollup transactions by * writing them to the 'CTC:batches' instance of the Chain Storage Container. * The CTC also allows any account to 'enqueue' an L2 transaction, which will require that the Sequencer * will eventually append it to the rollup state. * If the Sequencer does not include an enqueued transaction within the 'force inclusion period', * then any account may force it to be included by calling appendQueueBatch(). * * Compiler used: solc * Runtime target: EVM */ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_AddressResolver { /************* * Constants * *************/ // L2 tx gas-related uint256 constant public MIN_ROLLUP_TX_GAS = 100000; uint256 constant public MAX_ROLLUP_TX_SIZE = 50000; uint256 constant public L2_GAS_DISCOUNT_DIVISOR = 32; // Encoding-related (all in bytes) uint256 constant internal BATCH_CONTEXT_SIZE = 16; uint256 constant internal BATCH_CONTEXT_LENGTH_POS = 12; uint256 constant internal BATCH_CONTEXT_START_POS = 15; uint256 constant internal TX_DATA_HEADER_SIZE = 3; uint256 constant internal BYTES_TILL_TX_DATA = 65; /************* * Variables * *************/ uint256 public forceInclusionPeriodSeconds; uint256 public forceInclusionPeriodBlocks; uint256 public maxTransactionGasLimit; /*************** * Constructor * ***************/ constructor( address _libAddressManager, uint256 _forceInclusionPeriodSeconds, uint256 _forceInclusionPeriodBlocks, uint256 _maxTransactionGasLimit ) Lib_AddressResolver(_libAddressManager) { forceInclusionPeriodSeconds = _forceInclusionPeriodSeconds; forceInclusionPeriodBlocks = _forceInclusionPeriodBlocks; maxTransactionGasLimit = _maxTransactionGasLimit; } /******************** * Public Functions * ********************/ /** * Accesses the batch storage container. * @return Reference to the batch storage container. */ function batches() override public view returns ( iOVM_ChainStorageContainer ) { return iOVM_ChainStorageContainer( resolve("OVM_ChainStorageContainer-CTC-batches") ); } /** * Accesses the queue storage container. * @return Reference to the queue storage container. */ function queue() override public view returns ( iOVM_ChainStorageContainer ) { return iOVM_ChainStorageContainer( resolve("OVM_ChainStorageContainer-CTC-queue") ); } /** * Retrieves the total number of elements submitted. * @return _totalElements Total submitted elements. */ function getTotalElements() override public view returns ( uint256 _totalElements ) { (uint40 totalElements,,,) = _getBatchExtraData(); return uint256(totalElements); } /** * Retrieves the total number of batches submitted. * @return _totalBatches Total submitted batches. */ function getTotalBatches() override public view returns ( uint256 _totalBatches ) { return batches().length(); } /** * Returns the index of the next element to be enqueued. * @return Index for the next queue element. */ function getNextQueueIndex() override public view returns ( uint40 ) { (,uint40 nextQueueIndex,,) = _getBatchExtraData(); return nextQueueIndex; } /** * Returns the timestamp of the last transaction. * @return Timestamp for the last transaction. */ function getLastTimestamp() override public view returns ( uint40 ) { (,,uint40 lastTimestamp,) = _getBatchExtraData(); return lastTimestamp; } /** * Returns the blocknumber of the last transaction. * @return Blocknumber for the last transaction. */ function getLastBlockNumber() override public view returns ( uint40 ) { (,,,uint40 lastBlockNumber) = _getBatchExtraData(); return lastBlockNumber; } /** * 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 ) override public view returns ( Lib_OVMCodec.QueueElement memory _element ) { return _getQueueElement( _index, queue() ); } /** * Get the number of queue elements which have not yet been included. * @return Number of pending queue elements. */ function getNumPendingQueueElements() override public view returns ( uint40 ) { return getQueueLength() - getNextQueueIndex(); } /** * Retrieves the length of the queue, including * both pending and canonical transactions. * @return Length of the queue. */ function getQueueLength() override public view returns ( uint40 ) { return _getQueueLength( queue() ); } /** * Adds a transaction to the queue. * @param _target Target L2 contract to send the transaction to. * @param _gasLimit Gas limit for the enqueued L2 transaction. * @param _data Transaction data. */ function enqueue( address _target, uint256 _gasLimit, bytes memory _data ) override public { require( _data.length <= MAX_ROLLUP_TX_SIZE, "Transaction data size exceeds maximum for rollup transaction." ); require( _gasLimit <= maxTransactionGasLimit, "Transaction gas limit exceeds maximum for rollup transaction." ); require( _gasLimit >= MIN_ROLLUP_TX_GAS, "Transaction gas limit too low to enqueue." ); // We need to consume some amount of L1 gas in order to rate limit transactions going into // L2. However, L2 is cheaper than L1 so we only need to burn some small proportion of the // provided L1 gas. uint256 gasToConsume = _gasLimit/L2_GAS_DISCOUNT_DIVISOR; uint256 startingGas = gasleft(); // Although this check is not necessary (burn below will run out of gas if not true), it // gives the user an explicit reason as to why the enqueue attempt failed. require( startingGas > gasToConsume, "Insufficient gas for L2 rate limiting burn." ); // Here we do some "dumb" work in order to burn gas, although we should probably replace // this with something like minting gas token later on. uint256 i; while(startingGas - gasleft() < gasToConsume) { i++; } bytes32 transactionHash = keccak256( abi.encode( msg.sender, _target, _gasLimit, _data ) ); bytes32 timestampAndBlockNumber; assembly { timestampAndBlockNumber := timestamp() timestampAndBlockNumber := or(timestampAndBlockNumber, shl(40, number())) } iOVM_ChainStorageContainer queueRef = queue(); queueRef.push(transactionHash); queueRef.push(timestampAndBlockNumber); // The underlying queue data structure stores 2 elements // per insertion, so to get the real queue length we need // to divide by 2 and subtract 1. uint256 queueIndex = queueRef.length() / 2 - 1; emit TransactionEnqueued( msg.sender, _target, _gasLimit, _data, queueIndex, block.timestamp ); } /** * Appends a given number of queued transactions as a single batch. * param _numQueuedTransactions Number of transactions to append. */ function appendQueueBatch( uint256 // _numQueuedTransactions ) override public pure { // TEMPORARY: Disable `appendQueueBatch` for minnet revert("appendQueueBatch is currently disabled."); // _numQueuedTransactions = Math.min(_numQueuedTransactions, getNumPendingQueueElements()); // require( // _numQueuedTransactions > 0, // "Must append more than zero transactions." // ); // bytes32[] memory leaves = new bytes32[](_numQueuedTransactions); // uint40 nextQueueIndex = getNextQueueIndex(); // for (uint256 i = 0; i < _numQueuedTransactions; i++) { // if (msg.sender != resolve("OVM_Sequencer")) { // Lib_OVMCodec.QueueElement memory el = getQueueElement(nextQueueIndex); // require( // el.timestamp + forceInclusionPeriodSeconds < block.timestamp, // "Queue transactions cannot be submitted during the sequencer inclusion period." // ); // } // leaves[i] = _getQueueLeafHash(nextQueueIndex); // nextQueueIndex++; // } // Lib_OVMCodec.QueueElement memory lastElement = getQueueElement(nextQueueIndex - 1); // _appendBatch( // Lib_MerkleTree.getMerkleRoot(leaves), // _numQueuedTransactions, // _numQueuedTransactions, // lastElement.timestamp, // lastElement.blockNumber // ); // emit QueueBatchAppended( // nextQueueIndex - _numQueuedTransactions, // _numQueuedTransactions, // getTotalElements() // ); } /** * 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() override public { uint40 shouldStartAtElement; uint24 totalElementsToAppend; uint24 numContexts; assembly { shouldStartAtElement := shr(216, calldataload(4)) totalElementsToAppend := shr(232, calldataload(9)) numContexts := shr(232, calldataload(12)) } require( shouldStartAtElement == getTotalElements(), "Actual batch start index does not match expected start index." ); require( msg.sender == resolve("OVM_Sequencer"), "Function can only be called by the Sequencer." ); require( numContexts > 0, "Must provide at least one batch context." ); require( totalElementsToAppend > 0, "Must append at least one element." ); uint40 nextTransactionPtr = uint40(BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts); require( msg.data.length >= nextTransactionPtr, "Not enough BatchContexts provided." ); // Take a reference to the queue and its length so we don't have to keep resolving it. // Length isn't going to change during the course of execution, so it's fine to simply // resolve this once at the start. Saves gas. iOVM_ChainStorageContainer queueRef = queue(); uint40 queueLength = _getQueueLength(queueRef); // Reserve some memory to save gas on hashing later on. This is a relatively safe estimate // for the average transaction size that will prevent having to resize this chunk of memory // later on. Saves gas. bytes memory hashMemory = new bytes((msg.data.length / totalElementsToAppend) * 2); // Initialize the array of canonical chain leaves that we will append. bytes32[] memory leaves = new bytes32[](totalElementsToAppend); // Each leaf index corresponds to a tx, either sequenced or enqueued. uint32 leafIndex = 0; // Counter for number of sequencer transactions appended so far. uint32 numSequencerTransactions = 0; // We will sequentially append leaves which are pointers to the queue. // The initial queue index is what is currently in storage. uint40 nextQueueIndex = getNextQueueIndex(); BatchContext memory curContext; for (uint32 i = 0; i < numContexts; i++) { BatchContext memory nextContext = _getBatchContext(i); if (i == 0) { // Execute a special check for the first batch. _validateFirstBatchContext(nextContext); } // Execute this check on every single batch, including the first one. _validateNextBatchContext( curContext, nextContext, nextQueueIndex, queueRef ); // Now we can update our current context. curContext = nextContext; // Process sequencer transactions first. for (uint32 j = 0; j < curContext.numSequencedTransactions; j++) { uint256 txDataLength; assembly { txDataLength := shr(232, calldataload(nextTransactionPtr)) } require( txDataLength <= MAX_ROLLUP_TX_SIZE, "Transaction data size exceeds maximum for rollup transaction." ); leaves[leafIndex] = _getSequencerLeafHash( curContext, nextTransactionPtr, txDataLength, hashMemory ); nextTransactionPtr += uint40(TX_DATA_HEADER_SIZE + txDataLength); numSequencerTransactions++; leafIndex++; } // Now process any subsequent queue transactions. for (uint32 j = 0; j < curContext.numSubsequentQueueTransactions; j++) { require( nextQueueIndex < queueLength, "Not enough queued transactions to append." ); leaves[leafIndex] = _getQueueLeafHash(nextQueueIndex); nextQueueIndex++; leafIndex++; } } _validateFinalBatchContext( curContext, nextQueueIndex, queueLength, queueRef ); require( msg.data.length == nextTransactionPtr, "Not all sequencer transactions were processed." ); require( leafIndex == totalElementsToAppend, "Actual transaction index does not match expected total elements to append." ); // Generate the required metadata that we need to append this batch uint40 numQueuedTransactions = totalElementsToAppend - numSequencerTransactions; uint40 blockTimestamp; uint40 blockNumber; if (curContext.numSubsequentQueueTransactions == 0) { // The last element is a sequencer tx, therefore pull timestamp and block number from the last context. blockTimestamp = uint40(curContext.timestamp); blockNumber = uint40(curContext.blockNumber); } else { // The last element is a queue tx, therefore pull timestamp and block number from the queue element. // curContext.numSubsequentQueueTransactions > 0 which means that we've processed at least one queue element. // We increment nextQueueIndex after processing each queue element, // so the index of the last element we processed is nextQueueIndex - 1. Lib_OVMCodec.QueueElement memory lastElement = _getQueueElement( nextQueueIndex - 1, queueRef ); blockTimestamp = lastElement.timestamp; blockNumber = lastElement.blockNumber; } // For efficiency reasons getMerkleRoot modifies the `leaves` argument in place // while calculating the root hash therefore any arguments passed to it must not // be used again afterwards _appendBatch( Lib_MerkleTree.getMerkleRoot(leaves), totalElementsToAppend, numQueuedTransactions, blockTimestamp, blockNumber ); emit SequencerBatchAppended( nextQueueIndex - numQueuedTransactions, numQueuedTransactions, getTotalElements() ); } /** * 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 ) override public view returns ( bool ) { if (_txChainElement.isSequenced == true) { return _verifySequencerTransaction( _transaction, _txChainElement, _batchHeader, _inclusionProof ); } else { return _verifyQueueTransaction( _transaction, _txChainElement.queueIndex, _batchHeader, _inclusionProof ); } } /********************** * Internal Functions * **********************/ /** * Returns the BatchContext located at a particular index. * @param _index The index of the BatchContext * @return The BatchContext at the specified index. */ function _getBatchContext( uint256 _index ) internal pure returns ( BatchContext memory ) { uint256 contextPtr = 15 + _index * BATCH_CONTEXT_SIZE; uint256 numSequencedTransactions; uint256 numSubsequentQueueTransactions; uint256 ctxTimestamp; uint256 ctxBlockNumber; assembly { numSequencedTransactions := shr(232, calldataload(contextPtr)) numSubsequentQueueTransactions := shr(232, calldataload(add(contextPtr, 3))) ctxTimestamp := shr(216, calldataload(add(contextPtr, 6))) ctxBlockNumber := shr(216, calldataload(add(contextPtr, 11))) } return BatchContext({ numSequencedTransactions: numSequencedTransactions, numSubsequentQueueTransactions: numSubsequentQueueTransactions, timestamp: ctxTimestamp, blockNumber: ctxBlockNumber }); } /** * Parses the batch context from the extra data. * @return Total number of elements submitted. * @return Index of the next queue element. */ function _getBatchExtraData() internal view returns ( uint40, uint40, uint40, uint40 ) { bytes27 extraData = batches().getGlobalMetadata(); uint40 totalElements; uint40 nextQueueIndex; uint40 lastTimestamp; uint40 lastBlockNumber; assembly { extraData := shr(40, extraData) totalElements := and(extraData, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF) nextQueueIndex := shr(40, and(extraData, 0x00000000000000000000000000000000000000000000FFFFFFFFFF0000000000)) lastTimestamp := shr(80, and(extraData, 0x0000000000000000000000000000000000FFFFFFFFFF00000000000000000000)) lastBlockNumber := shr(120, and(extraData, 0x000000000000000000000000FFFFFFFFFF000000000000000000000000000000)) } return ( totalElements, nextQueueIndex, lastTimestamp, lastBlockNumber ); } /** * Encodes the batch context for the extra data. * @param _totalElements Total number of elements submitted. * @param _nextQueueIndex Index of the next queue element. * @param _timestamp Timestamp for the last batch. * @param _blockNumber Block number of the last batch. * @return Encoded batch context. */ function _makeBatchExtraData( uint40 _totalElements, uint40 _nextQueueIndex, uint40 _timestamp, uint40 _blockNumber ) internal pure returns ( bytes27 ) { bytes27 extraData; assembly { extraData := _totalElements extraData := or(extraData, shl(40, _nextQueueIndex)) extraData := or(extraData, shl(80, _timestamp)) extraData := or(extraData, shl(120, _blockNumber)) extraData := shl(40, extraData) } return extraData; } /** * Retrieves the hash of a queue element. * @param _index Index of the queue element to retrieve a hash for. * @return Hash of the queue element. */ function _getQueueLeafHash( uint256 _index ) internal pure returns ( bytes32 ) { return _hashTransactionChainElement( Lib_OVMCodec.TransactionChainElement({ isSequenced: false, queueIndex: _index, timestamp: 0, blockNumber: 0, txData: hex"" }) ); } /** * 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, iOVM_ChainStorageContainer _queueRef ) internal view returns ( Lib_OVMCodec.QueueElement memory _element ) { // The underlying queue data structure stores 2 elements // per insertion, so to get the actual desired queue index // we need to multiply by 2. uint40 trueIndex = uint40(_index * 2); bytes32 transactionHash = _queueRef.get(trueIndex); bytes32 timestampAndBlockNumber = _queueRef.get(trueIndex + 1); uint40 elementTimestamp; uint40 elementBlockNumber; assembly { elementTimestamp := and(timestampAndBlockNumber, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF) elementBlockNumber := shr(40, and(timestampAndBlockNumber, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000)) } return Lib_OVMCodec.QueueElement({ transactionHash: transactionHash, timestamp: elementTimestamp, blockNumber: elementBlockNumber }); } /** * Retrieves the length of the queue. * @return Length of the queue. */ function _getQueueLength( iOVM_ChainStorageContainer _queueRef ) internal view returns ( uint40 ) { // The underlying queue data structure stores 2 elements // per insertion, so to get the real queue length we need // to divide by 2. return uint40(_queueRef.length() / 2); } /** * Retrieves the hash of a sequencer element. * @param _context Batch context for the given element. * @param _nextTransactionPtr Pointer to the next transaction in the calldata. * @param _txDataLength Length of the transaction item. * @return Hash of the sequencer element. */ function _getSequencerLeafHash( BatchContext memory _context, uint256 _nextTransactionPtr, uint256 _txDataLength, bytes memory _hashMemory ) internal pure returns ( bytes32 ) { // Only allocate more memory if we didn't reserve enough to begin with. if (BYTES_TILL_TX_DATA + _txDataLength > _hashMemory.length) { _hashMemory = new bytes(BYTES_TILL_TX_DATA + _txDataLength); } uint256 ctxTimestamp = _context.timestamp; uint256 ctxBlockNumber = _context.blockNumber; bytes32 leafHash; assembly { let chainElementStart := add(_hashMemory, 0x20) // Set the first byte equal to `1` to indicate this is a sequencer chain element. // This distinguishes sequencer ChainElements from queue ChainElements because // all queue ChainElements are ABI encoded and the first byte of ABI encoded // elements is always zero mstore8(chainElementStart, 1) mstore(add(chainElementStart, 1), ctxTimestamp) mstore(add(chainElementStart, 33), ctxBlockNumber) calldatacopy(add(chainElementStart, BYTES_TILL_TX_DATA), add(_nextTransactionPtr, 3), _txDataLength) leafHash := keccak256(chainElementStart, add(BYTES_TILL_TX_DATA, _txDataLength)) } return leafHash; } /** * Retrieves the hash of a sequencer element. * @param _txChainElement The chain element which is hashed to calculate the leaf. * @return Hash of the sequencer element. */ function _getSequencerLeafHash( Lib_OVMCodec.TransactionChainElement memory _txChainElement ) internal view returns( bytes32 ) { bytes memory txData = _txChainElement.txData; uint256 txDataLength = _txChainElement.txData.length; bytes memory chainElement = new bytes(BYTES_TILL_TX_DATA + txDataLength); uint256 ctxTimestamp = _txChainElement.timestamp; uint256 ctxBlockNumber = _txChainElement.blockNumber; bytes32 leafHash; assembly { let chainElementStart := add(chainElement, 0x20) // Set the first byte equal to `1` to indicate this is a sequencer chain element. // This distinguishes sequencer ChainElements from queue ChainElements because // all queue ChainElements are ABI encoded and the first byte of ABI encoded // elements is always zero mstore8(chainElementStart, 1) mstore(add(chainElementStart, 1), ctxTimestamp) mstore(add(chainElementStart, 33), ctxBlockNumber) pop(staticcall(gas(), 0x04, add(txData, 0x20), txDataLength, add(chainElementStart, BYTES_TILL_TX_DATA), txDataLength)) leafHash := keccak256(chainElementStart, add(BYTES_TILL_TX_DATA, txDataLength)) } return leafHash; } /** * Inserts a batch into the chain of batches. * @param _transactionRoot Root of the transaction tree for this batch. * @param _batchSize Number of elements in the batch. * @param _numQueuedTransactions Number of queue transactions in the batch. * @param _timestamp The latest batch timestamp. * @param _blockNumber The latest batch blockNumber. */ function _appendBatch( bytes32 _transactionRoot, uint256 _batchSize, uint256 _numQueuedTransactions, uint40 _timestamp, uint40 _blockNumber ) internal { iOVM_ChainStorageContainer batchesRef = batches(); (uint40 totalElements, uint40 nextQueueIndex,,) = _getBatchExtraData(); Lib_OVMCodec.ChainBatchHeader memory header = Lib_OVMCodec.ChainBatchHeader({ batchIndex: batchesRef.length(), batchRoot: _transactionRoot, batchSize: _batchSize, prevTotalElements: totalElements, extraData: hex"" }); emit TransactionBatchAppended( header.batchIndex, header.batchRoot, header.batchSize, header.prevTotalElements, header.extraData ); bytes32 batchHeaderHash = Lib_OVMCodec.hashBatchHeader(header); bytes27 latestBatchContext = _makeBatchExtraData( totalElements + uint40(header.batchSize), nextQueueIndex + uint40(_numQueuedTransactions), _timestamp, _blockNumber ); batchesRef.push(batchHeaderHash, latestBatchContext); } /** * Checks that the first batch context in a sequencer submission is valid * @param _firstContext The batch context to validate. */ function _validateFirstBatchContext( BatchContext memory _firstContext ) internal view { // If there are existing elements, this batch must have the same context // or a later timestamp and block number. if (getTotalElements() > 0) { (,, uint40 lastTimestamp, uint40 lastBlockNumber) = _getBatchExtraData(); require( _firstContext.blockNumber >= lastBlockNumber, "Context block number is lower than last submitted." ); require( _firstContext.timestamp >= lastTimestamp, "Context timestamp is lower than last submitted." ); } // Sequencer cannot submit contexts which are more than the force inclusion period old. require( _firstContext.timestamp + forceInclusionPeriodSeconds >= block.timestamp, "Context timestamp too far in the past." ); require( _firstContext.blockNumber + forceInclusionPeriodBlocks >= block.number, "Context block number too far in the past." ); } /** * Checks that a given batch context has a time context which is below a given que element * @param _context The batch context to validate has values lower. * @param _queueIndex Index of the queue element we are validating came later than the context. * @param _queueRef The storage container for the queue. */ function _validateContextBeforeEnqueue( BatchContext memory _context, uint40 _queueIndex, iOVM_ChainStorageContainer _queueRef ) internal view { Lib_OVMCodec.QueueElement memory nextQueueElement = _getQueueElement( _queueIndex, _queueRef ); // If the force inclusion period has passed for an enqueued transaction, it MUST be the next chain element. require( block.timestamp < nextQueueElement.timestamp + forceInclusionPeriodSeconds, "Previously enqueued batches have expired and must be appended before a new sequencer batch." ); // Just like sequencer transaction times must be increasing relative to each other, // We also require that they be increasing relative to any interspersed queue elements. require( _context.timestamp <= nextQueueElement.timestamp, "Sequencer transaction timestamp exceeds that of next queue element." ); require( _context.blockNumber <= nextQueueElement.blockNumber, "Sequencer transaction blockNumber exceeds that of next queue element." ); } /** * Checks that a given batch context is valid based on its previous context, and the next queue elemtent. * @param _prevContext The previously validated batch context. * @param _nextContext The batch context to validate with this call. * @param _nextQueueIndex Index of the next queue element to process for the _nextContext's subsequentQueueElements. * @param _queueRef The storage container for the queue. */ function _validateNextBatchContext( BatchContext memory _prevContext, BatchContext memory _nextContext, uint40 _nextQueueIndex, iOVM_ChainStorageContainer _queueRef ) internal view { // All sequencer transactions' times must be greater than or equal to the previous ones. require( _nextContext.timestamp >= _prevContext.timestamp, "Context timestamp values must monotonically increase." ); require( _nextContext.blockNumber >= _prevContext.blockNumber, "Context blockNumber values must monotonically increase." ); // If there is going to be a queue element pulled in from this context: if (_nextContext.numSubsequentQueueTransactions > 0) { _validateContextBeforeEnqueue( _nextContext, _nextQueueIndex, _queueRef ); } } /** * Checks that the final batch context in a sequencer submission is valid. * @param _finalContext The batch context to validate. * @param _queueLength The length of the queue at the start of the batchAppend call. * @param _nextQueueIndex The next element in the queue that will be pulled into the CTC. * @param _queueRef The storage container for the queue. */ function _validateFinalBatchContext( BatchContext memory _finalContext, uint40 _nextQueueIndex, uint40 _queueLength, iOVM_ChainStorageContainer _queueRef ) internal view { // If the queue is not now empty, check the mononoticity of whatever the next batch that will come in is. if (_queueLength - _nextQueueIndex > 0 && _finalContext.numSubsequentQueueTransactions == 0) { _validateContextBeforeEnqueue( _finalContext, _nextQueueIndex, _queueRef ); } // Batches cannot be added from the future, or subsequent enqueue() contexts would violate monotonicity. require(_finalContext.timestamp <= block.timestamp, "Context timestamp is from the future."); require(_finalContext.blockNumber <= block.number, "Context block number is from the future."); } /** * Hashes a transaction chain element. * @param _element Chain element to hash. * @return Hash of the chain element. */ function _hashTransactionChainElement( Lib_OVMCodec.TransactionChainElement memory _element ) internal pure returns ( bytes32 ) { return keccak256( abi.encode( _element.isSequenced, _element.queueIndex, _element.timestamp, _element.blockNumber, _element.txData ) ); } /** * Verifies a sequencer transaction, returning true if it was indeed included in the CTC * @param _transaction The transaction we are verifying inclusion of. * @param _txChainElement The chain element that the transaction is claimed to be a part of. * @param _batchHeader Header of the batch the transaction was included in. * @param _inclusionProof An inclusion proof into the CTC at a particular index. * @return True if the transaction was included in the specified location, else false. */ function _verifySequencerTransaction( Lib_OVMCodec.Transaction memory _transaction, Lib_OVMCodec.TransactionChainElement memory _txChainElement, Lib_OVMCodec.ChainBatchHeader memory _batchHeader, Lib_OVMCodec.ChainInclusionProof memory _inclusionProof ) internal view returns ( bool ) { OVM_ExecutionManager ovmExecutionManager = OVM_ExecutionManager(resolve("OVM_ExecutionManager")); uint256 gasLimit = ovmExecutionManager.getMaxTransactionGasLimit(); bytes32 leafHash = _getSequencerLeafHash(_txChainElement); require( _verifyElement( leafHash, _batchHeader, _inclusionProof ), "Invalid Sequencer transaction inclusion proof." ); require( _transaction.blockNumber == _txChainElement.blockNumber && _transaction.timestamp == _txChainElement.timestamp && _transaction.entrypoint == resolve("OVM_DecompressionPrecompileAddress") && _transaction.gasLimit == gasLimit && _transaction.l1TxOrigin == address(0) && _transaction.l1QueueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE && keccak256(_transaction.data) == keccak256(_txChainElement.txData), "Invalid Sequencer transaction." ); return true; } /** * Verifies a queue transaction, returning true if it was indeed included in the CTC * @param _transaction The transaction we are verifying inclusion of. * @param _queueIndex The queueIndex of the queued transaction. * @param _batchHeader Header of the batch the transaction was included in. * @param _inclusionProof An inclusion proof into the CTC at a particular index (should point to queue tx). * @return True if the transaction was included in the specified location, else false. */ function _verifyQueueTransaction( Lib_OVMCodec.Transaction memory _transaction, uint256 _queueIndex, Lib_OVMCodec.ChainBatchHeader memory _batchHeader, Lib_OVMCodec.ChainInclusionProof memory _inclusionProof ) internal view returns ( bool ) { bytes32 leafHash = _getQueueLeafHash(_queueIndex); require( _verifyElement( leafHash, _batchHeader, _inclusionProof ), "Invalid Queue transaction inclusion proof." ); bytes32 transactionHash = keccak256( abi.encode( _transaction.l1TxOrigin, _transaction.entrypoint, _transaction.gasLimit, _transaction.data ) ); Lib_OVMCodec.QueueElement memory el = getQueueElement(_queueIndex); require( el.transactionHash == transactionHash && el.timestamp == _transaction.timestamp && el.blockNumber == _transaction.blockNumber, "Invalid Queue transaction." ); return true; } /** * 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 _verifyElement( bytes32 _element, Lib_OVMCodec.ChainBatchHeader memory _batchHeader, Lib_OVMCodec.ChainInclusionProof memory _proof ) internal view returns ( bool ) { require( Lib_OVMCodec.hashBatchHeader(_batchHeader) == batches().get(uint32(_batchHeader.batchIndex)), "Invalid batch header." ); require( Lib_MerkleTree.verify( _batchHeader.batchRoot, _element, _proof.index, _proof.siblings, _batchHeader.batchSize ), "Invalid inclusion proof." ); return true; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT // @unsupported: ovm 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_Bytes32Utils } from "../../libraries/utils/Lib_Bytes32Utils.sol"; import { Lib_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol"; import { Lib_ErrorUtils } from "../../libraries/utils/Lib_ErrorUtils.sol"; import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol"; /* Interface Imports */ import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol"; import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol"; /* Contract Imports */ import { OVM_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol"; /* External Imports */ import { Math } from "@openzeppelin/contracts/math/Math.sol"; /** * @title OVM_ExecutionManager * @dev The Execution Manager (EM) is the core of our OVM implementation, and provides a sandboxed * environment allowing us to execute OVM transactions deterministically on either Layer 1 or * Layer 2. * The EM's run() function is the first function called during the execution of any * transaction on L2. * For each context-dependent EVM operation the EM has a function which implements a corresponding * OVM operation, which will read state from the State Manager contract. * The EM relies on the Safety Checker to verify that code deployed to Layer 2 does not contain any * context-dependent operations. * * Compiler used: solc * Runtime target: EVM */ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { /******************************** * External Contract References * ********************************/ iOVM_SafetyChecker internal ovmSafetyChecker; iOVM_StateManager internal ovmStateManager; /******************************* * Execution Context Variables * *******************************/ GasMeterConfig internal gasMeterConfig; GlobalContext internal globalContext; TransactionContext internal transactionContext; MessageContext internal messageContext; TransactionRecord internal transactionRecord; MessageRecord internal messageRecord; /************************** * Gas Metering Constants * **************************/ address constant GAS_METADATA_ADDRESS = 0x06a506A506a506A506a506a506A506A506A506A5; uint256 constant NUISANCE_GAS_SLOAD = 20000; uint256 constant NUISANCE_GAS_SSTORE = 20000; uint256 constant MIN_NUISANCE_GAS_PER_CONTRACT = 30000; uint256 constant NUISANCE_GAS_PER_CONTRACT_BYTE = 100; uint256 constant MIN_GAS_FOR_INVALID_STATE_ACCESS = 30000; /************************** * Native Value Constants * **************************/ // Public so we can access and make assertions in integration tests. uint256 public constant CALL_WITH_VALUE_INTRINSIC_GAS = 90000; /************************** * Default Context Values * **************************/ uint256 constant DEFAULT_UINT256 = 0xdefa017defa017defa017defa017defa017defa017defa017defa017defa017d; address constant DEFAULT_ADDRESS = 0xdEfa017defA017DeFA017DEfa017DeFA017DeFa0; /************************************* * Container Contract Address Prefix * *************************************/ /** * @dev The Execution Manager and State Manager each have this 30 byte prefix, and are uncallable. */ address constant CONTAINER_CONTRACT_PREFIX = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; /*************** * Constructor * ***************/ /** * @param _libAddressManager Address of the Address Manager. */ constructor( address _libAddressManager, GasMeterConfig memory _gasMeterConfig, GlobalContext memory _globalContext ) Lib_AddressResolver(_libAddressManager) { ovmSafetyChecker = iOVM_SafetyChecker(resolve("OVM_SafetyChecker")); gasMeterConfig = _gasMeterConfig; globalContext = _globalContext; _resetContext(); } /********************** * Function Modifiers * **********************/ /** * Applies dynamically-sized refund to a transaction to account for the difference in execution * between L1 and L2, so that the overall cost of the ovmOPCODE is fixed. * @param _cost Desired gas cost for the function after the refund. */ modifier netGasCost( uint256 _cost ) { uint256 gasProvided = gasleft(); _; uint256 gasUsed = gasProvided - gasleft(); // We want to refund everything *except* the specified cost. if (_cost < gasUsed) { transactionRecord.ovmGasRefund += gasUsed - _cost; } } /** * Applies a fixed-size gas refund to a transaction to account for the difference in execution * between L1 and L2, so that the overall cost of an ovmOPCODE can be lowered. * @param _discount Amount of gas cost to refund for the ovmOPCODE. */ modifier fixedGasDiscount( uint256 _discount ) { uint256 gasProvided = gasleft(); _; uint256 gasUsed = gasProvided - gasleft(); // We want to refund the specified _discount, unless this risks underflow. if (_discount < gasUsed) { transactionRecord.ovmGasRefund += _discount; } else { // refund all we can without risking underflow. transactionRecord.ovmGasRefund += gasUsed; } } /** * Makes sure we're not inside a static context. */ modifier notStatic() { if (messageContext.isStatic == true) { _revertWithFlag(RevertFlag.STATIC_VIOLATION); } _; } /************************************ * Transaction Execution Entrypoint * ************************************/ /** * Starts the execution of a transaction via the OVM_ExecutionManager. * @param _transaction Transaction data to be executed. * @param _ovmStateManager iOVM_StateManager implementation providing account state. */ function run( Lib_OVMCodec.Transaction memory _transaction, address _ovmStateManager ) override external returns ( bytes memory ) { // Make sure that run() is not re-enterable. This condition should always be satisfied // Once run has been called once, due to the behavior of _isValidInput(). if (transactionContext.ovmNUMBER != DEFAULT_UINT256) { return bytes(""); } // Store our OVM_StateManager instance (significantly easier than attempting to pass the // address around in calldata). ovmStateManager = iOVM_StateManager(_ovmStateManager); // Make sure this function can't be called by anyone except the owner of the // OVM_StateManager (expected to be an OVM_StateTransitioner). We can revert here because // this would make the `run` itself invalid. require( // This method may return false during fraud proofs, but always returns true in L2 nodes' State Manager precompile. ovmStateManager.isAuthenticated(msg.sender), "Only authenticated addresses in ovmStateManager can call this function" ); // Initialize the execution context, must be initialized before we perform any gas metering // or we'll throw a nuisance gas error. _initContext(_transaction); // TEMPORARY: Gas metering is disabled for minnet. // // Check whether we need to start a new epoch, do so if necessary. // _checkNeedsNewEpoch(_transaction.timestamp); // Make sure the transaction's gas limit is valid. We don't revert here because we reserve // reverts for INVALID_STATE_ACCESS. if (_isValidInput(_transaction) == false) { _resetContext(); return bytes(""); } // TEMPORARY: Gas metering is disabled for minnet. // // Check gas right before the call to get total gas consumed by OVM transaction. // uint256 gasProvided = gasleft(); // Run the transaction, make sure to meter the gas usage. (, bytes memory returndata) = ovmCALL( _transaction.gasLimit - gasMeterConfig.minTransactionGasLimit, _transaction.entrypoint, 0, _transaction.data ); // TEMPORARY: Gas metering is disabled for minnet. // // Update the cumulative gas based on the amount of gas used. // uint256 gasUsed = gasProvided - gasleft(); // _updateCumulativeGas(gasUsed, _transaction.l1QueueOrigin); // Wipe the execution context. _resetContext(); return returndata; } /****************************** * Opcodes: Execution Context * ******************************/ /** * @notice Overrides CALLER. * @return _CALLER Address of the CALLER within the current message context. */ function ovmCALLER() override external view returns ( address _CALLER ) { return messageContext.ovmCALLER; } /** * @notice Overrides ADDRESS. * @return _ADDRESS Active ADDRESS within the current message context. */ function ovmADDRESS() override public view returns ( address _ADDRESS ) { return messageContext.ovmADDRESS; } /** * @notice Overrides CALLVALUE. * @return _CALLVALUE Value sent along with the call according to the current message context. */ function ovmCALLVALUE() override public view returns ( uint256 _CALLVALUE ) { return messageContext.ovmCALLVALUE; } /** * @notice Overrides TIMESTAMP. * @return _TIMESTAMP Value of the TIMESTAMP within the transaction context. */ function ovmTIMESTAMP() override external view returns ( uint256 _TIMESTAMP ) { return transactionContext.ovmTIMESTAMP; } /** * @notice Overrides NUMBER. * @return _NUMBER Value of the NUMBER within the transaction context. */ function ovmNUMBER() override external view returns ( uint256 _NUMBER ) { return transactionContext.ovmNUMBER; } /** * @notice Overrides GASLIMIT. * @return _GASLIMIT Value of the block's GASLIMIT within the transaction context. */ function ovmGASLIMIT() override external view returns ( uint256 _GASLIMIT ) { return transactionContext.ovmGASLIMIT; } /** * @notice Overrides CHAINID. * @return _CHAINID Value of the chain's CHAINID within the global context. */ function ovmCHAINID() override external view returns ( uint256 _CHAINID ) { return globalContext.ovmCHAINID; } /********************************* * Opcodes: L2 Execution Context * *********************************/ /** * @notice Specifies from which source (Sequencer or Queue) this transaction originated from. * @return _queueOrigin Enum indicating the ovmL1QUEUEORIGIN within the current message context. */ function ovmL1QUEUEORIGIN() override external view returns ( Lib_OVMCodec.QueueOrigin _queueOrigin ) { return transactionContext.ovmL1QUEUEORIGIN; } /** * @notice Specifies which L1 account, if any, sent this transaction by calling enqueue(). * @return _l1TxOrigin Address of the account which sent the tx into L2 from L1. */ function ovmL1TXORIGIN() override external view returns ( address _l1TxOrigin ) { return transactionContext.ovmL1TXORIGIN; } /******************** * Opcodes: Halting * ********************/ /** * @notice Overrides REVERT. * @param _data Bytes data to pass along with the REVERT. */ function ovmREVERT( bytes memory _data ) override public { _revertWithFlag(RevertFlag.INTENTIONAL_REVERT, _data); } /****************************** * Opcodes: Contract Creation * ******************************/ /** * @notice Overrides CREATE. * @param _bytecode Code to be used to CREATE a new contract. * @return Address of the created contract. * @return Revert data, if and only if the creation threw an exception. */ function ovmCREATE( bytes memory _bytecode ) override public notStatic fixedGasDiscount(40000) returns ( address, bytes memory ) { // Creator is always the current ADDRESS. address creator = ovmADDRESS(); // Check that the deployer is whitelisted, or // that arbitrary contract deployment has been enabled. _checkDeployerAllowed(creator); // Generate the correct CREATE address. address contractAddress = Lib_EthUtils.getAddressForCREATE( creator, _getAccountNonce(creator) ); return _createContract( contractAddress, _bytecode, MessageType.ovmCREATE ); } /** * @notice Overrides CREATE2. * @param _bytecode Code to be used to CREATE2 a new contract. * @param _salt Value used to determine the contract's address. * @return Address of the created contract. * @return Revert data, if and only if the creation threw an exception. */ function ovmCREATE2( bytes memory _bytecode, bytes32 _salt ) override external notStatic fixedGasDiscount(40000) returns ( address, bytes memory ) { // Creator is always the current ADDRESS. address creator = ovmADDRESS(); // Check that the deployer is whitelisted, or // that arbitrary contract deployment has been enabled. _checkDeployerAllowed(creator); // Generate the correct CREATE2 address. address contractAddress = Lib_EthUtils.getAddressForCREATE2( creator, _bytecode, _salt ); return _createContract( contractAddress, _bytecode, MessageType.ovmCREATE2 ); } /******************************* * Account Abstraction Opcodes * ******************************/ /** * Retrieves the nonce of the current ovmADDRESS. * @return _nonce Nonce of the current contract. */ function ovmGETNONCE() override external returns ( uint256 _nonce ) { return _getAccountNonce(ovmADDRESS()); } /** * Bumps the nonce of the current ovmADDRESS by one. */ function ovmINCREMENTNONCE() override external notStatic { address account = ovmADDRESS(); uint256 nonce = _getAccountNonce(account); // Prevent overflow. if (nonce + 1 > nonce) { _setAccountNonce(account, nonce + 1); } } /** * Creates a new EOA contract account, for account abstraction. * @dev Essentially functions like ovmCREATE or ovmCREATE2, but we can bypass a lot of checks * because the contract we're creating is trusted (no need to do safety checking or to * handle unexpected reverts). Doesn't need to return an address because the address is * assumed to be the user's actual address. * @param _messageHash Hash of a message signed by some user, for verification. * @param _v Signature `v` parameter. * @param _r Signature `r` parameter. * @param _s Signature `s` parameter. */ function ovmCREATEEOA( bytes32 _messageHash, uint8 _v, bytes32 _r, bytes32 _s ) override public notStatic { // Recover the EOA address from the message hash and signature parameters. Since we do the // hashing in advance, we don't have handle different message hashing schemes. Even if this // function were to return the wrong address (rather than explicitly returning the zero // address), the rest of the transaction would simply fail (since there's no EOA account to // actually execute the transaction). address eoa = ecrecover( _messageHash, _v + 27, _r, _s ); // Invalid signature is a case we proactively handle with a revert. We could alternatively // have this function return a `success` boolean, but this is just easier. if (eoa == address(0)) { ovmREVERT(bytes("Signature provided for EOA contract creation is invalid.")); } // If the user already has an EOA account, then there's no need to perform this operation. if (_hasEmptyAccount(eoa) == false) { return; } // We always need to initialize the contract with the default account values. _initPendingAccount(eoa); // Temporarily set the current address so it's easier to access on L2. address prevADDRESS = messageContext.ovmADDRESS; messageContext.ovmADDRESS = eoa; // Creates a duplicate of the OVM_ProxyEOA located at 0x42....09. Uses the following // "magic" prefix to deploy an exact copy of the code: // PUSH1 0x0D # size of this prefix in bytes // CODESIZE // SUB # subtract prefix size from codesize // DUP1 // PUSH1 0x0D // PUSH1 0x00 // CODECOPY # copy everything after prefix into memory at pos 0 // PUSH1 0x00 // RETURN # return the copied code address proxyEOA = Lib_EthUtils.createContract(abi.encodePacked( hex"600D380380600D6000396000f3", ovmEXTCODECOPY( Lib_PredeployAddresses.PROXY_EOA, 0, ovmEXTCODESIZE(Lib_PredeployAddresses.PROXY_EOA) ) )); // Reset the address now that we're done deploying. messageContext.ovmADDRESS = prevADDRESS; // Commit the account with its final values. _commitPendingAccount( eoa, address(proxyEOA), keccak256(Lib_EthUtils.getCode(address(proxyEOA))) ); _setAccountNonce(eoa, 0); } /********************************* * Opcodes: Contract Interaction * *********************************/ /** * @notice Overrides CALL. * @param _gasLimit Amount of gas to be passed into this call. * @param _address Address of the contract to call. * @param _value ETH value to pass with the call. * @param _calldata Data to send along with the call. * @return _success Whether or not the call returned (rather than reverted). * @return _returndata Data returned by the call. */ function ovmCALL( uint256 _gasLimit, address _address, uint256 _value, bytes memory _calldata ) override public fixedGasDiscount(100000) returns ( bool _success, bytes memory _returndata ) { // CALL updates the CALLER and ADDRESS. MessageContext memory nextMessageContext = messageContext; nextMessageContext.ovmCALLER = nextMessageContext.ovmADDRESS; nextMessageContext.ovmADDRESS = _address; nextMessageContext.ovmCALLVALUE = _value; return _callContract( nextMessageContext, _gasLimit, _address, _calldata, MessageType.ovmCALL ); } /** * @notice Overrides STATICCALL. * @param _gasLimit Amount of gas to be passed into this call. * @param _address Address of the contract to call. * @param _calldata Data to send along with the call. * @return _success Whether or not the call returned (rather than reverted). * @return _returndata Data returned by the call. */ function ovmSTATICCALL( uint256 _gasLimit, address _address, bytes memory _calldata ) override public fixedGasDiscount(80000) returns ( bool _success, bytes memory _returndata ) { // STATICCALL updates the CALLER, updates the ADDRESS, and runs in a static, valueless context. MessageContext memory nextMessageContext = messageContext; nextMessageContext.ovmCALLER = nextMessageContext.ovmADDRESS; nextMessageContext.ovmADDRESS = _address; nextMessageContext.isStatic = true; nextMessageContext.ovmCALLVALUE = 0; return _callContract( nextMessageContext, _gasLimit, _address, _calldata, MessageType.ovmSTATICCALL ); } /** * @notice Overrides DELEGATECALL. * @param _gasLimit Amount of gas to be passed into this call. * @param _address Address of the contract to call. * @param _calldata Data to send along with the call. * @return _success Whether or not the call returned (rather than reverted). * @return _returndata Data returned by the call. */ function ovmDELEGATECALL( uint256 _gasLimit, address _address, bytes memory _calldata ) override public fixedGasDiscount(40000) returns ( bool _success, bytes memory _returndata ) { // DELEGATECALL does not change anything about the message context. MessageContext memory nextMessageContext = messageContext; return _callContract( nextMessageContext, _gasLimit, _address, _calldata, MessageType.ovmDELEGATECALL ); } /** * @notice Legacy ovmCALL function which did not support ETH value; this maintains backwards compatibility. * @param _gasLimit Amount of gas to be passed into this call. * @param _address Address of the contract to call. * @param _calldata Data to send along with the call. * @return _success Whether or not the call returned (rather than reverted). * @return _returndata Data returned by the call. */ function ovmCALL( uint256 _gasLimit, address _address, bytes memory _calldata ) override public returns( bool _success, bytes memory _returndata ) { // Legacy ovmCALL assumed always-0 value. return ovmCALL( _gasLimit, _address, 0, _calldata ); } /************************************ * Opcodes: Contract Storage Access * ************************************/ /** * @notice Overrides SLOAD. * @param _key 32 byte key of the storage slot to load. * @return _value 32 byte value of the requested storage slot. */ function ovmSLOAD( bytes32 _key ) override external netGasCost(40000) returns ( bytes32 _value ) { // We always SLOAD from the storage of ADDRESS. address contractAddress = ovmADDRESS(); return _getContractStorage( contractAddress, _key ); } /** * @notice Overrides SSTORE. * @param _key 32 byte key of the storage slot to set. * @param _value 32 byte value for the storage slot. */ function ovmSSTORE( bytes32 _key, bytes32 _value ) override external notStatic netGasCost(60000) { // We always SSTORE to the storage of ADDRESS. address contractAddress = ovmADDRESS(); _putContractStorage( contractAddress, _key, _value ); } /********************************* * Opcodes: Contract Code Access * *********************************/ /** * @notice Overrides EXTCODECOPY. * @param _contract Address of the contract to copy code from. * @param _offset Offset in bytes from the start of contract code to copy beyond. * @param _length Total number of bytes to copy from the contract's code. * @return _code Bytes of code copied from the requested contract. */ function ovmEXTCODECOPY( address _contract, uint256 _offset, uint256 _length ) override public returns ( bytes memory _code ) { return Lib_EthUtils.getCode( _getAccountEthAddress(_contract), _offset, _length ); } /** * @notice Overrides EXTCODESIZE. * @param _contract Address of the contract to query the size of. * @return _EXTCODESIZE Size of the requested contract in bytes. */ function ovmEXTCODESIZE( address _contract ) override public returns ( uint256 _EXTCODESIZE ) { return Lib_EthUtils.getCodeSize( _getAccountEthAddress(_contract) ); } /** * @notice Overrides EXTCODEHASH. * @param _contract Address of the contract to query the hash of. * @return _EXTCODEHASH Hash of the requested contract. */ function ovmEXTCODEHASH( address _contract ) override external returns ( bytes32 _EXTCODEHASH ) { return Lib_EthUtils.getCodeHash( _getAccountEthAddress(_contract) ); } /*************************************** * Public Functions: ETH Value Opcodes * ***************************************/ /** * @notice Overrides BALANCE. * NOTE: In the future, this could be optimized to directly invoke EM._getContractStorage(...). * @param _contract Address of the contract to query the OVM_ETH balance of. * @return _BALANCE OVM_ETH balance of the requested contract. */ function ovmBALANCE( address _contract ) override public returns ( uint256 _BALANCE ) { // Easiest way to get the balance is query OVM_ETH as normal. bytes memory balanceOfCalldata = abi.encodeWithSignature( "balanceOf(address)", _contract ); // Static call because this should be a read-only query. (bool success, bytes memory returndata) = ovmSTATICCALL( gasleft(), Lib_PredeployAddresses.OVM_ETH, balanceOfCalldata ); // All balanceOf queries should successfully return a uint, otherwise this must be an OOG. if (!success || returndata.length != 32) { _revertWithFlag(RevertFlag.OUT_OF_GAS); } // Return the decoded balance. return abi.decode(returndata, (uint256)); } /** * @notice Overrides SELFBALANCE. * @return _BALANCE OVM_ETH balance of the requesting contract. */ function ovmSELFBALANCE() override external returns ( uint256 _BALANCE ) { return ovmBALANCE(ovmADDRESS()); } /*************************************** * Public Functions: Execution Context * ***************************************/ function getMaxTransactionGasLimit() external view override returns ( uint256 _maxTransactionGasLimit ) { return gasMeterConfig.maxTransactionGasLimit; } /******************************************** * Public Functions: Deployment Whitelisting * ********************************************/ /** * Checks whether the given address is on the whitelist to ovmCREATE/ovmCREATE2, and reverts if not. * @param _deployerAddress Address attempting to deploy a contract. */ function _checkDeployerAllowed( address _deployerAddress ) internal { // From an OVM semantics perspective, this will appear identical to // the deployer ovmCALLing the whitelist. This is fine--in a sense, we are forcing them to. (bool success, bytes memory data) = ovmSTATICCALL( gasleft(), Lib_PredeployAddresses.DEPLOYER_WHITELIST, abi.encodeWithSelector( OVM_DeployerWhitelist.isDeployerAllowed.selector, _deployerAddress ) ); bool isAllowed = abi.decode(data, (bool)); if (!isAllowed || !success) { _revertWithFlag(RevertFlag.CREATOR_NOT_ALLOWED); } } /******************************************** * Internal Functions: Contract Interaction * ********************************************/ /** * Creates a new contract and associates it with some contract address. * @param _contractAddress Address to associate the created contract with. * @param _bytecode Bytecode to be used to create the contract. * @return Final OVM contract address. * @return Revertdata, if and only if the creation threw an exception. */ function _createContract( address _contractAddress, bytes memory _bytecode, MessageType _messageType ) internal returns ( address, bytes memory ) { // We always update the nonce of the creating account, even if the creation fails. _setAccountNonce(ovmADDRESS(), _getAccountNonce(ovmADDRESS()) + 1); // We're stepping into a CREATE or CREATE2, so we need to update ADDRESS to point // to the contract's associated address and CALLER to point to the previous ADDRESS. MessageContext memory nextMessageContext = messageContext; nextMessageContext.ovmCALLER = messageContext.ovmADDRESS; nextMessageContext.ovmADDRESS = _contractAddress; // Run the common logic which occurs between call-type and create-type messages, // passing in the creation bytecode and `true` to trigger create-specific logic. (bool success, bytes memory data) = _handleExternalMessage( nextMessageContext, gasleft(), _contractAddress, _bytecode, _messageType ); // Yellow paper requires that address returned is zero if the contract deployment fails. return ( success ? _contractAddress : address(0), data ); } /** * Calls the deployed contract associated with a given address. * @param _nextMessageContext Message context to be used for the call. * @param _gasLimit Amount of gas to be passed into this call. * @param _contract OVM address to be called. * @param _calldata Data to send along with the call. * @return _success Whether or not the call returned (rather than reverted). * @return _returndata Data returned by the call. */ function _callContract( MessageContext memory _nextMessageContext, uint256 _gasLimit, address _contract, bytes memory _calldata, MessageType _messageType ) internal returns ( bool _success, bytes memory _returndata ) { // We reserve addresses of the form 0xdeaddeaddead...NNNN for the container contracts in L2 geth. // So, we block calls to these addresses since they are not safe to run as an OVM contract itself. if ( (uint256(_contract) & uint256(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000)) == uint256(CONTAINER_CONTRACT_PREFIX) ) { // EVM does not return data in the success case, see: https://github.com/ethereum/go-ethereum/blob/aae7660410f0ef90279e14afaaf2f429fdc2a186/core/vm/instructions.go#L600-L604 return (true, hex''); } // Both 0x0000... and the EVM precompiles have the same address on L1 and L2 --> no trie lookup needed. address codeContractAddress = uint(_contract) < 100 ? _contract : _getAccountEthAddress(_contract); return _handleExternalMessage( _nextMessageContext, _gasLimit, codeContractAddress, _calldata, _messageType ); } /** * Handles all interactions which involve the execution manager calling out to untrusted code (both calls and creates). * Ensures that OVM-related measures are enforced, including L2 gas refunds, nuisance gas, and flagged reversions. * * @param _nextMessageContext Message context to be used for the external message. * @param _gasLimit Amount of gas to be passed into this message. NOTE: this argument is overwritten in some cases to avoid stack-too-deep. * @param _contract OVM address being called or deployed to * @param _data Data for the message (either calldata or creation code) * @param _messageType What type of ovmOPCODE this message corresponds to. * @return Whether or not the message (either a call or deployment) succeeded. * @return Data returned by the message. */ function _handleExternalMessage( MessageContext memory _nextMessageContext, // NOTE: this argument is overwritten in some cases to avoid stack-too-deep. uint256 _gasLimit, address _contract, bytes memory _data, MessageType _messageType ) internal returns ( bool, bytes memory ) { uint256 messageValue = _nextMessageContext.ovmCALLVALUE; // If there is value in this message, we need to transfer the ETH over before switching contexts. if ( messageValue > 0 && _isValueType(_messageType) ) { // Handle out-of-intrinsic gas consistent with EVM behavior -- the subcall "appears to revert" if we don't have enough gas to transfer the ETH. // Similar to dynamic gas cost of value exceeding gas here: // https://github.com/ethereum/go-ethereum/blob/c503f98f6d5e80e079c1d8a3601d188af2a899da/core/vm/interpreter.go#L268-L273 if (gasleft() < CALL_WITH_VALUE_INTRINSIC_GAS) { return (false, hex""); } // If there *is* enough gas to transfer ETH, then we need to make sure this amount of gas is reserved (i.e. not // given to the _contract.call below) to guarantee that _handleExternalMessage can't run out of gas. // In particular, in the event that the call fails, we will need to transfer the ETH back to the sender. // Taking the lesser of _gasLimit and gasleft() - CALL_WITH_VALUE_INTRINSIC_GAS guarantees that the second // _attemptForcedEthTransfer below, if needed, always has enough gas to succeed. _gasLimit = Math.min( _gasLimit, gasleft() - CALL_WITH_VALUE_INTRINSIC_GAS // Cannot overflow due to the above check. ); // Now transfer the value of the call. // The target is interpreted to be the next message's ovmADDRESS account. bool transferredOvmEth = _attemptForcedEthTransfer( _nextMessageContext.ovmADDRESS, messageValue ); // If the ETH transfer fails (should only be possible in the case of insufficient balance), then treat this as a revert. // This mirrors EVM behavior, see https://github.com/ethereum/go-ethereum/blob/2dee31930c9977af2a9fcb518fb9838aa609a7cf/core/vm/evm.go#L298 if (!transferredOvmEth) { return (false, hex""); } } // We need to switch over to our next message context for the duration of this call. MessageContext memory prevMessageContext = messageContext; _switchMessageContext(prevMessageContext, _nextMessageContext); // Nuisance gas is a system used to bound the ability for an attacker to make fraud proofs // expensive by touching a lot of different accounts or storage slots. Since most contracts // only use a few storage slots during any given transaction, this shouldn't be a limiting // factor. uint256 prevNuisanceGasLeft = messageRecord.nuisanceGasLeft; uint256 nuisanceGasLimit = _getNuisanceGasLimit(_gasLimit); messageRecord.nuisanceGasLeft = nuisanceGasLimit; // Make the call and make sure to pass in the gas limit. Another instance of hidden // complexity. `_contract` is guaranteed to be a safe contract, meaning its return/revert // behavior can be controlled. In particular, we enforce that flags are passed through // revert data as to retrieve execution metadata that would normally be reverted out of // existence. bool success; bytes memory returndata; if (_isCreateType(_messageType)) { // safeCREATE() is a function which replicates a CREATE message, but uses return values // Which match that of CALL (i.e. bool, bytes). This allows many security checks to be // to be shared between untrusted call and create call frames. (success, returndata) = address(this).call{gas: _gasLimit}( abi.encodeWithSelector( this.safeCREATE.selector, _data, _contract ) ); } else { (success, returndata) = _contract.call{gas: _gasLimit}(_data); } // If the message threw an exception, its value should be returned back to the sender. // So, we force it back, BEFORE returning the messageContext to the previous addresses. // This operation is part of the reason we "reserved the intrinsic gas" above. if ( messageValue > 0 && _isValueType(_messageType) && !success ) { bool transferredOvmEth = _attemptForcedEthTransfer( prevMessageContext.ovmADDRESS, messageValue ); // Since we transferred it in above and the call reverted, the transfer back should always pass. // This code path should NEVER be triggered since we sent `messageValue` worth of OVM_ETH into the target // and reserved sufficient gas to execute the transfer, but in case there is some edge case which has // been missed, we revert the entire frame (and its parent) to make sure the ETH gets sent back. if (!transferredOvmEth) { _revertWithFlag(RevertFlag.OUT_OF_GAS); } } // Switch back to the original message context now that we're out of the call and all OVM_ETH is in the right place. _switchMessageContext(_nextMessageContext, prevMessageContext); // Assuming there were no reverts, the message record should be accurate here. We'll update // this value in the case of a revert. uint256 nuisanceGasLeft = messageRecord.nuisanceGasLeft; // Reverts at this point are completely OK, but we need to make a few updates based on the // information passed through the revert. if (success == false) { ( RevertFlag flag, uint256 nuisanceGasLeftPostRevert, uint256 ovmGasRefund, bytes memory returndataFromFlag ) = _decodeRevertData(returndata); // INVALID_STATE_ACCESS is the only flag that triggers an immediate abort of the // parent EVM message. This behavior is necessary because INVALID_STATE_ACCESS must // halt any further transaction execution that could impact the execution result. if (flag == RevertFlag.INVALID_STATE_ACCESS) { _revertWithFlag(flag); } // INTENTIONAL_REVERT, UNSAFE_BYTECODE, STATIC_VIOLATION, and CREATOR_NOT_ALLOWED aren't // dependent on the input state, so we can just handle them like standard reverts. Our only change here // is to record the gas refund reported by the call (enforced by safety checking). if ( flag == RevertFlag.INTENTIONAL_REVERT || flag == RevertFlag.UNSAFE_BYTECODE || flag == RevertFlag.STATIC_VIOLATION || flag == RevertFlag.CREATOR_NOT_ALLOWED ) { transactionRecord.ovmGasRefund = ovmGasRefund; } // INTENTIONAL_REVERT needs to pass up the user-provided return data encoded into the // flag, *not* the full encoded flag. Additionally, we surface custom error messages // to developers in the case of unsafe creations for improved devex. // All other revert types return no data. if ( flag == RevertFlag.INTENTIONAL_REVERT || flag == RevertFlag.UNSAFE_BYTECODE ) { returndata = returndataFromFlag; } else { returndata = hex''; } // Reverts mean we need to use up whatever "nuisance gas" was used by the call. // EXCEEDS_NUISANCE_GAS explicitly reduces the remaining nuisance gas for this message // to zero. OUT_OF_GAS is a "pseudo" flag given that messages return no data when they // run out of gas, so we have to treat this like EXCEEDS_NUISANCE_GAS. All other flags // will simply pass up the remaining nuisance gas. nuisanceGasLeft = nuisanceGasLeftPostRevert; } // We need to reset the nuisance gas back to its original value minus the amount used here. messageRecord.nuisanceGasLeft = prevNuisanceGasLeft - (nuisanceGasLimit - nuisanceGasLeft); return ( success, returndata ); } /** * Handles the creation-specific safety measures required for OVM contract deployment. * This function sanitizes the return types for creation messages to match calls (bool, bytes), * by being an external function which the EM can call, that mimics the success/fail case of the CREATE. * This allows for consistent handling of both types of messages in _handleExternalMessage(). * Having this step occur as a separate call frame also allows us to easily revert the * contract deployment in the event that the code is unsafe. * * @param _creationCode Code to pass into CREATE for deployment. * @param _address OVM address being deployed to. */ function safeCREATE( bytes memory _creationCode, address _address ) external { // The only way this should callable is from within _createContract(), // and it should DEFINITELY not be callable by a non-EM code contract. if (msg.sender != address(this)) { return; } // Check that there is not already code at this address. if (_hasEmptyAccount(_address) == false) { // Note: in the EVM, this case burns all allotted gas. For improved // developer experience, we do return the remaining gas. _revertWithFlag( RevertFlag.CREATE_COLLISION ); } // Check the creation bytecode against the OVM_SafetyChecker. if (ovmSafetyChecker.isBytecodeSafe(_creationCode) == false) { // Note: in the EVM, this case burns all allotted gas. For improved // developer experience, we do return the remaining gas. _revertWithFlag( RevertFlag.UNSAFE_BYTECODE, Lib_ErrorUtils.encodeRevertString("Contract creation code contains unsafe opcodes. Did you use the right compiler or pass an unsafe constructor argument?") ); } // We always need to initialize the contract with the default account values. _initPendingAccount(_address); // Actually execute the EVM create message. // NOTE: The inline assembly below means we can NOT make any evm calls between here and then. address ethAddress = Lib_EthUtils.createContract(_creationCode); if (ethAddress == address(0)) { // If the creation fails, the EVM lets us grab its revert data. This may contain a revert flag // to be used above in _handleExternalMessage, so we pass the revert data back up unmodified. assembly { returndatacopy(0,0,returndatasize()) revert(0, returndatasize()) } } // Again simply checking that the deployed code is safe too. Contracts can generate // arbitrary deployment code, so there's no easy way to analyze this beforehand. bytes memory deployedCode = Lib_EthUtils.getCode(ethAddress); if (ovmSafetyChecker.isBytecodeSafe(deployedCode) == false) { _revertWithFlag( RevertFlag.UNSAFE_BYTECODE, Lib_ErrorUtils.encodeRevertString("Constructor attempted to deploy unsafe bytecode.") ); } // Contract creation didn't need to be reverted and the bytecode is safe. We finish up by // associating the desired address with the newly created contract's code hash and address. _commitPendingAccount( _address, ethAddress, Lib_EthUtils.getCodeHash(ethAddress) ); } /****************************************** * Internal Functions: Value Manipulation * ******************************************/ /** * Invokes an ovmCALL to OVM_ETH.transfer on behalf of the current ovmADDRESS, allowing us to force movement of OVM_ETH in correspondence with ETH's native value functionality. * WARNING: this will send on behalf of whatever the messageContext.ovmADDRESS is in storage at the time of the call. * NOTE: In the future, this could be optimized to directly invoke EM._setContractStorage(...). * @param _to Amount of OVM_ETH to be sent. * @param _value Amount of OVM_ETH to send. * @return _success Whether or not the transfer worked. */ function _attemptForcedEthTransfer( address _to, uint256 _value ) internal returns( bool _success ) { bytes memory transferCalldata = abi.encodeWithSignature( "transfer(address,uint256)", _to, _value ); // OVM_ETH inherits from the UniswapV2ERC20 standard. In this implementation, its return type // is a boolean. However, the implementation always returns true if it does not revert. // Thus, success of the call frame is sufficient to infer success of the transfer itself. (bool success, ) = ovmCALL( gasleft(), Lib_PredeployAddresses.OVM_ETH, 0, transferCalldata ); return success; } /****************************************** * Internal Functions: State Manipulation * ******************************************/ /** * Checks whether an account exists within the OVM_StateManager. * @param _address Address of the account to check. * @return _exists Whether or not the account exists. */ function _hasAccount( address _address ) internal returns ( bool _exists ) { _checkAccountLoad(_address); return ovmStateManager.hasAccount(_address); } /** * Checks whether a known empty account exists within the OVM_StateManager. * @param _address Address of the account to check. * @return _exists Whether or not the account empty exists. */ function _hasEmptyAccount( address _address ) internal returns ( bool _exists ) { _checkAccountLoad(_address); return ovmStateManager.hasEmptyAccount(_address); } /** * Sets the nonce of an account. * @param _address Address of the account to modify. * @param _nonce New account nonce. */ function _setAccountNonce( address _address, uint256 _nonce ) internal { _checkAccountChange(_address); ovmStateManager.setAccountNonce(_address, _nonce); } /** * Gets the nonce of an account. * @param _address Address of the account to access. * @return _nonce Nonce of the account. */ function _getAccountNonce( address _address ) internal returns ( uint256 _nonce ) { _checkAccountLoad(_address); return ovmStateManager.getAccountNonce(_address); } /** * Retrieves the Ethereum address of an account. * @param _address Address of the account to access. * @return _ethAddress Corresponding Ethereum address. */ function _getAccountEthAddress( address _address ) internal returns ( address _ethAddress ) { _checkAccountLoad(_address); return ovmStateManager.getAccountEthAddress(_address); } /** * Creates the default account object for the given address. * @param _address Address of the account create. */ function _initPendingAccount( address _address ) internal { // Although it seems like `_checkAccountChange` would be more appropriate here, we don't // actually consider an account "changed" until it's inserted into the state (in this case // by `_commitPendingAccount`). _checkAccountLoad(_address); ovmStateManager.initPendingAccount(_address); } /** * Stores additional relevant data for a new account, thereby "committing" it to the state. * This function is only called during `ovmCREATE` and `ovmCREATE2` after a successful contract * creation. * @param _address Address of the account to commit. * @param _ethAddress Address of the associated deployed contract. * @param _codeHash Hash of the code stored at the address. */ function _commitPendingAccount( address _address, address _ethAddress, bytes32 _codeHash ) internal { _checkAccountChange(_address); ovmStateManager.commitPendingAccount( _address, _ethAddress, _codeHash ); } /** * Retrieves the value of a storage slot. * @param _contract Address of the contract to query. * @param _key 32 byte key of the storage slot. * @return _value 32 byte storage slot value. */ function _getContractStorage( address _contract, bytes32 _key ) internal returns ( bytes32 _value ) { _checkContractStorageLoad(_contract, _key); return ovmStateManager.getContractStorage(_contract, _key); } /** * Sets the value of a storage slot. * @param _contract Address of the contract to modify. * @param _key 32 byte key of the storage slot. * @param _value 32 byte storage slot value. */ function _putContractStorage( address _contract, bytes32 _key, bytes32 _value ) internal { // We don't set storage if the value didn't change. Although this acts as a convenient // optimization, it's also necessary to avoid the case in which a contract with no storage // attempts to store the value "0" at any key. Putting this value (and therefore requiring // that the value be committed into the storage trie after execution) would incorrectly // modify the storage root. if (_getContractStorage(_contract, _key) == _value) { return; } _checkContractStorageChange(_contract, _key); ovmStateManager.putContractStorage(_contract, _key, _value); } /** * Validation whenever a contract needs to be loaded. Checks that the account exists, charges * nuisance gas if the account hasn't been loaded before. * @param _address Address of the account to load. */ function _checkAccountLoad( address _address ) internal { // See `_checkContractStorageLoad` for more information. if (gasleft() < MIN_GAS_FOR_INVALID_STATE_ACCESS) { _revertWithFlag(RevertFlag.OUT_OF_GAS); } // See `_checkContractStorageLoad` for more information. if (ovmStateManager.hasAccount(_address) == false) { _revertWithFlag(RevertFlag.INVALID_STATE_ACCESS); } // Check whether the account has been loaded before and mark it as loaded if not. We need // this because "nuisance gas" only applies to the first time that an account is loaded. ( bool _wasAccountAlreadyLoaded ) = ovmStateManager.testAndSetAccountLoaded(_address); // If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based // on the size of the contract code. if (_wasAccountAlreadyLoaded == false) { _useNuisanceGas( (Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE) + MIN_NUISANCE_GAS_PER_CONTRACT ); } } /** * Validation whenever a contract needs to be changed. Checks that the account exists, charges * nuisance gas if the account hasn't been changed before. * @param _address Address of the account to change. */ function _checkAccountChange( address _address ) internal { // Start by checking for a load as we only want to charge nuisance gas proportional to // contract size once. _checkAccountLoad(_address); // Check whether the account has been changed before and mark it as changed if not. We need // this because "nuisance gas" only applies to the first time that an account is changed. ( bool _wasAccountAlreadyChanged ) = ovmStateManager.testAndSetAccountChanged(_address); // If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based // on the size of the contract code. if (_wasAccountAlreadyChanged == false) { ovmStateManager.incrementTotalUncommittedAccounts(); _useNuisanceGas( (Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE) + MIN_NUISANCE_GAS_PER_CONTRACT ); } } /** * Validation whenever a slot needs to be loaded. Checks that the account exists, charges * nuisance gas if the slot hasn't been loaded before. * @param _contract Address of the account to load from. * @param _key 32 byte key to load. */ function _checkContractStorageLoad( address _contract, bytes32 _key ) internal { // Another case of hidden complexity. If we didn't enforce this requirement, then a // contract could pass in just enough gas to cause the INVALID_STATE_ACCESS check to fail // on L1 but not on L2. A contract could use this behavior to prevent the // OVM_ExecutionManager from detecting an invalid state access. Reverting with OUT_OF_GAS // allows us to also charge for the full message nuisance gas, because you deserve that for // trying to break the contract in this way. if (gasleft() < MIN_GAS_FOR_INVALID_STATE_ACCESS) { _revertWithFlag(RevertFlag.OUT_OF_GAS); } // We need to make sure that the transaction isn't trying to access storage that hasn't // been provided to the OVM_StateManager. We'll immediately abort if this is the case. // We know that we have enough gas to do this check because of the above test. if (ovmStateManager.hasContractStorage(_contract, _key) == false) { _revertWithFlag(RevertFlag.INVALID_STATE_ACCESS); } // Check whether the slot has been loaded before and mark it as loaded if not. We need // this because "nuisance gas" only applies to the first time that a slot is loaded. ( bool _wasContractStorageAlreadyLoaded ) = ovmStateManager.testAndSetContractStorageLoaded(_contract, _key); // If we hadn't already loaded the account, then we'll need to charge some fixed amount of // "nuisance gas". if (_wasContractStorageAlreadyLoaded == false) { _useNuisanceGas(NUISANCE_GAS_SLOAD); } } /** * Validation whenever a slot needs to be changed. Checks that the account exists, charges * nuisance gas if the slot hasn't been changed before. * @param _contract Address of the account to change. * @param _key 32 byte key to change. */ function _checkContractStorageChange( address _contract, bytes32 _key ) internal { // Start by checking for load to make sure we have the storage slot and that we charge the // "nuisance gas" necessary to prove the storage slot state. _checkContractStorageLoad(_contract, _key); // Check whether the slot has been changed before and mark it as changed if not. We need // this because "nuisance gas" only applies to the first time that a slot is changed. ( bool _wasContractStorageAlreadyChanged ) = ovmStateManager.testAndSetContractStorageChanged(_contract, _key); // If we hadn't already changed the account, then we'll need to charge some fixed amount of // "nuisance gas". if (_wasContractStorageAlreadyChanged == false) { // Changing a storage slot means that we're also going to have to change the // corresponding account, so do an account change check. _checkAccountChange(_contract); ovmStateManager.incrementTotalUncommittedContractStorage(); _useNuisanceGas(NUISANCE_GAS_SSTORE); } } /************************************ * Internal Functions: Revert Logic * ************************************/ /** * Simple encoding for revert data. * @param _flag Flag to revert with. * @param _data Additional user-provided revert data. * @return _revertdata Encoded revert data. */ function _encodeRevertData( RevertFlag _flag, bytes memory _data ) internal view returns ( bytes memory _revertdata ) { // Out of gas and create exceptions will fundamentally return no data, so simulating it shouldn't either. if ( _flag == RevertFlag.OUT_OF_GAS ) { return bytes(''); } // INVALID_STATE_ACCESS doesn't need to return any data other than the flag. if (_flag == RevertFlag.INVALID_STATE_ACCESS) { return abi.encode( _flag, 0, 0, bytes('') ); } // Just ABI encode the rest of the parameters. return abi.encode( _flag, messageRecord.nuisanceGasLeft, transactionRecord.ovmGasRefund, _data ); } /** * Simple decoding for revert data. * @param _revertdata Revert data to decode. * @return _flag Flag used to revert. * @return _nuisanceGasLeft Amount of nuisance gas unused by the message. * @return _ovmGasRefund Amount of gas refunded during the message. * @return _data Additional user-provided revert data. */ function _decodeRevertData( bytes memory _revertdata ) internal pure returns ( RevertFlag _flag, uint256 _nuisanceGasLeft, uint256 _ovmGasRefund, bytes memory _data ) { // A length of zero means the call ran out of gas, just return empty data. if (_revertdata.length == 0) { return ( RevertFlag.OUT_OF_GAS, 0, 0, bytes('') ); } // ABI decode the incoming data. return abi.decode(_revertdata, (RevertFlag, uint256, uint256, bytes)); } /** * Causes a message to revert or abort. * @param _flag Flag to revert with. * @param _data Additional user-provided data. */ function _revertWithFlag( RevertFlag _flag, bytes memory _data ) internal view { bytes memory revertdata = _encodeRevertData( _flag, _data ); assembly { revert(add(revertdata, 0x20), mload(revertdata)) } } /** * Causes a message to revert or abort. * @param _flag Flag to revert with. */ function _revertWithFlag( RevertFlag _flag ) internal { _revertWithFlag(_flag, bytes('')); } /****************************************** * Internal Functions: Nuisance Gas Logic * ******************************************/ /** * Computes the nuisance gas limit from the gas limit. * @dev This function is currently using a naive implementation whereby the nuisance gas limit * is set to exactly equal the lesser of the gas limit or remaining gas. It's likely that * this implementation is perfectly fine, but we may change this formula later. * @param _gasLimit Gas limit to compute from. * @return _nuisanceGasLimit Computed nuisance gas limit. */ function _getNuisanceGasLimit( uint256 _gasLimit ) internal view returns ( uint256 _nuisanceGasLimit ) { return _gasLimit < gasleft() ? _gasLimit : gasleft(); } /** * Uses a certain amount of nuisance gas. * @param _amount Amount of nuisance gas to use. */ function _useNuisanceGas( uint256 _amount ) internal { // Essentially the same as a standard OUT_OF_GAS, except we also retain a record of the gas // refund to be given at the end of the transaction. if (messageRecord.nuisanceGasLeft < _amount) { _revertWithFlag(RevertFlag.EXCEEDS_NUISANCE_GAS); } messageRecord.nuisanceGasLeft -= _amount; } /************************************ * Internal Functions: Gas Metering * ************************************/ /** * Checks whether a transaction needs to start a new epoch and does so if necessary. * @param _timestamp Transaction timestamp. */ function _checkNeedsNewEpoch( uint256 _timestamp ) internal { if ( _timestamp >= ( _getGasMetadata(GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP) + gasMeterConfig.secondsPerEpoch ) ) { _putGasMetadata( GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP, _timestamp ); _putGasMetadata( GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS, _getGasMetadata( GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS ) ); _putGasMetadata( GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS, _getGasMetadata( GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS ) ); } } /** * Validates the input values of a transaction. * @return _valid Whether or not the transaction data is valid. */ function _isValidInput( Lib_OVMCodec.Transaction memory _transaction ) view internal returns ( bool ) { // Prevent reentrancy to run(): // This check prevents calling run with the default ovmNumber. // Combined with the first check in run(): // if (transactionContext.ovmNUMBER != DEFAULT_UINT256) { return; } // It should be impossible to re-enter since run() returns before any other call frames are created. // Since this value is already being written to storage, we save much gas compared to // using the standard nonReentrant pattern. if (_transaction.blockNumber == DEFAULT_UINT256) { return false; } if (_isValidGasLimit(_transaction.gasLimit, _transaction.l1QueueOrigin) == false) { return false; } return true; } /** * Validates the gas limit for a given transaction. * @param _gasLimit Gas limit provided by the transaction. * param _queueOrigin Queue from which the transaction originated. * @return _valid Whether or not the gas limit is valid. */ function _isValidGasLimit( uint256 _gasLimit, Lib_OVMCodec.QueueOrigin // _queueOrigin ) view internal returns ( bool _valid ) { // Always have to be below the maximum gas limit. if (_gasLimit > gasMeterConfig.maxTransactionGasLimit) { return false; } // Always have to be above the minimum gas limit. if (_gasLimit < gasMeterConfig.minTransactionGasLimit) { return false; } // TEMPORARY: Gas metering is disabled for minnet. return true; // GasMetadataKey cumulativeGasKey; // GasMetadataKey prevEpochGasKey; // if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) { // cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS; // prevEpochGasKey = GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS; // } else { // cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS; // prevEpochGasKey = GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS; // } // return ( // ( // _getGasMetadata(cumulativeGasKey) // - _getGasMetadata(prevEpochGasKey) // + _gasLimit // ) < gasMeterConfig.maxGasPerQueuePerEpoch // ); } /** * Updates the cumulative gas after a transaction. * @param _gasUsed Gas used by the transaction. * @param _queueOrigin Queue from which the transaction originated. */ function _updateCumulativeGas( uint256 _gasUsed, Lib_OVMCodec.QueueOrigin _queueOrigin ) internal { GasMetadataKey cumulativeGasKey; if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) { cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS; } else { cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS; } _putGasMetadata( cumulativeGasKey, ( _getGasMetadata(cumulativeGasKey) + gasMeterConfig.minTransactionGasLimit + _gasUsed - transactionRecord.ovmGasRefund ) ); } /** * Retrieves the value of a gas metadata key. * @param _key Gas metadata key to retrieve. * @return _value Value stored at the given key. */ function _getGasMetadata( GasMetadataKey _key ) internal returns ( uint256 _value ) { return uint256(_getContractStorage( GAS_METADATA_ADDRESS, bytes32(uint256(_key)) )); } /** * Sets the value of a gas metadata key. * @param _key Gas metadata key to set. * @param _value Value to store at the given key. */ function _putGasMetadata( GasMetadataKey _key, uint256 _value ) internal { _putContractStorage( GAS_METADATA_ADDRESS, bytes32(uint256(_key)), bytes32(uint256(_value)) ); } /***************************************** * Internal Functions: Execution Context * *****************************************/ /** * Swaps over to a new message context. * @param _prevMessageContext Context we're switching from. * @param _nextMessageContext Context we're switching to. */ function _switchMessageContext( MessageContext memory _prevMessageContext, MessageContext memory _nextMessageContext ) internal { // These conditionals allow us to avoid unneccessary SSTOREs. However, they do mean that the current storage // value for the messageContext MUST equal the _prevMessageContext argument, or an SSTORE might be erroneously skipped. if (_prevMessageContext.ovmCALLER != _nextMessageContext.ovmCALLER) { messageContext.ovmCALLER = _nextMessageContext.ovmCALLER; } if (_prevMessageContext.ovmADDRESS != _nextMessageContext.ovmADDRESS) { messageContext.ovmADDRESS = _nextMessageContext.ovmADDRESS; } if (_prevMessageContext.isStatic != _nextMessageContext.isStatic) { messageContext.isStatic = _nextMessageContext.isStatic; } if (_prevMessageContext.ovmCALLVALUE != _nextMessageContext.ovmCALLVALUE) { messageContext.ovmCALLVALUE = _nextMessageContext.ovmCALLVALUE; } } /** * Initializes the execution context. * @param _transaction OVM transaction being executed. */ function _initContext( Lib_OVMCodec.Transaction memory _transaction ) internal { transactionContext.ovmTIMESTAMP = _transaction.timestamp; transactionContext.ovmNUMBER = _transaction.blockNumber; transactionContext.ovmTXGASLIMIT = _transaction.gasLimit; transactionContext.ovmL1QUEUEORIGIN = _transaction.l1QueueOrigin; transactionContext.ovmL1TXORIGIN = _transaction.l1TxOrigin; transactionContext.ovmGASLIMIT = gasMeterConfig.maxGasPerQueuePerEpoch; messageRecord.nuisanceGasLeft = _getNuisanceGasLimit(_transaction.gasLimit); } /** * Resets the transaction and message context. */ function _resetContext() internal { transactionContext.ovmL1TXORIGIN = DEFAULT_ADDRESS; transactionContext.ovmTIMESTAMP = DEFAULT_UINT256; transactionContext.ovmNUMBER = DEFAULT_UINT256; transactionContext.ovmGASLIMIT = DEFAULT_UINT256; transactionContext.ovmTXGASLIMIT = DEFAULT_UINT256; transactionContext.ovmL1QUEUEORIGIN = Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE; transactionRecord.ovmGasRefund = DEFAULT_UINT256; messageContext.ovmCALLER = DEFAULT_ADDRESS; messageContext.ovmADDRESS = DEFAULT_ADDRESS; messageContext.isStatic = false; messageRecord.nuisanceGasLeft = DEFAULT_UINT256; // Reset the ovmStateManager. ovmStateManager = iOVM_StateManager(address(0)); } /****************************************** * Internal Functions: Message Typechecks * ******************************************/ /** * Returns whether or not the given message type is a CREATE-type. * @param _messageType the message type in question. */ function _isCreateType( MessageType _messageType ) internal pure returns( bool ) { return ( _messageType == MessageType.ovmCREATE || _messageType == MessageType.ovmCREATE2 ); } /** * Returns whether or not the given message type (potentially) requires the transfer of ETH value along with the message. * @param _messageType the message type in question. */ function _isValueType( MessageType _messageType ) internal pure returns( bool ) { // ovmSTATICCALL and ovmDELEGATECALL types do not accept or transfer value. return ( _messageType == MessageType.ovmCALL || _messageType == MessageType.ovmCREATE || _messageType == MessageType.ovmCREATE2 ); } /***************************** * L2-only Helper Functions * *****************************/ /** * Unreachable helper function for simulating eth_calls with an OVM message context. * This function will throw an exception in all cases other than when used as a custom entrypoint in L2 Geth to simulate eth_call. * @param _transaction the message transaction to simulate. * @param _from the OVM account the simulated call should be from. * @param _value the amount of ETH value to send. * @param _ovmStateManager the address of the OVM_StateManager precompile in the L2 state. */ function simulateMessage( Lib_OVMCodec.Transaction memory _transaction, address _from, uint256 _value, iOVM_StateManager _ovmStateManager ) external returns ( bytes memory ) { // Prevent this call from having any effect unless in a custom-set VM frame require(msg.sender == address(0)); // Initialize the EM's internal state, ignoring nuisance gas. ovmStateManager = _ovmStateManager; _initContext(_transaction); messageRecord.nuisanceGasLeft = uint(-1); // Set the ovmADDRESS to the _from so that the subsequent call frame "comes from" them. messageContext.ovmADDRESS = _from; // Execute the desired message. bool isCreate = _transaction.entrypoint == address(0); if (isCreate) { (address created, bytes memory revertData) = ovmCREATE(_transaction.data); if (created == address(0)) { return abi.encode(false, revertData); } else { // The eth_call RPC endpoint for to = undefined will return the deployed bytecode // in the success case, differing from standard create messages. return abi.encode(true, Lib_EthUtils.getCode(created)); } } else { (bool success, bytes memory returndata) = ovmCALL( _transaction.gasLimit, _transaction.entrypoint, _value, _transaction.data ); return abi.encode(success, returndata); } } }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.8.0; /* Interface Imports */ import { iOVM_DeployerWhitelist } from "../../iOVM/predeploys/iOVM_DeployerWhitelist.sol"; /** * @title OVM_DeployerWhitelist * @dev The Deployer Whitelist is a temporary predeploy used to provide additional safety during the * initial phases of our mainnet roll out. It is owned by the Optimism team, and defines accounts * which are allowed to deploy contracts on Layer2. The Execution Manager will only allow an * ovmCREATE or ovmCREATE2 operation to proceed if the deployer's address whitelisted. * * Compiler used: optimistic-solc * Runtime target: OVM */ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { /********************** * Contract Constants * **********************/ bool public initialized; bool public allowArbitraryDeployment; address override public owner; mapping (address => bool) public whitelist; /********************** * Function Modifiers * **********************/ /** * Blocks functions to anyone except the contract owner. */ modifier onlyOwner() { require( msg.sender == owner, "Function can only be called by the owner of this contract." ); _; } /******************** * Public Functions * ********************/ /** * Initializes the whitelist. * @param _owner Address of the owner for this contract. * @param _allowArbitraryDeployment Whether or not to allow arbitrary contract deployment. */ function initialize( address _owner, bool _allowArbitraryDeployment ) override external { if (initialized == true) { return; } initialized = true; allowArbitraryDeployment = _allowArbitraryDeployment; owner = _owner; } /** * Adds or removes an address from the deployment whitelist. * @param _deployer Address to update permissions for. * @param _isWhitelisted Whether or not the address is whitelisted. */ function setWhitelistedDeployer( address _deployer, bool _isWhitelisted ) override external onlyOwner { whitelist[_deployer] = _isWhitelisted; } /** * Updates the owner of this contract. * @param _owner Address of the new owner. */ function setOwner( address _owner ) override public onlyOwner { owner = _owner; } /** * Updates the arbitrary deployment flag. * @param _allowArbitraryDeployment Whether or not to allow arbitrary contract deployment. */ function setAllowArbitraryDeployment( bool _allowArbitraryDeployment ) override public onlyOwner { allowArbitraryDeployment = _allowArbitraryDeployment; } /** * Permanently enables arbitrary contract deployment and deletes the owner. */ function enableArbitraryContractDeployment() override external onlyOwner { setAllowArbitraryDeployment(true); setOwner(address(0)); } /** * Checks whether an address is allowed to deploy contracts. * @param _deployer Address to check. * @return _allowed Whether or not the address can deploy contracts. */ function isDeployerAllowed( address _deployer ) override external returns ( bool ) { return ( initialized == false || allowArbitraryDeployment == true || whitelist[_deployer] ); } }
// 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; }
// 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 iOVM_ExecutionManager { /********** * Enums * *********/ enum RevertFlag { OUT_OF_GAS, INTENTIONAL_REVERT, EXCEEDS_NUISANCE_GAS, INVALID_STATE_ACCESS, UNSAFE_BYTECODE, CREATE_COLLISION, STATIC_VIOLATION, CREATOR_NOT_ALLOWED } enum GasMetadataKey { CURRENT_EPOCH_START_TIMESTAMP, CUMULATIVE_SEQUENCER_QUEUE_GAS, CUMULATIVE_L1TOL2_QUEUE_GAS, PREV_EPOCH_SEQUENCER_QUEUE_GAS, PREV_EPOCH_L1TOL2_QUEUE_GAS } enum MessageType { ovmCALL, ovmSTATICCALL, ovmDELEGATECALL, ovmCREATE, ovmCREATE2 } /*********** * Structs * ***********/ struct GasMeterConfig { uint256 minTransactionGasLimit; uint256 maxTransactionGasLimit; uint256 maxGasPerQueuePerEpoch; uint256 secondsPerEpoch; } struct GlobalContext { uint256 ovmCHAINID; } struct TransactionContext { Lib_OVMCodec.QueueOrigin ovmL1QUEUEORIGIN; uint256 ovmTIMESTAMP; uint256 ovmNUMBER; uint256 ovmGASLIMIT; uint256 ovmTXGASLIMIT; address ovmL1TXORIGIN; } struct TransactionRecord { uint256 ovmGasRefund; } struct MessageContext { address ovmCALLER; address ovmADDRESS; uint256 ovmCALLVALUE; bool isStatic; } struct MessageRecord { uint256 nuisanceGasLeft; } /************************************ * Transaction Execution Entrypoint * ************************************/ function run( Lib_OVMCodec.Transaction calldata _transaction, address _txStateManager ) external returns (bytes memory); /******************* * Context Opcodes * *******************/ function ovmCALLER() external view returns (address _caller); function ovmADDRESS() external view returns (address _address); function ovmCALLVALUE() external view returns (uint _callValue); function ovmTIMESTAMP() external view returns (uint256 _timestamp); function ovmNUMBER() external view returns (uint256 _number); function ovmGASLIMIT() external view returns (uint256 _gasLimit); function ovmCHAINID() external view returns (uint256 _chainId); /********************** * L2 Context Opcodes * **********************/ function ovmL1QUEUEORIGIN() external view returns (Lib_OVMCodec.QueueOrigin _queueOrigin); function ovmL1TXORIGIN() external view returns (address _l1TxOrigin); /******************* * Halting Opcodes * *******************/ function ovmREVERT(bytes memory _data) external; /***************************** * Contract Creation Opcodes * *****************************/ function ovmCREATE(bytes memory _bytecode) external returns (address _contract, bytes memory _revertdata); function ovmCREATE2(bytes memory _bytecode, bytes32 _salt) external returns (address _contract, bytes memory _revertdata); /******************************* * Account Abstraction Opcodes * ******************************/ function ovmGETNONCE() external returns (uint256 _nonce); function ovmINCREMENTNONCE() external; function ovmCREATEEOA(bytes32 _messageHash, uint8 _v, bytes32 _r, bytes32 _s) external; /**************************** * Contract Calling Opcodes * ****************************/ // Valueless ovmCALL for maintaining backwards compatibility with legacy OVM bytecode. function ovmCALL(uint256 _gasLimit, address _address, bytes memory _calldata) external returns (bool _success, bytes memory _returndata); function ovmCALL(uint256 _gasLimit, address _address, uint256 _value, bytes memory _calldata) external returns (bool _success, bytes memory _returndata); function ovmSTATICCALL(uint256 _gasLimit, address _address, bytes memory _calldata) external returns (bool _success, bytes memory _returndata); function ovmDELEGATECALL(uint256 _gasLimit, address _address, bytes memory _calldata) external returns (bool _success, bytes memory _returndata); /**************************** * Contract Storage Opcodes * ****************************/ function ovmSLOAD(bytes32 _key) external returns (bytes32 _value); function ovmSSTORE(bytes32 _key, bytes32 _value) external; /************************* * Contract Code Opcodes * *************************/ function ovmEXTCODECOPY(address _contract, uint256 _offset, uint256 _length) external returns (bytes memory _code); function ovmEXTCODESIZE(address _contract) external returns (uint256 _size); function ovmEXTCODEHASH(address _contract) external returns (bytes32 _hash); /********************* * ETH Value Opcodes * *********************/ function ovmBALANCE(address _contract) external returns (uint256 _balance); function ovmSELFBALANCE() external returns (uint256 _balance); /*************************************** * Public Functions: Execution Context * ***************************************/ function getMaxTransactionGasLimit() external view returns (uint _maxTransactionGasLimit); }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.8.0; /** * @title iOVM_SafetyChecker */ interface iOVM_SafetyChecker { /******************** * Public Functions * ********************/ function isBytecodeSafe(bytes calldata _bytecode) external pure returns (bool); }
// 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_StateManager */ interface iOVM_StateManager { /******************* * Data Structures * *******************/ enum ItemState { ITEM_UNTOUCHED, ITEM_LOADED, ITEM_CHANGED, ITEM_COMMITTED } /*************************** * Public Functions: Misc * ***************************/ function isAuthenticated(address _address) external view returns (bool); /*************************** * Public Functions: Setup * ***************************/ function owner() external view returns (address _owner); function ovmExecutionManager() external view returns (address _ovmExecutionManager); function setExecutionManager(address _ovmExecutionManager) external; /************************************ * Public Functions: Account Access * ************************************/ function putAccount(address _address, Lib_OVMCodec.Account memory _account) external; function putEmptyAccount(address _address) external; function getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account); function hasAccount(address _address) external view returns (bool _exists); function hasEmptyAccount(address _address) external view returns (bool _exists); function setAccountNonce(address _address, uint256 _nonce) external; function getAccountNonce(address _address) external view returns (uint256 _nonce); function getAccountEthAddress(address _address) external view returns (address _ethAddress); function getAccountStorageRoot(address _address) external view returns (bytes32 _storageRoot); function initPendingAccount(address _address) external; function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external; function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded); function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged); function commitAccount(address _address) external returns (bool _wasAccountCommitted); function incrementTotalUncommittedAccounts() external; function getTotalUncommittedAccounts() external view returns (uint256 _total); function wasAccountChanged(address _address) external view returns (bool); function wasAccountCommitted(address _address) external view returns (bool); /************************************ * Public Functions: Storage Access * ************************************/ function putContractStorage(address _contract, bytes32 _key, bytes32 _value) external; function getContractStorage(address _contract, bytes32 _key) external view returns (bytes32 _value); function hasContractStorage(address _contract, bytes32 _key) external view returns (bool _exists); function testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded); function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged); function commitContractStorage(address _contract, bytes32 _key) external returns (bool _wasContractStorageCommitted); function incrementTotalUncommittedContractStorage() external; function getTotalUncommittedContractStorage() external view returns (uint256 _total); function wasContractStorageChanged(address _contract, bytes32 _key) external view returns (bool); function wasContractStorageCommitted(address _contract, bytes32 _key) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.8.0; /** * @title iOVM_DeployerWhitelist */ interface iOVM_DeployerWhitelist { /******************** * Public Functions * ********************/ function initialize(address _owner, bool _allowArbitraryDeployment) external; function owner() external returns (address _owner); function setWhitelistedDeployer(address _deployer, bool _isWhitelisted) external; function setOwner(address _newOwner) external; function setAllowArbitraryDeployment(bool _allowArbitraryDeployment) external; function enableArbitraryContractDeployment() external; function isDeployerAllowed(address _deployer) external returns (bool _allowed); }
// 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"; /** * @title Lib_OVMCodec */ library Lib_OVMCodec { /********* * Enums * *********/ 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; } /********************** * Internal Functions * **********************/ /** * 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 Lib_PredeployAddresses */ library Lib_PredeployAddresses { address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; address internal constant ECDSA_CONTRACT_ACCOUNT = 0x4200000000000000000000000000000000000003; address internal constant SEQUENCER_ENTRYPOINT = 0x4200000000000000000000000000000000000005; address payable internal constant OVM_ETH = 0x4200000000000000000000000000000000000006; address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008; address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009; address internal constant EXECUTION_MANAGER_WRAPPER = 0x420000000000000000000000000000000000000B; address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; address internal constant ERC1820_REGISTRY = 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24; address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.8.0; /* External Imports */ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Lib_AddressManager */ contract Lib_AddressManager is Ownable { /********** * Events * **********/ event AddressSet( string indexed _name, address _newAddress, address _oldAddress ); /************* * Variables * *************/ mapping (bytes32 => address) private addresses; /******************** * Public Functions * ********************/ /** * Changes the address associated with a particular name. * @param _name String name to associate an address with. * @param _address Address to associate with the name. */ function setAddress( string memory _name, address _address ) external onlyOwner { bytes32 nameHash = _getNameHash(_name); address oldAddress = addresses[nameHash]; addresses[nameHash] = _address; emit AddressSet( _name, _address, oldAddress ); } /** * Retrieves the address associated with a given name. * @param _name Name to retrieve an address for. * @return Address associated with the given name. */ function getAddress( string memory _name ) external view returns ( address ) { return addresses[_getNameHash(_name)]; } /********************** * Internal Functions * **********************/ /** * Computes the hash of a name. * @param _name Name to compute a hash for. * @return Hash of the given name. */ function _getNameHash( string memory _name ) internal pure returns ( bytes32 ) { 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 { /************* * Variables * *************/ Lib_AddressManager public libAddressManager; /*************** * Constructor * ***************/ /** * @param _libAddressManager Address of the Lib_AddressManager. */ constructor( address _libAddressManager ) { libAddressManager = Lib_AddressManager(_libAddressManager); } /******************** * Public Functions * ********************/ /** * Resolves the address associated with a given name. * @param _name Name to resolve an address for. * @return Address associated with the given name. */ function resolve( string memory _name ) public view returns ( address ) { return libAddressManager.getAddress(_name); } }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.8.0; /** * @title Lib_RLPReader * @dev Adapted from "RLPReader" by Hamdi Allam ([email protected]). */ 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; /** * @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 The RLP encoded string in bytes. */ function writeBytes( bytes memory _in ) internal pure returns ( bytes memory ) { 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 The RLP encoded list of items in bytes. */ function writeList( bytes[] memory _in ) internal pure returns ( bytes memory ) { bytes memory list = _flatten(_in); return abi.encodePacked(_writeLength(list.length, 192), list); } /** * RLP encodes a string. * @param _in The string to encode. * @return The RLP encoded string in bytes. */ function writeString( string memory _in ) internal pure returns ( bytes memory ) { return writeBytes(bytes(_in)); } /** * RLP encodes an address. * @param _in The address to encode. * @return The RLP encoded address in bytes. */ function writeAddress( address _in ) internal pure returns ( bytes memory ) { return writeBytes(abi.encodePacked(_in)); } /** * RLP encodes a bytes32 value. * @param _in The bytes32 to encode. * @return _out The RLP encoded bytes32 in bytes. */ function writeBytes32( bytes32 _in ) internal pure returns ( bytes memory _out ) { return writeBytes(abi.encodePacked(_in)); } /** * RLP encodes a uint. * @param _in The uint256 to encode. * @return The RLP encoded uint256 in bytes. */ function writeUint( uint256 _in ) internal pure returns ( bytes memory ) { return writeBytes(_toBinary(_in)); } /** * RLP encodes a bool. * @param _in The bool to encode. * @return The RLP encoded bool in bytes. */ function writeBool( bool _in ) internal pure returns ( bytes memory ) { 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 RLP encoded bytes. */ function _writeLength( uint256 _len, uint256 _offset ) private pure returns ( bytes memory ) { 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 RLP encoded bytes. */ function _toBinary( uint256 _x ) private pure returns ( bytes memory ) { 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 The flattened byte string. */ function _flatten( bytes[] memory _list ) private pure returns ( bytes memory ) { 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; /** * @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 (_start >= _bytes.length) { 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 // @unsupported: ovm pragma solidity >0.5.0 <0.8.0; pragma experimental ABIEncoderV2; /* Library Imports */ import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol"; import { Lib_Bytes32Utils } from "./Lib_Bytes32Utils.sol"; /** * @title Lib_EthUtils */ library Lib_EthUtils { /********************** * Internal Functions * **********************/ /** * Gets the code for a given address. * @param _address Address to get code for. * @param _offset Offset to start reading from. * @param _length Number of bytes to read. * @return Code read from the contract. */ function getCode( address _address, uint256 _offset, uint256 _length ) internal view returns ( bytes memory ) { bytes memory code; assembly { code := mload(0x40) mstore(0x40, add(code, add(_length, 0x20))) mstore(code, _length) extcodecopy(_address, add(code, 0x20), _offset, _length) } return code; } /** * Gets the full code for a given address. * @param _address Address to get code for. * @return Full code of the contract. */ function getCode( address _address ) internal view returns ( bytes memory ) { return getCode( _address, 0, getCodeSize(_address) ); } /** * Gets the size of a contract's code in bytes. * @param _address Address to get code size for. * @return Size of the contract's code in bytes. */ function getCodeSize( address _address ) internal view returns ( uint256 ) { uint256 codeSize; assembly { codeSize := extcodesize(_address) } return codeSize; } /** * Gets the hash of a contract's code. * @param _address Address to get a code hash for. * @return Hash of the contract's code. */ function getCodeHash( address _address ) internal view returns ( bytes32 ) { bytes32 codeHash; assembly { codeHash := extcodehash(_address) } return codeHash; } /** * Creates a contract with some given initialization code. * @param _code Contract initialization code. * @return Address of the created contract. */ function createContract( bytes memory _code ) internal returns ( address ) { address created; assembly { created := create( 0, add(_code, 0x20), mload(_code) ) } return created; } /** * Computes the address that would be generated by CREATE. * @param _creator Address creating the contract. * @param _nonce Creator's nonce. * @return Address to be generated by CREATE. */ function getAddressForCREATE( address _creator, uint256 _nonce ) internal pure returns ( address ) { bytes[] memory encoded = new bytes[](2); encoded[0] = Lib_RLPWriter.writeAddress(_creator); encoded[1] = Lib_RLPWriter.writeUint(_nonce); bytes memory encodedList = Lib_RLPWriter.writeList(encoded); return Lib_Bytes32Utils.toAddress(keccak256(encodedList)); } /** * Computes the address that would be generated by CREATE2. * @param _creator Address creating the contract. * @param _bytecode Bytecode of the contract to be created. * @param _salt 32 byte salt value mixed into the hash. * @return Address to be generated by CREATE2. */ function getAddressForCREATE2( address _creator, bytes memory _bytecode, bytes32 _salt ) internal pure returns ( address ) { bytes32 hashedData = keccak256(abi.encodePacked( byte(0xff), _creator, _salt, keccak256(_bytecode) )); return Lib_Bytes32Utils.toAddress(hashedData); } }
// 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; } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_libAddressManager","type":"address"},{"internalType":"uint256","name":"_forceInclusionPeriodSeconds","type":"uint256"},{"internalType":"uint256","name":"_forceInclusionPeriodBlocks","type":"uint256"},{"internalType":"uint256","name":"_maxTransactionGasLimit","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_startingQueueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numQueueElements","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalElements","type":"uint256"}],"name":"QueueBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_startingQueueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numQueueElements","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalElements","type":"uint256"}],"name":"SequencerBatchAppended","type":"event"},{"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":"TransactionBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_l1TxOrigin","type":"address"},{"indexed":false,"internalType":"address","name":"_target","type":"address"},{"indexed":false,"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_queueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"TransactionEnqueued","type":"event"},{"inputs":[],"name":"L2_GAS_DISCOUNT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ROLLUP_TX_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_ROLLUP_TX_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"appendQueueBatch","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"appendSequencerBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batches","outputs":[{"internalType":"contract iOVM_ChainStorageContainer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"enqueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forceInclusionPeriodBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceInclusionPeriodSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockNumber","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextQueueIndex","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumPendingQueueElements","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getQueueElement","outputs":[{"components":[{"internalType":"bytes32","name":"transactionHash","type":"bytes32"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"uint40","name":"blockNumber","type":"uint40"}],"internalType":"struct Lib_OVMCodec.QueueElement","name":"_element","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQueueLength","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"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":[],"name":"libAddressManager","outputs":[{"internalType":"contract Lib_AddressManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTransactionGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queue","outputs":[{"internalType":"contract iOVM_ChainStorageContainer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"resolve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"enum Lib_OVMCodec.QueueOrigin","name":"l1QueueOrigin","type":"uint8"},{"internalType":"address","name":"l1TxOrigin","type":"address"},{"internalType":"address","name":"entrypoint","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Lib_OVMCodec.Transaction","name":"_transaction","type":"tuple"},{"components":[{"internalType":"bool","name":"isSequenced","type":"bool"},{"internalType":"uint256","name":"queueIndex","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes","name":"txData","type":"bytes"}],"internalType":"struct Lib_OVMCodec.TransactionChainElement","name":"_txChainElement","type":"tuple"},{"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":"_inclusionProof","type":"tuple"}],"name":"verifyTransaction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200315338038062003153833981016040819052620000349162000067565b600080546001600160a01b0319166001600160a01b039590951694909417909355600191909155600255600355620000b2565b600080600080608085870312156200007d578384fd5b84516001600160a01b038116811462000094578485fd5b60208601516040870151606090970151919890975090945092505050565b61309180620000c26000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c8063876ed5cb116100b8578063cfdf677e1161007c578063cfdf677e1461023f578063d0f8934414610247578063e10d29ee1461024f578063e561dddc14610257578063f722b41a1461025f578063facdc5da1461026757610142565b8063876ed5cb146102175780638d38c6c11461021f578063b8f7700514610227578063c139eb151461022f578063c2cf696f1461023757610142565b80634de569ce1161010a5780634de569ce146101c25780635ae6256d146101e25780636fee07e0146101ea57806378f4b2f2146101ff5780637a167a8a146102075780637aa63a861461020f57610142565b8063138387a414610147578063299ca478146101655780632a7f18be1461017a578063378997701461019a578063461a4478146101af575b600080fd5b61014f61027a565b60405161015c91906124c7565b60405180910390f35b61016d610280565b60405161015c91906123eb565b61018d610188366004612388565b61028f565b60405161015c9190612e4e565b6101a26102b0565b60405161015c9190612e8d565b61016d6101bd36600461221b565b6102c4565b6101d56101d0366004612261565b6103a0565b60405161015c9190612484565b6101a26103da565b6101fd6101f8366004612188565b6103ee565b005b61014f61066d565b6101a2610674565b61014f610689565b61014f6106a4565b61014f6106aa565b6101a26106b0565b61014f6106c7565b61014f6106cd565b61016d6106d2565b6101fd6106f5565b61016d610b69565b61014f610b8c565b6101a2610c06565b6101fd610275366004612388565b610c1e565b60025481565b6000546001600160a01b031681565b610297611ed9565b6102a8826102a3610b69565b610c36565b90505b919050565b6000806102bb610d76565b50935050505090565b6000805460405163bf40fac160e01b81526020600482018181528551602484015285516001600160a01b039094169363bf40fac19387938392604490920191908501908083838b5b8381101561032457818101518382015260200161030c565b50505050905090810190601f1680156103515780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561036e57600080fd5b505afa158015610382573d6000803e3d6000fd5b505050506040513d602081101561039857600080fd5b505192915050565b82516000901515600114156103c2576103bb85858585610e24565b90506103d2565b6103bb8585602001518585610fef565b949350505050565b6000806103e5610d76565b94505050505090565b61c3508151111561041a5760405162461bcd60e51b81526004016104119061259b565b60405180910390fd5b60035482111561043c5760405162461bcd60e51b8152600401610411906127a1565b620186a082101561045f5760405162461bcd60e51b815260040161041190612983565b6020820460005a90508181116104875760405162461bcd60e51b815260040161041190612b8a565b60005b825a8303101561049c5760010161048a565b6000338787876040516020016104b594939291906123ff565b60408051601f19818403018152919052805160209091012090504360281b421760006104df610b69565b60405163b298e36b60e01b81529091506001600160a01b0382169063b298e36b9061050e9086906004016124c7565b600060405180830381600087803b15801561052857600080fd5b505af115801561053c573d6000803e3d6000fd5b505060405163b298e36b60e01b81526001600160a01b038416925063b298e36b915061056c9085906004016124c7565b600060405180830381600087803b15801561058657600080fd5b505af115801561059a573d6000803e3d6000fd5b50505050600060016002836001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b1580156105dd57600080fd5b505afa1580156105f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106159190612203565b8161061c57fe5b040390507f4b388aecf9fa6cc92253704e5975a6129a4f735bdbd99567df4ed0094ee4ceb5338b8b8b85426040516106599695949392919061243c565b60405180910390a150505050505050505050565b620186a081565b60008061067f610d76565b5090935050505090565b600080610694610d76565b50505064ffffffffff1692915050565b61c35081565b60035481565b60006106c26106bd610b69565b6110c4565b905090565b60015481565b602081565b60006106c2604051806060016040528060258152602001612f08602591396102c4565b60043560d81c60093560e890811c90600c35901c610711610689565b8364ffffffffff16146107365760405162461bcd60e51b815260040161041190612a35565b6107646040518060400160405280600d81526020016c27ab26afa9b2b8bab2b731b2b960991b8152506102c4565b6001600160a01b0316336001600160a01b0316146107945760405162461bcd60e51b815260040161041190612a92565b60008162ffffff16116107b95760405162461bcd60e51b8152600401610411906127fe565b60008262ffffff16116107de5760405162461bcd60e51b815260040161041190612cdf565b600f601062ffffff8316020164ffffffffff81163610156108115760405162461bcd60e51b815260040161041190612d66565b600061081b610b69565b90506000610828826110c4565b9050600062ffffff8616368161083a57fe5b0460020267ffffffffffffffff8111801561085457600080fd5b506040519080825280601f01601f19166020018201604052801561087f576020820181803683370190505b50905060008662ffffff1667ffffffffffffffff811180156108a057600080fd5b506040519080825280602002602001820160405280156108ca578160200160208202803683370190505b50905060008060006108da610674565b90506108e4611ef9565b60005b8a62ffffff168163ffffffff161015610a3b57600061090b8263ffffffff16611147565b905063ffffffff82166109215761092181611197565b61092d8382868d611264565b80925060005b835163ffffffff821610156109b1578b3560e81c61c3508111156109695760405162461bcd60e51b81526004016104119061259b565b61097c858e64ffffffffff16838d6112cf565b898963ffffffff168151811061098e57fe5b60209081029190910101529b909b016003019a6001968701969586019501610933565b5060005b83602001518163ffffffff161015610a31578964ffffffffff168564ffffffffff16106109f45760405162461bcd60e51b815260040161041190612da8565b610a048564ffffffffff16611363565b888863ffffffff1681518110610a1657fe5b602090810291909101015260019687019694850194016109b5565b50506001016108e7565b50610a488183898b6113a8565b3664ffffffffff8a1614610a6e5760405162461bcd60e51b815260040161041190612846565b8a62ffffff168463ffffffff1614610a985760405162461bcd60e51b815260040161041190612894565b6000838c62ffffff160363ffffffff169050600080836020015160001415610acb57505060408201516060830151610af3565b6000610ae16001870364ffffffffff168d610c36565b90508060200151925080604001519150505b610b14610aff8961141b565b8f62ffffff168564ffffffffff16858561184f565b7f602f1aeac0ca2e7a13e281a9ef0ad7838542712ce16780fa2ecffd351f05f89983860384610b41610689565b604051610b5093929190612e9f565b60405180910390a1505050505050505050505050505050565b60006106c2604051806060016040528060238152602001613005602391396102c4565b6000610b966106d2565b6001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c29190612203565b6000610c10610674565b610c186106b0565b03905090565b60405162461bcd60e51b81526004016104119061250b565b610c3e611ed9565b604051634a83e9cd60e11b815260028402906000906001600160a01b03851690639507d39a90610c72908590600401612e8d565b60206040518083038186803b158015610c8a57600080fd5b505afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190612203565b90506000846001600160a01b0316639507d39a846001016040518263ffffffff1660e01b8152600401610cf59190612e8d565b60206040518083038186803b158015610d0d57600080fd5b505afa158015610d21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d459190612203565b6040805160608101825293845264ffffffffff828116602086015260289290921c9091169083015250949350505050565b6000806000806000610d866106d2565b6001600160a01b031663ccf8f9696040518163ffffffff1660e01b815260040160206040518083038186803b158015610dbe57600080fd5b505afa158015610dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df691906121dd565b64ffffffffff602882901c811697605083901c82169750607883901c8216965060a09290921c169350915050565b600080610e5c6040518060400160405280601481526020017327ab26afa2bc32b1baba34b7b726b0b730b3b2b960611b8152506102c4565b90506000816001600160a01b0316631c4712a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e9957600080fd5b505afa158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed19190612203565b90506000610ede87611a02565b9050610eeb818787611a9b565b610f075760405162461bcd60e51b8152600401610411906126ca565b86606001518860200151148015610f22575060408701518851145b8015610f635750610f4a604051806060016040528060228152602001612ee6602291396102c4565b6001600160a01b031688608001516001600160a01b0316145b8015610f725750818860a00151145b8015610f89575060608801516001600160a01b0316155b8015610fa45750600088604001516001811115610fa257fe5b145b8015610fc557508660800151805190602001208860c0015180519060200120145b610fe15760405162461bcd60e51b81526004016104119061276a565b506001979650505050505050565b600080610ffb85611363565b9050611008818585611a9b565b6110245760405162461bcd60e51b815260040161041190612c2a565b6000866060015187608001518860a001518960c0015160405160200161104d94939291906123ff565b60405160208183030381529060405280519060200120905060006110708761028f565b80519091508214801561108e57508751602082015164ffffffffff16145b80156110a857508760200151816040015164ffffffffff16145b610fe15760405162461bcd60e51b815260040161041190612adf565b60006002826001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b15801561110157600080fd5b505afa158015611115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111399190612203565b8161114057fe5b0492915050565b61114f611ef9565b5060408051608081018252601092909202600f81013560e890811c84526012820135901c6020840152601581013560d890811c92840192909252601a0135901c606082015290565b60006111a1610689565b1115611211576000806111b2610d76565b9350935050508064ffffffffff16836060015110156111e35760405162461bcd60e51b815260040161041190612718565b8164ffffffffff168360400151101561120e5760405162461bcd60e51b8152600401610411906125f8565b50505b4260015482604001510110156112395760405162461bcd60e51b815260040161041190612d20565b4360025482606001510110156112615760405162461bcd60e51b815260040161041190612552565b50565b83604001518360400151101561128c5760405162461bcd60e51b815260040161041190612bd5565b8360600151836060015110156112b45760405162461bcd60e51b815260040161041190612df1565b6020830151156112c9576112c9838383611b8c565b50505050565b60008151836041011115611326578260410167ffffffffffffffff811180156112f757600080fd5b506040519080825280601f01601f191660200182016040528015611322576020820181803683370190505b5091505b6040850151606086015160006020850160018153836001820152826021820152866003890160418301376041870190209350505050949350505050565b60006102a86040518060a00160405280600015158152602001848152602001600081526020016000815260200160405180602001604052806000815250815250611c2d565b600083830364ffffffffff161180156113c357506020840151155b156113d3576113d3848483611b8c565b42846040015111156113f75760405162461bcd60e51b815260040161041190612b45565b43846060015111156112c95760405162461bcd60e51b815260040161041190612904565b60008082511161145c5760405162461bcd60e51b81526004018080602001828103825260348152602001806130286034913960400191505060405180910390fd5b815160011415611482578160008151811061147357fe5b602002602001015190506102ab565b60408051610200810182527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381527f633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d60208201527f890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d818301527f3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd86060808301919091527fecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da60808301527fdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da560a08301527f617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d760c08301527f292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead60e08301527fe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e106101008301527f7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f826101208301527fe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e836365166101408301527f3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c6101608301527fad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e6101808301527fa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab6101a08301527f4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c8626101c08301527f2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf106101e083015282518381529081018352909160009190602082018180368337505085519192506000918291508180805b600184111561182b5750506002820460018084161460005b828110156117a7578a816002028151811061174e57fe5b602002602001015196508a816002026001018151811061176a57fe5b6020026020010151955086602089015285604089015287805190602001208b828151811061179457fe5b6020908102919091010152600101611737565b50801561180a578960018503815181106117bd57fe5b602002602001015195508783601081106117d357fe5b602002015160001b945085602088015284604088015286805190602001208a83815181106117fd57fe5b6020026020010181815250505b80611816576000611819565b60015b60ff168201935060019092019161171f565b8960008151811061183857fe5b602002602001015198505050505050505050919050565b60006118596106d2565b9050600080611866610d76565b50509150915060006040518060a00160405280856001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b1580156118b257600080fd5b505afa1580156118c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ea9190612203565b81526020018a81526020018981526020018464ffffffffff16815260200160405180602001604052806000815250815250905080600001517f127186556e7be68c7e31263195225b4de02820707889540969f62c05cf73525e826020015183604001518460600151856080015160405161196794939291906124e6565b60405180910390a2600061197a82611c75565b90506000611992836040015186018a86018a8a611c9e565b60405163080549db60e21b81529091506001600160a01b03871690632015276c906119c390859085906004016124d0565b600060405180830381600087803b1580156119dd57600080fd5b505af11580156119f1573d6000803e3d6000fd5b505050505050505050505050505050565b6080810151805160009190826041820167ffffffffffffffff81118015611a2857600080fd5b506040519080825280601f01601f191660200182016040528015611a53576020820181803683370190505b5060408601516060870151919250906000602084016001815383600182015282602182015285604182018760208a0160045afa50604190950190942095505050505050919050565b6000611aa56106d2565b8351604051634a83e9cd60e11b81526001600160a01b039290921691639507d39a91611ad391600401612e7c565b60206040518083038186803b158015611aeb57600080fd5b505afa158015611aff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b239190612203565b611b2c84611c75565b14611b495760405162461bcd60e51b815260040161041190612b16565b611b66836020015185846000015185602001518760400151611cbd565b611b825760405162461bcd60e51b81526004016104119061294c565b5060019392505050565b6000611b9f8364ffffffffff1683610c36565b9050600154816020015164ffffffffff16014210611bcf5760405162461bcd60e51b815260040161041190612647565b806020015164ffffffffff1684604001511115611bfe5760405162461bcd60e51b8152600401610411906129cc565b806040015164ffffffffff16846060015111156112c95760405162461bcd60e51b815260040161041190612c74565b8051602080830151604080850151606086015160808701519251600096611c5896909594910161248f565b604051602081830303815290604052805190602001209050919050565b60008160200151826040015183606001518460800151604051602001611c5894939291906124e6565b602892831b9390931760509190911b1760789290921b91909117901b90565b6000808211611cfd5760405162461bcd60e51b8152600401808060200182810382526037815260200180612f816037913960400191505060405180910390fd5b818410611d3b5760405162461bcd60e51b8152600401808060200182810382526024815260200180612f2d6024913960400191505060405180910390fd5b611d4482611e42565b835114611d825760405162461bcd60e51b815260040180806020018281038252604d815260200180612fb8604d913960600191505060405180910390fd5b8460005b8451811015611e35578560011660011415611de457848181518110611da757fe5b6020026020010151826040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209150611e29565b81858281518110611df157fe5b602002602001015160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b600195861c9501611d86565b5090951495945050505050565b6000808211611e825760405162461bcd60e51b8152600401808060200182810382526030815260200180612f516030913960400191505060405180910390fd5b8160011415611e93575060006102ab565b81600060805b60018110611ec3576000196001821b01811b831615611ebb5791821c91908101905b60011c611e99565b506001811b8414611ed2576001015b9392505050565b604080516060810182526000808252602082018190529181019190915290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b600067ffffffffffffffff831115611f3557fe5b611f48601f8401601f1916602001612ec1565b9050828152838383011115611f5c57600080fd5b828260208301376000602084830101529392505050565b80356001600160a01b03811681146102ab57600080fd5b600082601f830112611f9a578081fd5b611ed283833560208501611f21565b8035600281106102ab57600080fd5b600060a08284031215611fc9578081fd5b60405160a0810167ffffffffffffffff8282108183111715611fe757fe5b8160405282935084358352602085013560208401526040850135604084015260608501356060840152608085013591508082111561202457600080fd5b5061203185828601611f8a565b6080830152505092915050565b60006040828403121561204f578081fd5b6040516040810167ffffffffffffffff828210818311171561206d57fe5b816040528293508435835260209150818501358181111561208d57600080fd5b8501601f8101871361209e57600080fd5b8035828111156120aa57fe5b83810292506120ba848401612ec1565b8181528481019083860185850187018b10156120d557600080fd5b600095505b838610156120f85780358352600195909501949186019186016120da565b5080868801525050505050505092915050565b600060a0828403121561211c578081fd5b60405160a0810167ffffffffffffffff828210818311171561213a57fe5b8160405282935084359150811515821461215357600080fd5b818352602085013560208401526040850135604084015260608501356060840152608085013591508082111561202457600080fd5b60008060006060848603121561219c578283fd5b6121a584611f73565b925060208401359150604084013567ffffffffffffffff8111156121c7578182fd5b6121d386828701611f8a565b9150509250925092565b6000602082840312156121ee578081fd5b815164ffffffffff1981168114611ed2578182fd5b600060208284031215612214578081fd5b5051919050565b60006020828403121561222c578081fd5b813567ffffffffffffffff811115612242578182fd5b8201601f81018413612252578182fd5b6103d284823560208401611f21565b60008060008060808587031215612276578081fd5b843567ffffffffffffffff8082111561228d578283fd5b9086019060e082890312156122a0578283fd5b6122aa60e0612ec1565b82358152602083013560208201526122c460408401611fa9565b60408201526122d560608401611f73565b60608201526122e660808401611f73565b608082015260a083013560a082015260c083013582811115612306578485fd5b6123128a828601611f8a565b60c0830152509550602087013591508082111561232d578283fd5b6123398883890161210b565b9450604087013591508082111561234e578283fd5b61235a88838901611fb8565b9350606087013591508082111561236f578283fd5b5061237c8782880161203e565b91505092959194509250565b600060208284031215612399578081fd5b5035919050565b60008151808452815b818110156123c5576020818501810151868301820152016123a9565b818111156123d65782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612432908301846123a0565b9695505050505050565b6001600160a01b038781168252861660208201526040810185905260c06060820181905260009061246f908301866123a0565b60808301949094525060a00152949350505050565b901515815260200190565b6000861515825285602083015284604083015283606083015260a060808301526124bc60a08301846123a0565b979650505050505050565b90815260200190565b91825264ffffffffff1916602082015260400190565b60008582528460208301528360408301526080606083015261243260808301846123a0565b60208082526027908201527f617070656e64517565756542617463682069732063757272656e746c7920646960408201526639b0b13632b21760c91b606082015260800190565b60208082526029908201527f436f6e7465787420626c6f636b206e756d62657220746f6f2066617220696e206040820152683a3432903830b9ba1760b91b606082015260800190565b6020808252603d908201527f5472616e73616374696f6e20646174612073697a652065786365656473206d6160408201527f78696d756d20666f7220726f6c6c7570207472616e73616374696f6e2e000000606082015260800190565b6020808252602f908201527f436f6e746578742074696d657374616d70206973206c6f776572207468616e2060408201526e3630b9ba1039bab136b4ba3a32b21760891b606082015260800190565b6020808252605b908201527f50726576696f75736c7920656e7175657565642062617463686573206861766560408201527f206578706972656420616e64206d75737420626520617070656e64656420626560608201527f666f72652061206e65772073657175656e6365722062617463682e0000000000608082015260a00190565b6020808252602e908201527f496e76616c69642053657175656e636572207472616e73616374696f6e20696e60408201526d31b63ab9b4b7b710383937b7b31760911b606082015260800190565b60208082526032908201527f436f6e7465787420626c6f636b206e756d626572206973206c6f77657220746860408201527130b7103630b9ba1039bab136b4ba3a32b21760711b606082015260800190565b6020808252601e908201527f496e76616c69642053657175656e636572207472616e73616374696f6e2e0000604082015260600190565b6020808252603d908201527f5472616e73616374696f6e20676173206c696d69742065786365656473206d6160408201527f78696d756d20666f7220726f6c6c7570207472616e73616374696f6e2e000000606082015260800190565b60208082526028908201527f4d7573742070726f76696465206174206c65617374206f6e652062617463682060408201526731b7b73a32bc3a1760c11b606082015260800190565b6020808252602e908201527f4e6f7420616c6c2073657175656e636572207472616e73616374696f6e73207760408201526d32b93290383937b1b2b9b9b2b21760911b606082015260800190565b6020808252604a908201527f41637475616c207472616e73616374696f6e20696e64657820646f6573206e6f60408201527f74206d6174636820657870656374656420746f74616c20656c656d656e7473206060820152693a379030b83832b7321760b11b608082015260a00190565b60208082526028908201527f436f6e7465787420626c6f636b206e756d6265722069732066726f6d2074686560408201526710333aba3ab9329760c11b606082015260800190565b60208082526018908201527f496e76616c696420696e636c7573696f6e2070726f6f662e0000000000000000604082015260600190565b60208082526029908201527f5472616e73616374696f6e20676173206c696d697420746f6f206c6f7720746f6040820152681032b738bab2bab29760b91b606082015260800190565b60208082526043908201527f53657175656e636572207472616e73616374696f6e2074696d657374616d702060408201527f657863656564732074686174206f66206e65787420717565756520656c656d65606082015262373a1760e91b608082015260a00190565b6020808252603d908201527f41637475616c20626174636820737461727420696e64657820646f6573206e6f60408201527f74206d6174636820657870656374656420737461727420696e6465782e000000606082015260800190565b6020808252602d908201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279207460408201526c34329029b2b8bab2b731b2b91760991b606082015260800190565b6020808252601a908201527f496e76616c6964205175657565207472616e73616374696f6e2e000000000000604082015260600190565b60208082526015908201527424b73b30b634b2103130ba31b4103432b0b232b91760591b604082015260600190565b60208082526025908201527f436f6e746578742074696d657374616d702069732066726f6d207468652066756040820152643a3ab9329760d91b606082015260800190565b6020808252602b908201527f496e73756666696369656e742067617320666f72204c322072617465206c696d60408201526a34ba34b73390313ab9371760a91b606082015260800190565b60208082526035908201527f436f6e746578742074696d657374616d702076616c756573206d757374206d6f6040820152743737ba37b734b1b0b6363c9034b731b932b0b9b29760591b606082015260800190565b6020808252602a908201527f496e76616c6964205175657565207472616e73616374696f6e20696e636c757360408201526934b7b710383937b7b31760b11b606082015260800190565b60208082526045908201527f53657175656e636572207472616e73616374696f6e20626c6f636b4e756d626560408201527f7220657863656564732074686174206f66206e65787420717565756520656c6560608201526436b2b73a1760d91b608082015260a00190565b60208082526021908201527f4d75737420617070656e64206174206c65617374206f6e6520656c656d656e746040820152601760f91b606082015260800190565b60208082526026908201527f436f6e746578742074696d657374616d7020746f6f2066617220696e20746865604082015265103830b9ba1760d11b606082015260800190565b60208082526022908201527f4e6f7420656e6f756768204261746368436f6e74657874732070726f76696465604082015261321760f11b606082015260800190565b60208082526029908201527f4e6f7420656e6f75676820717565756564207472616e73616374696f6e732074604082015268379030b83832b7321760b91b606082015260800190565b60208082526037908201527f436f6e7465787420626c6f636b4e756d6265722076616c756573206d7573742060408201527f6d6f6e6f746f6e6963616c6c7920696e6372656173652e000000000000000000606082015260800190565b8151815260208083015164ffffffffff90811691830191909152604092830151169181019190915260600190565b63ffffffff91909116815260200190565b64ffffffffff91909116815260200190565b64ffffffffff9384168152919092166020820152604081019190915260600190565b60405181810167ffffffffffffffff81118282101715612edd57fe5b60405291905056fe4f564d5f4465636f6d7072657373696f6e507265636f6d70696c65416464726573734f564d5f436861696e53746f72616765436f6e7461696e65722d4354432d626174636865734c69625f4d65726b6c65547265653a20496e646578206f7574206f6620626f756e64732e4c69625f4d65726b6c65547265653a2043616e6e6f7420636f6d70757465206365696c286c6f675f3229206f6620302e4c69625f4d65726b6c65547265653a20546f74616c206c6561766573206d7573742062652067726561746572207468616e207a65726f2e4c69625f4d65726b6c65547265653a20546f74616c207369626c696e677320646f6573206e6f7420636f72726563746c7920636f72726573706f6e6420746f20746f74616c206c65617665732e4f564d5f436861696e53746f72616765436f6e7461696e65722d4354432d71756575654c69625f4d65726b6c65547265653a204d7573742070726f76696465206174206c65617374206f6e65206c65616620686173682ea2646970667358221220ccd26d70e29e57df01efbc12fcd4152555b136a977c6cd56cd6a3e465f2e8fef64736f6c63430007060033000000000000000000000000de1fcfb0851916ca5101820a69b13a4e276bd81f0000000000000000000000000000000000000000000000000000000000c0238000000000000000000000000000000000000000000000000000000000000ccf2a0000000000000000000000000000000000000000000000000000000000a7d8c0
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101425760003560e01c8063876ed5cb116100b8578063cfdf677e1161007c578063cfdf677e1461023f578063d0f8934414610247578063e10d29ee1461024f578063e561dddc14610257578063f722b41a1461025f578063facdc5da1461026757610142565b8063876ed5cb146102175780638d38c6c11461021f578063b8f7700514610227578063c139eb151461022f578063c2cf696f1461023757610142565b80634de569ce1161010a5780634de569ce146101c25780635ae6256d146101e25780636fee07e0146101ea57806378f4b2f2146101ff5780637a167a8a146102075780637aa63a861461020f57610142565b8063138387a414610147578063299ca478146101655780632a7f18be1461017a578063378997701461019a578063461a4478146101af575b600080fd5b61014f61027a565b60405161015c91906124c7565b60405180910390f35b61016d610280565b60405161015c91906123eb565b61018d610188366004612388565b61028f565b60405161015c9190612e4e565b6101a26102b0565b60405161015c9190612e8d565b61016d6101bd36600461221b565b6102c4565b6101d56101d0366004612261565b6103a0565b60405161015c9190612484565b6101a26103da565b6101fd6101f8366004612188565b6103ee565b005b61014f61066d565b6101a2610674565b61014f610689565b61014f6106a4565b61014f6106aa565b6101a26106b0565b61014f6106c7565b61014f6106cd565b61016d6106d2565b6101fd6106f5565b61016d610b69565b61014f610b8c565b6101a2610c06565b6101fd610275366004612388565b610c1e565b60025481565b6000546001600160a01b031681565b610297611ed9565b6102a8826102a3610b69565b610c36565b90505b919050565b6000806102bb610d76565b50935050505090565b6000805460405163bf40fac160e01b81526020600482018181528551602484015285516001600160a01b039094169363bf40fac19387938392604490920191908501908083838b5b8381101561032457818101518382015260200161030c565b50505050905090810190601f1680156103515780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561036e57600080fd5b505afa158015610382573d6000803e3d6000fd5b505050506040513d602081101561039857600080fd5b505192915050565b82516000901515600114156103c2576103bb85858585610e24565b90506103d2565b6103bb8585602001518585610fef565b949350505050565b6000806103e5610d76565b94505050505090565b61c3508151111561041a5760405162461bcd60e51b81526004016104119061259b565b60405180910390fd5b60035482111561043c5760405162461bcd60e51b8152600401610411906127a1565b620186a082101561045f5760405162461bcd60e51b815260040161041190612983565b6020820460005a90508181116104875760405162461bcd60e51b815260040161041190612b8a565b60005b825a8303101561049c5760010161048a565b6000338787876040516020016104b594939291906123ff565b60408051601f19818403018152919052805160209091012090504360281b421760006104df610b69565b60405163b298e36b60e01b81529091506001600160a01b0382169063b298e36b9061050e9086906004016124c7565b600060405180830381600087803b15801561052857600080fd5b505af115801561053c573d6000803e3d6000fd5b505060405163b298e36b60e01b81526001600160a01b038416925063b298e36b915061056c9085906004016124c7565b600060405180830381600087803b15801561058657600080fd5b505af115801561059a573d6000803e3d6000fd5b50505050600060016002836001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b1580156105dd57600080fd5b505afa1580156105f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106159190612203565b8161061c57fe5b040390507f4b388aecf9fa6cc92253704e5975a6129a4f735bdbd99567df4ed0094ee4ceb5338b8b8b85426040516106599695949392919061243c565b60405180910390a150505050505050505050565b620186a081565b60008061067f610d76565b5090935050505090565b600080610694610d76565b50505064ffffffffff1692915050565b61c35081565b60035481565b60006106c26106bd610b69565b6110c4565b905090565b60015481565b602081565b60006106c2604051806060016040528060258152602001612f08602591396102c4565b60043560d81c60093560e890811c90600c35901c610711610689565b8364ffffffffff16146107365760405162461bcd60e51b815260040161041190612a35565b6107646040518060400160405280600d81526020016c27ab26afa9b2b8bab2b731b2b960991b8152506102c4565b6001600160a01b0316336001600160a01b0316146107945760405162461bcd60e51b815260040161041190612a92565b60008162ffffff16116107b95760405162461bcd60e51b8152600401610411906127fe565b60008262ffffff16116107de5760405162461bcd60e51b815260040161041190612cdf565b600f601062ffffff8316020164ffffffffff81163610156108115760405162461bcd60e51b815260040161041190612d66565b600061081b610b69565b90506000610828826110c4565b9050600062ffffff8616368161083a57fe5b0460020267ffffffffffffffff8111801561085457600080fd5b506040519080825280601f01601f19166020018201604052801561087f576020820181803683370190505b50905060008662ffffff1667ffffffffffffffff811180156108a057600080fd5b506040519080825280602002602001820160405280156108ca578160200160208202803683370190505b50905060008060006108da610674565b90506108e4611ef9565b60005b8a62ffffff168163ffffffff161015610a3b57600061090b8263ffffffff16611147565b905063ffffffff82166109215761092181611197565b61092d8382868d611264565b80925060005b835163ffffffff821610156109b1578b3560e81c61c3508111156109695760405162461bcd60e51b81526004016104119061259b565b61097c858e64ffffffffff16838d6112cf565b898963ffffffff168151811061098e57fe5b60209081029190910101529b909b016003019a6001968701969586019501610933565b5060005b83602001518163ffffffff161015610a31578964ffffffffff168564ffffffffff16106109f45760405162461bcd60e51b815260040161041190612da8565b610a048564ffffffffff16611363565b888863ffffffff1681518110610a1657fe5b602090810291909101015260019687019694850194016109b5565b50506001016108e7565b50610a488183898b6113a8565b3664ffffffffff8a1614610a6e5760405162461bcd60e51b815260040161041190612846565b8a62ffffff168463ffffffff1614610a985760405162461bcd60e51b815260040161041190612894565b6000838c62ffffff160363ffffffff169050600080836020015160001415610acb57505060408201516060830151610af3565b6000610ae16001870364ffffffffff168d610c36565b90508060200151925080604001519150505b610b14610aff8961141b565b8f62ffffff168564ffffffffff16858561184f565b7f602f1aeac0ca2e7a13e281a9ef0ad7838542712ce16780fa2ecffd351f05f89983860384610b41610689565b604051610b5093929190612e9f565b60405180910390a1505050505050505050505050505050565b60006106c2604051806060016040528060238152602001613005602391396102c4565b6000610b966106d2565b6001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c29190612203565b6000610c10610674565b610c186106b0565b03905090565b60405162461bcd60e51b81526004016104119061250b565b610c3e611ed9565b604051634a83e9cd60e11b815260028402906000906001600160a01b03851690639507d39a90610c72908590600401612e8d565b60206040518083038186803b158015610c8a57600080fd5b505afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190612203565b90506000846001600160a01b0316639507d39a846001016040518263ffffffff1660e01b8152600401610cf59190612e8d565b60206040518083038186803b158015610d0d57600080fd5b505afa158015610d21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d459190612203565b6040805160608101825293845264ffffffffff828116602086015260289290921c9091169083015250949350505050565b6000806000806000610d866106d2565b6001600160a01b031663ccf8f9696040518163ffffffff1660e01b815260040160206040518083038186803b158015610dbe57600080fd5b505afa158015610dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df691906121dd565b64ffffffffff602882901c811697605083901c82169750607883901c8216965060a09290921c169350915050565b600080610e5c6040518060400160405280601481526020017327ab26afa2bc32b1baba34b7b726b0b730b3b2b960611b8152506102c4565b90506000816001600160a01b0316631c4712a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e9957600080fd5b505afa158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed19190612203565b90506000610ede87611a02565b9050610eeb818787611a9b565b610f075760405162461bcd60e51b8152600401610411906126ca565b86606001518860200151148015610f22575060408701518851145b8015610f635750610f4a604051806060016040528060228152602001612ee6602291396102c4565b6001600160a01b031688608001516001600160a01b0316145b8015610f725750818860a00151145b8015610f89575060608801516001600160a01b0316155b8015610fa45750600088604001516001811115610fa257fe5b145b8015610fc557508660800151805190602001208860c0015180519060200120145b610fe15760405162461bcd60e51b81526004016104119061276a565b506001979650505050505050565b600080610ffb85611363565b9050611008818585611a9b565b6110245760405162461bcd60e51b815260040161041190612c2a565b6000866060015187608001518860a001518960c0015160405160200161104d94939291906123ff565b60405160208183030381529060405280519060200120905060006110708761028f565b80519091508214801561108e57508751602082015164ffffffffff16145b80156110a857508760200151816040015164ffffffffff16145b610fe15760405162461bcd60e51b815260040161041190612adf565b60006002826001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b15801561110157600080fd5b505afa158015611115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111399190612203565b8161114057fe5b0492915050565b61114f611ef9565b5060408051608081018252601092909202600f81013560e890811c84526012820135901c6020840152601581013560d890811c92840192909252601a0135901c606082015290565b60006111a1610689565b1115611211576000806111b2610d76565b9350935050508064ffffffffff16836060015110156111e35760405162461bcd60e51b815260040161041190612718565b8164ffffffffff168360400151101561120e5760405162461bcd60e51b8152600401610411906125f8565b50505b4260015482604001510110156112395760405162461bcd60e51b815260040161041190612d20565b4360025482606001510110156112615760405162461bcd60e51b815260040161041190612552565b50565b83604001518360400151101561128c5760405162461bcd60e51b815260040161041190612bd5565b8360600151836060015110156112b45760405162461bcd60e51b815260040161041190612df1565b6020830151156112c9576112c9838383611b8c565b50505050565b60008151836041011115611326578260410167ffffffffffffffff811180156112f757600080fd5b506040519080825280601f01601f191660200182016040528015611322576020820181803683370190505b5091505b6040850151606086015160006020850160018153836001820152826021820152866003890160418301376041870190209350505050949350505050565b60006102a86040518060a00160405280600015158152602001848152602001600081526020016000815260200160405180602001604052806000815250815250611c2d565b600083830364ffffffffff161180156113c357506020840151155b156113d3576113d3848483611b8c565b42846040015111156113f75760405162461bcd60e51b815260040161041190612b45565b43846060015111156112c95760405162461bcd60e51b815260040161041190612904565b60008082511161145c5760405162461bcd60e51b81526004018080602001828103825260348152602001806130286034913960400191505060405180910390fd5b815160011415611482578160008151811061147357fe5b602002602001015190506102ab565b60408051610200810182527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381527f633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d60208201527f890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d818301527f3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd86060808301919091527fecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da60808301527fdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da560a08301527f617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d760c08301527f292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead60e08301527fe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e106101008301527f7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f826101208301527fe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e836365166101408301527f3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c6101608301527fad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e6101808301527fa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab6101a08301527f4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c8626101c08301527f2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf106101e083015282518381529081018352909160009190602082018180368337505085519192506000918291508180805b600184111561182b5750506002820460018084161460005b828110156117a7578a816002028151811061174e57fe5b602002602001015196508a816002026001018151811061176a57fe5b6020026020010151955086602089015285604089015287805190602001208b828151811061179457fe5b6020908102919091010152600101611737565b50801561180a578960018503815181106117bd57fe5b602002602001015195508783601081106117d357fe5b602002015160001b945085602088015284604088015286805190602001208a83815181106117fd57fe5b6020026020010181815250505b80611816576000611819565b60015b60ff168201935060019092019161171f565b8960008151811061183857fe5b602002602001015198505050505050505050919050565b60006118596106d2565b9050600080611866610d76565b50509150915060006040518060a00160405280856001600160a01b0316631f7b6d326040518163ffffffff1660e01b815260040160206040518083038186803b1580156118b257600080fd5b505afa1580156118c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ea9190612203565b81526020018a81526020018981526020018464ffffffffff16815260200160405180602001604052806000815250815250905080600001517f127186556e7be68c7e31263195225b4de02820707889540969f62c05cf73525e826020015183604001518460600151856080015160405161196794939291906124e6565b60405180910390a2600061197a82611c75565b90506000611992836040015186018a86018a8a611c9e565b60405163080549db60e21b81529091506001600160a01b03871690632015276c906119c390859085906004016124d0565b600060405180830381600087803b1580156119dd57600080fd5b505af11580156119f1573d6000803e3d6000fd5b505050505050505050505050505050565b6080810151805160009190826041820167ffffffffffffffff81118015611a2857600080fd5b506040519080825280601f01601f191660200182016040528015611a53576020820181803683370190505b5060408601516060870151919250906000602084016001815383600182015282602182015285604182018760208a0160045afa50604190950190942095505050505050919050565b6000611aa56106d2565b8351604051634a83e9cd60e11b81526001600160a01b039290921691639507d39a91611ad391600401612e7c565b60206040518083038186803b158015611aeb57600080fd5b505afa158015611aff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b239190612203565b611b2c84611c75565b14611b495760405162461bcd60e51b815260040161041190612b16565b611b66836020015185846000015185602001518760400151611cbd565b611b825760405162461bcd60e51b81526004016104119061294c565b5060019392505050565b6000611b9f8364ffffffffff1683610c36565b9050600154816020015164ffffffffff16014210611bcf5760405162461bcd60e51b815260040161041190612647565b806020015164ffffffffff1684604001511115611bfe5760405162461bcd60e51b8152600401610411906129cc565b806040015164ffffffffff16846060015111156112c95760405162461bcd60e51b815260040161041190612c74565b8051602080830151604080850151606086015160808701519251600096611c5896909594910161248f565b604051602081830303815290604052805190602001209050919050565b60008160200151826040015183606001518460800151604051602001611c5894939291906124e6565b602892831b9390931760509190911b1760789290921b91909117901b90565b6000808211611cfd5760405162461bcd60e51b8152600401808060200182810382526037815260200180612f816037913960400191505060405180910390fd5b818410611d3b5760405162461bcd60e51b8152600401808060200182810382526024815260200180612f2d6024913960400191505060405180910390fd5b611d4482611e42565b835114611d825760405162461bcd60e51b815260040180806020018281038252604d815260200180612fb8604d913960600191505060405180910390fd5b8460005b8451811015611e35578560011660011415611de457848181518110611da757fe5b6020026020010151826040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209150611e29565b81858281518110611df157fe5b602002602001015160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b600195861c9501611d86565b5090951495945050505050565b6000808211611e825760405162461bcd60e51b8152600401808060200182810382526030815260200180612f516030913960400191505060405180910390fd5b8160011415611e93575060006102ab565b81600060805b60018110611ec3576000196001821b01811b831615611ebb5791821c91908101905b60011c611e99565b506001811b8414611ed2576001015b9392505050565b604080516060810182526000808252602082018190529181019190915290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b600067ffffffffffffffff831115611f3557fe5b611f48601f8401601f1916602001612ec1565b9050828152838383011115611f5c57600080fd5b828260208301376000602084830101529392505050565b80356001600160a01b03811681146102ab57600080fd5b600082601f830112611f9a578081fd5b611ed283833560208501611f21565b8035600281106102ab57600080fd5b600060a08284031215611fc9578081fd5b60405160a0810167ffffffffffffffff8282108183111715611fe757fe5b8160405282935084358352602085013560208401526040850135604084015260608501356060840152608085013591508082111561202457600080fd5b5061203185828601611f8a565b6080830152505092915050565b60006040828403121561204f578081fd5b6040516040810167ffffffffffffffff828210818311171561206d57fe5b816040528293508435835260209150818501358181111561208d57600080fd5b8501601f8101871361209e57600080fd5b8035828111156120aa57fe5b83810292506120ba848401612ec1565b8181528481019083860185850187018b10156120d557600080fd5b600095505b838610156120f85780358352600195909501949186019186016120da565b5080868801525050505050505092915050565b600060a0828403121561211c578081fd5b60405160a0810167ffffffffffffffff828210818311171561213a57fe5b8160405282935084359150811515821461215357600080fd5b818352602085013560208401526040850135604084015260608501356060840152608085013591508082111561202457600080fd5b60008060006060848603121561219c578283fd5b6121a584611f73565b925060208401359150604084013567ffffffffffffffff8111156121c7578182fd5b6121d386828701611f8a565b9150509250925092565b6000602082840312156121ee578081fd5b815164ffffffffff1981168114611ed2578182fd5b600060208284031215612214578081fd5b5051919050565b60006020828403121561222c578081fd5b813567ffffffffffffffff811115612242578182fd5b8201601f81018413612252578182fd5b6103d284823560208401611f21565b60008060008060808587031215612276578081fd5b843567ffffffffffffffff8082111561228d578283fd5b9086019060e082890312156122a0578283fd5b6122aa60e0612ec1565b82358152602083013560208201526122c460408401611fa9565b60408201526122d560608401611f73565b60608201526122e660808401611f73565b608082015260a083013560a082015260c083013582811115612306578485fd5b6123128a828601611f8a565b60c0830152509550602087013591508082111561232d578283fd5b6123398883890161210b565b9450604087013591508082111561234e578283fd5b61235a88838901611fb8565b9350606087013591508082111561236f578283fd5b5061237c8782880161203e565b91505092959194509250565b600060208284031215612399578081fd5b5035919050565b60008151808452815b818110156123c5576020818501810151868301820152016123a9565b818111156123d65782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612432908301846123a0565b9695505050505050565b6001600160a01b038781168252861660208201526040810185905260c06060820181905260009061246f908301866123a0565b60808301949094525060a00152949350505050565b901515815260200190565b6000861515825285602083015284604083015283606083015260a060808301526124bc60a08301846123a0565b979650505050505050565b90815260200190565b91825264ffffffffff1916602082015260400190565b60008582528460208301528360408301526080606083015261243260808301846123a0565b60208082526027908201527f617070656e64517565756542617463682069732063757272656e746c7920646960408201526639b0b13632b21760c91b606082015260800190565b60208082526029908201527f436f6e7465787420626c6f636b206e756d62657220746f6f2066617220696e206040820152683a3432903830b9ba1760b91b606082015260800190565b6020808252603d908201527f5472616e73616374696f6e20646174612073697a652065786365656473206d6160408201527f78696d756d20666f7220726f6c6c7570207472616e73616374696f6e2e000000606082015260800190565b6020808252602f908201527f436f6e746578742074696d657374616d70206973206c6f776572207468616e2060408201526e3630b9ba1039bab136b4ba3a32b21760891b606082015260800190565b6020808252605b908201527f50726576696f75736c7920656e7175657565642062617463686573206861766560408201527f206578706972656420616e64206d75737420626520617070656e64656420626560608201527f666f72652061206e65772073657175656e6365722062617463682e0000000000608082015260a00190565b6020808252602e908201527f496e76616c69642053657175656e636572207472616e73616374696f6e20696e60408201526d31b63ab9b4b7b710383937b7b31760911b606082015260800190565b60208082526032908201527f436f6e7465787420626c6f636b206e756d626572206973206c6f77657220746860408201527130b7103630b9ba1039bab136b4ba3a32b21760711b606082015260800190565b6020808252601e908201527f496e76616c69642053657175656e636572207472616e73616374696f6e2e0000604082015260600190565b6020808252603d908201527f5472616e73616374696f6e20676173206c696d69742065786365656473206d6160408201527f78696d756d20666f7220726f6c6c7570207472616e73616374696f6e2e000000606082015260800190565b60208082526028908201527f4d7573742070726f76696465206174206c65617374206f6e652062617463682060408201526731b7b73a32bc3a1760c11b606082015260800190565b6020808252602e908201527f4e6f7420616c6c2073657175656e636572207472616e73616374696f6e73207760408201526d32b93290383937b1b2b9b9b2b21760911b606082015260800190565b6020808252604a908201527f41637475616c207472616e73616374696f6e20696e64657820646f6573206e6f60408201527f74206d6174636820657870656374656420746f74616c20656c656d656e7473206060820152693a379030b83832b7321760b11b608082015260a00190565b60208082526028908201527f436f6e7465787420626c6f636b206e756d6265722069732066726f6d2074686560408201526710333aba3ab9329760c11b606082015260800190565b60208082526018908201527f496e76616c696420696e636c7573696f6e2070726f6f662e0000000000000000604082015260600190565b60208082526029908201527f5472616e73616374696f6e20676173206c696d697420746f6f206c6f7720746f6040820152681032b738bab2bab29760b91b606082015260800190565b60208082526043908201527f53657175656e636572207472616e73616374696f6e2074696d657374616d702060408201527f657863656564732074686174206f66206e65787420717565756520656c656d65606082015262373a1760e91b608082015260a00190565b6020808252603d908201527f41637475616c20626174636820737461727420696e64657820646f6573206e6f60408201527f74206d6174636820657870656374656420737461727420696e6465782e000000606082015260800190565b6020808252602d908201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279207460408201526c34329029b2b8bab2b731b2b91760991b606082015260800190565b6020808252601a908201527f496e76616c6964205175657565207472616e73616374696f6e2e000000000000604082015260600190565b60208082526015908201527424b73b30b634b2103130ba31b4103432b0b232b91760591b604082015260600190565b60208082526025908201527f436f6e746578742074696d657374616d702069732066726f6d207468652066756040820152643a3ab9329760d91b606082015260800190565b6020808252602b908201527f496e73756666696369656e742067617320666f72204c322072617465206c696d60408201526a34ba34b73390313ab9371760a91b606082015260800190565b60208082526035908201527f436f6e746578742074696d657374616d702076616c756573206d757374206d6f6040820152743737ba37b734b1b0b6363c9034b731b932b0b9b29760591b606082015260800190565b6020808252602a908201527f496e76616c6964205175657565207472616e73616374696f6e20696e636c757360408201526934b7b710383937b7b31760b11b606082015260800190565b60208082526045908201527f53657175656e636572207472616e73616374696f6e20626c6f636b4e756d626560408201527f7220657863656564732074686174206f66206e65787420717565756520656c6560608201526436b2b73a1760d91b608082015260a00190565b60208082526021908201527f4d75737420617070656e64206174206c65617374206f6e6520656c656d656e746040820152601760f91b606082015260800190565b60208082526026908201527f436f6e746578742074696d657374616d7020746f6f2066617220696e20746865604082015265103830b9ba1760d11b606082015260800190565b60208082526022908201527f4e6f7420656e6f756768204261746368436f6e74657874732070726f76696465604082015261321760f11b606082015260800190565b60208082526029908201527f4e6f7420656e6f75676820717565756564207472616e73616374696f6e732074604082015268379030b83832b7321760b91b606082015260800190565b60208082526037908201527f436f6e7465787420626c6f636b4e756d6265722076616c756573206d7573742060408201527f6d6f6e6f746f6e6963616c6c7920696e6372656173652e000000000000000000606082015260800190565b8151815260208083015164ffffffffff90811691830191909152604092830151169181019190915260600190565b63ffffffff91909116815260200190565b64ffffffffff91909116815260200190565b64ffffffffff9384168152919092166020820152604081019190915260600190565b60405181810167ffffffffffffffff81118282101715612edd57fe5b60405291905056fe4f564d5f4465636f6d7072657373696f6e507265636f6d70696c65416464726573734f564d5f436861696e53746f72616765436f6e7461696e65722d4354432d626174636865734c69625f4d65726b6c65547265653a20496e646578206f7574206f6620626f756e64732e4c69625f4d65726b6c65547265653a2043616e6e6f7420636f6d70757465206365696c286c6f675f3229206f6620302e4c69625f4d65726b6c65547265653a20546f74616c206c6561766573206d7573742062652067726561746572207468616e207a65726f2e4c69625f4d65726b6c65547265653a20546f74616c207369626c696e677320646f6573206e6f7420636f72726563746c7920636f72726573706f6e6420746f20746f74616c206c65617665732e4f564d5f436861696e53746f72616765436f6e7461696e65722d4354432d71756575654c69625f4d65726b6c65547265653a204d7573742070726f76696465206174206c65617374206f6e65206c65616620686173682ea2646970667358221220ccd26d70e29e57df01efbc12fcd4152555b136a977c6cd56cd6a3e465f2e8fef64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000de1fcfb0851916ca5101820a69b13a4e276bd81f0000000000000000000000000000000000000000000000000000000000c0238000000000000000000000000000000000000000000000000000000000000ccf2a0000000000000000000000000000000000000000000000000000000000a7d8c0
-----Decoded View---------------
Arg [0] : _libAddressManager (address): 0xdE1FCfB0851916CA5101820A69b13a4E276bd81F
Arg [1] : _forceInclusionPeriodSeconds (uint256): 12592000
Arg [2] : _forceInclusionPeriodBlocks (uint256): 839466
Arg [3] : _maxTransactionGasLimit (uint256): 11000000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000de1fcfb0851916ca5101820a69b13a4e276bd81f
Arg [1] : 0000000000000000000000000000000000000000000000000000000000c02380
Arg [2] : 00000000000000000000000000000000000000000000000000000000000ccf2a
Arg [3] : 0000000000000000000000000000000000000000000000000000000000a7d8c0
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 25 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.