Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Bridge
Compiler Version
v0.6.11+commit.5ef660b1
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./Inbox.sol"; import "./Outbox.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "./interfaces/IBridge.sol"; contract Bridge is OwnableUpgradeable, IBridge { using Address for address; struct InOutInfo { uint256 index; bool allowed; } mapping(address => InOutInfo) private allowedInboxesMap; mapping(address => InOutInfo) private allowedOutboxesMap; address[] public allowedInboxList; address[] public allowedOutboxList; address public override activeOutbox; // Accumulator for delayed inbox; tail represents hash of the current state; each element represents the inclusion of a new message. bytes32[] public override inboxAccs; function initialize() external initializer { __Ownable_init(); } function allowedInboxes(address inbox) external view override returns (bool) { return allowedInboxesMap[inbox].allowed; } function allowedOutboxes(address outbox) external view override returns (bool) { return allowedOutboxesMap[outbox].allowed; } function deliverMessageToInbox( uint8 kind, address sender, bytes32 messageDataHash ) external payable override returns (uint256) { require(allowedInboxesMap[msg.sender].allowed, "NOT_FROM_INBOX"); uint256 count = inboxAccs.length; bytes32 messageHash = Messages.messageHash( kind, sender, block.number, block.timestamp, // solhint-disable-line not-rely-on-time count, tx.gasprice, messageDataHash ); bytes32 prevAcc = 0; if (count > 0) { prevAcc = inboxAccs[count - 1]; } inboxAccs.push(Messages.addMessageToInbox(prevAcc, messageHash)); emit MessageDelivered(count, prevAcc, msg.sender, kind, sender, messageDataHash); return count; } function executeCall( address destAddr, uint256 amount, bytes calldata data ) external override returns (bool success, bytes memory returnData) { require(allowedOutboxesMap[msg.sender].allowed, "NOT_FROM_OUTBOX"); if (data.length > 0) require(destAddr.isContract(), "NO_CODE_AT_DEST"); address currentOutbox = activeOutbox; activeOutbox = msg.sender; // We set and reset active outbox around external call so activeOutbox remains valid during call (success, returnData) = destAddr.call{ value: amount }(data); activeOutbox = currentOutbox; emit BridgeCallTriggered(msg.sender, destAddr, amount, data); } function setInbox(address inbox, bool enabled) external override onlyOwner { InOutInfo storage info = allowedInboxesMap[inbox]; bool alreadyEnabled = info.allowed; emit InboxToggle(inbox, enabled); if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { return; } if (enabled) { allowedInboxesMap[inbox] = InOutInfo(allowedInboxList.length, true); allowedInboxList.push(inbox); } else { allowedInboxList[info.index] = allowedInboxList[allowedInboxList.length - 1]; allowedInboxesMap[allowedInboxList[info.index]].index = info.index; allowedInboxList.pop(); delete allowedInboxesMap[inbox]; } } function setOutbox(address outbox, bool enabled) external override onlyOwner { InOutInfo storage info = allowedOutboxesMap[outbox]; bool alreadyEnabled = info.allowed; emit OutboxToggle(outbox, enabled); if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { return; } if (enabled) { allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true); allowedOutboxList.push(outbox); } else { allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1]; allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index; allowedOutboxList.pop(); delete allowedOutboxesMap[outbox]; } } function messageCount() external view override returns (uint256) { return inboxAccs.length; } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./interfaces/IInbox.sol"; import "./interfaces/IBridge.sol"; import "../rollup/Rollup.sol"; import "./Messages.sol"; import "../libraries/Cloneable.sol"; import "../libraries/Whitelist.sol"; import "../libraries/ProxyUtil.sol"; import "../libraries/AddressAliasHelper.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "./Bridge.sol"; contract Inbox is IInbox, WhitelistConsumer, Cloneable { uint8 internal constant ETH_TRANSFER = 0; uint8 internal constant L2_MSG = 3; uint8 internal constant L1MessageType_L2FundedByL1 = 7; uint8 internal constant L1MessageType_submitRetryableTx = 9; uint8 internal constant L2MessageType_unsignedEOATx = 0; uint8 internal constant L2MessageType_unsignedContractTx = 1; IBridge public override bridge; bool public isEthDepositPaused; bool public shouldRewriteSender; function initialize(IBridge _bridge, address _whitelist) external { require(address(bridge) == address(0), "ALREADY_INIT"); bridge = _bridge; WhitelistConsumer.whitelist = _whitelist; } /** * @notice Send a generic L2 message to the chain * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input * @param messageData Data of the message being sent */ function sendL2MessageFromOrigin(bytes calldata messageData) external onlyWhitelisted returns (uint256) { // solhint-disable-next-line avoid-tx-origin require(msg.sender == tx.origin, "origin only"); uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData)); emit InboxMessageDeliveredFromOrigin(msgNum); return msgNum; } /** * @notice Send a generic L2 message to the chain * @dev This method can be used to send any type of message that doesn't require L1 validation * @param messageData Data of the message being sent */ function sendL2Message(bytes calldata messageData) external override onlyWhitelisted returns (uint256) { uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData)); emit InboxMessageDelivered(msgNum, messageData); return msgNum; } function sendL1FundedUnsignedTransaction( uint256 maxGas, uint256 gasPriceBid, uint256 nonce, address destAddr, bytes calldata data ) external payable virtual override onlyWhitelisted returns (uint256) { return _deliverMessage( L1MessageType_L2FundedByL1, msg.sender, abi.encodePacked( L2MessageType_unsignedEOATx, maxGas, gasPriceBid, nonce, uint256(uint160(bytes20(destAddr))), msg.value, data ) ); } function sendL1FundedContractTransaction( uint256 maxGas, uint256 gasPriceBid, address destAddr, bytes calldata data ) external payable virtual override onlyWhitelisted returns (uint256) { return _deliverMessage( L1MessageType_L2FundedByL1, msg.sender, abi.encodePacked( L2MessageType_unsignedContractTx, maxGas, gasPriceBid, uint256(uint160(bytes20(destAddr))), msg.value, data ) ); } function sendUnsignedTransaction( uint256 maxGas, uint256 gasPriceBid, uint256 nonce, address destAddr, uint256 amount, bytes calldata data ) external virtual override onlyWhitelisted returns (uint256) { return _deliverMessage( L2_MSG, msg.sender, abi.encodePacked( L2MessageType_unsignedEOATx, maxGas, gasPriceBid, nonce, uint256(uint160(bytes20(destAddr))), amount, data ) ); } function sendContractTransaction( uint256 maxGas, uint256 gasPriceBid, address destAddr, uint256 amount, bytes calldata data ) external virtual override onlyWhitelisted returns (uint256) { return _deliverMessage( L2_MSG, msg.sender, abi.encodePacked( L2MessageType_unsignedContractTx, maxGas, gasPriceBid, uint256(uint160(bytes20(destAddr))), amount, data ) ); } modifier onlyOwner() { // the rollup contract owns the bridge address rollup = Bridge(address(bridge)).owner(); // we want to validate the owner of the rollup address owner = RollupBase(rollup).owner(); require(msg.sender == owner, "NOT_ROLLUP"); _; } event PauseToggled(bool enabled); /// @notice pauses eth deposits function pauseEthDeposits() external override onlyOwner { require(!isEthDepositPaused, "ALREADY_PAUSED"); isEthDepositPaused = true; emit PauseToggled(true); } /// @notice unpauses eth deposits function unpauseEthDeposits() external override onlyOwner { require(isEthDepositPaused, "NOT_PAUSED"); isEthDepositPaused = false; emit PauseToggled(false); } event RewriteToggled(bool enabled); /// @notice start rewriting addresses in eth deposits function startRewriteAddress() external override onlyOwner { require(!shouldRewriteSender, "ALREADY_REWRITING"); shouldRewriteSender = true; emit RewriteToggled(true); } /// @notice stop rewriting addresses in eth deposits function stopRewriteAddress() external override onlyOwner { require(shouldRewriteSender, "NOT_REWRITING"); shouldRewriteSender = false; emit RewriteToggled(false); } /// @notice deposit eth from L1 to L2 /// @dev this function should not be called inside contract constructors function depositEth(uint256 maxSubmissionCost) external payable virtual override onlyWhitelisted returns (uint256) { require(!isEthDepositPaused, "ETH_DEPOSIT_PAUSED"); address sender = msg.sender; if (shouldRewriteSender && !Address.isContract(sender) && tx.origin == msg.sender) { // isContract check fails if this function is called during a contract's constructor. // We don't adjust the address for calls coming from L1 contracts since their addresses get remapped // If the caller is an EOA, we adjust the address. // This is needed because unsigned messages to the L2 (such as retryables) // have the L1 sender address mapped. // Here we preemptively reverse the mapping for EOAs so deposits work as expected sender = AddressAliasHelper.undoL1ToL2Alias(sender); } return _deliverMessage( L1MessageType_submitRetryableTx, sender, abi.encodePacked( // the beneficiary and other refund addresses don't get rewritten by arb-os // so we use the original msg.sender value uint256(uint160(bytes20(msg.sender))), uint256(0), msg.value, maxSubmissionCost, uint256(uint160(bytes20(msg.sender))), uint256(uint160(bytes20(msg.sender))), uint256(0), uint256(0), uint256(0), "" ) ); } /** * @notice Put an message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts * @dev all msg.value will deposited to callValueRefundAddress on L2 * @param destAddr destination L2 contract address * @param l2CallValue call value for retryable L2 message * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee * @param excessFeeRefundAddress maxgas x gasprice - execution cost gets credited here on L2 balance * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled * @param maxGas Max gas deducted from user's L2 balance to cover L2 execution * @param gasPriceBid price bid for L2 execution * @param data ABI encoded data of L2 message * @return unique id for retryable transaction (keccak256(requestID, uint(0) ) */ function createRetryableTicket( address destAddr, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 maxGas, uint256 gasPriceBid, bytes calldata data ) external payable virtual override onlyWhitelisted returns (uint256) { return _deliverMessage( L1MessageType_submitRetryableTx, msg.sender, abi.encodePacked( uint256(uint160(bytes20(destAddr))), l2CallValue, msg.value, maxSubmissionCost, uint256(uint160(bytes20(excessFeeRefundAddress))), uint256(uint160(bytes20(callValueRefundAddress))), maxGas, gasPriceBid, data.length, data ) ); } function _deliverMessage( uint8 _kind, address _sender, bytes memory _messageData ) internal returns (uint256) { uint256 msgNum = deliverToBridge(_kind, _sender, keccak256(_messageData)); emit InboxMessageDelivered(msgNum, _messageData); return msgNum; } function deliverToBridge( uint8 kind, address sender, bytes32 messageDataHash ) internal returns (uint256) { return bridge.deliverMessageToInbox{ value: msg.value }(kind, sender, messageDataHash); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./interfaces/IOutbox.sol"; import "./interfaces/IBridge.sol"; import "./Messages.sol"; import "../libraries/MerkleLib.sol"; import "../libraries/BytesLib.sol"; import "../libraries/Cloneable.sol"; import "@openzeppelin/contracts/proxy/BeaconProxy.sol"; import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; contract Outbox is IOutbox, Cloneable { using BytesLib for bytes; struct OutboxEntry { // merkle root of outputs bytes32 root; // mapping from output id => is spent mapping(bytes32 => bool) spentOutput; } bytes1 internal constant MSG_ROOT = 0; uint8 internal constant SendType_sendTxToL1 = 3; address public rollup; IBridge public bridge; mapping(uint256 => OutboxEntry) public outboxEntries; struct L2ToL1Context { uint128 l2Block; uint128 l1Block; uint128 timestamp; uint128 batchNum; bytes32 outputId; address sender; } // Note, these variables are set and then wiped during a single transaction. // Therefore their values don't need to be maintained, and their slots will // be empty outside of transactions L2ToL1Context internal context; uint128 public constant OUTBOX_VERSION = 1; function initialize(address _rollup, IBridge _bridge) external { require(rollup == address(0), "ALREADY_INIT"); rollup = _rollup; bridge = _bridge; } /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account /// When the return value is zero, that means this is a system message /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies function l2ToL1Sender() external view override returns (address) { return context.sender; } function l2ToL1Block() external view override returns (uint256) { return uint256(context.l2Block); } function l2ToL1EthBlock() external view override returns (uint256) { return uint256(context.l1Block); } function l2ToL1Timestamp() external view override returns (uint256) { return uint256(context.timestamp); } function l2ToL1BatchNum() external view override returns (uint256) { return uint256(context.batchNum); } function l2ToL1OutputId() external view override returns (bytes32) { return context.outputId; } function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths) external override { require(msg.sender == rollup, "ONLY_ROLLUP"); // If we've reached here, we've already confirmed that sum(sendLengths) == sendsData.length uint256 messageCount = sendLengths.length; uint256 offset = 0; for (uint256 i = 0; i < messageCount; i++) { handleOutgoingMessage(bytes(sendsData[offset:offset + sendLengths[i]])); offset += sendLengths[i]; } } function handleOutgoingMessage(bytes memory data) private { // Otherwise we have an unsupported message type and we skip the message if (data[0] == MSG_ROOT) { require(data.length == 97, "BAD_LENGTH"); uint256 batchNum = data.toUint(1); // Ensure no outbox entry already exists w/ batch number require(!outboxEntryExists(batchNum), "ENTRY_ALREADY_EXISTS"); // This is the total number of msgs included in the root, it can be used to // detect when all msgs were executed against a root. // It currently isn't stored, but instead emitted in an event for utility uint256 numInBatch = data.toUint(33); bytes32 outputRoot = data.toBytes32(65); OutboxEntry memory newOutboxEntry = OutboxEntry(outputRoot); outboxEntries[batchNum] = newOutboxEntry; // keeping redundant batchnum in event (batchnum and old outboxindex field) for outbox version interface compatibility emit OutboxEntryCreated(batchNum, batchNum, outputRoot, numInBatch); } } /** * @notice Executes a messages in an Outbox entry. * @dev Reverts if dispute period hasn't expired, since the outbox entry * is only created once the rollup confirms the respective assertion. * @param batchNum Index of OutboxEntry in outboxEntries array * @param proof Merkle proof of message inclusion in outbox entry * @param index Merkle path to message * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1) * @param destAddr destination address for L1 contract call * @param l2Block l2 block number at which sendTxToL1 call was made * @param l1Block l1 block number at which sendTxToL1 call was made * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made * @param amount value in L1 message in wei * @param calldataForL1 abi-encoded L1 message data */ function executeTransaction( uint256 batchNum, bytes32[] calldata proof, uint256 index, address l2Sender, address destAddr, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 amount, bytes calldata calldataForL1 ) external override { bytes32 outputId; { bytes32 userTx = calculateItemHash( l2Sender, destAddr, l2Block, l1Block, l2Timestamp, amount, calldataForL1 ); outputId = recordOutputAsSpent(batchNum, proof, index, userTx); emit OutBoxTransactionExecuted(destAddr, l2Sender, batchNum, index); } // we temporarily store the previous values so the outbox can naturally // unwind itself when there are nested calls to `executeTransaction` L2ToL1Context memory prevContext = context; context = L2ToL1Context({ sender: l2Sender, l2Block: uint128(l2Block), l1Block: uint128(l1Block), timestamp: uint128(l2Timestamp), batchNum: uint128(batchNum), outputId: outputId }); // set and reset vars around execution so they remain valid during call executeBridgeCall(destAddr, amount, calldataForL1); context = prevContext; } function recordOutputAsSpent( uint256 batchNum, bytes32[] memory proof, uint256 path, bytes32 item ) internal returns (bytes32) { require(proof.length < 256, "PROOF_TOO_LONG"); require(path < 2**proof.length, "PATH_NOT_MINIMAL"); // Hash the leaf an extra time to prove it's a leaf bytes32 calcRoot = calculateMerkleRoot(proof, path, item); OutboxEntry storage outboxEntry = outboxEntries[batchNum]; require(outboxEntry.root != bytes32(0), "NO_OUTBOX_ENTRY"); // With a minimal path, the pair of path and proof length should always identify // a unique leaf. The path itself is not enough since the path length to different // leaves could potentially be different bytes32 uniqueKey = keccak256(abi.encodePacked(path, proof.length)); require(!outboxEntry.spentOutput[uniqueKey], "ALREADY_SPENT"); require(calcRoot == outboxEntry.root, "BAD_ROOT"); outboxEntry.spentOutput[uniqueKey] = true; return uniqueKey; } function executeBridgeCall( address destAddr, uint256 amount, bytes memory data ) internal { (bool success, bytes memory returndata) = bridge.executeCall(destAddr, amount, data); if (!success) { if (returndata.length > 0) { // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert("BRIDGE_CALL_FAILED"); } } } function calculateItemHash( address l2Sender, address destAddr, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 amount, bytes calldata calldataForL1 ) public pure returns (bytes32) { return keccak256( abi.encodePacked( SendType_sendTxToL1, uint256(uint160(bytes20(l2Sender))), uint256(uint160(bytes20(destAddr))), l2Block, l1Block, l2Timestamp, amount, calldataForL1 ) ); } function calculateMerkleRoot( bytes32[] memory proof, uint256 path, bytes32 item ) public pure returns (bytes32) { return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item))); } function outboxEntryExists(uint256 batchNum) public view override returns (bool) { return outboxEntries[batchNum].root != bytes32(0); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { 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; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface IBridge { event MessageDelivered( uint256 indexed messageIndex, bytes32 indexed beforeInboxAcc, address inbox, uint8 kind, address sender, bytes32 messageDataHash ); event BridgeCallTriggered( address indexed outbox, address indexed destAddr, uint256 amount, bytes data ); event InboxToggle(address indexed inbox, bool enabled); event OutboxToggle(address indexed outbox, bool enabled); function deliverMessageToInbox( uint8 kind, address sender, bytes32 messageDataHash ) external payable returns (uint256); function executeCall( address destAddr, uint256 amount, bytes calldata data ) external returns (bool success, bytes memory returnData); // These are only callable by the admin function setInbox(address inbox, bool enabled) external; function setOutbox(address inbox, bool enabled) external; // View functions function activeOutbox() external view returns (address); function allowedInboxes(address inbox) external view returns (bool); function allowedOutboxes(address outbox) external view returns (bool); function inboxAccs(uint256 index) external view returns (bytes32); function messageCount() external view returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./IBridge.sol"; import "./IMessageProvider.sol"; interface IInbox is IMessageProvider { function sendL2Message(bytes calldata messageData) external returns (uint256); function sendUnsignedTransaction( uint256 maxGas, uint256 gasPriceBid, uint256 nonce, address destAddr, uint256 amount, bytes calldata data ) external returns (uint256); function sendContractTransaction( uint256 maxGas, uint256 gasPriceBid, address destAddr, uint256 amount, bytes calldata data ) external returns (uint256); function sendL1FundedUnsignedTransaction( uint256 maxGas, uint256 gasPriceBid, uint256 nonce, address destAddr, bytes calldata data ) external payable returns (uint256); function sendL1FundedContractTransaction( uint256 maxGas, uint256 gasPriceBid, address destAddr, bytes calldata data ) external payable returns (uint256); function createRetryableTicket( address destAddr, uint256 arbTxCallValue, uint256 maxSubmissionCost, address submissionRefundAddress, address valueRefundAddress, uint256 maxGas, uint256 gasPriceBid, bytes calldata data ) external payable returns (uint256); function depositEth(uint256 maxSubmissionCost) external payable returns (uint256); function bridge() external view returns (IBridge); function pauseEthDeposits() external; function unpauseEthDeposits() external; function startRewriteAddress() external; function stopRewriteAddress() external; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/proxy/Proxy.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./RollupEventBridge.sol"; import "./RollupCore.sol"; import "./RollupLib.sol"; import "./INode.sol"; import "./INodeFactory.sol"; import "../challenge/IChallenge.sol"; import "../challenge/IChallengeFactory.sol"; import "../bridge/interfaces/IBridge.sol"; import "../bridge/interfaces/IOutbox.sol"; import "../bridge/Messages.sol"; import "../libraries/ProxyUtil.sol"; import "../libraries/Cloneable.sol"; import "./facets/IRollupFacets.sol"; abstract contract RollupBase is Cloneable, RollupCore, Pausable { // Rollup Config uint256 public confirmPeriodBlocks; uint256 public extraChallengeTimeBlocks; uint256 public avmGasSpeedLimitPerBlock; uint256 public baseStake; // Bridge is an IInbox and IOutbox IBridge public delayedBridge; ISequencerInbox public sequencerBridge; IOutbox public outbox; RollupEventBridge public rollupEventBridge; IChallengeFactory public challengeFactory; INodeFactory public nodeFactory; address public owner; address public stakeToken; uint256 public minimumAssertionPeriod; uint256 public STORAGE_GAP_1; uint256 public STORAGE_GAP_2; uint256 public challengeExecutionBisectionDegree; address[] internal facets; mapping(address => bool) isValidator; /// @notice DEPRECATED -- this method is deprecated but still mantained for backward compatibility /// @dev this actually returns the avmGasSpeedLimitPerBlock /// @return this actually returns the avmGasSpeedLimitPerBlock function arbGasSpeedLimitPerBlock() external view returns (uint256) { return avmGasSpeedLimitPerBlock; } } contract Rollup is Proxy, RollupBase { using Address for address; constructor(uint256 _confirmPeriodBlocks) public Cloneable() Pausable() { // constructor is used so logic contract can't be init'ed confirmPeriodBlocks = _confirmPeriodBlocks; require(isInit(), "CONSTRUCTOR_NOT_INIT"); } function isInit() internal view returns (bool) { return confirmPeriodBlocks != 0; } // _rollupParams = [ confirmPeriodBlocks, extraChallengeTimeBlocks, avmGasSpeedLimitPerBlock, baseStake ] // connectedContracts = [delayedBridge, sequencerInbox, outbox, rollupEventBridge, challengeFactory, nodeFactory] function initialize( bytes32 _machineHash, uint256[4] calldata _rollupParams, address _stakeToken, address _owner, bytes calldata _extraConfig, address[6] calldata connectedContracts, address[2] calldata _facets, uint256[2] calldata sequencerInboxParams ) public { require(!isInit(), "ALREADY_INIT"); // calls initialize method in user facet require(_facets[0].isContract(), "FACET_0_NOT_CONTRACT"); require(_facets[1].isContract(), "FACET_1_NOT_CONTRACT"); (bool success, ) = _facets[1].delegatecall( abi.encodeWithSelector(IRollupUser.initialize.selector, _stakeToken) ); require(success, "FAIL_INIT_FACET"); delayedBridge = IBridge(connectedContracts[0]); sequencerBridge = ISequencerInbox(connectedContracts[1]); outbox = IOutbox(connectedContracts[2]); delayedBridge.setOutbox(connectedContracts[2], true); rollupEventBridge = RollupEventBridge(connectedContracts[3]); delayedBridge.setInbox(connectedContracts[3], true); rollupEventBridge.rollupInitialized( _rollupParams[0], _rollupParams[2], _owner, _extraConfig ); challengeFactory = IChallengeFactory(connectedContracts[4]); nodeFactory = INodeFactory(connectedContracts[5]); INode node = createInitialNode(_machineHash); initializeCore(node); confirmPeriodBlocks = _rollupParams[0]; extraChallengeTimeBlocks = _rollupParams[1]; avmGasSpeedLimitPerBlock = _rollupParams[2]; baseStake = _rollupParams[3]; owner = _owner; // A little over 15 minutes minimumAssertionPeriod = 75; challengeExecutionBisectionDegree = 400; sequencerBridge.setMaxDelay(sequencerInboxParams[0], sequencerInboxParams[1]); // facets[0] == admin, facets[1] == user facets = _facets; emit RollupCreated(_machineHash); require(isInit(), "INITIALIZE_NOT_INIT"); } function postUpgradeInit() external { // it is assumed the rollup contract is behind a Proxy controlled by a proxy admin // this function can only be called by the proxy admin contract address proxyAdmin = ProxyUtil.getProxyAdmin(); require(msg.sender == proxyAdmin, "NOT_FROM_ADMIN"); // this upgrade moves the delay blocks and seconds tracking to the sequencer inbox // because of that we need to update the admin facet logic to allow the owner to set // these values in the sequencer inbox STORAGE_GAP_1 = 0; STORAGE_GAP_2 = 0; } function createInitialNode(bytes32 _machineHash) private returns (INode) { bytes32 state = RollupLib.stateHash( RollupLib.ExecutionState( 0, // total gas used _machineHash, 0, // inbox count 0, // send count 0, // log count 0, // send acc 0, // log acc block.number, // block proposed 1 // Initialization message already in inbox ) ); return INode( nodeFactory.createNode( state, 0, // challenge hash (not challengeable) 0, // confirm data 0, // prev node block.number // deadline block (not challengeable) ) ); } /** * This contract uses a dispatch pattern from EIP-2535: Diamonds * together with Open Zeppelin's proxy */ function getFacets() external view returns (address, address) { return (getAdminFacet(), getUserFacet()); } function getAdminFacet() public view returns (address) { return facets[0]; } function getUserFacet() public view returns (address) { return facets[1]; } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual override returns (address) { require(msg.data.length >= 4, "NO_FUNC_SIG"); address rollupOwner = owner; // if there is an owner and it is the sender, delegate to admin facet address target = rollupOwner != address(0) && rollupOwner == msg.sender ? getAdminFacet() : getUserFacet(); require(target.isContract(), "TARGET_NOT_CONTRACT"); return target; } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; library Messages { function messageHash( uint8 kind, address sender, uint256 blockNumber, uint256 timestamp, uint256 inboxSeqNum, uint256 gasPriceL1, bytes32 messageDataHash ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( kind, sender, blockNumber, timestamp, inboxSeqNum, gasPriceL1, messageDataHash ) ); } function addMessageToInbox(bytes32 inbox, bytes32 message) internal pure returns (bytes32) { return keccak256(abi.encodePacked(inbox, message)); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2020, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./ICloneable.sol"; contract Cloneable is ICloneable { string private constant NOT_CLONE = "NOT_CLONE"; bool private isMasterCopy; constructor() public { isMasterCopy = true; } function isMaster() external view override returns (bool) { return isMasterCopy; } function safeSelfDestruct(address payable dest) internal { require(!isMasterCopy, NOT_CLONE); selfdestruct(dest); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; abstract contract WhitelistConsumer { address public whitelist; event WhitelistSourceUpdated(address newSource); modifier onlyWhitelisted { if (whitelist != address(0)) { require(Whitelist(whitelist).isAllowed(msg.sender), "NOT_WHITELISTED"); } _; } function updateWhitelistSource(address newSource) external { require(msg.sender == whitelist, "NOT_FROM_LIST"); whitelist = newSource; emit WhitelistSourceUpdated(newSource); } } contract Whitelist { address public owner; mapping(address => bool) public isAllowed; event OwnerUpdated(address newOwner); event WhitelistUpgraded(address newWhitelist, address[] targets); constructor() public { owner = msg.sender; } modifier onlyOwner { require(msg.sender == owner, "ONLY_OWNER"); _; } function setOwner(address newOwner) external onlyOwner { owner = newOwner; emit OwnerUpdated(newOwner); } function setWhitelist(address[] memory user, bool[] memory val) external onlyOwner { require(user.length == val.length, "INVALID_INPUT"); for (uint256 i = 0; i < user.length; i++) { isAllowed[user[i]] = val[i]; } } // set new whitelist to address(0) to disable whitelist function triggerConsumers(address newWhitelist, address[] memory targets) external onlyOwner { for (uint256 i = 0; i < targets.length; i++) { WhitelistConsumer(targets[i]).updateWhitelistSource(newWhitelist); } emit WhitelistUpgraded(newWhitelist, targets); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; library ProxyUtil { function getProxyAdmin() internal view returns (address admin) { // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/proxy/TransparentUpgradeableProxy.sol#L48 // Storage slot with the admin of the proxy contract. // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; assembly { admin := sload(slot) } } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; library AddressAliasHelper { /// @notice Utility function that converts the msg.sender viewed in the L2 to the /// address in the L1 that submitted a tx to the inbox /// @param l2address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2address) internal pure returns (address l1Address) { uint160 offset = uint160(0x1111000000000000000000000000000000001111); l1Address = address(uint160(l2address) - offset); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface IMessageProvider { event InboxMessageDelivered(uint256 indexed messageNum, bytes data); event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback () external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive () external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overriden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./Rollup.sol"; import "./facets/IRollupFacets.sol"; import "../bridge/interfaces/IBridge.sol"; import "../bridge/interfaces/IMessageProvider.sol"; import "./INode.sol"; import "../libraries/Cloneable.sol"; contract RollupEventBridge is IMessageProvider, Cloneable { uint8 internal constant INITIALIZATION_MSG_TYPE = 11; uint8 internal constant ROLLUP_PROTOCOL_EVENT_TYPE = 8; uint8 internal constant CREATE_NODE_EVENT = 0; uint8 internal constant CONFIRM_NODE_EVENT = 1; uint8 internal constant REJECT_NODE_EVENT = 2; uint8 internal constant STAKE_CREATED_EVENT = 3; IBridge bridge; address rollup; modifier onlyRollup() { require(msg.sender == rollup, "ONLY_ROLLUP"); _; } function initialize(address _bridge, address _rollup) external { require(rollup == address(0), "ALREADY_INIT"); bridge = IBridge(_bridge); rollup = _rollup; } function rollupInitialized( uint256 confirmPeriodBlocks, uint256 avmGasSpeedLimitPerBlock, address owner, bytes calldata extraConfig ) external onlyRollup { bytes memory initMsg = abi.encodePacked( keccak256("ChallengePeriodEthBlocks"), confirmPeriodBlocks, keccak256("SpeedLimitPerSecond"), avmGasSpeedLimitPerBlock / 100, // convert avm gas to arbgas keccak256("ChainOwner"), uint256(uint160(bytes20(owner))), extraConfig ); uint256 num = bridge.deliverMessageToInbox( INITIALIZATION_MSG_TYPE, address(0), keccak256(initMsg) ); emit InboxMessageDelivered(num, initMsg); } function nodeCreated( uint256 nodeNum, uint256 prev, uint256 deadline, address asserter ) external onlyRollup { deliverToBridge( abi.encodePacked( CREATE_NODE_EVENT, nodeNum, prev, block.number, deadline, uint256(uint160(bytes20(asserter))) ) ); } function nodeConfirmed(uint256 nodeNum) external onlyRollup { deliverToBridge(abi.encodePacked(CONFIRM_NODE_EVENT, nodeNum)); } function nodeRejected(uint256 nodeNum) external onlyRollup { deliverToBridge(abi.encodePacked(REJECT_NODE_EVENT, nodeNum)); } function stakeCreated(address staker, uint256 nodeNum) external onlyRollup { deliverToBridge( abi.encodePacked( STAKE_CREATED_EVENT, uint256(uint160(bytes20(staker))), nodeNum, block.number ) ); } function deliverToBridge(bytes memory message) private { emit InboxMessageDelivered( bridge.deliverMessageToInbox( ROLLUP_PROTOCOL_EVENT_TYPE, msg.sender, keccak256(message) ), message ); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./INode.sol"; import "./IRollupCore.sol"; import "./RollupLib.sol"; import "./INodeFactory.sol"; import "./RollupEventBridge.sol"; import "../bridge/interfaces/ISequencerInbox.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; contract RollupCore is IRollupCore { using SafeMath for uint256; // Stakers become Zombies after losing a challenge struct Zombie { address stakerAddress; uint256 latestStakedNode; } struct Staker { uint256 index; uint256 latestStakedNode; uint256 amountStaked; // currentChallenge is 0 if staker is not in a challenge address currentChallenge; bool isStaked; } uint256 private _latestConfirmed; uint256 private _firstUnresolvedNode; uint256 private _latestNodeCreated; uint256 private _lastStakeBlock; mapping(uint256 => INode) private _nodes; mapping(uint256 => bytes32) private _nodeHashes; address payable[] private _stakerList; mapping(address => Staker) public override _stakerMap; Zombie[] private _zombies; mapping(address => uint256) private _withdrawableFunds; /** * @notice Get the address of the Node contract for the given node * @param nodeNum Index of the node * @return Address of the Node contract */ function getNode(uint256 nodeNum) public view override returns (INode) { return _nodes[nodeNum]; } /** * @notice Get the address of the staker at the given index * @param stakerNum Index of the staker * @return Address of the staker */ function getStakerAddress(uint256 stakerNum) external view override returns (address) { return _stakerList[stakerNum]; } /** * @notice Check whether the given staker is staked * @param staker Staker address to check * @return True or False for whether the staker was staked */ function isStaked(address staker) public view override returns (bool) { return _stakerMap[staker].isStaked; } /** * @notice Get the latest staked node of the given staker * @param staker Staker address to lookup * @return Latest node staked of the staker */ function latestStakedNode(address staker) public view override returns (uint256) { return _stakerMap[staker].latestStakedNode; } /** * @notice Get the current challenge of the given staker * @param staker Staker address to lookup * @return Current challenge of the staker */ function currentChallenge(address staker) public view override returns (address) { return _stakerMap[staker].currentChallenge; } /** * @notice Get the amount staked of the given staker * @param staker Staker address to lookup * @return Amount staked of the staker */ function amountStaked(address staker) public view override returns (uint256) { return _stakerMap[staker].amountStaked; } /** * @notice Get the original staker address of the zombie at the given index * @param zombieNum Index of the zombie to lookup * @return Original staker address of the zombie */ function zombieAddress(uint256 zombieNum) public view override returns (address) { return _zombies[zombieNum].stakerAddress; } /** * @notice Get Latest node that the given zombie at the given index is staked on * @param zombieNum Index of the zombie to lookup * @return Latest node that the given zombie is staked on */ function zombieLatestStakedNode(uint256 zombieNum) public view override returns (uint256) { return _zombies[zombieNum].latestStakedNode; } /// @return Current number of un-removed zombies function zombieCount() public view override returns (uint256) { return _zombies.length; } function isZombie(address staker) public view override returns (bool) { for (uint256 i = 0; i < _zombies.length; i++) { if (staker == _zombies[i].stakerAddress) { return true; } } return false; } /** * @notice Get the amount of funds withdrawable by the given address * @param owner Address to check the funds of * @return Amount of funds withdrawable by owner */ function withdrawableFunds(address owner) external view override returns (uint256) { return _withdrawableFunds[owner]; } /** * @return Index of the first unresolved node * @dev If all nodes have been resolved, this will be latestNodeCreated + 1 */ function firstUnresolvedNode() public view override returns (uint256) { return _firstUnresolvedNode; } /// @return Index of the latest confirmed node function latestConfirmed() public view override returns (uint256) { return _latestConfirmed; } /// @return Index of the latest rollup node created function latestNodeCreated() public view override returns (uint256) { return _latestNodeCreated; } /// @return Ethereum block that the most recent stake was created function lastStakeBlock() external view override returns (uint256) { return _lastStakeBlock; } /// @return Number of active stakers currently staked function stakerCount() public view override returns (uint256) { return _stakerList.length; } /** * @notice Initialize the core with an initial node * @param initialNode Initial node to start the chain with */ function initializeCore(INode initialNode) internal { _nodes[0] = initialNode; _firstUnresolvedNode = 1; } /** * @notice React to a new node being created by storing it an incrementing the latest node counter * @param node Node that was newly created * @param nodeHash The hash of said node */ function nodeCreated(INode node, bytes32 nodeHash) internal { _latestNodeCreated++; _nodes[_latestNodeCreated] = node; _nodeHashes[_latestNodeCreated] = nodeHash; } /// @return Node hash as of this node number function getNodeHash(uint256 index) public view override returns (bytes32) { return _nodeHashes[index]; } /// @notice Reject the next unresolved node function _rejectNextNode() internal { destroyNode(_firstUnresolvedNode); _firstUnresolvedNode++; } /// @notice Confirm the next unresolved node function confirmNextNode( bytes32 beforeSendAcc, bytes calldata sendsData, uint256[] calldata sendLengths, uint256 afterSendCount, bytes32 afterLogAcc, uint256 afterLogCount, IOutbox outbox, RollupEventBridge rollupEventBridge ) internal { confirmNode( _firstUnresolvedNode, beforeSendAcc, sendsData, sendLengths, afterSendCount, afterLogAcc, afterLogCount, outbox, rollupEventBridge ); } function confirmNode( uint256 nodeNum, bytes32 beforeSendAcc, bytes calldata sendsData, uint256[] calldata sendLengths, uint256 afterSendCount, bytes32 afterLogAcc, uint256 afterLogCount, IOutbox outbox, RollupEventBridge rollupEventBridge ) internal { bytes32 afterSendAcc = RollupLib.feedAccumulator(sendsData, sendLengths, beforeSendAcc); INode node = getNode(nodeNum); // Authenticate data against node's confirm data pre-image require( node.confirmData() == RollupLib.confirmHash( beforeSendAcc, afterSendAcc, afterLogAcc, afterSendCount, afterLogCount ), "CONFIRM_DATA" ); // trusted external call to outbox outbox.processOutgoingMessages(sendsData, sendLengths); destroyNode(_latestConfirmed); _latestConfirmed = nodeNum; _firstUnresolvedNode = nodeNum + 1; rollupEventBridge.nodeConfirmed(nodeNum); emit NodeConfirmed(nodeNum, afterSendAcc, afterSendCount, afterLogAcc, afterLogCount); } /** * @notice Create a new stake at latest confirmed node * @param stakerAddress Address of the new staker * @param depositAmount Stake amount of the new staker */ function createNewStake(address payable stakerAddress, uint256 depositAmount) internal { uint256 stakerIndex = _stakerList.length; _stakerList.push(stakerAddress); _stakerMap[stakerAddress] = Staker( stakerIndex, _latestConfirmed, depositAmount, address(0), // new staker is not in challenge true ); _lastStakeBlock = block.number; emit UserStakeUpdated(stakerAddress, 0, depositAmount); } /** * @notice Check to see whether the two stakers are in the same challenge * @param stakerAddress1 Address of the first staker * @param stakerAddress2 Address of the second staker * @return Address of the challenge that the two stakers are in */ function inChallenge(address stakerAddress1, address stakerAddress2) internal view returns (address) { Staker storage staker1 = _stakerMap[stakerAddress1]; Staker storage staker2 = _stakerMap[stakerAddress2]; address challenge = staker1.currentChallenge; require(challenge != address(0), "NO_CHAL"); require(challenge == staker2.currentChallenge, "DIFF_IN_CHAL"); return challenge; } /** * @notice Make the given staker as not being in a challenge * @param stakerAddress Address of the staker to remove from a challenge */ function clearChallenge(address stakerAddress) internal { Staker storage staker = _stakerMap[stakerAddress]; staker.currentChallenge = address(0); } /** * @notice Mark both the given stakers as engaged in the challenge * @param staker1 Address of the first staker * @param staker2 Address of the second staker * @param challenge Address of the challenge both stakers are now in */ function challengeStarted( address staker1, address staker2, address challenge ) internal { _stakerMap[staker1].currentChallenge = challenge; _stakerMap[staker2].currentChallenge = challenge; } /** * @notice Add to the stake of the given staker by the given amount * @param stakerAddress Address of the staker to increase the stake of * @param amountAdded Amount of stake to add to the staker */ function increaseStakeBy(address stakerAddress, uint256 amountAdded) internal { Staker storage staker = _stakerMap[stakerAddress]; uint256 initialStaked = staker.amountStaked; uint256 finalStaked = initialStaked.add(amountAdded); staker.amountStaked = finalStaked; emit UserStakeUpdated(stakerAddress, initialStaked, finalStaked); } /** * @notice Reduce the stake of the given staker to the given target * @param stakerAddress Address of the staker to reduce the stake of * @param target Amount of stake to leave with the staker * @return Amount of value released from the stake */ function reduceStakeTo(address stakerAddress, uint256 target) internal returns (uint256) { Staker storage staker = _stakerMap[stakerAddress]; uint256 current = staker.amountStaked; require(target <= current, "TOO_LITTLE_STAKE"); uint256 amountWithdrawn = current.sub(target); staker.amountStaked = target; increaseWithdrawableFunds(stakerAddress, amountWithdrawn); emit UserStakeUpdated(stakerAddress, current, target); return amountWithdrawn; } /** * @notice Remove the given staker and turn them into a zombie * @param stakerAddress Address of the staker to remove */ function turnIntoZombie(address stakerAddress) internal { Staker storage staker = _stakerMap[stakerAddress]; _zombies.push(Zombie(stakerAddress, staker.latestStakedNode)); deleteStaker(stakerAddress); } /** * @notice Update the latest staked node of the zombie at the given index * @param zombieNum Index of the zombie to move * @param latest New latest node the zombie is staked on */ function zombieUpdateLatestStakedNode(uint256 zombieNum, uint256 latest) internal { _zombies[zombieNum].latestStakedNode = latest; } /** * @notice Remove the zombie at the given index * @param zombieNum Index of the zombie to remove */ function removeZombie(uint256 zombieNum) internal { _zombies[zombieNum] = _zombies[_zombies.length - 1]; _zombies.pop(); } /** * @notice Remove the given staker and return their stake * @param stakerAddress Address of the staker withdrawing their stake */ function withdrawStaker(address stakerAddress) internal { Staker storage staker = _stakerMap[stakerAddress]; uint256 initialStaked = staker.amountStaked; increaseWithdrawableFunds(stakerAddress, initialStaked); deleteStaker(stakerAddress); emit UserStakeUpdated(stakerAddress, initialStaked, 0); } /** * @notice Advance the given staker to the given node * @param stakerAddress Address of the staker adding their stake * @param nodeNum Index of the node to stake on */ function stakeOnNode( address stakerAddress, uint256 nodeNum, uint256 confirmPeriodBlocks ) internal { Staker storage staker = _stakerMap[stakerAddress]; INode node = _nodes[nodeNum]; uint256 newStakerCount = node.addStaker(stakerAddress); staker.latestStakedNode = nodeNum; if (newStakerCount == 1) { INode parent = _nodes[node.prev()]; parent.newChildConfirmDeadline(block.number.add(confirmPeriodBlocks)); } } /** * @notice Clear the withdrawable funds for the given address * @param owner Address of the account to remove funds from * @return Amount of funds removed from account */ function withdrawFunds(address owner) internal returns (uint256) { uint256 amount = _withdrawableFunds[owner]; _withdrawableFunds[owner] = 0; emit UserWithdrawableFundsUpdated(owner, amount, 0); return amount; } /** * @notice Increase the withdrawable funds for the given address * @param owner Address of the account to add withdrawable funds to */ function increaseWithdrawableFunds(address owner, uint256 amount) internal { uint256 initialWithdrawable = _withdrawableFunds[owner]; uint256 finalWithdrawable = initialWithdrawable.add(amount); _withdrawableFunds[owner] = finalWithdrawable; emit UserWithdrawableFundsUpdated(owner, initialWithdrawable, finalWithdrawable); } /** * @notice Remove the given staker * @param stakerAddress Address of the staker to remove */ function deleteStaker(address stakerAddress) private { Staker storage staker = _stakerMap[stakerAddress]; uint256 stakerIndex = staker.index; _stakerList[stakerIndex] = _stakerList[_stakerList.length - 1]; _stakerMap[_stakerList[stakerIndex]].index = stakerIndex; _stakerList.pop(); delete _stakerMap[stakerAddress]; } /** * @notice Destroy the given node and clear out its address * @param nodeNum Index of the node to remove */ function destroyNode(uint256 nodeNum) internal { _nodes[nodeNum].destroy(); _nodes[nodeNum] = INode(0); } function nodeDeadline( uint256 avmGasSpeedLimitPerBlock, uint256 gasUsed, uint256 confirmPeriodBlocks, INode prevNode ) internal view returns (uint256 deadlineBlock) { // Set deadline rounding up to the nearest block uint256 checkTime = gasUsed.add(avmGasSpeedLimitPerBlock.sub(1)).div(avmGasSpeedLimitPerBlock); deadlineBlock = max(block.number.add(confirmPeriodBlocks), prevNode.deadlineBlock()).add( checkTime ); uint256 olderSibling = prevNode.latestChildNumber(); if (olderSibling != 0) { deadlineBlock = max(deadlineBlock, getNode(olderSibling).deadlineBlock()); } return deadlineBlock; } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } struct StakeOnNewNodeFrame { uint256 currentInboxSize; INode node; bytes32 executionHash; INode prevNode; bytes32 lastHash; bool hasSibling; uint256 deadlineBlock; uint256 gasUsed; uint256 sequencerBatchEnd; bytes32 sequencerBatchAcc; } struct CreateNodeDataFrame { uint256 prevNode; uint256 confirmPeriodBlocks; uint256 avmGasSpeedLimitPerBlock; ISequencerInbox sequencerInbox; RollupEventBridge rollupEventBridge; INodeFactory nodeFactory; } uint8 internal constant MAX_SEND_COUNT = 100; function createNewNode( RollupLib.Assertion memory assertion, bytes32[3][2] calldata assertionBytes32Fields, uint256[4][2] calldata assertionIntFields, bytes calldata sequencerBatchProof, CreateNodeDataFrame memory inputDataFrame, bytes32 expectedNodeHash ) internal returns (bytes32 newNodeHash) { StakeOnNewNodeFrame memory memoryFrame; { // validate data memoryFrame.gasUsed = RollupLib.assertionGasUsed(assertion); memoryFrame.prevNode = getNode(inputDataFrame.prevNode); memoryFrame.currentInboxSize = inputDataFrame.sequencerInbox.messageCount(); // Make sure the previous state is correct against the node being built on require( RollupLib.stateHash(assertion.beforeState) == memoryFrame.prevNode.stateHash(), "PREV_STATE_HASH" ); // Ensure that the assertion doesn't read past the end of the current inbox require( assertion.afterState.inboxCount <= memoryFrame.currentInboxSize, "INBOX_PAST_END" ); // Insure inbox tip after assertion is included in a sequencer-inbox batch and return inbox acc; this gives replay protection against the state of the inbox (memoryFrame.sequencerBatchEnd, memoryFrame.sequencerBatchAcc) = inputDataFrame .sequencerInbox .proveInboxContainsMessage(sequencerBatchProof, assertion.afterState.inboxCount); } { memoryFrame.executionHash = RollupLib.executionHash(assertion); memoryFrame.deadlineBlock = nodeDeadline( inputDataFrame.avmGasSpeedLimitPerBlock, memoryFrame.gasUsed, inputDataFrame.confirmPeriodBlocks, memoryFrame.prevNode ); memoryFrame.hasSibling = memoryFrame.prevNode.latestChildNumber() > 0; // here we don't use ternacy operator to remain compatible with slither if (memoryFrame.hasSibling) { memoryFrame.lastHash = getNodeHash(memoryFrame.prevNode.latestChildNumber()); } else { memoryFrame.lastHash = getNodeHash(inputDataFrame.prevNode); } memoryFrame.node = INode( inputDataFrame.nodeFactory.createNode( RollupLib.stateHash(assertion.afterState), RollupLib.challengeRoot(assertion, memoryFrame.executionHash, block.number), RollupLib.confirmHash(assertion), inputDataFrame.prevNode, memoryFrame.deadlineBlock ) ); } { uint256 nodeNum = latestNodeCreated() + 1; memoryFrame.prevNode.childCreated(nodeNum); newNodeHash = RollupLib.nodeHash( memoryFrame.hasSibling, memoryFrame.lastHash, memoryFrame.executionHash, memoryFrame.sequencerBatchAcc ); require(newNodeHash == expectedNodeHash, "UNEXPECTED_NODE_HASH"); nodeCreated(memoryFrame.node, newNodeHash); inputDataFrame.rollupEventBridge.nodeCreated( nodeNum, inputDataFrame.prevNode, memoryFrame.deadlineBlock, msg.sender ); } emit NodeCreated( latestNodeCreated(), getNodeHash(inputDataFrame.prevNode), newNodeHash, memoryFrame.executionHash, memoryFrame.currentInboxSize, memoryFrame.sequencerBatchEnd, memoryFrame.sequencerBatchAcc, assertionBytes32Fields, assertionIntFields ); return newNodeHash; } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../challenge/ChallengeLib.sol"; import "./INode.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; library RollupLib { using SafeMath for uint256; struct Config { bytes32 machineHash; uint256 confirmPeriodBlocks; uint256 extraChallengeTimeBlocks; uint256 avmGasSpeedLimitPerBlock; uint256 baseStake; address stakeToken; address owner; address sequencer; uint256 sequencerDelayBlocks; uint256 sequencerDelaySeconds; bytes extraConfig; } struct ExecutionState { uint256 gasUsed; bytes32 machineHash; uint256 inboxCount; uint256 sendCount; uint256 logCount; bytes32 sendAcc; bytes32 logAcc; uint256 proposedBlock; uint256 inboxMaxCount; } function stateHash(ExecutionState memory execState) internal pure returns (bytes32) { return keccak256( abi.encodePacked( execState.gasUsed, execState.machineHash, execState.inboxCount, execState.sendCount, execState.logCount, execState.sendAcc, execState.logAcc, execState.proposedBlock, execState.inboxMaxCount ) ); } struct Assertion { ExecutionState beforeState; ExecutionState afterState; } function decodeExecutionState( bytes32[3] memory bytes32Fields, uint256[4] memory intFields, uint256 proposedBlock, uint256 inboxMaxCount ) internal pure returns (ExecutionState memory) { return ExecutionState( intFields[0], bytes32Fields[0], intFields[1], intFields[2], intFields[3], bytes32Fields[1], bytes32Fields[2], proposedBlock, inboxMaxCount ); } function decodeAssertion( bytes32[3][2] memory bytes32Fields, uint256[4][2] memory intFields, uint256 beforeProposedBlock, uint256 beforeInboxMaxCount, uint256 inboxMaxCount ) internal view returns (Assertion memory) { return Assertion( decodeExecutionState( bytes32Fields[0], intFields[0], beforeProposedBlock, beforeInboxMaxCount ), decodeExecutionState(bytes32Fields[1], intFields[1], block.number, inboxMaxCount) ); } function executionStateChallengeHash(ExecutionState memory state) internal pure returns (bytes32) { return ChallengeLib.assertionHash( state.gasUsed, ChallengeLib.assertionRestHash( state.inboxCount, state.machineHash, state.sendAcc, state.sendCount, state.logAcc, state.logCount ) ); } function executionHash(Assertion memory assertion) internal pure returns (bytes32) { return ChallengeLib.bisectionChunkHash( assertion.beforeState.gasUsed, assertion.afterState.gasUsed - assertion.beforeState.gasUsed, RollupLib.executionStateChallengeHash(assertion.beforeState), RollupLib.executionStateChallengeHash(assertion.afterState) ); } function assertionGasUsed(RollupLib.Assertion memory assertion) internal pure returns (uint256) { return assertion.afterState.gasUsed.sub(assertion.beforeState.gasUsed); } function challengeRoot( Assertion memory assertion, bytes32 assertionExecHash, uint256 blockProposed ) internal pure returns (bytes32) { return challengeRootHash(assertionExecHash, blockProposed, assertion.afterState.inboxCount); } function challengeRootHash( bytes32 execution, uint256 proposedTime, uint256 maxMessageCount ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(execution, proposedTime, maxMessageCount)); } function confirmHash(Assertion memory assertion) internal pure returns (bytes32) { return confirmHash( assertion.beforeState.sendAcc, assertion.afterState.sendAcc, assertion.afterState.logAcc, assertion.afterState.sendCount, assertion.afterState.logCount ); } function confirmHash( bytes32 beforeSendAcc, bytes32 afterSendAcc, bytes32 afterLogAcc, uint256 afterSendCount, uint256 afterLogCount ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( beforeSendAcc, afterSendAcc, afterSendCount, afterLogAcc, afterLogCount ) ); } function feedAccumulator( bytes memory messageData, uint256[] memory messageLengths, bytes32 beforeAcc ) internal pure returns (bytes32) { uint256 offset = 0; uint256 messageCount = messageLengths.length; uint256 dataLength = messageData.length; bytes32 messageAcc = beforeAcc; for (uint256 i = 0; i < messageCount; i++) { uint256 messageLength = messageLengths[i]; require(offset + messageLength <= dataLength, "DATA_OVERRUN"); bytes32 messageHash; assembly { messageHash := keccak256(add(messageData, add(offset, 32)), messageLength) } messageAcc = keccak256(abi.encodePacked(messageAcc, messageHash)); offset += messageLength; } require(offset == dataLength, "DATA_LENGTH"); return messageAcc; } function nodeHash( bool hasSibling, bytes32 lastHash, bytes32 assertionExecHash, bytes32 inboxAcc ) internal pure returns (bytes32) { uint8 hasSiblingInt = hasSibling ? 1 : 0; return keccak256(abi.encodePacked(hasSiblingInt, lastHash, assertionExecHash, inboxAcc)); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface INode { function initialize( address _rollup, bytes32 _stateHash, bytes32 _challengeHash, bytes32 _confirmData, uint256 _prev, uint256 _deadlineBlock ) external; function destroy() external; function addStaker(address staker) external returns (uint256); function removeStaker(address staker) external; function childCreated(uint256) external; function newChildConfirmDeadline(uint256 deadline) external; function stateHash() external view returns (bytes32); function challengeHash() external view returns (bytes32); function confirmData() external view returns (bytes32); function prev() external view returns (uint256); function deadlineBlock() external view returns (uint256); function noChildConfirmedBeforeBlock() external view returns (uint256); function stakerCount() external view returns (uint256); function stakers(address staker) external view returns (bool); function firstChildBlock() external view returns (uint256); function latestChildNumber() external view returns (uint256); function requirePastDeadline() external view; function requirePastChildConfirmDeadline() external view; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface INodeFactory { function createNode( bytes32 _stateHash, bytes32 _challengeHash, bytes32 _confirmData, uint256 _prev, uint256 _deadlineBlock ) external returns (address); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../bridge/interfaces/IBridge.sol"; import "../bridge/interfaces/ISequencerInbox.sol"; import "../arch/IOneStepProof.sol"; interface IChallenge { function initializeChallenge( IOneStepProof[] calldata _executors, address _resultReceiver, bytes32 _executionHash, uint256 _maxMessageCount, address _asserter, address _challenger, uint256 _asserterTimeLeft, uint256 _challengerTimeLeft, ISequencerInbox _sequencerBridge, IBridge _delayedBridge ) external; function currentResponderTimeLeft() external view returns (uint256); function lastMoveBlock() external view returns (uint256); function timeout() external; function asserter() external view returns (address); function challenger() external view returns (address); function clearChallenge() external; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../bridge/interfaces/IBridge.sol"; import "../bridge/interfaces/ISequencerInbox.sol"; interface IChallengeFactory { function createChallenge( address _resultReceiver, bytes32 _executionHash, uint256 _maxMessageCount, address _asserter, address _challenger, uint256 _asserterTimeLeft, uint256 _challengerTimeLeft, ISequencerInbox _sequencerBridge, IBridge _delayedBridge ) external returns (address); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface IOutbox { event OutboxEntryCreated( uint256 indexed batchNum, uint256 outboxEntryIndex, bytes32 outputRoot, uint256 numInBatch ); event OutBoxTransactionExecuted( address indexed destAddr, address indexed l2Sender, uint256 indexed outboxEntryIndex, uint256 transactionIndex ); function l2ToL1Sender() external view returns (address); function l2ToL1Block() external view returns (uint256); function l2ToL1EthBlock() external view returns (uint256); function l2ToL1Timestamp() external view returns (uint256); function l2ToL1BatchNum() external view returns (uint256); function l2ToL1OutputId() external view returns (bytes32); function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths) external; function outboxEntryExists(uint256 batchNum) external view returns (bool); function executeTransaction( uint256 outboxIndex, bytes32[] calldata proof, uint256 index, address l2Sender, address destAddr, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 amount, bytes calldata calldataForL1) external; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../INode.sol"; import "../../bridge/interfaces/IOutbox.sol"; interface IRollupUser { function initialize(address _stakeToken) external; function completeChallenge(address winningStaker, address losingStaker) external; function returnOldDeposit(address stakerAddress) external; function requireUnresolved(uint256 nodeNum) external view; function requireUnresolvedExists() external view; function countStakedZombies(INode node) external view returns (uint256); } interface IRollupAdmin { event OwnerFunctionCalled(uint256 indexed id); /** * @notice Add a contract authorized to put messages into this rollup's inbox * @param _outbox Outbox contract to add */ function setOutbox(IOutbox _outbox) external; /** * @notice Disable an old outbox from interacting with the bridge * @param _outbox Outbox contract to remove */ function removeOldOutbox(address _outbox) external; /** * @notice Enable or disable an inbox contract * @param _inbox Inbox contract to add or remove * @param _enabled New status of inbox */ function setInbox(address _inbox, bool _enabled) external; /** * @notice Pause interaction with the rollup contract */ function pause() external; /** * @notice Resume interaction with the rollup contract */ function resume() external; /** * @notice Set the addresses of rollup logic facets called * @param newAdminFacet address of logic that owner of rollup calls * @param newUserFacet ddress of logic that user of rollup calls */ function setFacets(address newAdminFacet, address newUserFacet) external; /** * @notice Set the addresses of the validator whitelist * @dev It is expected that both arrays are same length, and validator at * position i corresponds to the value at position i * @param _validator addresses to set in the whitelist * @param _val value to set in the whitelist for corresponding address */ function setValidator(address[] memory _validator, bool[] memory _val) external; /** * @notice Set a new owner address for the rollup * @param newOwner address of new rollup owner */ function setOwner(address newOwner) external; /** * @notice Set minimum assertion period for the rollup * @param newPeriod new minimum period for assertions */ function setMinimumAssertionPeriod(uint256 newPeriod) external; /** * @notice Set number of blocks until a node is considered confirmed * @param newConfirmPeriod new number of blocks until a node is confirmed */ function setConfirmPeriodBlocks(uint256 newConfirmPeriod) external; /** * @notice Set number of extra blocks after a challenge * @param newExtraTimeBlocks new number of blocks */ function setExtraChallengeTimeBlocks(uint256 newExtraTimeBlocks) external; /** * @notice Set speed limit per block * @param newAvmGasSpeedLimitPerBlock maximum avmgas to be used per block */ function setAvmGasSpeedLimitPerBlock(uint256 newAvmGasSpeedLimitPerBlock) external; /** * @notice Set base stake required for an assertion * @param newBaseStake maximum avmgas to be used per block */ function setBaseStake(uint256 newBaseStake) external; /** * @notice Set the token used for stake, where address(0) == eth * @dev Before changing the base stake token, you might need to change the * implementation of the Rollup User facet! * @param newStakeToken address of token used for staking */ function setStakeToken(address newStakeToken) external; /** * @notice Set max delay for sequencer inbox * @param newSequencerInboxMaxDelayBlocks max number of blocks * @param newSequencerInboxMaxDelaySeconds max number of seconds */ function setSequencerInboxMaxDelay( uint256 newSequencerInboxMaxDelayBlocks, uint256 newSequencerInboxMaxDelaySeconds ) external; /** * @notice Set execution bisection degree * @param newChallengeExecutionBisectionDegree execution bisection degree */ function setChallengeExecutionBisectionDegree(uint256 newChallengeExecutionBisectionDegree) external; /** * @notice Updates a whitelist address for its consumers * @dev setting the newWhitelist to address(0) disables it for consumers * @param whitelist old whitelist to be deprecated * @param newWhitelist new whitelist to be used * @param targets whitelist consumers to be triggered */ function updateWhitelistConsumers( address whitelist, address newWhitelist, address[] memory targets ) external; /** * @notice Updates a whitelist's entries * @dev user at position i will be assigned value i * @param whitelist whitelist to be updated * @param user users to be updated in the whitelist * @param val if user is or not allowed in the whitelist */ function setWhitelistEntries( address whitelist, address[] memory user, bool[] memory val ) external; /** * @notice Updates whether an address is a sequencer at the sequencer inbox * @param newSequencer address to be modified * @param isSequencer whether this address should be authorized as a sequencer */ function setIsSequencer(address newSequencer, bool isSequencer) external; /** * @notice Upgrades the implementation of a beacon controlled by the rollup * @param beacon address of beacon to be upgraded * @param newImplementation new address of implementation */ function upgradeBeacon(address beacon, address newImplementation) external; function forceResolveChallenge(address[] memory stackerA, address[] memory stackerB) external; function forceRefundStaker(address[] memory stacker) external; function forceCreateNode( bytes32 expectedNodeHash, bytes32[3][2] calldata assertionBytes32Fields, uint256[4][2] calldata assertionIntFields, bytes calldata sequencerBatchProof, uint256 beforeProposedBlock, uint256 beforeInboxMaxCount, uint256 prevNode ) external; function forceConfirmNode( uint256 nodeNum, bytes32 beforeSendAcc, bytes calldata sendsData, uint256[] calldata sendLengths, uint256 afterSendCount, bytes32 afterLogAcc, uint256 afterLogCount ) external; }
// 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: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "./INode.sol"; interface IRollupCore { function _stakerMap(address stakerAddress) external view returns ( uint256, uint256, uint256, address, bool ); event RollupCreated(bytes32 machineHash); event NodeCreated( uint256 indexed nodeNum, bytes32 indexed parentNodeHash, bytes32 nodeHash, bytes32 executionHash, uint256 inboxMaxCount, uint256 afterInboxBatchEndCount, bytes32 afterInboxBatchAcc, bytes32[3][2] assertionBytes32Fields, uint256[4][2] assertionIntFields ); event NodeConfirmed( uint256 indexed nodeNum, bytes32 afterSendAcc, uint256 afterSendCount, bytes32 afterLogAcc, uint256 afterLogCount ); event NodeRejected(uint256 indexed nodeNum); event RollupChallengeStarted( address indexed challengeContract, address asserter, address challenger, uint256 challengedNode ); event UserStakeUpdated(address indexed user, uint256 initialBalance, uint256 finalBalance); event UserWithdrawableFundsUpdated( address indexed user, uint256 initialBalance, uint256 finalBalance ); function getNode(uint256 nodeNum) external view returns (INode); /** * @notice Get the address of the staker at the given index * @param stakerNum Index of the staker * @return Address of the staker */ function getStakerAddress(uint256 stakerNum) external view returns (address); /** * @notice Check whether the given staker is staked * @param staker Staker address to check * @return True or False for whether the staker was staked */ function isStaked(address staker) external view returns (bool); /** * @notice Get the latest staked node of the given staker * @param staker Staker address to lookup * @return Latest node staked of the staker */ function latestStakedNode(address staker) external view returns (uint256); /** * @notice Get the current challenge of the given staker * @param staker Staker address to lookup * @return Current challenge of the staker */ function currentChallenge(address staker) external view returns (address); /** * @notice Get the amount staked of the given staker * @param staker Staker address to lookup * @return Amount staked of the staker */ function amountStaked(address staker) external view returns (uint256); /** * @notice Get the original staker address of the zombie at the given index * @param zombieNum Index of the zombie to lookup * @return Original staker address of the zombie */ function zombieAddress(uint256 zombieNum) external view returns (address); /** * @notice Get Latest node that the given zombie at the given index is staked on * @param zombieNum Index of the zombie to lookup * @return Latest node that the given zombie is staked on */ function zombieLatestStakedNode(uint256 zombieNum) external view returns (uint256); /// @return Current number of un-removed zombies function zombieCount() external view returns (uint256); function isZombie(address staker) external view returns (bool); /** * @notice Get the amount of funds withdrawable by the given address * @param owner Address to check the funds of * @return Amount of funds withdrawable by owner */ function withdrawableFunds(address owner) external view returns (uint256); /** * @return Index of the first unresolved node * @dev If all nodes have been resolved, this will be latestNodeCreated + 1 */ function firstUnresolvedNode() external view returns (uint256); /// @return Index of the latest confirmed node function latestConfirmed() external view returns (uint256); /// @return Index of the latest rollup node created function latestNodeCreated() external view returns (uint256); /// @return Ethereum block that the most recent stake was created function lastStakeBlock() external view returns (uint256); /// @return Number of active stakers currently staked function stakerCount() external view returns (uint256); /// @return Node hash as of this node number function getNodeHash(uint256 index) external view returns (bytes32); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface ISequencerInbox { event SequencerBatchDelivered( uint256 indexed firstMessageNum, bytes32 indexed beforeAcc, uint256 newMessageCount, bytes32 afterAcc, bytes transactions, uint256[] lengths, uint256[] sectionsMetadata, uint256 seqBatchIndex, address sequencer ); event SequencerBatchDeliveredFromOrigin( uint256 indexed firstMessageNum, bytes32 indexed beforeAcc, uint256 newMessageCount, bytes32 afterAcc, uint256 seqBatchIndex ); event DelayedInboxForced( uint256 indexed firstMessageNum, bytes32 indexed beforeAcc, uint256 newMessageCount, uint256 totalDelayedMessagesRead, bytes32[2] afterAccAndDelayed, uint256 seqBatchIndex ); /// @notice DEPRECATED - look at IsSequencerUpdated for new updates // event SequencerAddressUpdated(address newAddress); event IsSequencerUpdated(address addr, bool isSequencer); event MaxDelayUpdated(uint256 newMaxDelayBlocks, uint256 newMaxDelaySeconds); /// @notice DEPRECATED - look at MaxDelayUpdated for new updates // event MaxDelayBlocksUpdated(uint256 newValue); /// @notice DEPRECATED - look at MaxDelayUpdated for new updates // event MaxDelaySecondsUpdated(uint256 newValue); function setMaxDelay(uint256 newMaxDelayBlocks, uint256 newMaxDelaySeconds) external; function setIsSequencer(address addr, bool isSequencer) external; function messageCount() external view returns (uint256); function maxDelayBlocks() external view returns (uint256); function maxDelaySeconds() external view returns (uint256); function inboxAccs(uint256 index) external view returns (bytes32); function getInboxAccsLength() external view returns (uint256); function proveInboxContainsMessage(bytes calldata proof, uint256 inboxCount) external view returns (uint256, bytes32); /// @notice DEPRECATED - use isSequencer instead function sequencer() external view returns (address); function isSequencer(address seq) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../libraries/MerkleLib.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; library ChallengeLib { using SafeMath for uint256; function firstSegmentSize(uint256 totalCount, uint256 bisectionCount) internal pure returns (uint256) { return totalCount / bisectionCount + (totalCount % bisectionCount); } function otherSegmentSize(uint256 totalCount, uint256 bisectionCount) internal pure returns (uint256) { return totalCount / bisectionCount; } function bisectionChunkHash( uint256 _segmentStart, uint256 _segmentLength, bytes32 _startHash, bytes32 _endHash ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_segmentStart, _segmentLength, _startHash, _endHash)); } function assertionHash(uint256 _avmGasUsed, bytes32 _restHash) internal pure returns (bytes32) { // Note: make sure this doesn't return Challenge.UNREACHABLE_ASSERTION (currently 0) return keccak256(abi.encodePacked(_avmGasUsed, _restHash)); } function assertionRestHash( uint256 _totalMessagesRead, bytes32 _machineState, bytes32 _sendAcc, uint256 _sendCount, bytes32 _logAcc, uint256 _logCount ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( _totalMessagesRead, _machineState, _sendAcc, _sendCount, _logAcc, _logCount ) ); } function updatedBisectionRoot( bytes32[] memory _chainHashes, uint256 _challengedSegmentStart, uint256 _challengedSegmentLength ) internal pure returns (bytes32) { uint256 bisectionCount = _chainHashes.length - 1; bytes32[] memory hashes = new bytes32[](bisectionCount); uint256 chunkSize = ChallengeLib.firstSegmentSize(_challengedSegmentLength, bisectionCount); uint256 segmentStart = _challengedSegmentStart; hashes[0] = ChallengeLib.bisectionChunkHash( segmentStart, chunkSize, _chainHashes[0], _chainHashes[1] ); segmentStart = segmentStart.add(chunkSize); chunkSize = ChallengeLib.otherSegmentSize(_challengedSegmentLength, bisectionCount); for (uint256 i = 1; i < bisectionCount; i++) { hashes[i] = ChallengeLib.bisectionChunkHash( segmentStart, chunkSize, _chainHashes[i], _chainHashes[i + 1] ); segmentStart = segmentStart.add(chunkSize); } return MerkleLib.generateRoot(hashes); } function verifySegmentProof( bytes32 challengeState, bytes32 item, bytes32[] calldata _merkleNodes, uint256 _merkleRoute ) internal pure returns (bool) { return challengeState == MerkleLib.calculateRoot(_merkleNodes, _merkleRoute, item); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; library MerkleLib { function generateRoot(bytes32[] memory _hashes) internal pure returns (bytes32) { bytes32[] memory prevLayer = _hashes; while (prevLayer.length > 1) { bytes32[] memory nextLayer = new bytes32[]((prevLayer.length + 1) / 2); for (uint256 i = 0; i < nextLayer.length; i++) { if (2 * i + 1 < prevLayer.length) { nextLayer[i] = keccak256( abi.encodePacked(prevLayer[2 * i], prevLayer[2 * i + 1]) ); } else { nextLayer[i] = prevLayer[2 * i]; } } prevLayer = nextLayer; } return prevLayer[0]; } function calculateRoot( bytes32[] memory nodes, uint256 route, bytes32 item ) internal pure returns (bytes32) { uint256 proofItems = nodes.length; require(proofItems <= 256); bytes32 h = item; for (uint256 i = 0; i < proofItems; i++) { if (route % 2 == 0) { h = keccak256(abi.encodePacked(nodes[i], h)); } else { h = keccak256(abi.encodePacked(h, nodes[i])); } route /= 2; } return h; } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; interface ICloneable { function isMaster() external view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2020, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.6.11; import "../bridge/interfaces/IBridge.sol"; import "../bridge/interfaces/ISequencerInbox.sol"; interface IOneStepProof { // Bridges is sequencer bridge then delayed bridge function executeStep( address[2] calldata bridges, uint256 initialMessagesRead, bytes32[2] calldata accs, bytes calldata proof, bytes calldata bproof ) external view returns ( uint64 gas, uint256 afterMessagesRead, bytes32[4] memory fields ); function executeStepDebug( address[2] calldata bridges, uint256 initialMessagesRead, bytes32[2] calldata accs, bytes calldata proof, bytes calldata bproof ) external view returns (string memory startMachine, string memory afterMachine); }
// SPDX-License-Identifier: MIT /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity ^0.6.11; /* solhint-disable no-inline-assembly */ library BytesLib { function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= (_start + 20), "Read out of bounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= (_start + 1), "Read out of bounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= (_start + 32), "Read out of bounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= (_start + 32), "Read out of bounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } } /* solhint-enable no-inline-assembly */
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Proxy.sol"; import "../utils/Address.sol"; import "./IBeacon.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. * * _Available since v3.4._ */ contract BeaconProxy is Proxy { /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 private constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Initializes the proxy with `beacon`. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity * constructor. * * Requirements: * * - `beacon` must be a contract with the interface {IBeacon}. */ constructor(address beacon, bytes memory data) public payable { assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1)); _setBeacon(beacon, data); } /** * @dev Returns the current beacon address. */ function _beacon() internal view virtual returns (address beacon) { bytes32 slot = _BEACON_SLOT; // solhint-disable-next-line no-inline-assembly assembly { beacon := sload(slot) } } /** * @dev Returns the current implementation address of the associated beacon. */ function _implementation() internal view virtual override returns (address) { return IBeacon(_beacon()).implementation(); } /** * @dev Changes the proxy to use a new beacon. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. * * Requirements: * * - `beacon` must be a contract. * - The implementation returned by `beacon` must be a contract. */ function _setBeacon(address beacon, bytes memory data) internal virtual { require( Address.isContract(beacon), "BeaconProxy: beacon is not a contract" ); require( Address.isContract(IBeacon(beacon).implementation()), "BeaconProxy: beacon implementation is not a contract" ); bytes32 slot = _BEACON_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, beacon) } if (data.length > 0) { Address.functionDelegateCall(_implementation(), data, "BeaconProxy: function call failed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IBeacon.sol"; import "../access/Ownable.sol"; import "../utils/Address.sol"; /** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their * implementation contract, which is where they will delegate all function calls. * * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. */ contract UpgradeableBeacon is IBeacon, Ownable { address private _implementation; /** * @dev Emitted when the implementation returned by the beacon is changed. */ event Upgraded(address indexed implementation); /** * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the * beacon. */ constructor(address implementation_) public { _setImplementation(implementation_); } /** * @dev Returns the current implementation address. */ function implementation() public view virtual override returns (address) { return _implementation; } /** * @dev Upgrades the beacon to a new implementation. * * Emits an {Upgraded} event. * * Requirements: * * - msg.sender must be the owner of the contract. * - `newImplementation` must be a contract. */ function upgradeTo(address newImplementation) public virtual onlyOwner { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation contract address for this beacon * * Requirements: * * - `newImplementation` must be a contract. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); _implementation = newImplementation; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// 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; import "../proxy/Initializable.sol"; /* * @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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } 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; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; import "../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbox","type":"address"},{"indexed":true,"internalType":"address","name":"destAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"BridgeCallTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"inbox","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"InboxToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"messageIndex","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"beforeInboxAcc","type":"bytes32"},{"indexed":false,"internalType":"address","name":"inbox","type":"address"},{"indexed":false,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes32","name":"messageDataHash","type":"bytes32"}],"name":"MessageDelivered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbox","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"OutboxToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"activeOutbox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allowedInboxList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"inbox","type":"address"}],"name":"allowedInboxes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allowedOutboxList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbox","type":"address"}],"name":"allowedOutboxes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"messageDataHash","type":"bytes32"}],"name":"deliverMessageToInbox","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"executeCall","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"inboxAccs","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"inbox","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setInbox","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbox","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setOutbox","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506112c3806100206000396000f3fe6080604052600436106100c85760003560e01c8063945e11471161007a578063945e1147146101f75780639e5d4c4914610221578063ab5d894314610336578063c29372de1461034b578063cee3d7281461037e578063d9dd67ab146103b9578063e45b7ce6146103e3578063f2fde38b1461041e576100c8565b806302bbfad1146100cd5780633dbcc8d114610114578063413b35bd14610129578063715018a6146101705780637ee94329146101875780638129fc1c146101cd5780638da5cb5b146101e2575b600080fd5b610102600480360360608110156100e357600080fd5b5060ff813516906001600160a01b036020820135169060400135610451565b60408051918252519081900360200190f35b34801561012057600080fd5b50610102610567565b34801561013557600080fd5b5061015c6004803603602081101561014c57600080fd5b50356001600160a01b031661056d565b604080519115158252519081900360200190f35b34801561017c57600080fd5b5061018561058e565b005b34801561019357600080fd5b506101b1600480360360208110156101aa57600080fd5b5035610628565b604080516001600160a01b039092168252519081900360200190f35b3480156101d957600080fd5b5061018561064f565b3480156101ee57600080fd5b506101b16106f9565b34801561020357600080fd5b506101b16004803603602081101561021a57600080fd5b5035610708565b34801561022d57600080fd5b506102b36004803603606081101561024457600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561027457600080fd5b82018360208201111561028657600080fd5b803590602001918460018302840111640100000000831117156102a857600080fd5b509092509050610715565b604051808315151515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156102fa5781810151838201526020016102e2565b50505050905090810190601f1680156103275780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561034257600080fd5b506101b16108e9565b34801561035757600080fd5b5061015c6004803603602081101561036e57600080fd5b50356001600160a01b03166108f8565b34801561038a57600080fd5b50610185600480360360408110156103a157600080fd5b506001600160a01b0381351690602001351515610919565b3480156103c557600080fd5b50610102600480360360208110156103dc57600080fd5b5035610b92565b3480156103ef57600080fd5b506101856004803603604081101561040657600080fd5b506001600160a01b0381351690602001351515610bb0565b34801561042a57600080fd5b506101856004803603602081101561044157600080fd5b50356001600160a01b0316610e27565b3360009081526065602052604081206001015460ff166104a9576040805162461bcd60e51b815260206004820152600e60248201526d09c9ea8be8ca49e9abe929c849eb60931b604482015290519081900360640190fd5b606a5460006104bd86864342863a8a610f18565b9050600082156104e557606a60018403815481106104d757fe5b906000526020600020015490505b606a6104f18284610f8e565b8154600181018355600092835260209283902001556040805133815260ff8a16928101929092526001600160a01b038816828201526060820187905251829185917f23be8e12e420b5da9fb98d8102572f640fb3c11a0085060472dfc0ed194b3cf79181900360800190a3509095945050505050565b606a5490565b6001600160a01b031660009081526066602052604090206001015460ff1690565b610596610fba565b6001600160a01b03166105a76106f9565b6001600160a01b0316146105f0576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6033546040516000916001600160a01b03169060008051602061126e833981519152908390a3603380546001600160a01b0319169055565b6067818154811061063557fe5b6000918252602090912001546001600160a01b0316905081565b600054610100900460ff16806106685750610668610fbe565b80610676575060005460ff16155b6106b15760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff161580156106dc576000805460ff1961ff0019909116610100171660011790555b6106e4610fcf565b80156106f6576000805461ff00191690555b50565b6033546001600160a01b031690565b6068818154811061063557fe5b3360009081526066602052604081206001015460609060ff16610771576040805162461bcd60e51b815260206004820152600f60248201526e09c9ea8be8ca49e9abe9eaaa8849eb608b1b604482015290519081900360640190fd5b82156107cc57610789866001600160a01b031661106c565b6107cc576040805162461bcd60e51b815260206004820152600f60248201526e1393d7d0d3d11157d05517d11154d5608a1b604482015290519081900360640190fd5b606980546001600160a01b0319811633179091556040516001600160a01b0391821691881690879087908790808383808284376040519201945060009350909150508083038185875af1925050503d8060008114610846576040519150601f19603f3d011682016040523d82523d6000602084013e61084b565b606091505b50606980546001600160a01b0319166001600160a01b0385811691909117909155604080518a81526020810182815291810189905293965091945089169133917f2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d466918a918a918a9160608201848480828437600083820152604051601f909101601f1916909201829003965090945050505050a35094509492505050565b6069546001600160a01b031681565b6001600160a01b031660009081526065602052604090206001015460ff1690565b610921610fba565b6001600160a01b03166109326106f9565b6001600160a01b03161461097b576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152606660209081526040918290206001810154835186151581529351919460ff9091169390927f49477e7356dbcb654ab85d7534b50126772d938130d1350e23e2540370c8dffa92918290030190a28080156109e25750825b806109f45750801580156109f4575082155b15610a00575050610b8e565b8215610a8f57604080518082018252606880548252600160208084018281526001600160a01b038a16600081815260669093529582209451855551938201805460ff1916941515949094179093558154908101825591527fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c220977530180546001600160a01b0319169091179055610b8b565b606880546000198101908110610aa157fe5b6000918252602090912001548254606880546001600160a01b03909316929091908110610aca57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160000154606660006068856000015481548110610b1257fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020556068805480610b4257fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526066905260408120908155600101805460ff191690555b50505b5050565b606a8181548110610b9f57fe5b600091825260209091200154905081565b610bb8610fba565b6001600160a01b0316610bc96106f9565b6001600160a01b031614610c12576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152606560209081526040918290206001810154835186151581529351919460ff9091169390927f6675ce8882cb71637de5903a193d218cc0544be9c0650cb83e0955f6aa2bf52192918290030190a2808015610c795750825b80610c8b575080158015610c8b575082155b15610c97575050610b8e565b8215610d2657604080518082018252606780548252600160208084018281526001600160a01b038a16600081815260659093529582209451855551938201805460ff1916941515949094179093558154908101825591527f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae0180546001600160a01b0319169091179055610b8b565b606780546000198101908110610d3857fe5b6000918252602090912001548254606780546001600160a01b03909316929091908110610d6157fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160000154606560006067856000015481548110610da957fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020556067805480610dd957fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526065905260408120908155600101805460ff1916905550505050565b610e2f610fba565b6001600160a01b0316610e406106f9565b6001600160a01b031614610e89576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b038116610ece5760405162461bcd60e51b81526004018080602001828103825260268152602001806111fa6026913960400191505060405180910390fd5b6033546040516001600160a01b0380841692169060008051602061126e83398151915290600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b6040805160f89890981b6001600160f81b0319166020808a019190915260609790971b6bffffffffffffffffffffffff19166021890152603588019590955260558701939093526075860191909152609585015260b5808501919091528151808503909101815260d59093019052815191012090565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b3390565b6000610fc93061106c565b15905090565b600054610100900460ff1680610fe85750610fe8610fbe565b80610ff6575060005460ff16155b6110315760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff1615801561105c576000805460ff1961ff0019909116610100171660011790555b611064611072565b6106e4611112565b3b151590565b600054610100900460ff168061108b575061108b610fbe565b80611099575060005460ff16155b6110d45760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff161580156106e4576000805460ff1961ff00199091166101001716600117905580156106f6576000805461ff001916905550565b600054610100900460ff168061112b575061112b610fbe565b80611139575060005460ff16155b6111745760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff1615801561119f576000805460ff1961ff0019909116610100171660011790555b60006111a9610fba565b603380546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602061126e833981519152908290a35080156106f6576000805461ff00191690555056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65644f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a2646970667358221220e0c6592adeab5e479b23743fe54cacd75233b9d3d3c962be1a93fd94f81eb19c64736f6c634300060b0033
Deployed Bytecode
0x6080604052600436106100c85760003560e01c8063945e11471161007a578063945e1147146101f75780639e5d4c4914610221578063ab5d894314610336578063c29372de1461034b578063cee3d7281461037e578063d9dd67ab146103b9578063e45b7ce6146103e3578063f2fde38b1461041e576100c8565b806302bbfad1146100cd5780633dbcc8d114610114578063413b35bd14610129578063715018a6146101705780637ee94329146101875780638129fc1c146101cd5780638da5cb5b146101e2575b600080fd5b610102600480360360608110156100e357600080fd5b5060ff813516906001600160a01b036020820135169060400135610451565b60408051918252519081900360200190f35b34801561012057600080fd5b50610102610567565b34801561013557600080fd5b5061015c6004803603602081101561014c57600080fd5b50356001600160a01b031661056d565b604080519115158252519081900360200190f35b34801561017c57600080fd5b5061018561058e565b005b34801561019357600080fd5b506101b1600480360360208110156101aa57600080fd5b5035610628565b604080516001600160a01b039092168252519081900360200190f35b3480156101d957600080fd5b5061018561064f565b3480156101ee57600080fd5b506101b16106f9565b34801561020357600080fd5b506101b16004803603602081101561021a57600080fd5b5035610708565b34801561022d57600080fd5b506102b36004803603606081101561024457600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561027457600080fd5b82018360208201111561028657600080fd5b803590602001918460018302840111640100000000831117156102a857600080fd5b509092509050610715565b604051808315151515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156102fa5781810151838201526020016102e2565b50505050905090810190601f1680156103275780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561034257600080fd5b506101b16108e9565b34801561035757600080fd5b5061015c6004803603602081101561036e57600080fd5b50356001600160a01b03166108f8565b34801561038a57600080fd5b50610185600480360360408110156103a157600080fd5b506001600160a01b0381351690602001351515610919565b3480156103c557600080fd5b50610102600480360360208110156103dc57600080fd5b5035610b92565b3480156103ef57600080fd5b506101856004803603604081101561040657600080fd5b506001600160a01b0381351690602001351515610bb0565b34801561042a57600080fd5b506101856004803603602081101561044157600080fd5b50356001600160a01b0316610e27565b3360009081526065602052604081206001015460ff166104a9576040805162461bcd60e51b815260206004820152600e60248201526d09c9ea8be8ca49e9abe929c849eb60931b604482015290519081900360640190fd5b606a5460006104bd86864342863a8a610f18565b9050600082156104e557606a60018403815481106104d757fe5b906000526020600020015490505b606a6104f18284610f8e565b8154600181018355600092835260209283902001556040805133815260ff8a16928101929092526001600160a01b038816828201526060820187905251829185917f23be8e12e420b5da9fb98d8102572f640fb3c11a0085060472dfc0ed194b3cf79181900360800190a3509095945050505050565b606a5490565b6001600160a01b031660009081526066602052604090206001015460ff1690565b610596610fba565b6001600160a01b03166105a76106f9565b6001600160a01b0316146105f0576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6033546040516000916001600160a01b03169060008051602061126e833981519152908390a3603380546001600160a01b0319169055565b6067818154811061063557fe5b6000918252602090912001546001600160a01b0316905081565b600054610100900460ff16806106685750610668610fbe565b80610676575060005460ff16155b6106b15760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff161580156106dc576000805460ff1961ff0019909116610100171660011790555b6106e4610fcf565b80156106f6576000805461ff00191690555b50565b6033546001600160a01b031690565b6068818154811061063557fe5b3360009081526066602052604081206001015460609060ff16610771576040805162461bcd60e51b815260206004820152600f60248201526e09c9ea8be8ca49e9abe9eaaa8849eb608b1b604482015290519081900360640190fd5b82156107cc57610789866001600160a01b031661106c565b6107cc576040805162461bcd60e51b815260206004820152600f60248201526e1393d7d0d3d11157d05517d11154d5608a1b604482015290519081900360640190fd5b606980546001600160a01b0319811633179091556040516001600160a01b0391821691881690879087908790808383808284376040519201945060009350909150508083038185875af1925050503d8060008114610846576040519150601f19603f3d011682016040523d82523d6000602084013e61084b565b606091505b50606980546001600160a01b0319166001600160a01b0385811691909117909155604080518a81526020810182815291810189905293965091945089169133917f2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d466918a918a918a9160608201848480828437600083820152604051601f909101601f1916909201829003965090945050505050a35094509492505050565b6069546001600160a01b031681565b6001600160a01b031660009081526065602052604090206001015460ff1690565b610921610fba565b6001600160a01b03166109326106f9565b6001600160a01b03161461097b576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152606660209081526040918290206001810154835186151581529351919460ff9091169390927f49477e7356dbcb654ab85d7534b50126772d938130d1350e23e2540370c8dffa92918290030190a28080156109e25750825b806109f45750801580156109f4575082155b15610a00575050610b8e565b8215610a8f57604080518082018252606880548252600160208084018281526001600160a01b038a16600081815260669093529582209451855551938201805460ff1916941515949094179093558154908101825591527fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c220977530180546001600160a01b0319169091179055610b8b565b606880546000198101908110610aa157fe5b6000918252602090912001548254606880546001600160a01b03909316929091908110610aca57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160000154606660006068856000015481548110610b1257fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020556068805480610b4257fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526066905260408120908155600101805460ff191690555b50505b5050565b606a8181548110610b9f57fe5b600091825260209091200154905081565b610bb8610fba565b6001600160a01b0316610bc96106f9565b6001600160a01b031614610c12576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152606560209081526040918290206001810154835186151581529351919460ff9091169390927f6675ce8882cb71637de5903a193d218cc0544be9c0650cb83e0955f6aa2bf52192918290030190a2808015610c795750825b80610c8b575080158015610c8b575082155b15610c97575050610b8e565b8215610d2657604080518082018252606780548252600160208084018281526001600160a01b038a16600081815260659093529582209451855551938201805460ff1916941515949094179093558154908101825591527f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae0180546001600160a01b0319169091179055610b8b565b606780546000198101908110610d3857fe5b6000918252602090912001548254606780546001600160a01b03909316929091908110610d6157fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160000154606560006067856000015481548110610da957fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020556067805480610dd957fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526065905260408120908155600101805460ff1916905550505050565b610e2f610fba565b6001600160a01b0316610e406106f9565b6001600160a01b031614610e89576040805162461bcd60e51b8152602060048201819052602482015260008051602061124e833981519152604482015290519081900360640190fd5b6001600160a01b038116610ece5760405162461bcd60e51b81526004018080602001828103825260268152602001806111fa6026913960400191505060405180910390fd5b6033546040516001600160a01b0380841692169060008051602061126e83398151915290600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b6040805160f89890981b6001600160f81b0319166020808a019190915260609790971b6bffffffffffffffffffffffff19166021890152603588019590955260558701939093526075860191909152609585015260b5808501919091528151808503909101815260d59093019052815191012090565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b3390565b6000610fc93061106c565b15905090565b600054610100900460ff1680610fe85750610fe8610fbe565b80610ff6575060005460ff16155b6110315760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff1615801561105c576000805460ff1961ff0019909116610100171660011790555b611064611072565b6106e4611112565b3b151590565b600054610100900460ff168061108b575061108b610fbe565b80611099575060005460ff16155b6110d45760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff161580156106e4576000805460ff1961ff00199091166101001716600117905580156106f6576000805461ff001916905550565b600054610100900460ff168061112b575061112b610fbe565b80611139575060005460ff16155b6111745760405162461bcd60e51b815260040180806020018281038252602e815260200180611220602e913960400191505060405180910390fd5b600054610100900460ff1615801561119f576000805460ff1961ff0019909116610100171660011790555b60006111a9610fba565b603380546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602061126e833981519152908290a35080156106f6576000805461ff00191690555056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65644f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a2646970667358221220e0c6592adeab5e479b23743fe54cacd75233b9d3d3c962be1a93fd94f81eb19c64736f6c634300060b0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 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.